3 /* userspec.c -- Parse a user and group string.
4 Copyright (C) 1989, 1990, 1991, 1992, 2001, 2004 Free Software Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20 /* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
25 #define alloca __builtin_alloca
40 #include <sys/types.h>
44 #if !HAVE_DECL_GETPWNAM
45 extern struct passwd *getpwnam (const char *name);
47 #if !HAVE_DECL_GETGRNAM
48 extern struct group *getgrnam (const char *name);
50 #if !HAVE_DECL_GETGRGID
51 extern struct group *getgrgid (gid_t gid);
61 /* Perform the equivalent of the statement `dest = strdup (src);',
62 but obtaining storage via alloca instead of from the heap. */
64 #define V_STRDUP(dest, src) \
67 int _len = strlen ((src)); \
68 (dest) = (char *) alloca (_len + 1); \
73 /* Return nonzero if STR represents an unsigned decimal integer,
74 otherwise return 0. */
77 cpio_isnumber (const char *str)
85 /* Extract from NAME, which has the form "[user][:.][group]",
86 a USERNAME, UID U, GROUPNAME, and GID G.
87 Either user or group, or both, must be present.
88 If the group is omitted but the ":" or "." separator is given,
89 use the given user's login group.
91 USERNAME and GROUPNAME will be in newly malloc'd memory.
92 Either one might be NULL instead, indicating that it was not
93 given and the corresponding numeric ID was left unchanged.
95 Return NULL if successful, a static error message string if not. */
98 parse_user_spec (const char *spec_arg, uid_t *uid, gid_t *gid,
99 char **username_arg, char **groupname_arg)
101 static const char *tired = "virtual memory exhausted";
102 const char *error_msg;
103 char *spec; /* A copy we can write on. */
106 char *g, *u, *separator;
110 *username_arg = *groupname_arg = NULL;
113 V_STRDUP (spec, spec_arg);
115 /* Find the separator if there is one. */
116 separator = index (spec, ':');
117 if (separator == NULL)
118 separator = index (spec, '.');
120 /* Replace separator with a NUL. */
121 if (separator != NULL)
124 /* Set U and G to non-zero length strings corresponding to user and
125 group specifiers or to NULL. */
126 u = (*spec == '\0' ? NULL : spec);
128 g = (separator == NULL || *(separator + 1) == '\0'
132 if (u == NULL && g == NULL)
133 return "can not omit both user and group";
141 if (!cpio_isnumber (u))
142 error_msg = _("invalid user");
146 use_login_group = (separator != NULL && g == NULL);
148 error_msg = _("cannot get the login group of a numeric UID");
156 if (g == NULL && separator != NULL)
158 /* A separator was given, but a group was not specified,
159 so get the login group. */
161 grp = getgrgid (pwd->pw_gid);
164 /* This is enough room to hold the unsigned decimal
165 representation of any 32-bit quantity and the trailing
168 sprintf (uint_buf, "%u", (unsigned) (pwd->pw_gid));
169 V_STRDUP (groupname, uint_buf);
173 V_STRDUP (groupname, grp->gr_name);
181 if (g != NULL && error_msg == NULL)
183 /* Explicit group. */
187 if (!cpio_isnumber (g))
188 error_msg = _("invalid group");
194 endgrent (); /* Save a file descriptor. */
196 if (error_msg == NULL)
197 V_STRDUP (groupname, g);
200 if (error_msg == NULL)
204 *username_arg = strdup (u);
205 if (*username_arg == NULL)
209 if (groupname != NULL && error_msg == NULL)
211 *groupname_arg = strdup (groupname);
212 if (*groupname_arg == NULL)
214 if (*username_arg != NULL)
216 free (*username_arg);
217 *username_arg = NULL;
229 #define NULL_CHECK(s) ((s) == NULL ? "(null)" : (s))
232 main (int argc, char **argv)
236 for (i = 1; i < argc; i++)
239 char *username, *groupname;
244 tmp = strdup (argv[i]);
245 e = parse_user_spec (tmp, &uid, &gid, &username, &groupname);
247 printf ("%s: %u %u %s %s %s\n",
251 NULL_CHECK (username),
252 NULL_CHECK (groupname),