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.
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
@end macro
@primaryAndSupplementaryGroups{id,user argument}
+@exitstatus
+
@node logname invocation
@section @command{logname}: Print current login name
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
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;
if (egid != rgid)
{
- putchar (' ');
+ putchar (delim);
if (!print_group (egid, use_names))
ok = false;
}
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;
}
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);
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]);
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');
}
{"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}
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);
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;
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)
{
case 'u':
just_user = true;
break;
+ case 'z':
+ opt_zero = true;
+ break;
case 'G':
just_group_list = true;
break;
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,
}
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)
{
print_full_info (argv[optind]);
}
- putchar ('\n');
+ putchar (opt_zero ? '\0' : '\n');
exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
}
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 \
--- /dev/null
+#!/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