Home | History | Annotate | Line # | Download | only in getent
      1  1.21       kre /*	$NetBSD: getent.c,v 1.21 2024/11/21 16:33:37 kre Exp $	*/
      2   1.1     lukem 
      3   1.1     lukem /*-
      4   1.8     lukem  * Copyright (c) 2004-2006 The NetBSD Foundation, Inc.
      5   1.1     lukem  * All rights reserved.
      6   1.1     lukem  *
      7   1.1     lukem  * This code is derived from software contributed to The NetBSD Foundation
      8   1.1     lukem  * by Luke Mewburn.
      9   1.1     lukem  *
     10   1.1     lukem  * Redistribution and use in source and binary forms, with or without
     11   1.1     lukem  * modification, are permitted provided that the following conditions
     12   1.1     lukem  * are met:
     13   1.1     lukem  * 1. Redistributions of source code must retain the above copyright
     14   1.1     lukem  *    notice, this list of conditions and the following disclaimer.
     15   1.1     lukem  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.1     lukem  *    notice, this list of conditions and the following disclaimer in the
     17   1.1     lukem  *    documentation and/or other materials provided with the distribution.
     18   1.1     lukem  *
     19   1.1     lukem  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20   1.1     lukem  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21   1.1     lukem  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22   1.1     lukem  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23   1.1     lukem  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24   1.1     lukem  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25   1.1     lukem  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26   1.1     lukem  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27   1.1     lukem  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28   1.1     lukem  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29   1.1     lukem  * POSSIBILITY OF SUCH DAMAGE.
     30   1.1     lukem  */
     31   1.1     lukem 
     32   1.1     lukem #include <sys/cdefs.h>
     33   1.1     lukem #ifndef lint
     34  1.21       kre __RCSID("$NetBSD: getent.c,v 1.21 2024/11/21 16:33:37 kre Exp $");
     35   1.1     lukem #endif /* not lint */
     36   1.1     lukem 
     37   1.1     lukem #include <sys/socket.h>
     38   1.1     lukem 
     39   1.1     lukem #include <assert.h>
     40   1.1     lukem #include <ctype.h>
     41   1.1     lukem #include <errno.h>
     42   1.1     lukem #include <grp.h>
     43   1.1     lukem #include <limits.h>
     44   1.1     lukem #include <netdb.h>
     45  1.14      tron #include <netgroup.h>
     46   1.1     lukem #include <pwd.h>
     47   1.1     lukem #include <stdio.h>
     48   1.5     lukem #include <stdarg.h>
     49  1.14      tron #include <stdbool.h>
     50   1.1     lukem #include <stdlib.h>
     51   1.1     lukem #include <string.h>
     52   1.1     lukem #include <unistd.h>
     53  1.10  christos #include <paths.h>
     54  1.10  christos #include <err.h>
     55   1.1     lukem 
     56   1.1     lukem #include <arpa/inet.h>
     57   1.1     lukem #include <arpa/nameser.h>
     58   1.1     lukem 
     59   1.7  ginsbach #include <net/if.h>
     60   1.7  ginsbach #include <net/if_ether.h>
     61   1.7  ginsbach 
     62   1.1     lukem #include <netinet/in.h>		/* for INET6_ADDRSTRLEN */
     63   1.1     lukem 
     64   1.6  ginsbach #include <rpc/rpcent.h>
     65   1.6  ginsbach 
     66  1.10  christos #include <disktab.h>
     67  1.10  christos 
     68  1.10  christos static int	usage(void) __attribute__((__noreturn__));
     69   1.1     lukem static int	parsenum(const char *, unsigned long *);
     70  1.10  christos static int	disktab(int, char *[]);
     71  1.12  christos static int	gettytab(int, char *[]);
     72   1.7  ginsbach static int	ethers(int, char *[]);
     73   1.1     lukem static int	group(int, char *[]);
     74   1.1     lukem static int	hosts(int, char *[]);
     75  1.14      tron static int	netgroup(int, char *[]);
     76   1.2     lukem static int	networks(int, char *[]);
     77   1.1     lukem static int	passwd(int, char *[]);
     78  1.10  christos static int	printcap(int, char *[]);
     79   1.3     lukem static int	protocols(int, char *[]);
     80   1.6  ginsbach static int	rpc(int, char *[]);
     81   1.4     lukem static int	services(int, char *[]);
     82   1.1     lukem static int	shells(int, char *[]);
     83   1.1     lukem 
     84   1.1     lukem enum {
     85   1.1     lukem 	RV_OK		= 0,
     86   1.1     lukem 	RV_USAGE	= 1,
     87   1.1     lukem 	RV_NOTFOUND	= 2,
     88  1.10  christos 	RV_NOENUM	= 3
     89   1.1     lukem };
     90   1.1     lukem 
     91   1.5     lukem static struct getentdb {
     92   1.5     lukem 	const char	*name;
     93   1.5     lukem 	int		(*callback)(int, char *[]);
     94   1.5     lukem } databases[] = {
     95  1.10  christos 	{	"disktab",	disktab,	},
     96   1.7  ginsbach 	{	"ethers",	ethers,		},
     97  1.12  christos 	{	"gettytab",	gettytab,	},
     98   1.5     lukem 	{	"group",	group,		},
     99   1.5     lukem 	{	"hosts",	hosts,		},
    100  1.14      tron 	{	"netgroup",	netgroup,	},
    101   1.5     lukem 	{	"networks",	networks,	},
    102   1.5     lukem 	{	"passwd",	passwd,		},
    103  1.15      yamt 	{	"printcap",	printcap,	},
    104   1.5     lukem 	{	"protocols",	protocols,	},
    105   1.6  ginsbach 	{	"rpc",		rpc,		},
    106   1.5     lukem 	{	"services",	services,	},
    107   1.5     lukem 	{	"shells",	shells,		},
    108   1.5     lukem 
    109   1.5     lukem 	{	NULL,		NULL,		},
    110   1.5     lukem };
    111   1.5     lukem 
    112   1.5     lukem 
    113   1.1     lukem int
    114   1.1     lukem main(int argc, char *argv[])
    115   1.1     lukem {
    116   1.5     lukem 	struct getentdb	*curdb;
    117   1.1     lukem 
    118   1.1     lukem 	setprogname(argv[0]);
    119   1.1     lukem 
    120   1.1     lukem 	if (argc < 2)
    121   1.1     lukem 		usage();
    122  1.10  christos 	for (curdb = databases; curdb->name != NULL; curdb++)
    123  1.10  christos 		if (strcmp(curdb->name, argv[1]) == 0)
    124  1.10  christos 			return (*curdb->callback)(argc, argv);
    125  1.10  christos 
    126  1.10  christos 	warn("Unknown database `%s'", argv[1]);
    127   1.1     lukem 	usage();
    128   1.1     lukem 	/* NOTREACHED */
    129   1.1     lukem }
    130   1.1     lukem 
    131   1.1     lukem static int
    132   1.1     lukem usage(void)
    133   1.1     lukem {
    134   1.5     lukem 	struct getentdb	*curdb;
    135  1.18  christos 	size_t i;
    136   1.1     lukem 
    137  1.10  christos 	(void)fprintf(stderr, "Usage: %s database [key ...]\n",
    138   1.1     lukem 	    getprogname());
    139  1.18  christos 	(void)fprintf(stderr, "\tdatabase may be one of:");
    140  1.18  christos 	for (i = 0, curdb = databases; curdb->name != NULL; curdb++, i++) {
    141  1.18  christos 		if (i % 7 == 0)
    142  1.18  christos 			(void)fputs("\n\t\t", stderr);
    143  1.18  christos 		(void)fprintf(stderr, "%s%s", i % 7 == 0 ? "" : " ",
    144  1.18  christos 		    curdb->name);
    145  1.18  christos 	}
    146  1.10  christos 	(void)fprintf(stderr, "\n");
    147   1.1     lukem 	exit(RV_USAGE);
    148   1.1     lukem 	/* NOTREACHED */
    149   1.1     lukem }
    150   1.1     lukem 
    151   1.1     lukem static int
    152   1.1     lukem parsenum(const char *word, unsigned long *result)
    153   1.1     lukem {
    154   1.1     lukem 	unsigned long	num;
    155   1.1     lukem 	char		*ep;
    156   1.1     lukem 
    157   1.1     lukem 	assert(word != NULL);
    158   1.1     lukem 	assert(result != NULL);
    159   1.1     lukem 
    160   1.1     lukem 	if (!isdigit((unsigned char)word[0]))
    161   1.1     lukem 		return 0;
    162   1.1     lukem 	errno = 0;
    163   1.1     lukem 	num = strtoul(word, &ep, 10);
    164   1.1     lukem 	if (num == ULONG_MAX && errno == ERANGE)
    165   1.1     lukem 		return 0;
    166   1.1     lukem 	if (*ep != '\0')
    167   1.1     lukem 		return 0;
    168   1.1     lukem 	*result = num;
    169   1.1     lukem 	return 1;
    170   1.1     lukem }
    171   1.1     lukem 
    172   1.5     lukem /*
    173   1.5     lukem  * printfmtstrings --
    174   1.5     lukem  *	vprintf(format, ...),
    175   1.5     lukem  *	then the aliases (beginning with prefix, separated by sep),
    176   1.5     lukem  *	then a newline
    177   1.5     lukem  */
    178  1.19     joerg static __printflike(4, 5) void
    179   1.5     lukem printfmtstrings(char *strings[], const char *prefix, const char *sep,
    180  1.10  christos     const char *fmt, ...)
    181   1.5     lukem {
    182   1.5     lukem 	va_list		ap;
    183   1.5     lukem 	const char	*curpref;
    184  1.10  christos 	size_t		i;
    185   1.1     lukem 
    186   1.5     lukem 	va_start(ap, fmt);
    187  1.10  christos 	(void)vprintf(fmt, ap);
    188  1.10  christos 	va_end(ap);
    189   1.1     lukem 
    190   1.5     lukem 	curpref = prefix;
    191   1.5     lukem 	for (i = 0; strings[i] != NULL; i++) {
    192  1.10  christos 		(void)printf("%s%s", curpref, strings[i]);
    193   1.5     lukem 		curpref = sep;
    194   1.1     lukem 	}
    195  1.10  christos 	(void)printf("\n");
    196   1.1     lukem }
    197   1.1     lukem 
    198   1.5     lukem 
    199   1.5     lukem 		/*
    200   1.7  ginsbach 		 * ethers
    201   1.7  ginsbach 		 */
    202   1.7  ginsbach 
    203   1.7  ginsbach static int
    204   1.7  ginsbach ethers(int argc, char *argv[])
    205   1.7  ginsbach {
    206   1.7  ginsbach 	char		hostname[MAXHOSTNAMELEN + 1], *hp;
    207   1.7  ginsbach 	struct ether_addr ea, *eap;
    208   1.7  ginsbach 	int		i, rv;
    209   1.7  ginsbach 
    210   1.7  ginsbach 	assert(argc > 1);
    211   1.7  ginsbach 	assert(argv != NULL);
    212   1.7  ginsbach 
    213  1.10  christos #define ETHERSPRINT	(void)printf("%-17s  %s\n", ether_ntoa(eap), hp)
    214   1.7  ginsbach 
    215   1.7  ginsbach 	rv = RV_OK;
    216   1.7  ginsbach 	if (argc == 2) {
    217  1.10  christos 		warnx("Enumeration not supported on ethers");
    218   1.7  ginsbach 		rv = RV_NOENUM;
    219   1.7  ginsbach 	} else {
    220   1.7  ginsbach 		for (i = 2; i < argc; i++) {
    221   1.7  ginsbach 			if ((eap = ether_aton(argv[i])) == NULL) {
    222   1.7  ginsbach 				eap = &ea;
    223   1.7  ginsbach 				hp = argv[i];
    224   1.7  ginsbach 				if (ether_hostton(hp, eap) != 0) {
    225   1.7  ginsbach 					rv = RV_NOTFOUND;
    226   1.7  ginsbach 					break;
    227   1.7  ginsbach 				}
    228   1.7  ginsbach 			} else {
    229   1.7  ginsbach 				hp = hostname;
    230   1.7  ginsbach 				if (ether_ntohost(hp, eap) != 0) {
    231   1.7  ginsbach 					rv = RV_NOTFOUND;
    232   1.7  ginsbach 					break;
    233   1.7  ginsbach 				}
    234   1.7  ginsbach 			}
    235   1.7  ginsbach 			ETHERSPRINT;
    236   1.7  ginsbach 		}
    237   1.7  ginsbach 	}
    238   1.7  ginsbach 	return rv;
    239   1.7  ginsbach }
    240   1.7  ginsbach 
    241   1.7  ginsbach 		/*
    242   1.5     lukem 		 * group
    243   1.5     lukem 		 */
    244   1.5     lukem 
    245   1.1     lukem static int
    246   1.1     lukem group(int argc, char *argv[])
    247   1.1     lukem {
    248   1.1     lukem 	struct group	*gr;
    249   1.1     lukem 	unsigned long	id;
    250   1.1     lukem 	int		i, rv;
    251   1.1     lukem 
    252   1.1     lukem 	assert(argc > 1);
    253   1.1     lukem 	assert(argv != NULL);
    254   1.1     lukem 
    255  1.20       kre #define GROUPPRINT	printfmtstrings(gr->gr_mem, "", ",", "%s:%s:%u:", \
    256   1.5     lukem 			    gr->gr_name, gr->gr_passwd, gr->gr_gid)
    257   1.5     lukem 
    258  1.10  christos 	(void)setgroupent(1);
    259   1.1     lukem 	rv = RV_OK;
    260   1.1     lukem 	if (argc == 2) {
    261   1.1     lukem 		while ((gr = getgrent()) != NULL)
    262   1.5     lukem 			GROUPPRINT;
    263   1.1     lukem 	} else {
    264   1.1     lukem 		for (i = 2; i < argc; i++) {
    265   1.1     lukem 			if (parsenum(argv[i], &id))
    266  1.10  christos 				gr = getgrgid((gid_t)id);
    267   1.1     lukem 			else
    268   1.1     lukem 				gr = getgrnam(argv[i]);
    269   1.1     lukem 			if (gr != NULL)
    270   1.5     lukem 				GROUPPRINT;
    271   1.1     lukem 			else {
    272   1.1     lukem 				rv = RV_NOTFOUND;
    273   1.1     lukem 				break;
    274   1.1     lukem 			}
    275   1.1     lukem 		}
    276   1.1     lukem 	}
    277   1.1     lukem 	endgrent();
    278   1.1     lukem 	return rv;
    279   1.1     lukem }
    280   1.1     lukem 
    281   1.3     lukem 
    282   1.1     lukem 		/*
    283   1.1     lukem 		 * hosts
    284   1.1     lukem 		 */
    285   1.1     lukem 
    286   1.1     lukem static void
    287   1.1     lukem hostsprint(const struct hostent *he)
    288   1.1     lukem {
    289   1.1     lukem 	char	buf[INET6_ADDRSTRLEN];
    290   1.1     lukem 
    291   1.1     lukem 	assert(he != NULL);
    292   1.1     lukem 	if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL)
    293  1.10  christos 		(void)strlcpy(buf, "# unknown", sizeof(buf));
    294   1.5     lukem 	printfmtstrings(he->h_aliases, "  ", " ", "%-16s  %s", buf, he->h_name);
    295   1.1     lukem }
    296   1.1     lukem 
    297   1.1     lukem static int
    298   1.1     lukem hosts(int argc, char *argv[])
    299   1.1     lukem {
    300   1.1     lukem 	struct hostent	*he;
    301   1.1     lukem 	char		addr[IN6ADDRSZ];
    302   1.1     lukem 	int		i, rv;
    303   1.1     lukem 
    304   1.1     lukem 	assert(argc > 1);
    305   1.1     lukem 	assert(argv != NULL);
    306   1.1     lukem 
    307   1.1     lukem 	sethostent(1);
    308   1.1     lukem 	rv = RV_OK;
    309   1.1     lukem 	if (argc == 2) {
    310   1.1     lukem 		while ((he = gethostent()) != NULL)
    311   1.1     lukem 			hostsprint(he);
    312   1.1     lukem 	} else {
    313   1.1     lukem 		for (i = 2; i < argc; i++) {
    314   1.1     lukem 			if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0)
    315   1.1     lukem 				he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6);
    316   1.1     lukem 			else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0)
    317   1.1     lukem 				he = gethostbyaddr(addr, INADDRSZ, AF_INET);
    318   1.1     lukem 			else
    319   1.1     lukem 				he = gethostbyname(argv[i]);
    320   1.1     lukem 			if (he != NULL)
    321   1.1     lukem 				hostsprint(he);
    322   1.1     lukem 			else {
    323   1.1     lukem 				rv = RV_NOTFOUND;
    324   1.1     lukem 				break;
    325   1.1     lukem 			}
    326   1.1     lukem 		}
    327   1.1     lukem 	}
    328   1.1     lukem 	endhostent();
    329   1.1     lukem 	return rv;
    330   1.1     lukem }
    331   1.1     lukem 
    332  1.14      tron 		/*
    333  1.14      tron 		 * netgroup
    334  1.14      tron 		 */
    335  1.14      tron static int
    336  1.14      tron netgroup(int argc, char *argv[])
    337  1.14      tron {
    338  1.14      tron 	int		rv, i;
    339  1.14      tron 	bool		first;
    340  1.14      tron 	const char	*host, *user, *domain;
    341  1.14      tron 
    342  1.14      tron 	assert(argc > 1);
    343  1.14      tron 	assert(argv != NULL);
    344  1.14      tron 
    345  1.14      tron #define NETGROUPPRINT(s)	(((s) != NULL) ? (s) : "")
    346  1.14      tron 
    347  1.14      tron 	rv = RV_OK;
    348  1.14      tron 	if (argc == 2) {
    349  1.14      tron 		warnx("Enumeration not supported on netgroup");
    350  1.14      tron 		rv = RV_NOENUM;
    351  1.14      tron 	} else {
    352  1.14      tron 		for (i = 2; i < argc; i++) {
    353  1.14      tron 			setnetgrent(argv[i]);
    354  1.14      tron 			first = true;
    355  1.14      tron 			while (getnetgrent(&host, &user, &domain) != 0) {
    356  1.14      tron 				if (first) {
    357  1.14      tron 					first = false;
    358  1.14      tron 					(void)fputs(argv[i], stdout);
    359  1.14      tron 				}
    360  1.14      tron 				(void)printf(" (%s,%s,%s)",
    361  1.14      tron 				    NETGROUPPRINT(host),
    362  1.14      tron 				    NETGROUPPRINT(user),
    363  1.14      tron 				    NETGROUPPRINT(domain));
    364  1.14      tron 			}
    365  1.14      tron 			if (!first)
    366  1.14      tron 				(void)putchar('\n');
    367  1.14      tron 			endnetgrent();
    368  1.14      tron 		}
    369  1.14      tron 	}
    370  1.14      tron 
    371  1.14      tron 	return rv;
    372  1.14      tron }
    373   1.2     lukem 
    374   1.2     lukem 		/*
    375   1.2     lukem 		 * networks
    376   1.2     lukem 		 */
    377   1.2     lukem 
    378   1.2     lukem static void
    379   1.2     lukem networksprint(const struct netent *ne)
    380   1.2     lukem {
    381   1.2     lukem 	char		buf[INET6_ADDRSTRLEN];
    382   1.2     lukem 	struct	in_addr	ianet;
    383   1.2     lukem 
    384   1.2     lukem 	assert(ne != NULL);
    385   1.2     lukem 	ianet = inet_makeaddr(ne->n_net, 0);
    386   1.2     lukem 	if (inet_ntop(ne->n_addrtype, &ianet, buf, sizeof(buf)) == NULL)
    387  1.10  christos 		(void)strlcpy(buf, "# unknown", sizeof(buf));
    388   1.5     lukem 	printfmtstrings(ne->n_aliases, "  ", " ", "%-16s  %s", ne->n_name, buf);
    389   1.2     lukem }
    390   1.2     lukem 
    391   1.2     lukem static int
    392   1.2     lukem networks(int argc, char *argv[])
    393   1.2     lukem {
    394   1.2     lukem 	struct netent	*ne;
    395   1.2     lukem 	in_addr_t	net;
    396   1.2     lukem 	int		i, rv;
    397   1.2     lukem 
    398   1.2     lukem 	assert(argc > 1);
    399   1.2     lukem 	assert(argv != NULL);
    400   1.2     lukem 
    401   1.2     lukem 	setnetent(1);
    402   1.2     lukem 	rv = RV_OK;
    403   1.2     lukem 	if (argc == 2) {
    404   1.2     lukem 		while ((ne = getnetent()) != NULL)
    405   1.2     lukem 			networksprint(ne);
    406   1.2     lukem 	} else {
    407   1.2     lukem 		for (i = 2; i < argc; i++) {
    408   1.2     lukem 			net = inet_network(argv[i]);
    409   1.2     lukem 			if (net != INADDR_NONE)
    410   1.2     lukem 				ne = getnetbyaddr(net, AF_INET);
    411   1.2     lukem 			else
    412   1.2     lukem 				ne = getnetbyname(argv[i]);
    413   1.2     lukem 			if (ne != NULL)
    414   1.2     lukem 				networksprint(ne);
    415   1.2     lukem 			else {
    416   1.2     lukem 				rv = RV_NOTFOUND;
    417   1.2     lukem 				break;
    418   1.2     lukem 			}
    419   1.2     lukem 		}
    420   1.2     lukem 	}
    421   1.2     lukem 	endnetent();
    422   1.2     lukem 	return rv;
    423   1.2     lukem }
    424   1.2     lukem 
    425   1.3     lukem 
    426   1.1     lukem 		/*
    427   1.1     lukem 		 * passwd
    428   1.1     lukem 		 */
    429   1.1     lukem 
    430   1.1     lukem static int
    431   1.1     lukem passwd(int argc, char *argv[])
    432   1.1     lukem {
    433   1.1     lukem 	struct passwd	*pw;
    434   1.1     lukem 	unsigned long	id;
    435   1.1     lukem 	int		i, rv;
    436   1.1     lukem 
    437   1.1     lukem 	assert(argc > 1);
    438   1.1     lukem 	assert(argv != NULL);
    439   1.1     lukem 
    440  1.10  christos #define PASSWDPRINT	(void)printf("%s:%s:%u:%u:%s:%s:%s\n", \
    441   1.5     lukem 			    pw->pw_name, pw->pw_passwd, pw->pw_uid, \
    442   1.5     lukem 			    pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell)
    443   1.5     lukem 
    444  1.10  christos 	(void)setpassent(1);
    445   1.1     lukem 	rv = RV_OK;
    446   1.1     lukem 	if (argc == 2) {
    447   1.1     lukem 		while ((pw = getpwent()) != NULL)
    448   1.5     lukem 			PASSWDPRINT;
    449   1.1     lukem 	} else {
    450   1.1     lukem 		for (i = 2; i < argc; i++) {
    451   1.1     lukem 			if (parsenum(argv[i], &id))
    452  1.10  christos 				pw = getpwuid((uid_t)id);
    453   1.1     lukem 			else
    454   1.1     lukem 				pw = getpwnam(argv[i]);
    455   1.1     lukem 			if (pw != NULL)
    456   1.5     lukem 				PASSWDPRINT;
    457   1.1     lukem 			else {
    458   1.1     lukem 				rv = RV_NOTFOUND;
    459   1.1     lukem 				break;
    460   1.1     lukem 			}
    461   1.1     lukem 		}
    462   1.1     lukem 	}
    463   1.1     lukem 	endpwent();
    464   1.1     lukem 	return rv;
    465   1.1     lukem }
    466   1.1     lukem 
    467  1.10  christos static char *
    468  1.10  christos mygetent(const char * const * db_array, const char *name)
    469  1.10  christos {
    470  1.10  christos 	char *buf = NULL;
    471  1.10  christos 	int error;
    472  1.10  christos 
    473  1.10  christos 	switch (error = cgetent(&buf, db_array, name)) {
    474  1.10  christos 	case -3:
    475  1.10  christos 		warnx("tc= loop in record `%s' in `%s'", name, db_array[0]);
    476  1.10  christos 		break;
    477  1.10  christos 	case -2:
    478  1.10  christos 		warn("system error fetching record `%s' in `%s'", name,
    479  1.10  christos 		    db_array[0]);
    480  1.10  christos 		break;
    481  1.10  christos 	case -1:
    482  1.10  christos 	case 0:
    483  1.10  christos 		break;
    484  1.10  christos 	case 1:
    485  1.10  christos 		warnx("tc= reference not found in record for `%s' in `%s'",
    486  1.10  christos 		    name, db_array[0]);
    487  1.10  christos 		break;
    488  1.10  christos 	default:
    489  1.10  christos 		warnx("unknown error %d in record `%s' in `%s'", error, name,
    490  1.10  christos 		    db_array[0]);
    491  1.10  christos 		break;
    492  1.10  christos 	}
    493  1.10  christos 	return buf;
    494  1.10  christos }
    495  1.10  christos 
    496  1.10  christos static char *
    497  1.10  christos mygetone(const char * const * db_array, int first)
    498  1.10  christos {
    499  1.10  christos 	char *buf = NULL;
    500  1.10  christos 	int error;
    501  1.10  christos 
    502  1.10  christos 	switch (error = (first ? cgetfirst : cgetnext)(&buf, db_array)) {
    503  1.10  christos 	case -2:
    504  1.10  christos 		warnx("tc= loop in `%s'", db_array[0]);
    505  1.10  christos 		break;
    506  1.10  christos 	case -1:
    507  1.10  christos 		warn("system error fetching record in `%s'", db_array[0]);
    508  1.10  christos 		break;
    509  1.10  christos 	case 0:
    510  1.10  christos 	case 1:
    511  1.10  christos 		break;
    512  1.10  christos 	case 2:
    513  1.10  christos 		warnx("tc= reference not found in `%s'", db_array[0]);
    514  1.10  christos 		break;
    515  1.10  christos 	default:
    516  1.10  christos 		warnx("unknown error %d in `%s'", error, db_array[0]);
    517  1.10  christos 		break;
    518  1.10  christos 	}
    519  1.10  christos 	return buf;
    520  1.10  christos }
    521  1.10  christos 
    522  1.10  christos static void
    523  1.10  christos capprint(const char *cap)
    524  1.10  christos {
    525  1.10  christos 	char *c = strchr(cap, ':');
    526  1.10  christos 	if (c)
    527  1.10  christos 		if (c == cap)
    528  1.10  christos 			(void)printf("true\n");
    529  1.10  christos 		else {
    530  1.10  christos 			int l = (int)(c - cap);
    531  1.10  christos 			(void)printf("%*.*s\n", l, l, cap);
    532  1.10  christos 		}
    533  1.10  christos 	else
    534  1.10  christos 		(void)printf("%s\n", cap);
    535  1.10  christos }
    536  1.11  christos 
    537  1.11  christos static void
    538  1.11  christos prettyprint(char *b)
    539  1.11  christos {
    540  1.11  christos #define TERMWIDTH 65
    541  1.11  christos 	int did = 0;
    542  1.11  christos 	size_t len;
    543  1.11  christos 	char *s, c;
    544  1.11  christos 
    545  1.11  christos 	for (;;) {
    546  1.11  christos 		len = strlen(b);
    547  1.11  christos 		if (len <= TERMWIDTH) {
    548  1.11  christos done:
    549  1.11  christos 			if (did)
    550  1.11  christos 				printf("\t:");
    551  1.11  christos 			printf("%s\n", b);
    552  1.11  christos 			return;
    553  1.11  christos 		}
    554  1.11  christos 		for (s = b + TERMWIDTH; s > b && *s != ':'; s--)
    555  1.11  christos 			continue;
    556  1.11  christos 		if (*s++ != ':')
    557  1.11  christos 			goto done;
    558  1.11  christos 		c = *s;
    559  1.11  christos 		*s = '\0';
    560  1.11  christos 		if (did)
    561  1.11  christos 			printf("\t:");
    562  1.11  christos 		did++;
    563  1.11  christos 		printf("%s\\\n", b);
    564  1.11  christos 		*s = c;
    565  1.11  christos 		b = s;
    566  1.11  christos 	}
    567  1.11  christos }
    568  1.11  christos 
    569  1.11  christos static void
    570  1.11  christos handleone(const char * const *db_array, char *b, int recurse, int pretty,
    571  1.11  christos     int level)
    572  1.11  christos {
    573  1.11  christos 	char *tc;
    574  1.11  christos 
    575  1.11  christos 	if (level && pretty)
    576  1.11  christos 		printf("\n");
    577  1.11  christos 	if (pretty)
    578  1.11  christos 		prettyprint(b);
    579  1.11  christos 	else
    580  1.11  christos 		printf("%s\n", b);
    581  1.11  christos 	if (!recurse || cgetstr(b, "tc", &tc) <= 0)
    582  1.11  christos 		return;
    583  1.11  christos 
    584  1.11  christos 	b = mygetent(db_array, tc);
    585  1.11  christos 	free(tc);
    586  1.11  christos 
    587  1.11  christos 	if (b == NULL)
    588  1.11  christos 		return;
    589  1.11  christos 
    590  1.11  christos 	handleone(db_array, b, recurse, pretty, ++level);
    591  1.11  christos 	free(b);
    592  1.11  christos }
    593  1.11  christos 
    594  1.10  christos static int
    595  1.10  christos handlecap(const char *db, int argc, char *argv[])
    596  1.10  christos {
    597  1.10  christos 	static const char sfx[] = "=#:";
    598  1.10  christos 	const char *db_array[] = { db, NULL };
    599  1.10  christos 	char	*b, *cap;
    600  1.16     lukem 	int	i, rv, c;
    601  1.16     lukem 	size_t	j;
    602  1.11  christos 	int	expand = 1, recurse = 0, pretty = 0;
    603  1.10  christos 
    604  1.10  christos 	assert(argc > 1);
    605  1.10  christos 	assert(argv != NULL);
    606  1.10  christos 
    607  1.11  christos 	argc--;
    608  1.11  christos 	argv++;
    609  1.11  christos 	while ((c = getopt(argc, argv, "pnr")) != -1)
    610  1.11  christos 		switch (c) {
    611  1.11  christos 		case 'n':
    612  1.11  christos 			expand = 0;
    613  1.11  christos 			break;
    614  1.11  christos 		case 'r':
    615  1.11  christos 			expand = 0;
    616  1.11  christos 			recurse = 1;
    617  1.11  christos 			break;
    618  1.11  christos 		case 'p':
    619  1.11  christos 			pretty = 1;
    620  1.11  christos 			break;
    621  1.11  christos 		default:
    622  1.11  christos 			usage();
    623  1.11  christos 			break;
    624  1.11  christos 		}
    625  1.11  christos 
    626  1.11  christos 	argc -= optind;
    627  1.11  christos 	argv += optind;
    628  1.11  christos 	csetexpandtc(expand);
    629  1.10  christos 	rv = RV_OK;
    630  1.11  christos 	if (argc == 0) {
    631  1.10  christos 		for (b = mygetone(db_array, 1); b; b = mygetone(db_array, 0)) {
    632  1.11  christos 			handleone(db_array, b, recurse, pretty, 0);
    633  1.10  christos 			free(b);
    634  1.10  christos 		}
    635  1.10  christos 	} else {
    636  1.11  christos 		if ((b = mygetent(db_array, argv[0])) == NULL)
    637  1.10  christos 			return RV_NOTFOUND;
    638  1.11  christos 		if (argc == 1)
    639  1.11  christos 			handleone(db_array, b, recurse, pretty, 0);
    640  1.10  christos 		else {
    641  1.11  christos 			for (i = 2; i < argc; i++) {
    642  1.10  christos 				for (j = 0; j < sizeof(sfx) - 1; j++) {
    643  1.10  christos 					cap = cgetcap(b, argv[i], sfx[j]);
    644  1.10  christos 					if (cap) {
    645  1.10  christos 						capprint(cap);
    646  1.10  christos 						break;
    647  1.21       kre 					}
    648  1.10  christos 				}
    649  1.10  christos 				if (j == sizeof(sfx) - 1)
    650  1.10  christos 					printf("false\n");
    651  1.10  christos 			}
    652  1.10  christos 		}
    653  1.10  christos 		free(b);
    654  1.10  christos 	}
    655  1.10  christos 	return rv;
    656  1.10  christos }
    657  1.10  christos 
    658  1.10  christos 		/*
    659  1.12  christos 		 * gettytab
    660  1.12  christos 		 */
    661  1.12  christos 
    662  1.12  christos static int
    663  1.12  christos gettytab(int argc, char *argv[])
    664  1.12  christos {
    665  1.12  christos 	return handlecap(_PATH_GETTYTAB, argc, argv);
    666  1.12  christos }
    667  1.12  christos 
    668  1.12  christos 		/*
    669  1.10  christos 		 * printcap
    670  1.10  christos 		 */
    671  1.10  christos 
    672  1.10  christos static int
    673  1.10  christos printcap(int argc, char *argv[])
    674  1.10  christos {
    675  1.10  christos 	return handlecap(_PATH_PRINTCAP, argc, argv);
    676  1.10  christos }
    677   1.3     lukem 
    678   1.3     lukem 		/*
    679  1.10  christos 		 * disktab
    680  1.10  christos 		 */
    681  1.10  christos 
    682  1.10  christos static int
    683  1.10  christos disktab(int argc, char *argv[])
    684  1.10  christos {
    685  1.10  christos 	return handlecap(_PATH_DISKTAB, argc, argv);
    686  1.10  christos }
    687  1.10  christos 
    688  1.10  christos 		/*
    689   1.3     lukem 		 * protocols
    690   1.3     lukem 		 */
    691   1.3     lukem 
    692   1.3     lukem static int
    693   1.3     lukem protocols(int argc, char *argv[])
    694   1.3     lukem {
    695   1.3     lukem 	struct protoent	*pe;
    696   1.3     lukem 	unsigned long	id;
    697   1.3     lukem 	int		i, rv;
    698   1.3     lukem 
    699   1.3     lukem 	assert(argc > 1);
    700   1.3     lukem 	assert(argv != NULL);
    701   1.3     lukem 
    702   1.5     lukem #define PROTOCOLSPRINT	printfmtstrings(pe->p_aliases, "  ", " ", \
    703   1.5     lukem 			    "%-16s  %5d", pe->p_name, pe->p_proto)
    704   1.5     lukem 
    705   1.3     lukem 	setprotoent(1);
    706   1.3     lukem 	rv = RV_OK;
    707   1.3     lukem 	if (argc == 2) {
    708   1.3     lukem 		while ((pe = getprotoent()) != NULL)
    709   1.5     lukem 			PROTOCOLSPRINT;
    710   1.3     lukem 	} else {
    711   1.3     lukem 		for (i = 2; i < argc; i++) {
    712   1.3     lukem 			if (parsenum(argv[i], &id))
    713  1.10  christos 				pe = getprotobynumber((int)id);
    714   1.3     lukem 			else
    715   1.3     lukem 				pe = getprotobyname(argv[i]);
    716   1.3     lukem 			if (pe != NULL)
    717   1.5     lukem 				PROTOCOLSPRINT;
    718   1.3     lukem 			else {
    719   1.3     lukem 				rv = RV_NOTFOUND;
    720   1.3     lukem 				break;
    721   1.3     lukem 			}
    722   1.3     lukem 		}
    723   1.3     lukem 	}
    724   1.3     lukem 	endprotoent();
    725   1.3     lukem 	return rv;
    726   1.3     lukem }
    727   1.3     lukem 
    728   1.6  ginsbach 		/*
    729   1.6  ginsbach 		 * rpc
    730   1.6  ginsbach 		 */
    731   1.6  ginsbach 
    732   1.6  ginsbach static int
    733   1.6  ginsbach rpc(int argc, char *argv[])
    734   1.6  ginsbach {
    735   1.6  ginsbach 	struct rpcent	*re;
    736   1.6  ginsbach 	unsigned long	id;
    737   1.6  ginsbach 	int		i, rv;
    738  1.21       kre 
    739   1.6  ginsbach 	assert(argc > 1);
    740   1.6  ginsbach 	assert(argv != NULL);
    741   1.6  ginsbach 
    742   1.6  ginsbach #define RPCPRINT	printfmtstrings(re->r_aliases, "  ", " ", \
    743   1.6  ginsbach 				"%-16s  %6d", \
    744   1.6  ginsbach 				re->r_name, re->r_number)
    745   1.6  ginsbach 
    746   1.6  ginsbach 	setrpcent(1);
    747   1.6  ginsbach 	rv = RV_OK;
    748   1.6  ginsbach 	if (argc == 2) {
    749   1.6  ginsbach 		while ((re = getrpcent()) != NULL)
    750   1.6  ginsbach 			RPCPRINT;
    751   1.6  ginsbach 	} else {
    752   1.6  ginsbach 		for (i = 2; i < argc; i++) {
    753   1.6  ginsbach 			if (parsenum(argv[i], &id))
    754  1.10  christos 				re = getrpcbynumber((int)id);
    755   1.6  ginsbach 			else
    756   1.6  ginsbach 				re = getrpcbyname(argv[i]);
    757   1.6  ginsbach 			if (re != NULL)
    758   1.6  ginsbach 				RPCPRINT;
    759   1.6  ginsbach 			else {
    760   1.6  ginsbach 				rv = RV_NOTFOUND;
    761   1.6  ginsbach 				break;
    762   1.6  ginsbach 			}
    763   1.6  ginsbach 		}
    764   1.6  ginsbach 	}
    765   1.6  ginsbach 	endrpcent();
    766   1.6  ginsbach 	return rv;
    767   1.6  ginsbach }
    768   1.3     lukem 
    769   1.1     lukem 		/*
    770   1.4     lukem 		 * services
    771   1.4     lukem 		 */
    772   1.4     lukem 
    773   1.4     lukem static int
    774   1.4     lukem services(int argc, char *argv[])
    775   1.4     lukem {
    776   1.4     lukem 	struct servent	*se;
    777   1.4     lukem 	unsigned long	id;
    778   1.4     lukem 	char		*proto;
    779   1.4     lukem 	int		i, rv;
    780   1.4     lukem 
    781   1.4     lukem 	assert(argc > 1);
    782   1.4     lukem 	assert(argv != NULL);
    783   1.4     lukem 
    784   1.5     lukem #define SERVICESPRINT	printfmtstrings(se->s_aliases, "  ", " ", \
    785   1.5     lukem 			    "%-16s  %5d/%s", \
    786   1.5     lukem 			    se->s_name, ntohs(se->s_port), se->s_proto)
    787   1.5     lukem 
    788   1.4     lukem 	setservent(1);
    789   1.4     lukem 	rv = RV_OK;
    790   1.4     lukem 	if (argc == 2) {
    791   1.4     lukem 		while ((se = getservent()) != NULL)
    792   1.5     lukem 			SERVICESPRINT;
    793   1.4     lukem 	} else {
    794   1.4     lukem 		for (i = 2; i < argc; i++) {
    795   1.4     lukem 			proto = strchr(argv[i], '/');
    796   1.4     lukem 			if (proto != NULL)
    797   1.4     lukem 				*proto++ = '\0';
    798   1.4     lukem 			if (parsenum(argv[i], &id))
    799   1.9    simonb 				se = getservbyport(htons(id), proto);
    800   1.4     lukem 			else
    801   1.4     lukem 				se = getservbyname(argv[i], proto);
    802   1.4     lukem 			if (se != NULL)
    803   1.5     lukem 				SERVICESPRINT;
    804   1.4     lukem 			else {
    805   1.4     lukem 				rv = RV_NOTFOUND;
    806   1.4     lukem 				break;
    807   1.4     lukem 			}
    808   1.4     lukem 		}
    809   1.4     lukem 	}
    810   1.4     lukem 	endservent();
    811   1.4     lukem 	return rv;
    812   1.4     lukem }
    813   1.4     lukem 
    814   1.4     lukem 
    815   1.4     lukem 		/*
    816   1.1     lukem 		 * shells
    817   1.1     lukem 		 */
    818   1.1     lukem 
    819   1.1     lukem static int
    820   1.1     lukem shells(int argc, char *argv[])
    821   1.1     lukem {
    822   1.1     lukem 	const char	*sh;
    823   1.1     lukem 	int		i, rv;
    824   1.1     lukem 
    825   1.1     lukem 	assert(argc > 1);
    826   1.1     lukem 	assert(argv != NULL);
    827   1.1     lukem 
    828  1.10  christos #define SHELLSPRINT	(void)printf("%s\n", sh)
    829   1.5     lukem 
    830   1.1     lukem 	setusershell();
    831   1.1     lukem 	rv = RV_OK;
    832   1.1     lukem 	if (argc == 2) {
    833   1.1     lukem 		while ((sh = getusershell()) != NULL)
    834   1.5     lukem 			SHELLSPRINT;
    835   1.1     lukem 	} else {
    836   1.1     lukem 		for (i = 2; i < argc; i++) {
    837   1.1     lukem 			setusershell();
    838   1.1     lukem 			while ((sh = getusershell()) != NULL) {
    839   1.1     lukem 				if (strcmp(sh, argv[i]) == 0) {
    840   1.5     lukem 					SHELLSPRINT;
    841   1.1     lukem 					break;
    842   1.1     lukem 				}
    843   1.1     lukem 			}
    844   1.1     lukem 			if (sh == NULL) {
    845   1.1     lukem 				rv = RV_NOTFOUND;
    846   1.1     lukem 				break;
    847   1.1     lukem 			}
    848   1.1     lukem 		}
    849   1.1     lukem 	}
    850   1.1     lukem 	endusershell();
    851   1.1     lukem 	return rv;
    852   1.1     lukem }
    853