@@ -142,6 +142,7 @@ struct Remove {
142142 /// Whether to bypass the remove prompt.
143143 #[ clap( long) ]
144144 yes : bool ,
145+ #[ cfg( unix) ]
145146 /// Whether to bypass the root check
146147 #[ clap( long) ]
147148 bypass_root_check : bool ,
@@ -198,12 +199,11 @@ impl Install {
198199 self . no_default_features ,
199200 ) ?;
200201
201- if !self . bypass_root_check {
202- anyhow:: ensure!(
203- elevate:: check( ) == elevate:: RunningAs :: User ,
204- "Running as root is not recommended. Use --bypass-root-check to override."
205- ) ;
206- }
202+ #[ cfg( unix) ]
203+ anyhow:: ensure!(
204+ self . bypass_root_check || !is_root( ) ,
205+ "Running as root is not recommended. Use --bypass-root-check to override."
206+ ) ;
207207
208208 let ( mut ext_dir, mut php_ini) = if let Some ( install_dir) = self . install_dir {
209209 ( install_dir, None )
@@ -246,10 +246,10 @@ impl Install {
246246 }
247247}
248248
249- // Update extension information in the ini file, if fails, try with sudo again .
250- //
251- // Write to a temp file then move it to given path. Use `sudo` on unix to move
252- // file if needed .
249+ /// Update extension line in the ini file.
250+ ///
251+ /// Write to a temp file then copy it to a given path. If this fails, then try
252+ /// `sudo mv` on unix .
253253fn update_ini_file ( php_ini : & PathBuf , ext_name : & str , disable : bool ) -> anyhow:: Result < ( ) > {
254254 let current_ini_content = std:: fs:: read_to_string ( php_ini) ?;
255255 let mut ext_line = format ! ( "extension={ext_name}" ) ;
@@ -267,25 +267,29 @@ fn update_ini_file(php_ini: &PathBuf, ext_name: &str, disable: bool) -> anyhow::
267267 }
268268
269269 new_lines. push ( & ext_line) ;
270+
270271 write_to_file ( new_lines. join ( "\n " ) , php_ini) ?;
271272 Ok ( ( ) )
272273}
273274
274- // Copy extension, if fails, try with sudo cp.
275- //
276- // Checking if we have write permission for ext_dir may fail due to ACL, group
277- // list and and other nuances. See
278- // https://doc.rust-lang.org/std/fs/struct.Permissions.html#method.readonly
275+ /// Copy extension, if fails, try with sudo cp.
276+ ///
277+ /// Checking if we have write permission for ext_dir may fail due to ACL, group
278+ /// list and and other nuances. See
279+ /// https://doc.rust-lang.org/std/fs/struct.Permissions.html#method.readonly.
279280fn copy_extension ( ext_path : & Utf8PathBuf , ext_dir : & PathBuf ) -> anyhow:: Result < ( ) > {
280281 if let Err ( _e) = std:: fs:: copy ( ext_path, ext_dir) {
281282 #[ cfg( unix) ]
282283 {
283- let _ = std:: process:: Command :: new ( "sudo" )
284+ let s = std:: process:: Command :: new ( "sudo" )
284285 . arg ( "cp" )
285286 . arg ( ext_path)
286287 . arg ( ext_dir)
287288 . status ( ) ?;
289+ anyhow:: ensure!( s. success( ) , "Failed to copy extension" ) ;
288290 }
291+ #[ cfg( not( unix) ) ]
292+ anyhow:: bail!( "Failed to copy extension: {_e}" ) ;
289293 }
290294 Ok ( ( ) )
291295}
@@ -599,28 +603,27 @@ fn build_ext(
599603 bail ! ( "Failed to retrieve extension path from artifact" )
600604}
601605
602- // Write given string to a given filepath.
603- //
604- // - Write to a temp file first.
605- // - Copy the temp file to the given filepath.
606- // - If it fails, move tempfile using `sudo mv`.
607- //
608- // TODO: Try with sudo when error is permission related.
606+ /// Write content to a given filepath.
607+ ///
608+ /// We may not have write permission but we may have sudo privilege on unix. So
609+ /// we write to a temp file and then try moving it to given filepath, and retry
610+ /// with sudo on unix.
609611fn write_to_file ( content : String , filepath : & PathBuf ) -> anyhow:: Result < ( ) > {
610612 // write to a temp file
611613 let tempf = std:: env:: temp_dir ( ) . join ( "__tmp_cargo_php" ) ;
612614 std:: fs:: write ( & tempf, content) ?;
613615
614- // Now move. `rename` will overwrite existing file.
616+ // Now try moving, `rename` will overwrite existing file.
615617 if std:: fs:: rename ( & tempf, filepath) . is_err ( ) {
616618 #[ cfg( unix) ]
617619 {
618620 // if not successful, try with sudo on unix.
619- let _ = std:: process:: Command :: new ( "sudo" )
621+ let s = std:: process:: Command :: new ( "sudo" )
620622 . arg ( "mv" )
621623 . arg ( & tempf)
622624 . arg ( filepath)
623625 . status ( ) ?;
626+ anyhow:: ensure!( s. success( ) , "Falied to write to {filepath:?}" ) ;
624627 }
625628
626629 #[ cfg( not( unix) ) ]
@@ -629,3 +632,14 @@ fn write_to_file(content: String, filepath: &PathBuf) -> anyhow::Result<()> {
629632
630633 Ok ( ( ) )
631634}
635+
636+ #[ cfg( unix) ]
637+ fn is_root ( ) -> bool {
638+ let uid = unsafe { libc:: getuid ( ) } ;
639+ let euid = unsafe { libc:: geteuid ( ) } ;
640+
641+ match ( uid, euid) {
642+ ( _, 0 ) => true , // suid set
643+ ( _, _) => false ,
644+ }
645+ }
0 commit comments