@@ -200,7 +200,10 @@ impl Install {
200
200
) ?;
201
201
202
202
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
+ ) ;
204
207
}
205
208
206
209
let ( mut ext_dir, mut php_ini) = if let Some ( install_dir) = self . install_dir {
@@ -231,43 +234,74 @@ impl Install {
231
234
ext_dir. push ( ext_name) ;
232
235
}
233
236
234
- std :: fs :: copy ( & ext_path, & ext_dir) . with_context ( || {
237
+ copy_extension ( & ext_path, & ext_dir) . with_context ( || {
235
238
"Failed to copy extension from target directory to extension directory"
236
239
} ) ?;
237
240
238
241
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 ( )
240
260
. read ( true )
241
261
. write ( true )
242
262
. open ( php_ini)
243
- . with_context ( || "Failed to open `php.ini`" ) ?;
263
+ . with_context ( || "Failed to open `php.ini`" ) ?
264
+ }
265
+ } ;
244
266
245
- let mut ext_line = format ! ( "extension={ext_name}" ) ;
267
+ let mut ext_line = format ! ( "extension={ext_name}" ) ;
246
268
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
+ }
253
275
254
- new_lines. push ( line) ;
255
- }
276
+ new_lines. push ( line) ;
277
+ }
256
278
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
+ }
261
283
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
+ }
268
290
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) ?;
270
303
}
304
+ Ok ( ( ) )
271
305
}
272
306
273
307
/// Returns the path to the extension directory utilised by the PHP interpreter,
@@ -328,12 +362,6 @@ impl Remove {
328
362
329
363
let artifact = find_ext ( self . manifest . as_ref ( ) ) ?;
330
364
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
-
337
365
let ( mut ext_path, mut php_ini) = if let Some ( install_dir) = self . install_dir {
338
366
( install_dir, None )
339
367
} else {
@@ -584,12 +612,3 @@ fn build_ext(
584
612
585
613
bail ! ( "Failed to retrieve extension path from artifact" )
586
614
}
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