28
28
#include <fcntl.h>
29
29
#include <errno.h>
30
30
#include <endian.h>
31
-
32
31
#include <stdio.h>
33
32
#include <stdlib.h>
34
33
#include <string.h>
35
-
34
+ #include <getopt.h>
36
35
#include <stdint.h>
37
36
#include <pwd.h>
38
37
@@ -253,23 +252,22 @@ static int socket_receive_result(int fd, char *result, ssize_t result_len)
253
252
return 0 ;
254
253
}
255
254
256
- static void usage (void )
255
+ static void usage (int status )
257
256
{
258
- printf ("Usage: su [options] [LOGIN]\n\n" );
259
- printf ("Options:\n" );
260
- printf (" -c, --command COMMAND pass COMMAND to the invoked shell\n" );
261
- printf (" -h, --help display this help message and exit\n" );
262
- printf (" -, -l, --login make the shell a login shell\n" );
263
- // I'll look more into this to figure out what it's about,
264
- // maybe implement it later
265
- // printf(" -m, -p,\n");
266
- // printf(" --preserve-environment do not reset environment variables, and\n");
267
- // printf(" keep the same shell\n");
268
- printf (" -s, --shell SHELL use SHELL instead of the default in passwd\n" );
269
- printf (" -v, --version display version number and exit\n" );
270
- printf (" -V display version code and exit. this is\n" );
271
- printf (" used almost exclusively by Superuser.apk\n" );
272
- exit (EXIT_SUCCESS );
257
+ FILE * stream = (status == EXIT_SUCCESS ) ? stdout : stderr ;
258
+
259
+ fprintf (stream ,
260
+ "Usage: su [options] [LOGIN]\n\n"
261
+ "Options:\n"
262
+ " -c, --command COMMAND pass COMMAND to the invoked shell\n"
263
+ " -h, --help display this help message and exit\n"
264
+ " -, -l, --login, -m, -p,\n"
265
+ " --preserve-environment do nothing, kept for compatibility\n"
266
+ " -s, --shell SHELL use SHELL instead of the default " DEFAULT_COMMAND "\n"
267
+ " -v, --version display version number and exit\n"
268
+ " -V display version code and exit,\n"
269
+ " this is used almost exclusively by Superuser.apk\n" );
270
+ exit (status );
273
271
}
274
272
275
273
static void deny (void )
@@ -293,8 +291,8 @@ static void allow(char *shell, mode_t mask)
293
291
umask (mask );
294
292
send_intent (& su_from , & su_to , "" , 1 , 1 );
295
293
296
- if (!strcmp ( shell , "" ) ) {
297
- strcpy ( shell , DEFAULT_COMMAND ) ;
294
+ if (!shell ) {
295
+ shell = DEFAULT_COMMAND ;
298
296
}
299
297
exe = strrchr (shell , '/' );
300
298
exe = (exe ) ? exe + 1 : shell ;
@@ -317,48 +315,61 @@ int main(int argc, char *argv[])
317
315
{
318
316
struct stat st ;
319
317
int socket_serv_fd , fd ;
320
- char buf [64 ], shell [ PATH_MAX ] , * result ;
321
- int i , dballow ;
318
+ char buf [64 ], * shell = NULL , * result ;
319
+ int c , dballow ;
322
320
mode_t orig_umask ;
323
-
324
- for (i = 1 ; i < argc ; i ++ ) {
325
- if (!strcmp (argv [i ], "-c" ) || !strcmp (argv [i ], "--command" )) {
326
- if (++ i < argc ) {
327
- su_to .command = argv [i ];
328
- } else {
329
- usage ();
330
- }
331
- } else if (!strcmp (argv [i ], "-s" ) || !strcmp (argv [i ], "--shell" )) {
332
- if (++ i < argc ) {
333
- strncpy (shell , argv [i ], sizeof (shell ));
334
- shell [sizeof (shell ) - 1 ] = 0 ;
335
- } else {
336
- usage ();
337
- }
338
- } else if (!strcmp (argv [i ], "-v" ) || !strcmp (argv [i ], "--version" )) {
339
- printf ("%s\n" , VERSION );
340
- exit (EXIT_SUCCESS );
341
- } else if (!strcmp (argv [i ], "-V" )) {
342
- printf ("%d\n" , VERSION_CODE );
343
- exit (EXIT_SUCCESS );
344
- } else if (!strcmp (argv [i ], "-h" ) || !strcmp (argv [i ], "--help" )) {
345
- usage ();
346
- } else if (!strcmp (argv [i ], "-" ) || !strcmp (argv [i ], "-l" ) ||
347
- !strcmp (argv [i ], "--login" )) {
348
- ++ i ;
321
+ struct option long_opts [] = {
322
+ { "command" , required_argument , NULL , 'c' },
323
+ { "help" , no_argument , NULL , 'h' },
324
+ { "login" , no_argument , NULL , 'l' },
325
+ { "preserve-environment" , no_argument , NULL , 'p' },
326
+ { "shell" , required_argument , NULL , 's' },
327
+ { "version" , no_argument , NULL , 'v' },
328
+ { NULL , 0 , NULL , 0 },
329
+ };
330
+
331
+ while ((c = getopt_long (argc , argv , "c:hlmps:Vv" , long_opts , NULL )) != -1 ) {
332
+ switch (c ) {
333
+ case 'c' :
334
+ su_to .command = optarg ;
349
335
break ;
350
- } else {
336
+ case 'h' :
337
+ usage (EXIT_SUCCESS );
338
+ break ;
339
+ case 'l' : /* for compatibility */
340
+ case 'm' :
341
+ case 'p' :
342
+ break ;
343
+ case 's' :
344
+ shell = optarg ;
351
345
break ;
346
+ case 'V' :
347
+ printf ("%d\n" , VERSION_CODE );
348
+ exit (EXIT_SUCCESS );
349
+ case 'v' :
350
+ printf ("%s\n" , VERSION );
351
+ exit (EXIT_SUCCESS );
352
+ default :
353
+ /* Bionic getopt_long doesn't terminate its error output by newline */
354
+ fprintf (stderr , "\n" );
355
+ usage (2 );
352
356
}
353
357
}
354
- if (i < argc - 1 ) {
355
- usage ();
358
+ if (optind < argc && !strcmp (argv [optind ], "-" )) {
359
+ optind ++ ;
360
+ }
361
+ /*
362
+ * Other su implementations pass the remaining args to the shell.
363
+ * -- maybe implement this later
364
+ */
365
+ if (optind < argc - 1 ) {
366
+ usage (2 );
356
367
}
357
- if (i == argc - 1 ) {
368
+ if (optind == argc - 1 ) {
358
369
struct passwd * pw ;
359
- pw = getpwnam (argv [i ]);
370
+ pw = getpwnam (argv [optind ]);
360
371
if (!pw ) {
361
- su_to .uid = atoi (argv [i ]);
372
+ su_to .uid = atoi (argv [optind ]);
362
373
} else {
363
374
su_to .uid = pw -> pw_uid ;
364
375
}
0 commit comments