@@ -142,6 +142,7 @@ struct Remove {
142
142
/// Whether to bypass the remove prompt.
143
143
#[ clap( long) ]
144
144
yes : bool ,
145
+ #[ cfg( unix) ]
145
146
/// Whether to bypass the root check
146
147
#[ clap( long) ]
147
148
bypass_root_check : bool ,
@@ -198,12 +199,11 @@ impl Install {
198
199
self . no_default_features ,
199
200
) ?;
200
201
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
+ ) ;
207
207
208
208
let ( mut ext_dir, mut php_ini) = if let Some ( install_dir) = self . install_dir {
209
209
( install_dir, None )
@@ -246,10 +246,10 @@ impl Install {
246
246
}
247
247
}
248
248
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 .
253
253
fn update_ini_file ( php_ini : & PathBuf , ext_name : & str , disable : bool ) -> anyhow:: Result < ( ) > {
254
254
let current_ini_content = std:: fs:: read_to_string ( php_ini) ?;
255
255
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::
267
267
}
268
268
269
269
new_lines. push ( & ext_line) ;
270
+
270
271
write_to_file ( new_lines. join ( "\n " ) , php_ini) ?;
271
272
Ok ( ( ) )
272
273
}
273
274
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.
279
280
fn copy_extension ( ext_path : & Utf8PathBuf , ext_dir : & PathBuf ) -> anyhow:: Result < ( ) > {
280
281
if let Err ( _e) = std:: fs:: copy ( ext_path, ext_dir) {
281
282
#[ cfg( unix) ]
282
283
{
283
- let _ = std:: process:: Command :: new ( "sudo" )
284
+ let s = std:: process:: Command :: new ( "sudo" )
284
285
. arg ( "cp" )
285
286
. arg ( ext_path)
286
287
. arg ( ext_dir)
287
288
. status ( ) ?;
289
+ anyhow:: ensure!( s. success( ) , "Failed to copy extension" ) ;
288
290
}
291
+ #[ cfg( not( unix) ) ]
292
+ anyhow:: bail!( "Failed to copy extension: {_e}" ) ;
289
293
}
290
294
Ok ( ( ) )
291
295
}
@@ -599,28 +603,27 @@ fn build_ext(
599
603
bail ! ( "Failed to retrieve extension path from artifact" )
600
604
}
601
605
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.
609
611
fn write_to_file ( content : String , filepath : & PathBuf ) -> anyhow:: Result < ( ) > {
610
612
// write to a temp file
611
613
let tempf = std:: env:: temp_dir ( ) . join ( "__tmp_cargo_php" ) ;
612
614
std:: fs:: write ( & tempf, content) ?;
613
615
614
- // Now move. `rename` will overwrite existing file.
616
+ // Now try moving, `rename` will overwrite existing file.
615
617
if std:: fs:: rename ( & tempf, filepath) . is_err ( ) {
616
618
#[ cfg( unix) ]
617
619
{
618
620
// if not successful, try with sudo on unix.
619
- let _ = std:: process:: Command :: new ( "sudo" )
621
+ let s = std:: process:: Command :: new ( "sudo" )
620
622
. arg ( "mv" )
621
623
. arg ( & tempf)
622
624
. arg ( filepath)
623
625
. status ( ) ?;
626
+ anyhow:: ensure!( s. success( ) , "Falied to write to {filepath:?}" ) ;
624
627
}
625
628
626
629
#[ cfg( not( unix) ) ]
@@ -629,3 +632,14 @@ fn write_to_file(content: String, filepath: &PathBuf) -> anyhow::Result<()> {
629
632
630
633
Ok ( ( ) )
631
634
}
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