>From d6d980cc3a9b8f5b4df7a6e284944bfe5f905b19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A1draig=20Brady?= Date: Sun, 23 Sep 2018 20:50:07 -0700 Subject: [PATCH] id: adjustments to multiuser patch will merge with original --- NEWS | 4 +++ doc/coreutils.texi | 5 +++- src/id.c | 79 ++++++++++++++++++++++++++++-------------------------- tests/id/uid.sh | 5 ++++ tests/id/zero.sh | 13 +++++---- 5 files changed, 62 insertions(+), 44 deletions(-) diff --git a/NEWS b/NEWS index aa3b4f9..77c26df 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,10 @@ GNU coreutils NEWS -*- outline -*- df no longer corrupts displayed multibyte characters on macOS. +** New features + + id now supports specifying multiple users. + * Noteworthy changes in release 8.30 (2018-07-01) [stable] diff --git a/doc/coreutils.texi b/doc/coreutils.texi index 6eaeea0..e148e88 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi @@ -15273,8 +15273,11 @@ set the exit status to 1. @itemx --zero @opindex -z @opindex --zero -Delimit output items with NUL characters. +Delimit output items with ASCII NUL characters. This option is not permitted when using the default format. +When multiple users are specified, and the @option{--groups} option +is also in effect, groups are delimited with a single NUL character, +while users are delimited with two NUL characters. Example: @example diff --git a/src/id.c b/src/id.c index e608038..2f89736 100644 --- a/src/id.c +++ b/src/id.c @@ -44,15 +44,15 @@ /* If nonzero, output only the SELinux context. */ static bool just_context = 0; /* If true, delimit entries with NUL characters, not whitespace */ -bool opt_zero = false; +static bool opt_zero = false; /* If true, output the list of all group IDs. -G */ -bool just_group_list = false; +static bool just_group_list = false; /* If true, output only the group ID(s). -g */ -bool just_group = false; +static bool just_group = false; /* If true, output real UID/GID instead of default effective UID/GID. -r */ -bool use_real = false; +static bool use_real = false; /* If true, output only the user ID(s). -u */ -bool just_user = false; +static bool just_user = false; /* True unless errors have been encountered. */ static bool ok = true; /* If true, we are using multiple users. Terminate -G with double NUL. */ @@ -70,7 +70,7 @@ static char *context = NULL; static void print_user (uid_t uid); static void print_full_info (const char *username); -static void print_stuff(const char *pw_name); +static void print_stuff (const char *pw_name); static struct option const longopts[] = { @@ -95,7 +95,7 @@ usage (int status) { printf (_("Usage: %s [OPTION]... [USER]...\n"), program_name); fputs (_("\ -Print user and group information for the each specified USER,\n\ +Print user and group information for each specified USER,\n\ or (when USER omitted) for the current user.\n\ \n"), stdout); @@ -225,43 +225,44 @@ main (int argc, char **argv) } if (n_ids >= 1) - { + { multiple_users = n_ids > 1 ? true : false; /* Changing the value of n_ids to the last index in the array where we have the last possible user id. This helps us because we don't have - to declare a different variable to keep a track of where the last username - lies in argv[]. */ + to declare a different variable to keep a track of where the + last username lies in argv[]. */ n_ids += optind; /* For each username/userid to get its pw_name field */ for (; optind < n_ids; optind++) - { + { struct passwd *pwd = NULL; const char *spec = argv[optind]; /* Disallow an empty spec here as parse_user_spec() doesn't give an error for that as it seems it's a valid way to specify a noop or "reset special bits" depending on the system. */ - if (*spec) { - if (parse_user_spec(spec, &euid, NULL, NULL, NULL) == NULL) - { + if (*spec) + { + if (parse_user_spec (spec, &euid, NULL, NULL, NULL) == NULL) + { /* parse_user_spec will only extract a numeric spec, so we lookup that here to verify and also retrieve the PW_NAME used subsequently in group lookup. */ - pwd = getpwuid(euid); - } - } + pwd = getpwuid (euid); + } + } if (pwd == NULL) - { - error (0, errno, _("%s: no such user"), quote (argv[optind])); - ok &= false; - continue; - } - pw_name = xstrdup(pwd->pw_name); + { + error (0, errno, _("%s: no such user"), quote (argv[optind])); + ok &= false; + continue; + } + pw_name = xstrdup (pwd->pw_name); ruid = euid = pwd->pw_uid; rgid = egid = pwd->pw_gid; - print_stuff(pw_name); - IF_LINT (free (pw_name)); - } - } + print_stuff (pw_name); + free (pw_name); + } + } else { /* POSIX says identification functions (getuid, getgid, and @@ -300,8 +301,7 @@ main (int argc, char **argv) if (rgid == NO_GID && errno) die (EXIT_FAILURE, errno, _("cannot get real GID")); } - print_stuff(pw_name); - IF_LINT (free (pw_name)); + print_stuff (pw_name); } return ok ? EXIT_SUCCESS : EXIT_FAILURE; @@ -429,7 +429,7 @@ print_full_info (const char *username) /* Print information about the user based on the arguments passed. */ static void -print_stuff(const char *pw_name) +print_stuff (const char *pw_name) { if (just_user) print_user (use_real ? ruid : euid); @@ -440,22 +440,25 @@ print_stuff(const char *pw_name) users faced a problem in these functions. This value of 'ok' is later used to understand what status program should exit with. */ else if (just_group) - ok &= print_group (use_real ? rgid : egid, use_name); + ok &= print_group (use_real ? rgid : egid, use_name); else if (just_group_list) - ok &= print_group_list (pw_name, ruid, rgid, egid, - use_name, opt_zero ? '\0' : ' '); + ok &= print_group_list (pw_name, ruid, rgid, egid, + use_name, opt_zero ? '\0' : ' '); else if (just_context) - fputs (context, stdout); + fputs (context, stdout); else - print_full_info (pw_name); + print_full_info (pw_name); + /* When printing records for more than 1 user, at the end of groups of each user terminate the record with two consequent NUL characters to make parsing and distinguishing between two records possible. */ - if (opt_zero && just_group_list && multiple_users) + if (opt_zero && just_group_list && multiple_users) { - putchar('\0'); - putchar('\0'); + putchar ('\0'); + putchar ('\0'); } else + { putchar (opt_zero ? '\0' : '\n'); + } } diff --git a/tests/id/uid.sh b/tests/id/uid.sh index 61d3137..9d85643 100755 --- a/tests/id/uid.sh +++ b/tests/id/uid.sh @@ -24,6 +24,11 @@ user=$(id -nu) || fail=1 # Ensure the empty user spec is discarded returns_ 1 id '' || fail=1 +# Ensure we don't exit early, and process all users +id $user > user_out || fail=1 +returns_ 1 id '' $user >multi_user_out || fail=1 +compare user_out multi_user_out || fail=1 + for mode in '' '-G' '-g'; do id $mode $user > user_out || fail=1 # lookup name for comparison diff --git a/tests/id/zero.sh b/tests/id/zero.sh index 7a94edd..d0cf44c 100755 --- a/tests/id/zero.sh +++ b/tests/id/zero.sh @@ -78,9 +78,12 @@ for o in g gr u ur ; do done compare tmp1 tmp3 || fail=1 -# Seperate checks when we are testing for multiple users && -G. -# This is done because we terminate the records with two consequent -# NULs instead of the regular single NUL. +# Separate checks when we are testing for multiple users && -G. +# This is done because we terminate the records with two NULs +# instead of a regular single NUL. + +NL=' +' for o in G Gr ; do for n in '' n ; do @@ -89,10 +92,10 @@ for o in G Gr ; do id -${o}${n}z $users > gtmp2 || { test $? -ne 1 || test -z "$n" && fail=1; } # we replace all NULs with spaces, the result we get is there are two - # consequent spaces instead of two consequent NUL's, we pass this to sed + # consecutive spaces instead of two NUL's, we pass this to sed # to replace more than 1 space with a newline. This is ideally where a new # line should be. This should make the output similar to without -z. - tr '\0' ' ' < gtmp2 | sed 's/ \+ /\n/g' >> gtmp3 + tr '\0' ' ' < gtmp2 | sed "s/ /\\$NL/g" >> gtmp3 done done compare gtmp1 gtmp3 || fail=1 -- 2.9.3