summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS3
-rw-r--r--doc/coreutils.texi22
-rw-r--r--src/group-list.c6
-rw-r--r--src/group-list.h2
-rw-r--r--src/groups.c6
-rw-r--r--src/id.c36
-rw-r--r--tests/local.mk1
-rwxr-xr-xtests/misc/id-zero.sh62
8 files changed, 115 insertions, 23 deletions
diff --git a/NEWS b/NEWS
index d26722ddf..23c7b54fd 100644
--- a/NEWS
+++ b/NEWS
@@ -44,6 +44,9 @@ GNU coreutils NEWS -*- outline -*-
du accepts a new option: --inodes to show the number of inodes instead
of the blocks used.
+ id accepts a new option: --zero (-z) to delimit the output entries by
+ a NUL instead of a white space character.
+
id and ls with -Z report the SMACK security context where available.
mkdir, mkfifo and mknod with -Z set the SMACK context where available.
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 21216b4be..d022c4560 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -14516,9 +14516,20 @@ Print only the security context of the current user.
If SELinux is disabled then print a warning and
set the exit status to 1.
-@end table
+@item -z
+@itemx --zero
+@opindex -z
+@opindex --zero
+Delimit output items with NUL characters.
+This option is not permitted when using the default format.
-@exitstatus
+Example:
+@example
+$ id -Gn --zero
+users <NUL> devs <NUL>
+@end example
+
+@end table
@macro primaryAndSupplementaryGroups{cmd,arg}
Primary and supplementary groups for a process are normally inherited
@@ -14530,6 +14541,8 @@ database to be consulted afresh, and so will give a different result.
@end macro
@primaryAndSupplementaryGroups{id,user argument}
+@exitstatus
+
@node logname invocation
@section @command{logname}: Print current login name
@@ -14587,13 +14600,12 @@ groups [@var{username}]@dots{}
The group lists are equivalent to the output of the command @samp{id -Gn}.
-@primaryAndSupplementaryGroups{groups,list of users}
-
The only options are @option{--help} and @option{--version}. @xref{Common
options}.
-@exitstatus
+@primaryAndSupplementaryGroups{groups,list of users}
+@exitstatus
@node users invocation
@section @command{users}: Print login names of users currently logged in
diff --git a/src/group-list.c b/src/group-list.c
index 7d4995b5c..d54b05776 100644
--- a/src/group-list.c
+++ b/src/group-list.c
@@ -35,7 +35,7 @@
extern bool
print_group_list (const char *username,
uid_t ruid, gid_t rgid, gid_t egid,
- bool use_names)
+ bool use_names, char delim)
{
bool ok = true;
struct passwd *pwd = NULL;
@@ -52,7 +52,7 @@ print_group_list (const char *username,
if (egid != rgid)
{
- putchar (' ');
+ putchar (delim);
if (!print_group (egid, use_names))
ok = false;
}
@@ -79,7 +79,7 @@ print_group_list (const char *username,
for (i = 0; i < n_groups; i++)
if (groups[i] != rgid && groups[i] != egid)
{
- putchar (' ');
+ putchar (delim);
if (!print_group (groups[i], use_names))
ok = false;
}
diff --git a/src/group-list.h b/src/group-list.h
index 3fac88719..573de1def 100644
--- a/src/group-list.h
+++ b/src/group-list.h
@@ -16,4 +16,4 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
bool print_group (gid_t, bool);
-bool print_group_list (const char *, uid_t, gid_t, gid_t, bool);
+bool print_group_list (const char *, uid_t, gid_t, gid_t, bool, char);
diff --git a/src/groups.c b/src/groups.c
index 53332d56b..d30c9fb41 100644
--- a/src/groups.c
+++ b/src/groups.c
@@ -114,13 +114,13 @@ main (int argc, char **argv)
if (rgid == NO_GID && errno)
error (EXIT_FAILURE, errno, _("cannot get real GID"));
- if (!print_group_list (NULL, ruid, rgid, egid, true))
+ if (!print_group_list (NULL, ruid, rgid, egid, true, ' '))
ok = false;
putchar ('\n');
}
else
{
- /* At least one argument. Divulge the details of the specified users. */
+ /* At least one argument. Divulge the details of the specified users. */
while (optind < argc)
{
struct passwd *pwd = getpwnam (argv[optind]);
@@ -130,7 +130,7 @@ main (int argc, char **argv)
rgid = egid = pwd->pw_gid;
printf ("%s : ", argv[optind]);
- if (!print_group_list (argv[optind++], ruid, rgid, egid, true))
+ if (!print_group_list (argv[optind++], ruid, rgid, egid, true, ' '))
ok = false;
putchar ('\n');
}
diff --git a/src/id.c b/src/id.c
index 3e7016f7b..a0334ba73 100644
--- a/src/id.c
+++ b/src/id.c
@@ -67,6 +67,7 @@ static struct option const longopts[] =
{"name", no_argument, NULL, 'n'},
{"real", no_argument, NULL, 'r'},
{"user", no_argument, NULL, 'u'},
+ {"zero", no_argument, NULL, 'z'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
@@ -83,14 +84,18 @@ usage (int status)
fputs (_("\
Print user and group information for the specified USERNAME,\n\
or (when USERNAME omitted) for the current user.\n\
-\n\
- -a ignore, for compatibility with other versions\n\
- -Z, --context print only the security context of the current user\n\
- -g, --group print only the effective group ID\n\
- -G, --groups print all group IDs\n\
- -n, --name print a name instead of a number, for -ugG\n\
- -r, --real print the real ID instead of the effective ID, with -ugG\n\
- -u, --user print only the effective user ID\n\
+\n"),
+ stdout);
+ fputs (_("\
+ -a ignore, for compatibility with other versions\n\
+ -Z, --context print only the security context of the current user\n\
+ -g, --group print only the effective group ID\n\
+ -G, --groups print all group IDs\n\
+ -n, --name print a name instead of a number, for -ugG\n\
+ -r, --real print the real ID instead of the effective ID, with -ugG\n\
+ -u, --user print only the effective user ID\n\
+ -z, --zero delimit entries with NUL characters, not whitespace;\n\
+ not permitted in default format\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
@@ -109,6 +114,7 @@ main (int argc, char **argv)
int optc;
int selinux_enabled = (is_selinux_enabled () > 0);
bool smack_enabled = is_smack_enabled ();
+ bool opt_zero = false;
/* If true, output the list of all group IDs. -G */
bool just_group_list = false;
@@ -127,7 +133,7 @@ main (int argc, char **argv)
atexit (close_stdout);
- while ((optc = getopt_long (argc, argv, "agnruGZ", longopts, NULL)) != -1)
+ while ((optc = getopt_long (argc, argv, "agnruzGZ", longopts, NULL)) != -1)
{
switch (optc)
{
@@ -162,6 +168,9 @@ main (int argc, char **argv)
case 'u':
just_user = true;
break;
+ case 'z':
+ opt_zero = true;
+ break;
case 'G':
just_group_list = true;
break;
@@ -193,6 +202,10 @@ main (int argc, char **argv)
error (EXIT_FAILURE, 0,
_("cannot print only names or real IDs in default format"));
+ if (default_format && opt_zero)
+ error (EXIT_FAILURE, 0,
+ _("option --zero not permitted in default format"));
+
/* If we are on a SELinux/SMACK-enabled kernel, no user is specified, and
either --context is specified or none of (-u,-g,-G) is specified,
and we're not in POSIXLY_CORRECT mode, get our context. Otherwise,
@@ -269,7 +282,8 @@ main (int argc, char **argv)
}
else if (just_group_list)
{
- if (!print_group_list (argv[optind], ruid, rgid, egid, use_name))
+ if (!print_group_list (argv[optind], ruid, rgid, egid, use_name,
+ opt_zero ? '\0' : ' '))
ok = false;
}
else if (just_context)
@@ -280,7 +294,7 @@ main (int argc, char **argv)
{
print_full_info (argv[optind]);
}
- putchar ('\n');
+ putchar (opt_zero ? '\0' : '\n');
exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
}
diff --git a/tests/local.mk b/tests/local.mk
index b00ff5958..8f76b2371 100644
--- a/tests/local.mk
+++ b/tests/local.mk
@@ -277,6 +277,7 @@ all_tests = \
tests/misc/id-context.sh \
tests/misc/id-groups.sh \
tests/misc/id-setgid.sh \
+ tests/misc/id-zero.sh \
tests/misc/md5sum.pl \
tests/misc/md5sum-bsd.sh \
tests/misc/md5sum-newline.pl \
diff --git a/tests/misc/id-zero.sh b/tests/misc/id-zero.sh
new file mode 100755
index 000000000..cef5672fc
--- /dev/null
+++ b/tests/misc/id-zero.sh
@@ -0,0 +1,62 @@
+#!/bin/sh
+# Exercise "id --zero".
+
+# Copyright (C) 2013 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ id
+
+u="$( id -nu )"
+id || fail=1
+id "$u" || fail=1
+
+# id(1) should refuse --zero in default format.
+echo 'id: option --zero not permitted in default format' > err-exp \
+ || framework_failure_
+id --zero > out 2>err && fail=1
+compare /dev/null out || fail=1
+compare err-exp err || fail=1
+
+# Create a nice list of users.
+# Add $USER to ensure we have at least one explicit entry.
+users="$u"
+# Add a few typical users to test single group and multiple groups.
+for u in root man postfix sshd nobody ; do
+ id $u >/dev/null 2>&1 && users="$users $u"
+done
+# Add $users and '' (implicit $USER) to list to process.
+printf '%s\n' $users '' >> users || framework_failure_
+
+# Exercise "id -z" with various options.
+printf '\n' > exp || framework_failure_
+:> out || framework_failure_
+
+while read u ; do
+ for o in g gr G Gr u ur ; do
+ for n in '' n ; do
+ printf '%s: ' "id -${o}${n}[z] $u" >> exp || framework_failure_
+ printf '\n%s: ' "id -${o}${n}[z] $u" >> out || framework_failure_
+ id -${o}${n} $u >> exp || fail=1
+ id -${o}${n}z $u > tmp || fail=1
+ head -c-1 < tmp >> out || framework_failure_
+ done
+ done
+done < users
+printf '\n' >> out || framework_failure_
+tr '\0' ' ' < out > out2 || framework_failure_
+compare exp out2 || fail=1
+
+Exit $fail