]> git.cameronkatri.com Git - getent-darwin.git/blob - getent.c
Also let getent(1) print values of ut_pid.
[getent-darwin.git] / getent.c
1 /* $NetBSD: getent.c,v 1.7 2005/08/24 14:31:02 ginsbach Exp $ */
2
3 /*-
4 * Copyright (c) 2004 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Luke Mewburn.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD$");
41
42 #include <sys/socket.h>
43 #include <sys/param.h>
44 #include <arpa/inet.h>
45 #include <arpa/nameser.h>
46 #include <net/if.h>
47 #include <netinet/if_ether.h>
48 #include <netinet/in.h> /* for INET6_ADDRSTRLEN */
49 #include <rpc/rpcent.h>
50
51 #include <assert.h>
52 #include <ctype.h>
53 #include <errno.h>
54 #include <grp.h>
55 #include <limits.h>
56 #include <netdb.h>
57 #include <pwd.h>
58 #include <stdio.h>
59 #include <stdarg.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <unistd.h>
63 #include <utmpx.h>
64
65 static int usage(void);
66 static int parsenum(const char *, unsigned long *);
67 static int ethers(int, char *[]);
68 static int group(int, char *[]);
69 static int hosts(int, char *[]);
70 static int networks(int, char *[]);
71 static int passwd(int, char *[]);
72 static int protocols(int, char *[]);
73 static int rpc(int, char *[]);
74 static int services(int, char *[]);
75 static int shells(int, char *[]);
76 static int utmpx(int, char *[]);
77
78 enum {
79 RV_OK = 0,
80 RV_USAGE = 1,
81 RV_NOTFOUND = 2,
82 RV_NOENUM = 3
83 };
84
85 static struct getentdb {
86 const char *name;
87 int (*callback)(int, char *[]);
88 } databases[] = {
89 { "ethers", ethers, },
90 { "group", group, },
91 { "hosts", hosts, },
92 { "networks", networks, },
93 { "passwd", passwd, },
94 { "protocols", protocols, },
95 { "rpc", rpc, },
96 { "services", services, },
97 { "shells", shells, },
98 { "utmpx", utmpx, },
99
100 { NULL, NULL, },
101 };
102
103 int
104 main(int argc, char *argv[])
105 {
106 struct getentdb *curdb;
107
108 setprogname(argv[0]);
109
110 if (argc < 2)
111 usage();
112 for (curdb = databases; curdb->name != NULL; curdb++) {
113 if (strcmp(curdb->name, argv[1]) == 0) {
114 exit(curdb->callback(argc, argv));
115 }
116 }
117 fprintf(stderr, "Unknown database: %s\n", argv[1]);
118 usage();
119 /* NOTREACHED */
120 return RV_USAGE;
121 }
122
123 static int
124 usage(void)
125 {
126 struct getentdb *curdb;
127
128 fprintf(stderr, "Usage: %s database [key ...]\n",
129 getprogname());
130 fprintf(stderr, " database may be one of:\n\t");
131 for (curdb = databases; curdb->name != NULL; curdb++) {
132 fprintf(stderr, " %s", curdb->name);
133 }
134 fprintf(stderr, "\n");
135 exit(RV_USAGE);
136 /* NOTREACHED */
137 }
138
139 static int
140 parsenum(const char *word, unsigned long *result)
141 {
142 unsigned long num;
143 char *ep;
144
145 assert(word != NULL);
146 assert(result != NULL);
147
148 if (!isdigit((unsigned char)word[0]))
149 return 0;
150 errno = 0;
151 num = strtoul(word, &ep, 10);
152 if (num == ULONG_MAX && errno == ERANGE)
153 return 0;
154 if (*ep != '\0')
155 return 0;
156 *result = num;
157 return 1;
158 }
159
160 /*
161 * printfmtstrings --
162 * vprintf(format, ...),
163 * then the aliases (beginning with prefix, separated by sep),
164 * then a newline
165 */
166 static void
167 printfmtstrings(char *strings[], const char *prefix, const char *sep,
168 const char *fmt, ...)
169 {
170 va_list ap;
171 const char *curpref;
172 int i;
173
174 va_start(ap, fmt);
175 vprintf(fmt, ap);
176
177 curpref = prefix;
178 for (i = 0; strings[i] != NULL; i++) {
179 printf("%s%s", curpref, strings[i]);
180 curpref = sep;
181 }
182 printf("\n");
183 va_end(ap);
184 }
185
186 /*
187 * ethers
188 */
189 static int
190 ethers(int argc, char *argv[])
191 {
192 char hostname[MAXHOSTNAMELEN + 1], *hp;
193 struct ether_addr ea, *eap;
194 int i, rv;
195
196 assert(argc > 1);
197 assert(argv != NULL);
198
199 #define ETHERSPRINT printf("%-17s %s\n", ether_ntoa(eap), hp)
200
201 rv = RV_OK;
202 if (argc == 2) {
203 fprintf(stderr, "Enumeration not supported on ethers\n");
204 rv = RV_NOENUM;
205 } else {
206 for (i = 2; i < argc; i++) {
207 if ((eap = ether_aton(argv[i])) == NULL) {
208 eap = &ea;
209 hp = argv[i];
210 if (ether_hostton(hp, eap) != 0) {
211 rv = RV_NOTFOUND;
212 break;
213 }
214 } else {
215 hp = hostname;
216 if (ether_ntohost(hp, eap) != 0) {
217 rv = RV_NOTFOUND;
218 break;
219 }
220 }
221 ETHERSPRINT;
222 }
223 }
224 return rv;
225 }
226
227 /*
228 * group
229 */
230
231 static int
232 group(int argc, char *argv[])
233 {
234 struct group *gr;
235 unsigned long id;
236 int i, rv;
237
238 assert(argc > 1);
239 assert(argv != NULL);
240
241 #define GROUPPRINT printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u", \
242 gr->gr_name, gr->gr_passwd, gr->gr_gid)
243
244 setgroupent(1);
245 rv = RV_OK;
246 if (argc == 2) {
247 while ((gr = getgrent()) != NULL)
248 GROUPPRINT;
249 } else {
250 for (i = 2; i < argc; i++) {
251 if (parsenum(argv[i], &id))
252 gr = getgrgid((gid_t)id);
253 else
254 gr = getgrnam(argv[i]);
255 if (gr != NULL)
256 GROUPPRINT;
257 else {
258 rv = RV_NOTFOUND;
259 break;
260 }
261 }
262 }
263 endgrent();
264 return rv;
265 }
266
267
268 /*
269 * hosts
270 */
271
272 static void
273 hostsprint(const struct hostent *he)
274 {
275 char buf[INET6_ADDRSTRLEN];
276
277 assert(he != NULL);
278 if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL)
279 strlcpy(buf, "# unknown", sizeof(buf));
280 printfmtstrings(he->h_aliases, " ", " ", "%-16s %s", buf, he->h_name);
281 }
282
283 static int
284 hosts(int argc, char *argv[])
285 {
286 struct hostent *he;
287 char addr[IN6ADDRSZ];
288 int i, rv;
289
290 assert(argc > 1);
291 assert(argv != NULL);
292
293 sethostent(1);
294 rv = RV_OK;
295 if (argc == 2) {
296 while ((he = gethostent()) != NULL)
297 hostsprint(he);
298 } else {
299 for (i = 2; i < argc; i++) {
300 if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0)
301 he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6);
302 else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0)
303 he = gethostbyaddr(addr, INADDRSZ, AF_INET);
304 else
305 he = gethostbyname(argv[i]);
306 if (he != NULL)
307 hostsprint(he);
308 else {
309 rv = RV_NOTFOUND;
310 break;
311 }
312 }
313 }
314 endhostent();
315 return rv;
316 }
317
318 /*
319 * networks
320 */
321 static void
322 networksprint(const struct netent *ne)
323 {
324 char buf[INET6_ADDRSTRLEN];
325 struct in_addr ianet;
326
327 assert(ne != NULL);
328 ianet = inet_makeaddr(ne->n_net, 0);
329 if (inet_ntop(ne->n_addrtype, &ianet, buf, sizeof(buf)) == NULL)
330 strlcpy(buf, "# unknown", sizeof(buf));
331 printfmtstrings(ne->n_aliases, " ", " ", "%-16s %s", ne->n_name, buf);
332 }
333
334 static int
335 networks(int argc, char *argv[])
336 {
337 struct netent *ne;
338 in_addr_t net;
339 int i, rv;
340
341 assert(argc > 1);
342 assert(argv != NULL);
343
344 setnetent(1);
345 rv = RV_OK;
346 if (argc == 2) {
347 while ((ne = getnetent()) != NULL)
348 networksprint(ne);
349 } else {
350 for (i = 2; i < argc; i++) {
351 net = inet_network(argv[i]);
352 if (net != INADDR_NONE)
353 ne = getnetbyaddr(net, AF_INET);
354 else
355 ne = getnetbyname(argv[i]);
356 if (ne != NULL)
357 networksprint(ne);
358 else {
359 rv = RV_NOTFOUND;
360 break;
361 }
362 }
363 }
364 endnetent();
365 return rv;
366 }
367
368 /*
369 * passwd
370 */
371 static int
372 passwd(int argc, char *argv[])
373 {
374 struct passwd *pw;
375 unsigned long id;
376 int i, rv;
377
378 assert(argc > 1);
379 assert(argv != NULL);
380
381 #define PASSWDPRINT printf("%s:%s:%u:%u:%s:%s:%s\n", \
382 pw->pw_name, pw->pw_passwd, pw->pw_uid, \
383 pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell)
384
385 setpassent(1);
386 rv = RV_OK;
387 if (argc == 2) {
388 while ((pw = getpwent()) != NULL)
389 PASSWDPRINT;
390 } else {
391 for (i = 2; i < argc; i++) {
392 if (parsenum(argv[i], &id))
393 pw = getpwuid((uid_t)id);
394 else
395 pw = getpwnam(argv[i]);
396 if (pw != NULL)
397 PASSWDPRINT;
398 else {
399 rv = RV_NOTFOUND;
400 break;
401 }
402 }
403 }
404 endpwent();
405 return rv;
406 }
407
408 /*
409 * protocols
410 */
411 static int
412 protocols(int argc, char *argv[])
413 {
414 struct protoent *pe;
415 unsigned long id;
416 int i, rv;
417
418 assert(argc > 1);
419 assert(argv != NULL);
420
421 #define PROTOCOLSPRINT printfmtstrings(pe->p_aliases, " ", " ", \
422 "%-16s %5d", pe->p_name, pe->p_proto)
423
424 setprotoent(1);
425 rv = RV_OK;
426 if (argc == 2) {
427 while ((pe = getprotoent()) != NULL)
428 PROTOCOLSPRINT;
429 } else {
430 for (i = 2; i < argc; i++) {
431 if (parsenum(argv[i], &id))
432 pe = getprotobynumber((int)id);
433 else
434 pe = getprotobyname(argv[i]);
435 if (pe != NULL)
436 PROTOCOLSPRINT;
437 else {
438 rv = RV_NOTFOUND;
439 break;
440 }
441 }
442 }
443 endprotoent();
444 return rv;
445 }
446
447 /*
448 * rpc
449 */
450 static int
451 rpc(int argc, char *argv[])
452 {
453 struct rpcent *re;
454 unsigned long id;
455 int i, rv;
456
457 assert(argc > 1);
458 assert(argv != NULL);
459
460 #define RPCPRINT printfmtstrings(re->r_aliases, " ", " ", \
461 "%-16s %6d", \
462 re->r_name, re->r_number)
463
464 setrpcent(1);
465 rv = RV_OK;
466 if (argc == 2) {
467 while ((re = getrpcent()) != NULL)
468 RPCPRINT;
469 } else {
470 for (i = 2; i < argc; i++) {
471 if (parsenum(argv[i], &id))
472 re = getrpcbynumber((int)id);
473 else
474 re = getrpcbyname(argv[i]);
475 if (re != NULL)
476 RPCPRINT;
477 else {
478 rv = RV_NOTFOUND;
479 break;
480 }
481 }
482 }
483 endrpcent();
484 return rv;
485 }
486
487 /*
488 * services
489 */
490 static int
491 services(int argc, char *argv[])
492 {
493 struct servent *se;
494 unsigned long id;
495 char *proto;
496 int i, rv;
497
498 assert(argc > 1);
499 assert(argv != NULL);
500
501 #define SERVICESPRINT printfmtstrings(se->s_aliases, " ", " ", \
502 "%-16s %5d/%s", \
503 se->s_name, ntohs(se->s_port), se->s_proto)
504
505 setservent(1);
506 rv = RV_OK;
507 if (argc == 2) {
508 while ((se = getservent()) != NULL)
509 SERVICESPRINT;
510 } else {
511 for (i = 2; i < argc; i++) {
512 proto = strchr(argv[i], '/');
513 if (proto != NULL)
514 *proto++ = '\0';
515 if (parsenum(argv[i], &id))
516 se = getservbyport(htons((u_short)id), proto);
517 else
518 se = getservbyname(argv[i], proto);
519 if (se != NULL)
520 SERVICESPRINT;
521 else {
522 rv = RV_NOTFOUND;
523 break;
524 }
525 }
526 }
527 endservent();
528 return rv;
529 }
530
531 /*
532 * shells
533 */
534 static int
535 shells(int argc, char *argv[])
536 {
537 const char *sh;
538 int i, rv;
539
540 assert(argc > 1);
541 assert(argv != NULL);
542
543 #define SHELLSPRINT printf("%s\n", sh)
544
545 setusershell();
546 rv = RV_OK;
547 if (argc == 2) {
548 while ((sh = getusershell()) != NULL)
549 SHELLSPRINT;
550 } else {
551 for (i = 2; i < argc; i++) {
552 setusershell();
553 while ((sh = getusershell()) != NULL) {
554 if (strcmp(sh, argv[i]) == 0) {
555 SHELLSPRINT;
556 break;
557 }
558 }
559 if (sh == NULL) {
560 rv = RV_NOTFOUND;
561 break;
562 }
563 }
564 }
565 endusershell();
566 return rv;
567 }
568
569 /*
570 * utmpx
571 */
572
573 #define UTMPXPRINTID do { \
574 size_t i; \
575 for (i = 0; i < sizeof ut->ut_id; i++) \
576 printf("%02hhx", ut->ut_id[i]); \
577 } while (0)
578
579 static void
580 utmpxprint(const struct utmpx *ut)
581 {
582
583 if (ut->ut_type == EMPTY)
584 return;
585
586 printf("[%.24s] ", ctime(&ut->ut_tv.tv_sec));
587
588 switch (ut->ut_type) {
589 case BOOT_TIME:
590 printf("system boot\n");
591 return;
592 case SHUTDOWN_TIME:
593 printf("system shutdown\n");
594 return;
595 case OLD_TIME:
596 printf("old system time\n");
597 return;
598 case NEW_TIME:
599 printf("new system time\n");
600 return;
601 case USER_PROCESS:
602 printf("user process: id=\"");
603 UTMPXPRINTID;
604 printf("\" pid=\"%d\" user=\"%s\" line=\"%s\" host=\"%s\"\n",
605 ut->ut_pid, ut->ut_user, ut->ut_line, ut->ut_host);
606 break;
607 case DEAD_PROCESS:
608 printf("dead process: id=\"");
609 UTMPXPRINTID;
610 printf("\" pid=\"%d\"\n", ut->ut_pid);
611 break;
612 default:
613 printf("unknown record type\n");
614 break;
615 }
616 }
617
618 static int
619 utmpx(int argc, char *argv[])
620 {
621 const struct utmpx *ut;
622 int rv = RV_OK, db;
623
624 assert(argc > 1);
625 assert(argv != NULL);
626
627 if (argc == 2) {
628 db = UTXDB_ACTIVE;
629 } else if (argc == 3) {
630 if (strcmp(argv[2], "active") == 0)
631 db = UTXDB_ACTIVE;
632 else if (strcmp(argv[2], "lastlogin") == 0)
633 db = UTXDB_LASTLOGIN;
634 else if (strcmp(argv[2], "log") == 0)
635 db = UTXDB_LOG;
636 else
637 rv = RV_USAGE;
638 } else {
639 rv = RV_USAGE;
640 }
641
642 if (rv == RV_USAGE) {
643 fprintf(stderr, "Usage: %s utmpx [active | lastlogin | log]\n",
644 getprogname());
645 } else if (rv == RV_OK) {
646 if (setutxdb(db, NULL) != 0)
647 return (RV_NOTFOUND);
648 while ((ut = getutxent()) != NULL)
649 utmpxprint(ut);
650 endutxent();
651 }
652 return (rv);
653 }