Permalink
Browse files

Be compatible with other implementation of su

o use getopt_long(3), so -l, --login can be allowed anywhere in the argument list
o add -m and -p which do nothing
o su -h outputs usage in stdout and exits with 0 while
  su with invalid options outputs usage in stderr and exits with 2 now
  • Loading branch information...
git-core
git-core committed Dec 28, 2011
1 parent da86864 commit fc7479fab2d9d85c7c1f0bf1fee523a69d477a40
Showing with 65 additions and 54 deletions.
  1. +65 −54 su.c
View
119 su.c
@@ -28,11 +28,10 @@
#include <fcntl.h>

This comment has been minimized.

Show comment
Hide comment
@wowwow21098
@wowwow21098
#include <errno.h>
#include <endian.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

This comment has been minimized.

Show comment
Hide comment
@robertolson
#include <getopt.h>
#include <stdint.h>
#include <pwd.h>
@@ -253,23 +252,22 @@ static int socket_receive_result(int fd, char *result, ssize_t result_len)
return 0;
}
static void usage(void)
static void usage(int status)
{

This comment has been minimized.

Show comment
Hide comment
printf("Usage: su [options] [LOGIN]\n\n");
printf("Options:\n");
printf(" -c, --command COMMAND pass COMMAND to the invoked shell\n");
printf(" -h, --help display this help message and exit\n");
printf(" -, -l, --login make the shell a login shell\n");
// I'll look more into this to figure out what it's about,
// maybe implement it later

This comment has been minimized.

Show comment
Hide comment
@wowwow21098
@wowwow21098
// printf(" -m, -p,\n");
// printf(" --preserve-environment do not reset environment variables, and\n");
// printf(" keep the same shell\n");
printf(" -s, --shell SHELL use SHELL instead of the default in passwd\n");
printf(" -v, --version display version number and exit\n");
printf(" -V display version code and exit. this is\n");
printf(" used almost exclusively by Superuser.apk\n");
exit(EXIT_SUCCESS);
FILE *stream = (status == EXIT_SUCCESS) ? stdout : stderr;
fprintf(stream,
"Usage: su [options] [LOGIN]\n\n"
"Options:\n"
" -c, --command COMMAND pass COMMAND to the invoked shell\n"
" -h, --help display this help message and exit\n"
" -, -l, --login, -m, -p,\n"
" --preserve-environment do nothing, kept for compatibility\n"
" -s, --shell SHELL use SHELL instead of the default " DEFAULT_COMMAND "\n"
" -v, --version display version number and exit\n"
" -V display version code and exit,\n"
" this is used almost exclusively by Superuser.apk\n");
exit(status);
}
static void deny(void)
@@ -293,8 +291,8 @@ static void allow(char *shell, mode_t mask)
umask(mask);
send_intent(&su_from, &su_to, "", 1, 1);
if (!strcmp(shell, "")) {
strcpy(shell , DEFAULT_COMMAND);
if (!shell) {
shell = DEFAULT_COMMAND;
}
exe = strrchr (shell, '/');
exe = (exe) ? exe + 1 : shell;
@@ -317,48 +315,61 @@ int main(int argc, char *argv[])
{
struct stat st;
int socket_serv_fd, fd;
char buf[64], shell[PATH_MAX], *result;

This comment has been minimized.

Show comment
Hide comment
@robertolson
int i, dballow;
char buf[64], *shell = NULL, *result;
int c, dballow;
mode_t orig_umask;
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-c") || !strcmp(argv[i], "--command")) {
if (++i < argc) {
su_to.command = argv[i];
} else {
usage();
}
} else if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--shell")) {
if (++i < argc) {
strncpy(shell, argv[i], sizeof(shell));
shell[sizeof(shell) - 1] = 0;
} else {
usage();
}
} else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
printf("%s\n", VERSION);
exit(EXIT_SUCCESS);
} else if (!strcmp(argv[i], "-V")) {
printf("%d\n", VERSION_CODE);
exit(EXIT_SUCCESS);
} else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
usage();
} else if (!strcmp(argv[i], "-") || !strcmp(argv[i], "-l") ||
!strcmp(argv[i], "--login")) {
++i;
struct option long_opts[] = {
{ "command", required_argument, NULL, 'c' },
{ "help", no_argument, NULL, 'h' },
{ "login", no_argument, NULL, 'l' },
{ "preserve-environment", no_argument, NULL, 'p' },
{ "shell", required_argument, NULL, 's' },
{ "version", no_argument, NULL, 'v' },
{ NULL, 0, NULL, 0 },
};
while ((c = getopt_long(argc, argv, "c:hlmps:Vv", long_opts, NULL)) != -1) {
switch(c) {
case 'c':
su_to.command = optarg;
break;
} else {
case 'h':
usage(EXIT_SUCCESS);
break;
case 'l': /* for compatibility */
case 'm':
case 'p':
break;
case 's':
shell = optarg;
break;
case 'V':
printf("%d\n", VERSION_CODE);
exit(EXIT_SUCCESS);
case 'v':
printf("%s\n", VERSION);
exit(EXIT_SUCCESS);
default:
/* Bionic getopt_long doesn't terminate its error output by newline */
fprintf(stderr, "\n");
usage(2);
}
}
if (i < argc-1) {
usage();
if (optind < argc && !strcmp(argv[optind], "-")) {
optind++;
}
/*
* Other su implementations pass the remaining args to the shell.
* -- maybe implement this later
*/
if (optind < argc - 1) {
usage(2);
}
if (i == argc-1) {
if (optind == argc - 1) {
struct passwd *pw;
pw = getpwnam(argv[i]);
pw = getpwnam(argv[optind]);
if (!pw) {
su_to.uid = atoi(argv[i]);
su_to.uid = atoi(argv[optind]);
} else {
su_to.uid = pw->pw_uid;
}

1 comment on commit fc7479f

@pig670623

This comment has been minimized.

Show comment
Hide comment
Please sign in to comment.