1/*
2** Copyright (c) 2004 Haiku
3** Permission is hereby granted, free of charge, to any person obtaining a copy
4** of this software and associated documentation files (the "Software"), to deal
5** in the Software without restriction, including without limitation the rights
6** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7** copies of the Software, and to permit persons to whom the Software is
8** furnished to do so, subject to the following conditions:
9**
10** The above copyright notice and this permission notice shall be included in all
11** copies or substantial portions of the Software.
12**
13** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19** SOFTWARE.
20 */
21
22
23#include <sys/stat.h>
24#include <errno.h>
25#include <getopt.h>
26#include <grp.h>
27#include <pwd.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <unistd.h>
32
33static	void	print_user_info(int userID, char *suffix);
34static	void	print_group_info(int groupID, char *suffix);
35static	void	print_group_list(int listID);
36static	void	print_combined_info(void);
37static	void	suggest_help(void);
38static	void	usage(void);
39static	void	version(void);
40
41char *progName;
42static int gFlag, glFlag, nFlag, rFlag, uFlag;
43struct passwd *euidName;
44struct passwd *ruidName;
45struct group *egidName;
46struct group *rgidName;
47uid_t eUID;
48uid_t rUID;
49gid_t eGID;
50gid_t rGID;
51gid_t groupList;
52char *suffix;
53
54
55static void
56print_user_info(int userID, char *suffix) {
57	struct stat statBuffer;
58	struct passwd *userIDName;
59	if ((userIDName = getpwuid(userID)) != NULL) {
60		if (nFlag)
61   			fprintf(stdout, "%s%s", userIDName->pw_name, suffix);
62		else
63    		fprintf(stdout, "%u%s", eUID, suffix);
64	} else
65   		fprintf(stdout, "%-8d%s", statBuffer.st_uid, suffix);
66}
67
68
69static void
70print_group_info(int groupID, char *suffix) {
71	struct stat statBuffer;
72	struct group *groupIDName;
73	if ((groupIDName = getgrgid(groupID)) != NULL) {
74    	if (nFlag)
75    		fprintf(stdout, "%s%s", groupIDName->gr_name, suffix);
76    	else
77    		fprintf(stdout, "%u%s", groupID, suffix);
78	} else
79    	fprintf(stdout, " %-8d%s", statBuffer.st_gid, suffix);
80}
81
82static void
83print_group_list(int groupID) {
84	int cnt, id, lastID, nGroups;
85	gid_t *groups;
86	long ngroups_max;
87
88	ngroups_max = sysconf(NGROUPS_MAX) + 1;
89	groups = (gid_t *)malloc(ngroups_max *sizeof(gid_t));
90
91	nGroups = getgroups(ngroups_max, groups);
92
93	suffix = "";
94	print_group_info(groupID, suffix);
95	for (lastID = -1, cnt = 0; cnt < ngroups_max; ++cnt) {
96		if (lastID == (id = groups[cnt]))
97			continue;
98		suffix = " ";
99		print_group_info(id, suffix);
100		lastID = id;
101	}
102	fprintf(stdout, "\n");
103}
104
105
106static void
107print_combined_info() {
108	if ( eUID != rUID ) {
109		suffix = "";
110		rFlag = 1;
111		fprintf(stdout, "uid=");
112		print_user_info(rUID, suffix);
113		fprintf(stdout, "(");
114		nFlag = 1;
115		print_user_info(rUID, suffix);
116		fprintf(stdout, ") gid=");
117		rFlag = 1;	nFlag = 0;
118		print_group_info(rGID, suffix);
119		fprintf(stdout, "(");
120		rFlag = 0; nFlag = 1;
121		print_group_info(eGID, suffix);
122		fprintf(stdout, ") euid=");
123		rFlag = 0;	nFlag = 0;
124		print_user_info(eUID, suffix);
125		fprintf(stdout, "(");
126		rFlag = 0; nFlag = 1;
127		print_user_info(eUID, suffix);
128		fprintf(stdout, ")\n");
129	} else {
130		suffix = "";
131		rFlag = 1;
132		fprintf(stdout, "uid=");
133		print_user_info(rUID, suffix);
134		fprintf(stdout, "(");
135		nFlag = 1;
136		print_user_info(rUID, suffix);
137		fprintf(stdout, ") gid=");
138		rFlag = 1;	nFlag = 0;
139		print_group_info(rGID, suffix);
140		fprintf(stdout, "(");
141		rFlag = 1;	nFlag = 1;
142		print_group_info(rGID, suffix);
143		fprintf(stdout, ")\n");
144	}
145}
146
147
148static void
149suggest_help(void)
150{
151	(void)fprintf(stdout, "Try `%s --help' for more information.\n", progName);
152}
153
154
155static void
156usage(void)
157{
158	fprintf(stdout,
159"%s Haiku (https://www.haiku-os.org/)
160
161Usage: %s [OPTION]... [USERNAME]
162
163  -g, --group     print only the group ID
164  -G, --groups    print only the supplementary groups
165  -n, --name      print a name instead of a number, for -ugG
166  -r, --real      print the real ID instead of effective ID, for -ugG
167  -u, --user      print only the user ID
168      --help      display this help and exit
169      --version   output version information and exit
170
171Print information for USERNAME, or the current user.
172
173", progName, progName	);
174}
175
176
177static void
178version(void)
179{
180	fprintf(stdout, "%s Haiku (https://www.haiku-os.org/)\n", progName);
181}
182
183
184int
185main(int argc, char *argv[])
186{
187	int argOption;
188	int indexptr = 0;
189	char * const * optargv = argv;
190
191	struct option groupOption = { "group", no_argument, 0, 1 } ;
192	struct option groupsOption = { "groups", no_argument, 0, 2 } ;
193	struct option nameOption = { "name", no_argument, 0, 3 } ;
194	struct option realOption = { "real", no_argument, 0, 4 } ;
195	struct option userOption = { "user", no_argument, 0, 5 } ;
196	struct option helpOption = { "help", no_argument, 0, 6 } ;
197	struct option versionOption = { "version", no_argument, 0, 7 } ;
198
199	struct option options[] = {
200	groupOption, groupsOption, nameOption, realOption, userOption, helpOption, versionOption, {0}
201	};
202
203	struct passwd *suppliedName;
204
205	gFlag = glFlag = nFlag = rFlag = uFlag = 0;
206	progName = argv[0]; // don't put this before or between structs! werrry bad things happen. ;)
207
208	while ((argOption = getopt_long(argc, optargv, "gGnru", options, &indexptr)) != -1) {
209
210		switch (argOption) {
211			case 'g':
212				gFlag = 1;
213				break;
214			case 'G':
215				glFlag = 1;
216				break;
217			case 'n':
218				nFlag = 1;
219				break;
220			case 'r':
221				rFlag = 1;
222				break;
223			case 'u':
224				uFlag = 1;
225				break;
226			default:
227				switch (options[indexptr].val) {
228					case 6: // help
229						usage();
230						exit(0);
231					case 7: // version
232						version();
233						exit(0);
234					default:
235						suggest_help();
236						exit(0);
237				}
238				break;
239		}
240	}
241
242	if (argc - optind > 1)
243		usage();
244
245	if (argc - optind == 1) {
246		suppliedName = getpwnam(argv[optind]);
247
248		if (suppliedName == NULL) {
249			fprintf(stderr, "%s: %s: No such user\n", progName, argv[optind]);
250			suggest_help();
251			exit(1);
252		}
253		rUID = eUID = suppliedName->pw_uid;
254		rGID = eGID = suppliedName->pw_gid;
255    } else {
256		eUID = geteuid ();
257		rUID = getuid ();
258		eGID = getegid ();
259		rGID = getgid ();
260
261		euidName = getpwuid(eUID);
262		ruidName = getpwuid(rUID);
263		egidName = getgrgid(eGID);
264		rgidName = getgrgid(rGID);
265    }
266
267	if ( gFlag + glFlag + uFlag > 1 ) {
268		fprintf(stderr, "%s: cannot print only user and only group\n", progName);
269		suggest_help();
270		exit(1);
271	}
272
273	if ( gFlag + glFlag + uFlag == 0 && (rFlag || nFlag)) {
274		fprintf(stderr, "%s: cannot print only names or real IDs in default format\n", progName);
275		suggest_help();
276		exit(1);
277	}
278
279	if (gFlag) {
280	// group information
281		suffix = "\n";
282		if (rFlag)
283			print_group_info(rUID, suffix);
284		else
285			print_group_info(eUID, suffix);
286		exit(0);
287	}
288
289	if (glFlag) {
290	// group list
291		if (rFlag)
292			print_group_list(rUID);
293		else
294			print_group_list(eUID);
295		exit(0);
296	}
297
298	if (uFlag) {
299	// user information
300		suffix = "\n";
301		if (rFlag)
302			print_user_info(rUID, suffix);
303		else
304			print_user_info(eUID, suffix);
305		exit(0);
306	}
307
308	// no arguments? print combined info.
309	print_combined_info();
310
311	return B_NO_ERROR;
312}
313