source: trunk/essentials/app-arch/cpio/src/userspec.c

Last change on this file was 3332, checked in by bird, 18 years ago

cpio 2.7

File size: 5.9 KB
Line 
1/* userspec.c -- Parse a user and group string.
2 Copyright (C) 1989, 1990, 1991, 1992, 2001,
3 2004, 2005 Free Software Foundation, Inc.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public
16 License along with this program; if not, write to the Free
17 Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301 USA. */
19
20/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
21
22
23#include <system.h>
24
25#ifdef __GNUC__
26#define alloca __builtin_alloca
27#else
28#ifdef HAVE_ALLOCA_H
29#include <alloca.h>
30#else
31#ifdef _AIX
32 #pragma alloca
33#else
34char *alloca ();
35#endif
36#endif
37#endif
38
39#include <stdio.h>
40#include <ctype.h>
41#include <sys/types.h>
42#include <pwd.h>
43#include <grp.h>
44
45#if !HAVE_DECL_GETPWNAM
46extern struct passwd *getpwnam (const char *name);
47#endif
48#if !HAVE_DECL_GETGRNAM
49extern struct group *getgrnam (const char *name);
50#endif
51#if !HAVE_DECL_GETGRGID
52extern struct group *getgrgid (gid_t gid);
53#endif
54
55#ifndef HAVE_ENDPWENT
56# define endpwent()
57#endif
58#ifndef HAVE_ENDGRENT
59# define endgrent()
60#endif
61
62/* Perform the equivalent of the statement `dest = strdup (src);',
63 but obtaining storage via alloca instead of from the heap. */
64
65#define V_STRDUP(dest, src) \
66 do \
67 { \
68 int _len = strlen ((src)); \
69 (dest) = (char *) alloca (_len + 1); \
70 strcpy (dest, src); \
71 } \
72 while (0)
73
74/* Return nonzero if STR represents an unsigned decimal integer,
75 otherwise return 0. */
76
77static int
78isnumber_p (const char *str)
79{
80 for (; *str; str++)
81 if (!isdigit (*str))
82 return 0;
83 return 1;
84}
85
86/* Extract from NAME, which has the form "[user][:.][group]",
87 a USERNAME, UID U, GROUPNAME, and GID G.
88 Either user or group, or both, must be present.
89 If the group is omitted but the ":" or "." separator is given,
90 use the given user's login group.
91
92 USERNAME and GROUPNAME will be in newly malloc'd memory.
93 Either one might be NULL instead, indicating that it was not
94 given and the corresponding numeric ID was left unchanged.
95
96 Return NULL if successful, a static error message string if not. */
97
98const char *
99parse_user_spec (const char *spec_arg, uid_t *uid, gid_t *gid,
100 char **username_arg, char **groupname_arg)
101{
102 static const char *tired = "virtual memory exhausted";
103 const char *error_msg;
104 char *spec; /* A copy we can write on. */
105 struct passwd *pwd;
106 struct group *grp;
107 char *g, *u, *separator;
108 char *groupname;
109
110 error_msg = NULL;
111 *username_arg = *groupname_arg = NULL;
112 groupname = NULL;
113
114 V_STRDUP (spec, spec_arg);
115
116 /* Find the separator if there is one. */
117 separator = strchr (spec, ':');
118 if (separator == NULL)
119 separator = strchr (spec, '.');
120
121 /* Replace separator with a NUL. */
122 if (separator != NULL)
123 *separator = '\0';
124
125 /* Set U and G to non-zero length strings corresponding to user and
126 group specifiers or to NULL. */
127 u = (*spec == '\0' ? NULL : spec);
128
129 g = (separator == NULL || *(separator + 1) == '\0'
130 ? NULL
131 : separator + 1);
132
133 if (u == NULL && g == NULL)
134 return "can not omit both user and group";
135
136 if (u != NULL)
137 {
138 pwd = getpwnam (u);
139 if (pwd == NULL)
140 {
141
142 if (!isnumber_p (u))
143 error_msg = _("invalid user");
144 else
145 {
146 int use_login_group;
147 use_login_group = (separator != NULL && g == NULL);
148 if (use_login_group)
149 error_msg = _("cannot get the login group of a numeric UID");
150 else
151 *uid = atoi (u);
152 }
153 }
154 else
155 {
156 *uid = pwd->pw_uid;
157 if (g == NULL && separator != NULL)
158 {
159 /* A separator was given, but a group was not specified,
160 so get the login group. */
161 *gid = pwd->pw_gid;
162 grp = getgrgid (pwd->pw_gid);
163 if (grp == NULL)
164 {
165 /* This is enough room to hold the unsigned decimal
166 representation of any 32-bit quantity and the trailing
167 zero byte. */
168 char uint_buf[21];
169 sprintf (uint_buf, "%u", (unsigned) (pwd->pw_gid));
170 V_STRDUP (groupname, uint_buf);
171 }
172 else
173 {
174 V_STRDUP (groupname, grp->gr_name);
175 }
176 endgrent ();
177 }
178 }
179 endpwent ();
180 }
181
182 if (g != NULL && error_msg == NULL)
183 {
184 /* Explicit group. */
185 grp = getgrnam (g);
186 if (grp == NULL)
187 {
188 if (!isnumber_p (g))
189 error_msg = _("invalid group");
190 else
191 *gid = atoi (g);
192 }
193 else
194 *gid = grp->gr_gid;
195 endgrent (); /* Save a file descriptor. */
196
197 if (error_msg == NULL)
198 V_STRDUP (groupname, g);
199 }
200
201 if (error_msg == NULL)
202 {
203 if (u != NULL)
204 {
205 *username_arg = strdup (u);
206 if (*username_arg == NULL)
207 error_msg = tired;
208 }
209
210 if (groupname != NULL && error_msg == NULL)
211 {
212 *groupname_arg = strdup (groupname);
213 if (*groupname_arg == NULL)
214 {
215 if (*username_arg != NULL)
216 {
217 free (*username_arg);
218 *username_arg = NULL;
219 }
220 error_msg = tired;
221 }
222 }
223 }
224
225 return error_msg;
226}
227
228#ifdef TEST
229
230#define NULL_CHECK(s) ((s) == NULL ? "(null)" : (s))
231
232int
233main (int argc, char **argv)
234{
235 int i;
236
237 for (i = 1; i < argc; i++)
238 {
239 const char *e;
240 char *username, *groupname;
241 uid_t uid;
242 gid_t gid;
243 char *tmp;
244
245 tmp = strdup (argv[i]);
246 e = parse_user_spec (tmp, &uid, &gid, &username, &groupname);
247 free (tmp);
248 printf ("%s: %u %u %s %s %s\n",
249 argv[i],
250 (unsigned int) uid,
251 (unsigned int) gid,
252 NULL_CHECK (username),
253 NULL_CHECK (groupname),
254 NULL_CHECK (e));
255 }
256
257 exit (0);
258}
259
260#endif
Note: See TracBrowser for help on using the repository browser.