Compare getopt_long return value against -1, not EOF. Use NULL, not '(int *) 0'...
[platform/upstream/coreutils.git] / src / id.c
1 /* id -- print real and effective UIDs and GIDs
2    Copyright (C) 1989-1995, 1996 Free Software Foundation, Inc.
3
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)
7    any later version.
8
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.
13
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 Foundation,
16    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 /* Written by Arnold Robbins, arnold@audiofax.com.
19    Major rewrite by David MacKenzie, djm@gnu.ai.mit.edu. */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <getopt.h>
24 #include <sys/types.h>
25 #include <pwd.h>
26 #include <grp.h>
27 #include <getopt.h>
28
29 #include "system.h"
30 #include "error.h"
31
32 #ifdef _POSIX_VERSION
33 #include <limits.h>
34
35 #else /* not _POSIX_VERSION */
36 struct passwd *getpwuid ();
37 struct group *getgrgid ();
38 uid_t getuid ();
39 gid_t getgid ();
40 uid_t geteuid ();
41 gid_t getegid ();
42 #include <sys/param.h>
43 #endif /* not _POSIX_VERSION */
44
45 char *xmalloc ();
46 int getugroups ();
47
48 static void print_user __P ((int uid));
49 static void print_group __P ((int gid));
50 static void print_group_list __P ((char *username));
51 static void print_full_info __P ((char *username));
52 static void usage __P ((int status));
53
54 /* The name this program was run with. */
55 char *program_name;
56
57 /* If nonzero, output only the group ID(s). -g */
58 static int just_group = 0;
59
60 /* If nonzero, output user/group name instead of ID number. -n */
61 static int use_name = 0;
62
63 /* If nonzero, output real UID/GID instead of default effective UID/GID. -r */
64 static int use_real = 0;
65
66 /* If nonzero, output only the user ID(s). -u */
67 static int just_user = 0;
68
69 /* If nonzero, output only the supplementary groups. -G */
70 static int just_group_list = 0;
71
72 /* The real and effective IDs of the user to print. */
73 static uid_t ruid, euid;
74 static gid_t rgid, egid;
75
76 /* The number of errors encountered so far. */
77 static int problems = 0;
78
79 /* If nonzero, display usage information and exit.  */
80 static int show_help;
81
82 /* If nonzero, print the version on standard output and exit.  */
83 static int show_version;
84
85 static struct option const longopts[] =
86 {
87   {"group", no_argument, NULL, 'g'},
88   {"groups", no_argument, NULL, 'G'},
89   {"help", no_argument, &show_help, 1},
90   {"name", no_argument, NULL, 'n'},
91   {"real", no_argument, NULL, 'r'},
92   {"user", no_argument, NULL, 'u'},
93   {"version", no_argument, &show_version, 1},
94   {NULL, 0, NULL, 0}
95 };
96
97 int
98 main (int argc, char **argv)
99 {
100   int optc;
101
102   program_name = argv[0];
103   setlocale (LC_ALL, "");
104   bindtextdomain (PACKAGE, LOCALEDIR);
105   textdomain (PACKAGE);
106
107   while ((optc = getopt_long (argc, argv, "agnruG", longopts, NULL)) != -1)
108     {
109       switch (optc)
110         {
111         case 0:
112           break;
113         case 'a':
114           /* Ignore -a, for compatibility with SVR4.  */
115           break;
116         case 'g':
117           just_group = 1;
118           break;
119         case 'n':
120           use_name = 1;
121           break;
122         case 'r':
123           use_real = 1;
124           break;
125         case 'u':
126           just_user = 1;
127           break;
128         case 'G':
129           just_group_list = 1;
130           break;
131         default:
132           usage (1);
133         }
134     }
135
136   if (show_version)
137     {
138       printf ("id (%s) %s\n", GNU_PACKAGE, VERSION);
139       exit (0);
140     }
141
142   if (show_help)
143     usage (0);
144
145   if (just_user + just_group + just_group_list > 1)
146     error (1, 0, _("cannot print only user and only group"));
147
148   if (just_user + just_group + just_group_list == 0 && (use_real || use_name))
149     error (1, 0, _("cannot print only names or real IDs in default format"));
150
151   if (argc - optind > 1)
152     usage (1);
153
154   if (argc - optind == 1)
155     {
156       struct passwd *pwd = getpwnam (argv[optind]);
157       if (pwd == NULL)
158         error (1, 0, _("%s: No such user"), argv[optind]);
159       ruid = euid = pwd->pw_uid;
160       rgid = egid = pwd->pw_gid;
161     }
162   else
163     {
164       euid = geteuid ();
165       ruid = getuid ();
166       egid = getegid ();
167       rgid = getgid ();
168     }
169
170   if (just_user)
171     print_user (use_real ? ruid : euid);
172   else if (just_group)
173     print_group (use_real ? rgid : egid);
174   else if (just_group_list)
175     print_group_list (argv[optind]);
176   else
177     print_full_info (argv[optind]);
178   putchar ('\n');
179
180   exit (problems != 0);
181 }
182
183 /* Print the name or value of user ID UID. */
184
185 static void
186 print_user (int uid)
187 {
188   struct passwd *pwd = NULL;
189
190   if (use_name)
191     {
192       pwd = getpwuid (uid);
193       if (pwd == NULL)
194         problems++;
195     }
196
197   if (pwd == NULL)
198     printf ("%u", (unsigned) uid);
199   else
200     printf ("%s", pwd->pw_name);
201 }
202
203 /* Print the name or value of group ID GID. */
204
205 static void
206 print_group (int gid)
207 {
208   struct group *grp = NULL;
209
210   if (use_name)
211     {
212       grp = getgrgid (gid);
213       if (grp == NULL)
214         problems++;
215     }
216
217   if (grp == NULL)
218     printf ("%u", (unsigned) gid);
219   else
220     printf ("%s", grp->gr_name);
221 }
222
223 static int
224 xgetgroups (const char *username, int *n_groups, GETGROUPS_T **groups)
225 {
226   int max_n_groups;
227   int ng;
228   GETGROUPS_T *g;
229   int fail = 0;
230
231   if (username == 0)
232     max_n_groups = getgroups (0, NULL);
233   else
234     max_n_groups = getugroups (0, NULL, username);
235
236   /* Add 1 just in case max_n_groups is zero.  */
237   g = (GETGROUPS_T *) xmalloc (max_n_groups * sizeof (GETGROUPS_T) + 1);
238   if (username == 0)
239     ng = getgroups (max_n_groups, g);
240   else
241     ng = getugroups (max_n_groups, g, username);
242
243   if (ng < 0)
244     {
245       error (0, errno, _("cannot get supplemental group list"));
246       ++fail;
247       free (groups);
248     }
249   if (!fail)
250     {
251       *n_groups = ng;
252       *groups = g;
253     }
254   return fail;
255 }
256
257 /* Print all of the distinct groups the user is in. */
258
259 static void
260 print_group_list (char *username)
261 {
262   print_group (rgid);
263   if (egid != rgid)
264     {
265       putchar (' ');
266       print_group (egid);
267     }
268
269 #if HAVE_GETGROUPS
270   {
271     int n_groups;
272     GETGROUPS_T *groups;
273     register int i;
274
275     if (xgetgroups (username, &n_groups, &groups))
276       {
277         ++problems;
278         return;
279       }
280
281     for (i = 0; i < n_groups; i++)
282       if (groups[i] != rgid && groups[i] != egid)
283         {
284           putchar (' ');
285           print_group (groups[i]);
286         }
287     free (groups);
288   }
289 #endif
290 }
291
292 /* Print all of the info about the user's user and group IDs. */
293
294 static void
295 print_full_info (char *username)
296 {
297   struct passwd *pwd;
298   struct group *grp;
299
300   printf ("uid=%u", (unsigned) ruid);
301   pwd = getpwuid (ruid);
302   if (pwd == NULL)
303     problems++;
304   else
305     printf ("(%s)", pwd->pw_name);
306
307   printf (" gid=%u", (unsigned) rgid);
308   grp = getgrgid (rgid);
309   if (grp == NULL)
310     problems++;
311   else
312     printf ("(%s)", grp->gr_name);
313
314   if (euid != ruid)
315     {
316       printf (" euid=%u", (unsigned) euid);
317       pwd = getpwuid (euid);
318       if (pwd == NULL)
319         problems++;
320       else
321         printf ("(%s)", pwd->pw_name);
322     }
323
324   if (egid != rgid)
325     {
326       printf (" egid=%u", (unsigned) egid);
327       grp = getgrgid (egid);
328       if (grp == NULL)
329         problems++;
330       else
331         printf ("(%s)", grp->gr_name);
332     }
333
334 #if HAVE_GETGROUPS
335   {
336     int n_groups;
337     GETGROUPS_T *groups;
338     register int i;
339
340     if (xgetgroups (username, &n_groups, &groups))
341       {
342         ++problems;
343         return;
344       }
345
346     if (n_groups > 0)
347       fputs (_(" groups="), stdout);
348     for (i = 0; i < n_groups; i++)
349       {
350         if (i > 0)
351           putchar (',');
352         printf ("%u", (unsigned) groups[i]);
353         grp = getgrgid (groups[i]);
354         if (grp == NULL)
355           problems++;
356         else
357           printf ("(%s)", grp->gr_name);
358       }
359     free (groups);
360   }
361 #endif
362 }
363
364 static void
365 usage (int status)
366 {
367   if (status != 0)
368     fprintf (stderr, _("Try `%s --help' for more information.\n"),
369              program_name);
370   else
371     {
372       printf (_("Usage: %s [OPTION]... [USERNAME]\n"), program_name);
373       printf (_("\
374 Print information for USERNAME, or the current user.\n\
375 \n\
376   -a              ignore, for compatibility with other versions\n\
377   -g, --group     print only the group ID\n\
378   -G, --groups    print only the supplementary groups\n\
379   -n, --name      print a name instead of a number, for -ugG\n\
380   -r, --real      print the real ID instead of effective ID, for -ugG\n\
381   -u, --user      print only the user ID\n\
382       --help      display this help and exit\n\
383       --version   output version information and exit\n\
384 \n\
385 Without any OPTION, print some useful set of identified information.\n\
386 "));
387       puts (_("\nReport bugs to sh-utils-bugs@gnu.ai.mit.edu"));
388     }
389   exit (status);
390 }