No empty .Rs/.Re
[netbsd-mini2440.git] / usr.bin / getent / getent.c
blob522c0bf56811e0084fda5b6326bcf81f4c5158d7
1 /* $NetBSD: getent.c,v 1.15 2009/02/24 06:10:52 yamt Exp $ */
3 /*-
4 * Copyright (c) 2004-2006 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Luke Mewburn.
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __RCSID("$NetBSD: getent.c,v 1.15 2009/02/24 06:10:52 yamt Exp $");
35 #endif /* not lint */
37 #include <sys/socket.h>
39 #include <assert.h>
40 #include <ctype.h>
41 #include <errno.h>
42 #include <grp.h>
43 #include <limits.h>
44 #include <netdb.h>
45 #include <netgroup.h>
46 #include <pwd.h>
47 #include <stdio.h>
48 #include <stdarg.h>
49 #include <stdbool.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <unistd.h>
53 #include <paths.h>
54 #include <err.h>
56 #include <arpa/inet.h>
57 #include <arpa/nameser.h>
59 #include <net/if.h>
60 #include <net/if_ether.h>
62 #include <netinet/in.h> /* for INET6_ADDRSTRLEN */
64 #include <rpc/rpcent.h>
66 #include <disktab.h>
68 static int usage(void) __attribute__((__noreturn__));
69 static int parsenum(const char *, unsigned long *);
70 static int disktab(int, char *[]);
71 static int gettytab(int, char *[]);
72 static int ethers(int, char *[]);
73 static int group(int, char *[]);
74 static int hosts(int, char *[]);
75 static int netgroup(int, char *[]);
76 static int networks(int, char *[]);
77 static int passwd(int, char *[]);
78 static int printcap(int, char *[]);
79 static int protocols(int, char *[]);
80 static int rpc(int, char *[]);
81 static int services(int, char *[]);
82 static int shells(int, char *[]);
83 static int termcap(int, char *[]);
85 enum {
86 RV_OK = 0,
87 RV_USAGE = 1,
88 RV_NOTFOUND = 2,
89 RV_NOENUM = 3
92 static struct getentdb {
93 const char *name;
94 int (*callback)(int, char *[]);
95 } databases[] = {
96 { "disktab", disktab, },
97 { "ethers", ethers, },
98 { "gettytab", gettytab, },
99 { "group", group, },
100 { "hosts", hosts, },
101 { "netgroup", netgroup, },
102 { "networks", networks, },
103 { "passwd", passwd, },
104 { "printcap", printcap, },
105 { "protocols", protocols, },
106 { "rpc", rpc, },
107 { "services", services, },
108 { "shells", shells, },
109 { "termcap", termcap, },
111 { NULL, NULL, },
116 main(int argc, char *argv[])
118 struct getentdb *curdb;
120 setprogname(argv[0]);
122 if (argc < 2)
123 usage();
124 for (curdb = databases; curdb->name != NULL; curdb++)
125 if (strcmp(curdb->name, argv[1]) == 0)
126 return (*curdb->callback)(argc, argv);
128 warn("Unknown database `%s'", argv[1]);
129 usage();
130 /* NOTREACHED */
133 static int
134 usage(void)
136 struct getentdb *curdb;
138 (void)fprintf(stderr, "Usage: %s database [key ...]\n",
139 getprogname());
140 (void)fprintf(stderr, " database may be one of:\n\t");
141 for (curdb = databases; curdb->name != NULL; curdb++)
142 (void)fprintf(stderr, " %s", curdb->name);
143 (void)fprintf(stderr, "\n");
144 exit(RV_USAGE);
145 /* NOTREACHED */
148 static int
149 parsenum(const char *word, unsigned long *result)
151 unsigned long num;
152 char *ep;
154 assert(word != NULL);
155 assert(result != NULL);
157 if (!isdigit((unsigned char)word[0]))
158 return 0;
159 errno = 0;
160 num = strtoul(word, &ep, 10);
161 if (num == ULONG_MAX && errno == ERANGE)
162 return 0;
163 if (*ep != '\0')
164 return 0;
165 *result = num;
166 return 1;
170 * printfmtstrings --
171 * vprintf(format, ...),
172 * then the aliases (beginning with prefix, separated by sep),
173 * then a newline
175 static void
176 printfmtstrings(char *strings[], const char *prefix, const char *sep,
177 const char *fmt, ...)
179 va_list ap;
180 const char *curpref;
181 size_t i;
183 va_start(ap, fmt);
184 (void)vprintf(fmt, ap);
185 va_end(ap);
187 curpref = prefix;
188 for (i = 0; strings[i] != NULL; i++) {
189 (void)printf("%s%s", curpref, strings[i]);
190 curpref = sep;
192 (void)printf("\n");
197 * ethers
200 static int
201 ethers(int argc, char *argv[])
203 char hostname[MAXHOSTNAMELEN + 1], *hp;
204 struct ether_addr ea, *eap;
205 int i, rv;
207 assert(argc > 1);
208 assert(argv != NULL);
210 #define ETHERSPRINT (void)printf("%-17s %s\n", ether_ntoa(eap), hp)
212 rv = RV_OK;
213 if (argc == 2) {
214 warnx("Enumeration not supported on ethers");
215 rv = RV_NOENUM;
216 } else {
217 for (i = 2; i < argc; i++) {
218 if ((eap = ether_aton(argv[i])) == NULL) {
219 eap = &ea;
220 hp = argv[i];
221 if (ether_hostton(hp, eap) != 0) {
222 rv = RV_NOTFOUND;
223 break;
225 } else {
226 hp = hostname;
227 if (ether_ntohost(hp, eap) != 0) {
228 rv = RV_NOTFOUND;
229 break;
232 ETHERSPRINT;
235 return rv;
239 * group
242 static int
243 group(int argc, char *argv[])
245 struct group *gr;
246 unsigned long id;
247 int i, rv;
249 assert(argc > 1);
250 assert(argv != NULL);
252 #define GROUPPRINT printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u", \
253 gr->gr_name, gr->gr_passwd, gr->gr_gid)
255 (void)setgroupent(1);
256 rv = RV_OK;
257 if (argc == 2) {
258 while ((gr = getgrent()) != NULL)
259 GROUPPRINT;
260 } else {
261 for (i = 2; i < argc; i++) {
262 if (parsenum(argv[i], &id))
263 gr = getgrgid((gid_t)id);
264 else
265 gr = getgrnam(argv[i]);
266 if (gr != NULL)
267 GROUPPRINT;
268 else {
269 rv = RV_NOTFOUND;
270 break;
274 endgrent();
275 return rv;
280 * hosts
283 static void
284 hostsprint(const struct hostent *he)
286 char buf[INET6_ADDRSTRLEN];
288 assert(he != NULL);
289 if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL)
290 (void)strlcpy(buf, "# unknown", sizeof(buf));
291 printfmtstrings(he->h_aliases, " ", " ", "%-16s %s", buf, he->h_name);
294 static int
295 hosts(int argc, char *argv[])
297 struct hostent *he;
298 char addr[IN6ADDRSZ];
299 int i, rv;
301 assert(argc > 1);
302 assert(argv != NULL);
304 sethostent(1);
305 rv = RV_OK;
306 if (argc == 2) {
307 while ((he = gethostent()) != NULL)
308 hostsprint(he);
309 } else {
310 for (i = 2; i < argc; i++) {
311 if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0)
312 he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6);
313 else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0)
314 he = gethostbyaddr(addr, INADDRSZ, AF_INET);
315 else
316 he = gethostbyname(argv[i]);
317 if (he != NULL)
318 hostsprint(he);
319 else {
320 rv = RV_NOTFOUND;
321 break;
325 endhostent();
326 return rv;
330 * netgroup
332 static int
333 netgroup(int argc, char *argv[])
335 int rv, i;
336 bool first;
337 const char *host, *user, *domain;
339 assert(argc > 1);
340 assert(argv != NULL);
342 #define NETGROUPPRINT(s) (((s) != NULL) ? (s) : "")
344 rv = RV_OK;
345 if (argc == 2) {
346 warnx("Enumeration not supported on netgroup");
347 rv = RV_NOENUM;
348 } else {
349 for (i = 2; i < argc; i++) {
350 setnetgrent(argv[i]);
351 first = true;
352 while (getnetgrent(&host, &user, &domain) != 0) {
353 if (first) {
354 first = false;
355 (void)fputs(argv[i], stdout);
357 (void)printf(" (%s,%s,%s)",
358 NETGROUPPRINT(host),
359 NETGROUPPRINT(user),
360 NETGROUPPRINT(domain));
362 if (!first)
363 (void)putchar('\n');
364 endnetgrent();
368 return rv;
372 * networks
375 static void
376 networksprint(const struct netent *ne)
378 char buf[INET6_ADDRSTRLEN];
379 struct in_addr ianet;
381 assert(ne != NULL);
382 ianet = inet_makeaddr(ne->n_net, 0);
383 if (inet_ntop(ne->n_addrtype, &ianet, buf, sizeof(buf)) == NULL)
384 (void)strlcpy(buf, "# unknown", sizeof(buf));
385 printfmtstrings(ne->n_aliases, " ", " ", "%-16s %s", ne->n_name, buf);
388 static int
389 networks(int argc, char *argv[])
391 struct netent *ne;
392 in_addr_t net;
393 int i, rv;
395 assert(argc > 1);
396 assert(argv != NULL);
398 setnetent(1);
399 rv = RV_OK;
400 if (argc == 2) {
401 while ((ne = getnetent()) != NULL)
402 networksprint(ne);
403 } else {
404 for (i = 2; i < argc; i++) {
405 net = inet_network(argv[i]);
406 if (net != INADDR_NONE)
407 ne = getnetbyaddr(net, AF_INET);
408 else
409 ne = getnetbyname(argv[i]);
410 if (ne != NULL)
411 networksprint(ne);
412 else {
413 rv = RV_NOTFOUND;
414 break;
418 endnetent();
419 return rv;
424 * passwd
427 static int
428 passwd(int argc, char *argv[])
430 struct passwd *pw;
431 unsigned long id;
432 int i, rv;
434 assert(argc > 1);
435 assert(argv != NULL);
437 #define PASSWDPRINT (void)printf("%s:%s:%u:%u:%s:%s:%s\n", \
438 pw->pw_name, pw->pw_passwd, pw->pw_uid, \
439 pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell)
441 (void)setpassent(1);
442 rv = RV_OK;
443 if (argc == 2) {
444 while ((pw = getpwent()) != NULL)
445 PASSWDPRINT;
446 } else {
447 for (i = 2; i < argc; i++) {
448 if (parsenum(argv[i], &id))
449 pw = getpwuid((uid_t)id);
450 else
451 pw = getpwnam(argv[i]);
452 if (pw != NULL)
453 PASSWDPRINT;
454 else {
455 rv = RV_NOTFOUND;
456 break;
460 endpwent();
461 return rv;
464 static char *
465 mygetent(const char * const * db_array, const char *name)
467 char *buf = NULL;
468 int error;
470 switch (error = cgetent(&buf, db_array, name)) {
471 case -3:
472 warnx("tc= loop in record `%s' in `%s'", name, db_array[0]);
473 break;
474 case -2:
475 warn("system error fetching record `%s' in `%s'", name,
476 db_array[0]);
477 break;
478 case -1:
479 case 0:
480 break;
481 case 1:
482 warnx("tc= reference not found in record for `%s' in `%s'",
483 name, db_array[0]);
484 break;
485 default:
486 warnx("unknown error %d in record `%s' in `%s'", error, name,
487 db_array[0]);
488 break;
490 return buf;
493 static char *
494 mygetone(const char * const * db_array, int first)
496 char *buf = NULL;
497 int error;
499 switch (error = (first ? cgetfirst : cgetnext)(&buf, db_array)) {
500 case -2:
501 warnx("tc= loop in `%s'", db_array[0]);
502 break;
503 case -1:
504 warn("system error fetching record in `%s'", db_array[0]);
505 break;
506 case 0:
507 case 1:
508 break;
509 case 2:
510 warnx("tc= reference not found in `%s'", db_array[0]);
511 break;
512 default:
513 warnx("unknown error %d in `%s'", error, db_array[0]);
514 break;
516 return buf;
519 static void
520 capprint(const char *cap)
522 char *c = strchr(cap, ':');
523 if (c)
524 if (c == cap)
525 (void)printf("true\n");
526 else {
527 int l = (int)(c - cap);
528 (void)printf("%*.*s\n", l, l, cap);
530 else
531 (void)printf("%s\n", cap);
534 static void
535 prettyprint(char *b)
537 #define TERMWIDTH 65
538 int did = 0;
539 size_t len;
540 char *s, c;
542 for (;;) {
543 len = strlen(b);
544 if (len <= TERMWIDTH) {
545 done:
546 if (did)
547 printf("\t:");
548 printf("%s\n", b);
549 return;
551 for (s = b + TERMWIDTH; s > b && *s != ':'; s--)
552 continue;
553 if (*s++ != ':')
554 goto done;
555 c = *s;
556 *s = '\0';
557 if (did)
558 printf("\t:");
559 did++;
560 printf("%s\\\n", b);
561 *s = c;
562 b = s;
566 static void
567 handleone(const char * const *db_array, char *b, int recurse, int pretty,
568 int level)
570 char *tc;
572 if (level && pretty)
573 printf("\n");
574 if (pretty)
575 prettyprint(b);
576 else
577 printf("%s\n", b);
578 if (!recurse || cgetstr(b, "tc", &tc) <= 0)
579 return;
581 b = mygetent(db_array, tc);
582 free(tc);
584 if (b == NULL)
585 return;
587 handleone(db_array, b, recurse, pretty, ++level);
588 free(b);
591 static int
592 handlecap(const char *db, int argc, char *argv[])
594 static const char sfx[] = "=#:";
595 const char *db_array[] = { db, NULL };
596 char *b, *cap;
597 int i, rv, c;
598 size_t j;
599 int expand = 1, recurse = 0, pretty = 0;
601 assert(argc > 1);
602 assert(argv != NULL);
604 argc--;
605 argv++;
606 while ((c = getopt(argc, argv, "pnr")) != -1)
607 switch (c) {
608 case 'n':
609 expand = 0;
610 break;
611 case 'r':
612 expand = 0;
613 recurse = 1;
614 break;
615 case 'p':
616 pretty = 1;
617 break;
618 default:
619 usage();
620 break;
623 argc -= optind;
624 argv += optind;
625 csetexpandtc(expand);
626 rv = RV_OK;
627 if (argc == 0) {
628 for (b = mygetone(db_array, 1); b; b = mygetone(db_array, 0)) {
629 handleone(db_array, b, recurse, pretty, 0);
630 free(b);
632 } else {
633 if ((b = mygetent(db_array, argv[0])) == NULL)
634 return RV_NOTFOUND;
635 if (argc == 1)
636 handleone(db_array, b, recurse, pretty, 0);
637 else {
638 for (i = 2; i < argc; i++) {
639 for (j = 0; j < sizeof(sfx) - 1; j++) {
640 cap = cgetcap(b, argv[i], sfx[j]);
641 if (cap) {
642 capprint(cap);
643 break;
646 if (j == sizeof(sfx) - 1)
647 printf("false\n");
650 free(b);
652 return rv;
656 * gettytab
659 static int
660 gettytab(int argc, char *argv[])
662 return handlecap(_PATH_GETTYTAB, argc, argv);
666 * printcap
669 static int
670 printcap(int argc, char *argv[])
672 return handlecap(_PATH_PRINTCAP, argc, argv);
676 * disktab
679 static int
680 disktab(int argc, char *argv[])
682 return handlecap(_PATH_DISKTAB, argc, argv);
686 * termcap
689 static int
690 termcap(int argc, char *argv[])
692 return handlecap(_PATH_TERMCAP, argc, argv);
695 * protocols
698 static int
699 protocols(int argc, char *argv[])
701 struct protoent *pe;
702 unsigned long id;
703 int i, rv;
705 assert(argc > 1);
706 assert(argv != NULL);
708 #define PROTOCOLSPRINT printfmtstrings(pe->p_aliases, " ", " ", \
709 "%-16s %5d", pe->p_name, pe->p_proto)
711 setprotoent(1);
712 rv = RV_OK;
713 if (argc == 2) {
714 while ((pe = getprotoent()) != NULL)
715 PROTOCOLSPRINT;
716 } else {
717 for (i = 2; i < argc; i++) {
718 if (parsenum(argv[i], &id))
719 pe = getprotobynumber((int)id);
720 else
721 pe = getprotobyname(argv[i]);
722 if (pe != NULL)
723 PROTOCOLSPRINT;
724 else {
725 rv = RV_NOTFOUND;
726 break;
730 endprotoent();
731 return rv;
735 * rpc
738 static int
739 rpc(int argc, char *argv[])
741 struct rpcent *re;
742 unsigned long id;
743 int i, rv;
745 assert(argc > 1);
746 assert(argv != NULL);
748 #define RPCPRINT printfmtstrings(re->r_aliases, " ", " ", \
749 "%-16s %6d", \
750 re->r_name, re->r_number)
752 setrpcent(1);
753 rv = RV_OK;
754 if (argc == 2) {
755 while ((re = getrpcent()) != NULL)
756 RPCPRINT;
757 } else {
758 for (i = 2; i < argc; i++) {
759 if (parsenum(argv[i], &id))
760 re = getrpcbynumber((int)id);
761 else
762 re = getrpcbyname(argv[i]);
763 if (re != NULL)
764 RPCPRINT;
765 else {
766 rv = RV_NOTFOUND;
767 break;
771 endrpcent();
772 return rv;
776 * services
779 static int
780 services(int argc, char *argv[])
782 struct servent *se;
783 unsigned long id;
784 char *proto;
785 int i, rv;
787 assert(argc > 1);
788 assert(argv != NULL);
790 #define SERVICESPRINT printfmtstrings(se->s_aliases, " ", " ", \
791 "%-16s %5d/%s", \
792 se->s_name, ntohs(se->s_port), se->s_proto)
794 setservent(1);
795 rv = RV_OK;
796 if (argc == 2) {
797 while ((se = getservent()) != NULL)
798 SERVICESPRINT;
799 } else {
800 for (i = 2; i < argc; i++) {
801 proto = strchr(argv[i], '/');
802 if (proto != NULL)
803 *proto++ = '\0';
804 if (parsenum(argv[i], &id))
805 se = getservbyport(htons(id), proto);
806 else
807 se = getservbyname(argv[i], proto);
808 if (se != NULL)
809 SERVICESPRINT;
810 else {
811 rv = RV_NOTFOUND;
812 break;
816 endservent();
817 return rv;
822 * shells
825 static int
826 shells(int argc, char *argv[])
828 const char *sh;
829 int i, rv;
831 assert(argc > 1);
832 assert(argv != NULL);
834 #define SHELLSPRINT (void)printf("%s\n", sh)
836 setusershell();
837 rv = RV_OK;
838 if (argc == 2) {
839 while ((sh = getusershell()) != NULL)
840 SHELLSPRINT;
841 } else {
842 for (i = 2; i < argc; i++) {
843 setusershell();
844 while ((sh = getusershell()) != NULL) {
845 if (strcmp(sh, argv[i]) == 0) {
846 SHELLSPRINT;
847 break;
850 if (sh == NULL) {
851 rv = RV_NOTFOUND;
852 break;
856 endusershell();
857 return rv;