@@ -200,7 +200,10 @@ impl Install {
200200 ) ?;
201201
202202 if !self . bypass_root_check {
203- escalate_root ( ) ;
203+ anyhow:: ensure!(
204+ elevate:: check( ) == elevate:: RunningAs :: User ,
205+ "Running as root is not recommended. Use --bypass-root-check to override."
206+ ) ;
204207 }
205208
206209 let ( mut ext_dir, mut php_ini) = if let Some ( install_dir) = self . install_dir {
@@ -231,43 +234,74 @@ impl Install {
231234 ext_dir. push ( ext_name) ;
232235 }
233236
234- std :: fs :: copy ( & ext_path, & ext_dir) . with_context ( || {
237+ copy_extension ( & ext_path, & ext_dir) . with_context ( || {
235238 "Failed to copy extension from target directory to extension directory"
236239 } ) ?;
237240
238241 if let Some ( php_ini) = php_ini {
239- let mut file = OpenOptions :: new ( )
242+ copy_ini_file ( & php_ini, ext_name, self . disable )
243+ . with_context ( || "Failed to update `php.ini`" ) ?;
244+ }
245+
246+ Ok ( ( ) )
247+ }
248+ }
249+
250+ // Copy ini file, if fails, try with sudo again.
251+ fn copy_ini_file ( php_ini : & PathBuf , ext_name : & str , disable : bool ) -> anyhow:: Result < ( ) > {
252+ let mut file = match OpenOptions :: new ( ) . read ( true ) . write ( true ) . open ( php_ini) {
253+ Ok ( x) => x,
254+ Err ( _e) => {
255+ #[ cfg( unix) ]
256+ {
257+ elevate:: escalate_if_needed ( ) . expect ( "sudo failed" ) ;
258+ }
259+ OpenOptions :: new ( )
240260 . read ( true )
241261 . write ( true )
242262 . open ( php_ini)
243- . with_context ( || "Failed to open `php.ini`" ) ?;
263+ . with_context ( || "Failed to open `php.ini`" ) ?
264+ }
265+ } ;
244266
245- let mut ext_line = format ! ( "extension={ext_name}" ) ;
267+ let mut ext_line = format ! ( "extension={ext_name}" ) ;
246268
247- let mut new_lines = vec ! [ ] ;
248- for line in BufReader :: new ( & file) . lines ( ) {
249- let line = line. with_context ( || "Failed to read line from `php.ini`" ) ?;
250- if line. contains ( & ext_line) {
251- bail ! ( "Extension already enabled." ) ;
252- }
269+ let mut new_lines = vec ! [ ] ;
270+ for line in BufReader :: new ( & file) . lines ( ) {
271+ let line = line. with_context ( || "Failed to read line from `php.ini`" ) ?;
272+ if line. contains ( & ext_line) {
273+ bail ! ( "Extension already enabled." ) ;
274+ }
253275
254- new_lines. push ( line) ;
255- }
276+ new_lines. push ( line) ;
277+ }
256278
257- // Comment out extension if user specifies disable flag
258- if self . disable {
259- ext_line. insert ( 0 , ';' ) ;
260- }
279+ // Comment out extension if user specifies disable flag
280+ if disable {
281+ ext_line. insert ( 0 , ';' ) ;
282+ }
261283
262- new_lines. push ( ext_line) ;
263- file. rewind ( ) ?;
264- file. set_len ( 0 ) ?;
265- file. write ( new_lines. join ( "\n " ) . as_bytes ( ) )
266- . with_context ( || "Failed to update `php.ini`" ) ? ;
267- }
284+ new_lines. push ( ext_line) ;
285+ file. rewind ( ) ?;
286+ file. set_len ( 0 ) ?;
287+ let _ = file. write ( new_lines. join ( "\n " ) . as_bytes ( ) ) ? ;
288+ Ok ( ( ) )
289+ }
268290
269- Ok ( ( ) )
291+ // Copy extension, if fails, try with sudo again.
292+ //
293+ // We can check if we have write permission for ext_dir but due to ACL, group
294+ // list and and other nuances, it may not be reliable. See
295+ // https://doc.rust-lang.org/std/fs/struct.Permissions.html#method.readonly
296+ fn copy_extension ( ext_path : & Utf8PathBuf , ext_dir : & PathBuf ) -> anyhow:: Result < ( ) > {
297+ if let Err ( _e) = std:: fs:: copy ( ext_path, ext_dir) {
298+ #[ cfg( unix) ]
299+ {
300+ elevate:: escalate_if_needed ( ) . expect ( "sudo failed" ) ;
301+ }
302+ std:: fs:: copy ( ext_path, ext_dir) ?;
270303 }
304+ Ok ( ( ) )
271305}
272306
273307/// Returns the path to the extension directory utilised by the PHP interpreter,
@@ -328,12 +362,6 @@ impl Remove {
328362
329363 let artifact = find_ext ( self . manifest . as_ref ( ) ) ?;
330364
331- // Must be called after cargo_manifest call in find_path. Though we are setting PATHso that
332- // sudo can find cargo but cargo_manifest doesn't use PATH to locate cargo!
333- if !self . bypass_root_check {
334- escalate_root ( ) ;
335- }
336-
337365 let ( mut ext_path, mut php_ini) = if let Some ( install_dir) = self . install_dir {
338366 ( install_dir, None )
339367 } else {
@@ -584,12 +612,3 @@ fn build_ext(
584612
585613 bail ! ( "Failed to retrieve extension path from artifact" )
586614}
587-
588- fn escalate_root ( ) {
589- // use sudo and pass PATH for command like `cargo metadata` to keep working.
590- #[ cfg( unix) ]
591- {
592- sudo:: with_env ( & [ "CARGO" , "PATH" ] )
593- . expect ( "sudo failed! Use --bypass-root-check to disable." ) ;
594- }
595- }
0 commit comments