xref: /haiku/src/bin/id.c (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
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 
33 static	void	print_user_info(int userID, char *suffix);
34 static	void	print_group_info(int groupID, char *suffix);
35 static	void	print_group_list(int listID);
36 static	void	print_combined_info(void);
37 static	void	suggest_help(void);
38 static	void	usage(void);
39 static	void	version(void);
40 
41 char *progName;
42 static int gFlag, glFlag, nFlag, rFlag, uFlag;
43 struct passwd *euidName;
44 struct passwd *ruidName;
45 struct group *egidName;
46 struct group *rgidName;
47 uid_t eUID;
48 uid_t rUID;
49 gid_t eGID;
50 gid_t rGID;
51 gid_t groupList;
52 char *suffix;
53 
54 
55 static void
56 print_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 
69 static void
70 print_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 
82 static void
83 print_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 
106 static void
107 print_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 
148 static void
149 suggest_help(void)
150 {
151 	(void)fprintf(stdout, "Try `%s --help' for more information.\n", progName);
152 }
153 
154 
155 static void
156 usage(void)
157 {
158 	fprintf(stdout,
159 "%s Haiku (https://www.haiku-os.org/)
160 
161 Usage: %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 
171 Print information for USERNAME, or the current user.
172 
173 ", progName, progName	);
174 }
175 
176 
177 static void
178 version(void)
179 {
180 	fprintf(stdout, "%s Haiku (https://www.haiku-os.org/)\n", progName);
181 }
182 
183 
184 int
185 main(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