@@ -121,6 +121,9 @@ struct Install {
121121 /// Whether to bypass the install prompt.
122122 #[ clap( long) ]
123123 yes : bool ,
124+ /// Whether to bypass the root check
125+ #[ clap( long) ]
126+ bypass_root_check : bool ,
124127}
125128
126129#[ derive( Parser ) ]
@@ -140,6 +143,9 @@ struct Remove {
140143 /// Whether to bypass the remove prompt.
141144 #[ clap( long) ]
142145 yes : bool ,
146+ /// Whether to bypass the root check
147+ #[ clap( long) ]
148+ bypass_root_check : bool ,
143149}
144150
145151#[ cfg( not( windows) ) ]
@@ -193,6 +199,13 @@ impl Install {
193199 self . no_default_features ,
194200 ) ?;
195201
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+
196209 let ( mut ext_dir, mut php_ini) = if let Some ( install_dir) = self . install_dir {
197210 ( install_dir, None )
198211 } else {
@@ -221,50 +234,74 @@ impl Install {
221234 ext_dir. push ( ext_name) ;
222235 }
223236
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+ } ) ?;
229240
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`" ) ?;
233244 }
234245
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 ( )
237260 . read ( true )
238261 . write ( true )
239262 . open ( php_ini)
240- . with_context ( || "Failed to open `php.ini`" ) ?;
263+ . with_context ( || "Failed to open `php.ini`" ) ?
264+ }
265+ } ;
241266
242- let mut ext_line = format ! ( "extension={ext_name}" ) ;
267+ let mut ext_line = format ! ( "extension={ext_name}" ) ;
243268
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+ }
250275
251- new_lines. push ( line) ;
252- }
276+ new_lines. push ( line) ;
277+ }
253278
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+ }
258283
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+ }
265290
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) ?;
267303 }
304+ Ok ( ( ) )
268305}
269306
270307/// Returns the path to the extension directory utilised by the PHP interpreter,
0 commit comments