1 /* userspec.c -- Parse a user and group string.
2 Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
18 /* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
21 #if defined (CONFIG_BROKETS)
22 /* We use <config.h> instead of "config.h" so that a compilation
23 using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
24 (which it would do because it found this file in $srcdir). */
32 #define alloca __builtin_alloca
46 #include <sys/types.h>
50 #if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
67 #ifndef _POSIX_VERSION
68 struct passwd *getpwnam ();
69 struct group *getgrnam ();
70 struct group *getgrgid ();
78 /* Perform the equivalent of the statement `dest = strdup (src);',
79 but obtaining storage via alloca instead of from the heap. */
81 #define V_STRDUP(dest, src) \
84 int _len = strlen ((src)); \
85 (dest) = (char *) alloca (_len + 1); \
90 #define isdigit(c) ((c) >= '0' && (c) <= '9')
94 /* Return nonzero if STR represents an unsigned decimal integer,
95 otherwise return 0. */
107 /* Extract from NAME, which has the form "[user][:.][group]",
108 a USERNAME, UID U, GROUPNAME, and GID G.
109 Either user or group, or both, must be present.
110 If the group is omitted but the ":" or "." separator is given,
111 use the given user's login group.
113 USERNAME and GROUPNAME will be in newly malloc'd memory.
114 Either one might be NULL instead, indicating that it was not
115 given and the corresponding numeric ID was left unchanged.
117 Return NULL if successful, a static error message string if not. */
120 parse_user_spec (spec_arg, uid, gid, username_arg, groupname_arg)
121 const char *spec_arg;
124 char **username_arg, **groupname_arg;
126 static const char *tired = "virtual memory exhausted";
127 const char *error_msg;
128 char *spec; /* A copy we can write on. */
131 char *g, *u, *separator;
135 *username_arg = *groupname_arg = NULL;
138 V_STRDUP (spec, spec_arg);
140 /* Find the separator if there is one. */
141 separator = index (spec, ':');
142 if (separator == NULL)
143 separator = index (spec, '.');
145 /* Replace separator with a NUL. */
146 if (separator != NULL)
149 /* Set U and G to non-zero length strings corresponding to user and
150 group specifiers or to NULL. */
151 u = (*spec == '\0' ? NULL : spec);
153 g = (separator == NULL || *(separator + 1) == '\0'
157 if (u == NULL && g == NULL)
158 return "can not omit both user and group";
167 error_msg = "invalid user";
171 use_login_group = (separator != NULL && g == NULL);
173 error_msg = "cannot get the login group of a numeric UID";
181 if (g == NULL && separator != NULL)
183 /* A separator was given, but a group was not specified,
184 so get the login group. */
186 grp = getgrgid (pwd->pw_gid);
189 /* This is enough room to hold the unsigned decimal
190 representation of any 32-bit quantity and the trailing
193 sprintf (uint_buf, "%u", (unsigned) (pwd->pw_gid));
194 V_STRDUP (groupname, uint_buf);
198 V_STRDUP (groupname, grp->gr_name);
206 if (g != NULL && error_msg == NULL)
208 /* Explicit group. */
213 error_msg = "invalid group";
219 endgrent (); /* Save a file descriptor. */
221 if (error_msg == NULL)
222 V_STRDUP (groupname, g);
225 if (error_msg == NULL)
229 *username_arg = strdup (u);
230 if (*username_arg == NULL)
234 if (groupname != NULL && error_msg == NULL)
236 *groupname_arg = strdup (groupname);
237 if (*groupname_arg == NULL)
239 if (*username_arg != NULL)
241 free (*username_arg);
242 *username_arg = NULL;
254 #define NULL_CHECK(s) ((s) == NULL ? "(null)" : (s))
257 main (int argc, char **argv)
261 for (i = 1; i < argc; i++)
264 char *username, *groupname;
269 tmp = strdup (argv[i]);
270 e = parse_user_spec (tmp, &uid, &gid, &username, &groupname);
272 printf ("%s: %u %u %s %s %s\n",
276 NULL_CHECK (username),
277 NULL_CHECK (groupname),