summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS2
-rw-r--r--NEWS3
-rw-r--r--doc/coreutils.texi14
-rw-r--r--man/Makefile.am4
-rw-r--r--po/POTFILES.in4
-rw-r--r--src/Makefile.am22
-rw-r--r--src/group-list.c134
-rw-r--r--src/group-list.h19
-rw-r--r--src/groups.c153
-rwxr-xr-xsrc/groups.sh84
-rw-r--r--src/id.c108
11 files changed, 361 insertions, 186 deletions
diff --git a/AUTHORS b/AUTHORS
index 200e141d8..807857f9c 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -31,7 +31,7 @@ false: Jim Meyering
fmt: Ross Paterson
fold: David MacKenzie
ginstall: David MacKenzie
-groups: David MacKenzie
+groups: David MacKenzie, James Youngman
head: David MacKenzie, Jim Meyering
hostid: Jim Meyering
hostname: Jim Meyering
diff --git a/NEWS b/NEWS
index e05e1c318..af27aab1d 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,9 @@ GNU coreutils NEWS -*- outline -*-
** Bug fixes
+ configure --enable-no-install-program=groups now works.
+
+
ls no longer segfaults on files in /proc when linked with an older version
of libselinux. E.g., ls -l /proc/sys would dereference a NULL pointer.
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index dfab04001..23d0ab45b 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -12226,6 +12226,15 @@ Print only the user ID.
@exitstatus
+@macro primaryAndSupplementaryGroups{cmd,arg}
+Primary and supplementary groups for a process are normally inherited
+from its parent and are usually unchanged since login. This means
+that if you change the group database after logging in, @command{\cmd\}
+will not reflect your changes within your existing login session.
+Running @command{\cmd\} with a \arg\ causes the user and group
+database to be consulted afresh, and so will give a different result.
+@end macro
+@primaryAndSupplementaryGroups{id,user argument}
@node logname invocation
@section @command{logname}: Print current login name
@@ -12275,7 +12284,8 @@ options}.
groups for each given @var{username}, or the current process if no names
are given. If more than one name is given, the name of each user is
printed before
-the list of that user's groups. Synopsis:
+the list of that user's groups and the user name is separated from the
+group list by a colon. Synopsis:
@example
groups [@var{username}]@dots{}
@@ -12283,6 +12293,8 @@ 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}.
diff --git a/man/Makefile.am b/man/Makefile.am
index a4351d651..9076afcb0 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -15,7 +15,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-dist_man_MANS = groups.1 $(MAN)
+dist_man_MANS = $(MAN)
man_aux = $(dist_man_MANS:.1=.x)
@@ -59,7 +59,7 @@ factor.1: $(common_dep) $(srcdir)/factor.x ../src/factor.c
false.1: $(common_dep) $(srcdir)/false.x ../src/false.c
fmt.1: $(common_dep) $(srcdir)/fmt.x ../src/fmt.c
fold.1: $(common_dep) $(srcdir)/fold.x ../src/fold.c
-groups.1: $(common_dep) $(srcdir)/groups.x ../src/groups.sh
+groups.1: $(common_dep) $(srcdir)/groups.x ../src/groups.c
head.1: $(common_dep) $(srcdir)/head.x ../src/head.c
hostid.1: $(common_dep) $(srcdir)/hostid.x ../src/hostid.c
hostname.1: $(common_dep) $(srcdir)/hostname.x ../src/hostname.c
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 686332df6..e97510997 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,5 +1,5 @@
# List of files which contain translatable strings.
-# Copyright (C) 1996-2007 Free Software Foundation, Inc.
+# Copyright (C) 1996-2008 Free Software Foundation, Inc.
# These are nominally temporary...
lib/acl.c
@@ -60,6 +60,8 @@ src/factor.c
src/false.c
src/fmt.c
src/fold.c
+src/group-list.c
+src/groups.c
src/head.c
src/hostid.c
src/hostname.c
diff --git a/src/Makefile.am b/src/Makefile.am
index a0b1d0c0c..155f22bf3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -33,7 +33,7 @@ EXTRA_PROGRAMS = \
ginstall link ln dir vdir ls mkdir \
mkfifo mknod mktemp \
mv nohup readlink rm rmdir shred stat sync touch unlink \
- cat cksum comm csplit cut expand fmt fold head join md5sum \
+ cat cksum comm csplit cut expand fmt fold head join groups md5sum \
nl od paste pr ptx sha1sum sha224sum sha256sum sha384sum sha512sum \
shuf sort split sum tac tail tr tsort unexpand uniq wc \
basename date dirname echo env expr factor false \
@@ -42,7 +42,6 @@ EXTRA_PROGRAMS = \
test true tty whoami yes \
base64
-bin_SCRIPTS = groups
bin_PROGRAMS = $(OPTIONAL_BIN_PROGS)
noinst_PROGRAMS = setuidgid
@@ -53,6 +52,7 @@ noinst_HEADERS = \
cp-hash.h \
dircolors.h \
fs.h \
+ group-list.h \
ls.h \
remove.h \
system.h \
@@ -61,7 +61,7 @@ noinst_HEADERS = \
uname.h
EXTRA_DIST = dcgen dircolors.hin tac-pipe.c \
- groups.sh wheel-gen.pl extract-magic c99-to-c89.diff
+ wheel-gen.pl extract-magic c99-to-c89.diff
BUILT_SOURCES =
CLEANFILES = $(SCRIPTS) su
@@ -142,20 +142,6 @@ RELEASE_YEAR = \
`sed -n '/.*COPYRIGHT_YEAR = \([0-9][0-9][0-9][0-9]\) };/s//\1/p' \
$(top_srcdir)/lib/version-etc.c`
-# This depends on 'Makefile', so that version changes
-#(reflected in Makefile's VERSION definition)
-# are reflected into groups --version also between releases.
-groups: groups.sh Makefile
- rm -f $@ $@-t
- sed \
- -e 's!@''bindir''@!$(bindir)!' \
- -e 's/@''RELEASE_YEAR'@/$(RELEASE_YEAR)/ \
- -e 's/@''PACKAGE_NAME''@/$(PACKAGE_NAME)/' \
- -e 's/@''PACKAGE_BUGREPORT''@/$(PACKAGE_BUGREPORT)/' \
- -e 's/@''VERSION''@/$(VERSION)/' $(srcdir)/groups.sh > $@-t
- chmod +x $@-t
- mv $@-t $@
-
all-local: su$(EXEEXT)
installed_su = $(DESTDIR)$(bindir)/`echo su|sed '$(transform)'`
@@ -225,6 +211,8 @@ __SOURCES = lbracket.c
cp_SOURCES = cp.c $(copy_sources)
dir_SOURCES = ls.c ls-dir.c
vdir_SOURCES = ls.c ls-vdir.c
+id_SOURCES = id.c group-list.c
+groups_SOURCES = groups.c group-list.c
ln_SOURCES = ln.c
ls_SOURCES = ls.c ls-ls.c
chown_SOURCES = chown.c chown-core.c
diff --git a/src/group-list.c b/src/group-list.c
new file mode 100644
index 000000000..e788f8e87
--- /dev/null
+++ b/src/group-list.c
@@ -0,0 +1,134 @@
+/* group-list.c --Print a list of group IDs or names.
+ Copyright (C) 1989-2008 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/>. */
+
+/* Written by Arnold Robbins.
+ Major rewrite by David MacKenzie, djm@gnu.ai.mit.edu.
+ Extracted from id.c by James Youngman. */
+
+#include <config.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <getopt.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include "system.h"
+#include "error.h"
+#include "mgetgroups.h"
+#include "quote.h"
+#include "group-list.h"
+
+
+/* Print all of the distinct groups the user is in. */
+extern bool
+print_group_list (const char *username,
+ uid_t ruid, gid_t rgid, gid_t egid,
+ bool use_names)
+{
+ bool ok = true;
+ struct passwd *pwd;
+
+ pwd = getpwuid (ruid);
+ if (pwd == NULL)
+ ok = false;
+
+ if (!print_group (rgid, use_names))
+ ok = false;
+
+ if (egid != rgid)
+ {
+ putchar (' ');
+ if (!print_group (egid, use_names))
+ ok = false;
+ }
+
+#if HAVE_GETGROUPS
+ {
+ GETGROUPS_T *groups;
+ size_t i;
+
+ int n_groups = mgetgroups (username, (pwd ? pwd->pw_gid : (gid_t) -1),
+ &groups);
+ if (n_groups < 0)
+ {
+ if (username)
+ {
+ error (0, errno, _("failed to get groups for user %s"),
+ quote (username));
+ }
+ else
+ {
+ error (0, errno, _("failed to get groups for the current process"));
+ }
+ return false;
+ }
+
+ for (i = 0; i < n_groups; i++)
+ if (groups[i] != rgid && groups[i] != egid)
+ {
+ putchar (' ');
+ if (!print_group (groups[i], use_names))
+ ok = false;
+ }
+ free (groups);
+ return ok;
+ }
+#endif /* HAVE_GETGROUPS */
+}
+
+
+/* Print the name or value of group ID GID. */
+extern bool
+print_group (gid_t gid, bool use_name)
+{
+ struct group *grp = NULL;
+ bool ok = true;
+
+ if (use_name)
+ {
+ grp = getgrgid (gid);
+ if (grp == NULL)
+ {
+ error (0, 0, _("cannot find name for group ID %lu"),
+ (unsigned long int) gid);
+ ok = false;
+ }
+ }
+
+ if (grp == NULL)
+ {
+ if (printf ("%lu", (unsigned long int) gid) < 0)
+ {
+ error (0, errno, _("write error"));
+ ok = false;
+ }
+ }
+ else
+ {
+ if (printf ("%s", grp->gr_name) < 0)
+ {
+ error (0, errno, _("write error"));
+ ok = false;
+ }
+ }
+ return ok;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/src/group-list.h b/src/group-list.h
new file mode 100644
index 000000000..868585ede
--- /dev/null
+++ b/src/group-list.h
@@ -0,0 +1,19 @@
+/* group-list.h -- prototypes shared by id and groups.
+
+ Copyright (C) 2008 Free Software Foundation.
+
+ 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/>. */
+
+bool print_group (gid_t, bool);
+bool print_group_list (const char *, uid_t, gid_t, gid_t, bool);
diff --git a/src/groups.c b/src/groups.c
new file mode 100644
index 000000000..8a4673ced
--- /dev/null
+++ b/src/groups.c
@@ -0,0 +1,153 @@
+/* groups -- print the groups a user is in
+ Copyright (C) 1989-2008 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/>. */
+
+/* Written by James Youngman based on id.c and groups.sh,
+ which were written by Arnold Robbins and David MacKenzie. */
+
+#include <config.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+#include <getopt.h>
+
+#include "system.h"
+#include "error.h"
+#include "group-list.h"
+
+/* The name this program was run with. */
+char *program_name;
+
+/* The official name of this program (e.g., no `g' prefix). */
+#define PROGRAM_NAME "groups"
+
+#define AUTHORS "David MacKenzie", "James Youngman"
+
+
+static struct option const longopts[] =
+{
+ {GETOPT_HELP_OPTION_DECL},
+ {GETOPT_VERSION_OPTION_DECL},
+ {NULL, 0, NULL, 0}
+};
+
+void
+usage (int status)
+{
+ if (status != EXIT_SUCCESS)
+ fprintf (stderr, _("Try `%s --help' for more information.\n"),
+ program_name);
+ else
+ {
+ printf (_("Usage: %s [OPTION]... [USERNAME]\n"), program_name);
+ fputs (_("\
+Print information for USERNAME or, if no USERNAME is specified,\n\
+the current process (which is different if the groups database has changed).\n"),
+ stdout);
+ fputs (HELP_OPTION_DESCRIPTION, stdout);
+ fputs (VERSION_OPTION_DESCRIPTION, stdout);
+ emit_bug_reporting_address ();
+ }
+ exit (status);
+}
+
+static void
+write_error (void)
+{
+ error (0, errno, _("write error"));
+}
+
+
+int
+main (int argc, char **argv)
+{
+ int optc;
+ bool ok = true;
+ gid_t rgid, egid;
+ uid_t ruid;
+
+ initialize_main (&argc, &argv);
+ program_name = argv[0];
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ atexit (close_stdout);
+
+ /* Processing the arguments this way makes groups.c behave differently to
+ * groups.sh if one of the arguments is "--".
+ */
+ while ((optc = getopt_long (argc, argv, "", longopts, NULL)) != -1)
+ {
+ switch (optc)
+ {
+ case_GETOPT_HELP_CHAR;
+ case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
+ default:
+ usage (EXIT_FAILURE);
+ }
+ }
+
+ if (optind == argc)
+ {
+ /* No arguments. Divulge the details of the current process. */
+ ruid = getuid ();
+ egid = getegid ();
+ rgid = getgid ();
+
+ if (!print_group_list (NULL, ruid, rgid, egid, true))
+ ok = false;
+ if (EOF == putchar ('\n'))
+ {
+ write_error ();
+ ok = false;
+ }
+ }
+ else
+ {
+ /* At least one argument. Divulge the details of the specified users. */
+ while (optind < argc)
+ {
+ struct passwd *pwd = getpwnam (argv[optind]);
+ if (pwd == NULL)
+ error (EXIT_FAILURE, 0, _("%s: No such user"), argv[optind]);
+ ruid = pwd->pw_uid;
+ rgid = egid = pwd->pw_gid;
+
+ if (printf ("%s : ", argv[optind]) < 0)
+ {
+ write_error ();
+ ok = false;
+ }
+ if (!print_group_list (argv[optind++], ruid, rgid, egid, true))
+ ok = false;
+ if (EOF == putchar ('\n'))
+ {
+ write_error ();
+ ok = false;
+ }
+ }
+ }
+
+ exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/src/groups.sh b/src/groups.sh
deleted file mode 100755
index 7afe52e71..000000000
--- a/src/groups.sh
+++ /dev/null
@@ -1,84 +0,0 @@
-#!/bin/sh
-# groups -- print the groups a user is in
-# Copyright (C) 1991, 1997, 2000, 2002, 2004-2007 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/>.
-
-# Written by David MacKenzie <djm@gnu.ai.mit.edu>.
-
-# Make sure we get GNU id, if possible; also allow
-# it to be somewhere else in PATH if not installed yet.
-PATH=@bindir@:$PATH
-
-usage="Usage: $0 [OPTION]... [USERNAME]...
-
- --help display this help and exit
- --version output version information and exit
-
-Same as id -Gn. If no USERNAME, use current process.
-
-Report bugs to <@PACKAGE_BUGREPORT@>."
-
-version='groups (@PACKAGE_NAME@) @VERSION@
-Copyright (C) @RELEASE_YEAR@ Free Software Foundation, Inc.
-License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
-This is free software: you are free to change and redistribute it.
-There is NO WARRANTY, to the extent permitted by law.
-
-Written by David MacKenzie.'
-
-
-for arg
-do
- case $arg in
- --help | --hel | --he | --h)
- exec echo "$usage" ;;
- --version | --versio | --versi | --vers | --ver | --ve | --v)
- exec echo "$version" ;;
- --)
- shift
- break ;;
- -*)
- echo "$0: invalid option: $arg" >&2
- exit 1 ;;
- *)
- break ;;
- esac
-done
-
-# With fewer than two arguments, simply exec "id".
-case $# in
- 0|1) exec id -Gn -- "$@" ;;
-esac
-
-# With more, we need a loop, and be sure to exit nonzero upon failure.
-status=0
-write_error=0
-
-for name
-do
- if groups=`id -Gn -- "$name"`; then
- echo "$name : $groups" || {
- status=$?
- if test $write_error = 0; then
- echo "$0: write error" >&2
- write_error=1
- fi
- }
- else
- status=$?
- fi
-done
-
-exit $status
diff --git a/src/id.c b/src/id.c
index caf71e8c0..e4eda4071 100644
--- a/src/id.c
+++ b/src/id.c
@@ -1,5 +1,5 @@
/* id -- print real and effective UIDs and GIDs
- Copyright (C) 1989-2007 Free Software Foundation, Inc.
+ Copyright (C) 1989-2008 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
@@ -19,7 +19,6 @@
#include <config.h>
#include <stdio.h>
-#include <getopt.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
@@ -28,9 +27,9 @@
#include "system.h"
#include "error.h"
-#include "getugroups.h"
#include "mgetgroups.h"
#include "quote.h"
+#include "group-list.h"
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "id"
@@ -41,8 +40,6 @@
static int just_context = 0;
static void print_user (uid_t uid);
-static void print_group (gid_t gid);
-static void print_group_list (const char *username);
static void print_full_info (const char *username);
/* The name this program was run with. */
@@ -216,15 +213,27 @@ of a different user"));
}
if (just_user)
- print_user (use_real ? ruid : euid);
+ {
+ print_user (use_real ? ruid : euid);
+ }
else if (just_group)
- print_group (use_real ? rgid : egid);
+ {
+ if (!print_group (use_real ? rgid : egid, use_name))
+ ok = false;
+ }
else if (just_group_list)
- print_group_list (argv[optind]);
+ {
+ if (!print_group_list (argv[optind], ruid, rgid, egid, use_name))
+ ok = false;
+ }
else if (just_context)
- fputs (context, stdout);
+ {
+ fputs (context, stdout);
+ }
else
- print_full_info (argv[optind]);
+ {
+ print_full_info (argv[optind]);
+ }
putchar ('\n');
exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
@@ -254,74 +263,6 @@ print_user (uid_t uid)
printf ("%s", pwd->pw_name);
}
-/* Print the name or value of group ID GID. */
-
-static void
-print_group (gid_t gid)
-{
- struct group *grp = NULL;
-
- if (use_name)
- {
- grp = getgrgid (gid);
- if (grp == NULL)
- {
- error (0, 0, _("cannot find name for group ID %lu"),
- (unsigned long int) gid);
- ok = false;
- }
- }
-
- if (grp == NULL)
- printf ("%lu", (unsigned long int) gid);
- else
- printf ("%s", grp->gr_name);
-}
-
-/* Print all of the distinct groups the user is in. */
-
-static void
-print_group_list (const char *username)
-{
- struct passwd *pwd;
-
- pwd = getpwuid (ruid);
- if (pwd == NULL)
- ok = false;
-
- print_group (rgid);
- if (egid != rgid)
- {
- putchar (' ');
- print_group (egid);
- }
-
-#if HAVE_GETGROUPS
- {
- GETGROUPS_T *groups;
- size_t i;
-
- int n_groups = mgetgroups (username, (pwd ? pwd->pw_gid : (gid_t) -1),
- &groups);
- if (n_groups < 0)
- {
- error (0, errno, _("failed to get groups for user %s"),
- quote (username));
- ok = false;
- return;
- }
-
- for (i = 0; i < n_groups; i++)
- if (groups[i] != rgid && groups[i] != egid)
- {
- putchar (' ');
- print_group (groups[i]);
- }
- free (groups);
- }
-#endif /* HAVE_GETGROUPS */
-}
-
/* Print all of the info about the user's user and group IDs. */
static void
@@ -365,8 +306,15 @@ print_full_info (const char *username)
&groups);
if (n_groups < 0)
{
- error (0, errno, _("failed to get groups for user %s"),
- quote (username));
+ if (username)
+ {
+ error (0, errno, _("failed to get groups for user %s"),
+ quote (username));
+ }
+ else
+ {
+ error (0, errno, _("failed to get groups for the current process"));
+ }
ok = false;
return;
}