@@ -121,6 +121,9 @@ struct Install {
121
121
/// Whether to bypass the install prompt.
122
122
#[ clap( long) ]
123
123
yes : bool ,
124
+ /// Whether to bypass the root check
125
+ #[ clap( long) ]
126
+ bypass_root_check : bool ,
124
127
}
125
128
126
129
#[ derive( Parser ) ]
@@ -140,6 +143,9 @@ struct Remove {
140
143
/// Whether to bypass the remove prompt.
141
144
#[ clap( long) ]
142
145
yes : bool ,
146
+ /// Whether to bypass the root check
147
+ #[ clap( long) ]
148
+ bypass_root_check : bool ,
143
149
}
144
150
145
151
#[ cfg( not( windows) ) ]
@@ -193,6 +199,13 @@ impl Install {
193
199
self . no_default_features ,
194
200
) ?;
195
201
202
+ if !self . bypass_root_check {
203
+ anyhow:: ensure!(
204
+ elevate:: check( ) == elevate:: RunningAs :: User ,
205
+ "Running as root is not recommended. Use --bypass-root-check to override."
206
+ ) ;
207
+ }
208
+
196
209
let ( mut ext_dir, mut php_ini) = if let Some ( install_dir) = self . install_dir {
197
210
( install_dir, None )
198
211
} else {
@@ -221,50 +234,74 @@ impl Install {
221
234
ext_dir. push ( ext_name) ;
222
235
}
223
236
224
- // We copying of file fails, escalate the privilege and try again.
225
- if let Err ( _) = std:: fs:: copy ( & ext_path, & ext_dir) {
226
- // failed to copy. escalate the privileges and try again.
227
- #[ cfg( unix) ]
228
- let _ = sudo:: escalate_if_needed ( ) . ok ( ) ;
237
+ copy_extension ( & ext_path, & ext_dir) . with_context ( || {
238
+ "Failed to copy extension from target directory to extension directory"
239
+ } ) ?;
229
240
230
- std :: fs :: copy ( & ext_path , & ext_dir ) . with_context ( || {
231
- "Failed to copy extension from target directory to extension directory"
232
- } ) ?;
241
+ if let Some ( php_ini ) = php_ini {
242
+ copy_ini_file ( & php_ini , ext_name , self . disable )
243
+ . with_context ( || "Failed to update `php.ini`" ) ?;
233
244
}
234
245
235
- if let Some ( php_ini) = php_ini {
236
- let mut file = OpenOptions :: new ( )
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 ( )
237
260
. read ( true )
238
261
. write ( true )
239
262
. open ( php_ini)
240
- . with_context ( || "Failed to open `php.ini`" ) ?;
263
+ . with_context ( || "Failed to open `php.ini`" ) ?
264
+ }
265
+ } ;
241
266
242
- let mut ext_line = format ! ( "extension={ext_name}" ) ;
267
+ let mut ext_line = format ! ( "extension={ext_name}" ) ;
243
268
244
- let mut new_lines = vec ! [ ] ;
245
- for line in BufReader :: new ( & file) . lines ( ) {
246
- let line = line. with_context ( || "Failed to read line from `php.ini`" ) ?;
247
- if line. contains ( & ext_line) {
248
- bail ! ( "Extension already enabled." ) ;
249
- }
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
+ }
250
275
251
- new_lines. push ( line) ;
252
- }
276
+ new_lines. push ( line) ;
277
+ }
253
278
254
- // Comment out extension if user specifies disable flag
255
- if self . disable {
256
- ext_line. insert ( 0 , ';' ) ;
257
- }
279
+ // Comment out extension if user specifies disable flag
280
+ if disable {
281
+ ext_line. insert ( 0 , ';' ) ;
282
+ }
258
283
259
- new_lines. push ( ext_line) ;
260
- file. rewind ( ) ?;
261
- file. set_len ( 0 ) ?;
262
- file. write ( new_lines. join ( "\n " ) . as_bytes ( ) )
263
- . with_context ( || "Failed to update `php.ini`" ) ? ;
264
- }
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
+ }
265
290
266
- 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) ?;
267
303
}
304
+ Ok ( ( ) )
268
305
}
269
306
270
307
/// Returns the path to the extension directory utilised by the PHP interpreter,
0 commit comments