Home | History | Annotate | Line # | Download | only in getent
getent.c revision 1.12
      1  1.12  christos /*	$NetBSD: getent.c,v 1.12 2008/02/04 15:30:45 christos 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  * 3. All advertising materials mentioning features or use of this software
     19   1.1     lukem  *    must display the following acknowledgement:
     20   1.1     lukem  *	This product includes software developed by the NetBSD
     21   1.1     lukem  *	Foundation, Inc. and its contributors.
     22   1.1     lukem  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23   1.1     lukem  *    contributors may be used to endorse or promote products derived
     24   1.1     lukem  *    from this software without specific prior written permission.
     25   1.1     lukem  *
     26   1.1     lukem  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27   1.1     lukem  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28   1.1     lukem  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29   1.1     lukem  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30   1.1     lukem  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31   1.1     lukem  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32   1.1     lukem  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33   1.1     lukem  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34   1.1     lukem  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35   1.1     lukem  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36   1.1     lukem  * POSSIBILITY OF SUCH DAMAGE.
     37   1.1     lukem  */
     38   1.1     lukem 
     39   1.1     lukem #include <sys/cdefs.h>
     40   1.1     lukem #ifndef lint
     41  1.12  christos __RCSID("$NetBSD: getent.c,v 1.12 2008/02/04 15:30:45 christos Exp $");
     42   1.1     lukem #endif /* not lint */
     43   1.1     lukem 
     44   1.1     lukem #include <sys/socket.h>
     45   1.1     lukem 
     46   1.1     lukem #include <assert.h>
     47   1.1     lukem #include <ctype.h>
     48   1.1     lukem #include <errno.h>
     49   1.1     lukem #include <grp.h>
     50   1.1     lukem #include <limits.h>
     51   1.1     lukem #include <netdb.h>
     52   1.1     lukem #include <pwd.h>
     53   1.1     lukem #include <stdio.h>
     54   1.5     lukem #include <stdarg.h>
     55   1.1     lukem #include <stdlib.h>
     56   1.1     lukem #include <string.h>
     57   1.1     lukem #include <unistd.h>
     58  1.10  christos #include <paths.h>
     59  1.10  christos #include <err.h>
     60   1.1     lukem 
     61   1.1     lukem #include <arpa/inet.h>
     62   1.1     lukem #include <arpa/nameser.h>
     63   1.1     lukem 
     64   1.7  ginsbach #include <net/if.h>
     65   1.7  ginsbach #include <net/if_ether.h>
     66   1.7  ginsbach 
     67   1.1     lukem #include <netinet/in.h>		/* for INET6_ADDRSTRLEN */
     68   1.1     lukem 
     69   1.6  ginsbach #include <rpc/rpcent.h>
     70   1.6  ginsbach 
     71  1.10  christos #include <disktab.h>
     72  1.10  christos 
     73  1.10  christos static int	usage(void) __attribute__((__noreturn__));
     74   1.1     lukem static int	parsenum(const char *, unsigned long *);
     75  1.10  christos static int	disktab(int, char *[]);
     76  1.12  christos static int	gettytab(int, char *[]);
     77   1.7  ginsbach static int	ethers(int, char *[]);
     78   1.1     lukem static int	group(int, char *[]);
     79   1.1     lukem static int	hosts(int, char *[]);
     80   1.2     lukem static int	networks(int, char *[]);
     81   1.1     lukem static int	passwd(int, char *[]);
     82  1.10  christos static int	printcap(int, char *[]);
     83   1.3     lukem static int	protocols(int, char *[]);
     84   1.6  ginsbach static int	rpc(int, char *[]);
     85   1.4     lukem static int	services(int, char *[]);
     86   1.1     lukem static int	shells(int, char *[]);
     87  1.10  christos static int	termcap(int, char *[]);
     88   1.1     lukem 
     89   1.1     lukem enum {
     90   1.1     lukem 	RV_OK		= 0,
     91   1.1     lukem 	RV_USAGE	= 1,
     92   1.1     lukem 	RV_NOTFOUND	= 2,
     93  1.10  christos 	RV_NOENUM	= 3
     94   1.1     lukem };
     95   1.1     lukem 
     96   1.5     lukem static struct getentdb {
     97   1.5     lukem 	const char	*name;
     98   1.5     lukem 	int		(*callback)(int, char *[]);
     99   1.5     lukem } databases[] = {
    100  1.10  christos 	{	"disktab",	disktab,	},
    101   1.7  ginsbach 	{	"ethers",	ethers,		},
    102  1.12  christos 	{	"gettytab",	gettytab,	},
    103   1.5     lukem 	{	"group",	group,		},
    104   1.5     lukem 	{	"hosts",	hosts,		},
    105   1.5     lukem 	{	"networks",	networks,	},
    106   1.5     lukem 	{	"passwd",	passwd,		},
    107  1.10  christos 	{	"princap",	printcap,	},
    108   1.5     lukem 	{	"protocols",	protocols,	},
    109   1.6  ginsbach 	{	"rpc",		rpc,		},
    110   1.5     lukem 	{	"services",	services,	},
    111   1.5     lukem 	{	"shells",	shells,		},
    112  1.10  christos 	{	"termcap",	termcap,	},
    113   1.5     lukem 
    114   1.5     lukem 	{	NULL,		NULL,		},
    115   1.5     lukem };
    116   1.5     lukem 
    117   1.5     lukem 
    118   1.1     lukem int
    119   1.1     lukem main(int argc, char *argv[])
    120   1.1     lukem {
    121   1.5     lukem 	struct getentdb	*curdb;
    122   1.1     lukem 
    123   1.1     lukem 	setprogname(argv[0]);
    124   1.1     lukem 
    125   1.1     lukem 	if (argc < 2)
    126   1.1     lukem 		usage();
    127  1.10  christos 	for (curdb = databases; curdb->name != NULL; curdb++)
    128  1.10  christos 		if (strcmp(curdb->name, argv[1]) == 0)
    129  1.10  christos 			return (*curdb->callback)(argc, argv);
    130  1.10  christos 
    131  1.10  christos 	warn("Unknown database `%s'", argv[1]);
    132   1.1     lukem 	usage();
    133   1.1     lukem 	/* NOTREACHED */
    134   1.1     lukem }
    135   1.1     lukem 
    136   1.1     lukem static int
    137   1.1     lukem usage(void)
    138   1.1     lukem {
    139   1.5     lukem 	struct getentdb	*curdb;
    140   1.1     lukem 
    141  1.10  christos 	(void)fprintf(stderr, "Usage: %s database [key ...]\n",
    142   1.1     lukem 	    getprogname());
    143  1.10  christos 	(void)fprintf(stderr, "       database may be one of:\n\t");
    144  1.10  christos 	for (curdb = databases; curdb->name != NULL; curdb++)
    145  1.10  christos 		(void)fprintf(stderr, " %s", curdb->name);
    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.5     lukem static 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.5     lukem #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.2     lukem 
    333   1.2     lukem 		/*
    334   1.2     lukem 		 * networks
    335   1.2     lukem 		 */
    336   1.2     lukem 
    337   1.2     lukem static void
    338   1.2     lukem networksprint(const struct netent *ne)
    339   1.2     lukem {
    340   1.2     lukem 	char		buf[INET6_ADDRSTRLEN];
    341   1.2     lukem 	struct	in_addr	ianet;
    342   1.2     lukem 
    343   1.2     lukem 	assert(ne != NULL);
    344   1.2     lukem 	ianet = inet_makeaddr(ne->n_net, 0);
    345   1.2     lukem 	if (inet_ntop(ne->n_addrtype, &ianet, buf, sizeof(buf)) == NULL)
    346  1.10  christos 		(void)strlcpy(buf, "# unknown", sizeof(buf));
    347   1.5     lukem 	printfmtstrings(ne->n_aliases, "  ", " ", "%-16s  %s", ne->n_name, buf);
    348   1.2     lukem }
    349   1.2     lukem 
    350   1.2     lukem static int
    351   1.2     lukem networks(int argc, char *argv[])
    352   1.2     lukem {
    353   1.2     lukem 	struct netent	*ne;
    354   1.2     lukem 	in_addr_t	net;
    355   1.2     lukem 	int		i, rv;
    356   1.2     lukem 
    357   1.2     lukem 	assert(argc > 1);
    358   1.2     lukem 	assert(argv != NULL);
    359   1.2     lukem 
    360   1.2     lukem 	setnetent(1);
    361   1.2     lukem 	rv = RV_OK;
    362   1.2     lukem 	if (argc == 2) {
    363   1.2     lukem 		while ((ne = getnetent()) != NULL)
    364   1.2     lukem 			networksprint(ne);
    365   1.2     lukem 	} else {
    366   1.2     lukem 		for (i = 2; i < argc; i++) {
    367   1.2     lukem 			net = inet_network(argv[i]);
    368   1.2     lukem 			if (net != INADDR_NONE)
    369   1.2     lukem 				ne = getnetbyaddr(net, AF_INET);
    370   1.2     lukem 			else
    371   1.2     lukem 				ne = getnetbyname(argv[i]);
    372   1.2     lukem 			if (ne != NULL)
    373   1.2     lukem 				networksprint(ne);
    374   1.2     lukem 			else {
    375   1.2     lukem 				rv = RV_NOTFOUND;
    376   1.2     lukem 				break;
    377   1.2     lukem 			}
    378   1.2     lukem 		}
    379   1.2     lukem 	}
    380   1.2     lukem 	endnetent();
    381   1.2     lukem 	return rv;
    382   1.2     lukem }
    383   1.2     lukem 
    384   1.3     lukem 
    385   1.1     lukem 		/*
    386   1.1     lukem 		 * passwd
    387   1.1     lukem 		 */
    388   1.1     lukem 
    389   1.1     lukem static int
    390   1.1     lukem passwd(int argc, char *argv[])
    391   1.1     lukem {
    392   1.1     lukem 	struct passwd	*pw;
    393   1.1     lukem 	unsigned long	id;
    394   1.1     lukem 	int		i, rv;
    395   1.1     lukem 
    396   1.1     lukem 	assert(argc > 1);
    397   1.1     lukem 	assert(argv != NULL);
    398   1.1     lukem 
    399  1.10  christos #define PASSWDPRINT	(void)printf("%s:%s:%u:%u:%s:%s:%s\n", \
    400   1.5     lukem 			    pw->pw_name, pw->pw_passwd, pw->pw_uid, \
    401   1.5     lukem 			    pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell)
    402   1.5     lukem 
    403  1.10  christos 	(void)setpassent(1);
    404   1.1     lukem 	rv = RV_OK;
    405   1.1     lukem 	if (argc == 2) {
    406   1.1     lukem 		while ((pw = getpwent()) != NULL)
    407   1.5     lukem 			PASSWDPRINT;
    408   1.1     lukem 	} else {
    409   1.1     lukem 		for (i = 2; i < argc; i++) {
    410   1.1     lukem 			if (parsenum(argv[i], &id))
    411  1.10  christos 				pw = getpwuid((uid_t)id);
    412   1.1     lukem 			else
    413   1.1     lukem 				pw = getpwnam(argv[i]);
    414   1.1     lukem 			if (pw != NULL)
    415   1.5     lukem 				PASSWDPRINT;
    416   1.1     lukem 			else {
    417   1.1     lukem 				rv = RV_NOTFOUND;
    418   1.1     lukem 				break;
    419   1.1     lukem 			}
    420   1.1     lukem 		}
    421   1.1     lukem 	}
    422   1.1     lukem 	endpwent();
    423   1.1     lukem 	return rv;
    424   1.1     lukem }
    425   1.1     lukem 
    426  1.10  christos static char *
    427  1.10  christos mygetent(const char * const * db_array, const char *name)
    428  1.10  christos {
    429  1.10  christos 	char *buf = NULL;
    430  1.10  christos 	int error;
    431  1.10  christos 
    432  1.10  christos 	switch (error = cgetent(&buf, db_array, name)) {
    433  1.10  christos 	case -3:
    434  1.10  christos 		warnx("tc= loop in record `%s' in `%s'", name, db_array[0]);
    435  1.10  christos 		break;
    436  1.10  christos 	case -2:
    437  1.10  christos 		warn("system error fetching record `%s' in `%s'", name,
    438  1.10  christos 		    db_array[0]);
    439  1.10  christos 		break;
    440  1.10  christos 	case -1:
    441  1.10  christos 	case 0:
    442  1.10  christos 		break;
    443  1.10  christos 	case 1:
    444  1.10  christos 		warnx("tc= reference not found in record for `%s' in `%s'",
    445  1.10  christos 		    name, db_array[0]);
    446  1.10  christos 		break;
    447  1.10  christos 	default:
    448  1.10  christos 		warnx("unknown error %d in record `%s' in `%s'", error, name,
    449  1.10  christos 		    db_array[0]);
    450  1.10  christos 		break;
    451  1.10  christos 	}
    452  1.10  christos 	return buf;
    453  1.10  christos }
    454  1.10  christos 
    455  1.10  christos static char *
    456  1.10  christos mygetone(const char * const * db_array, int first)
    457  1.10  christos {
    458  1.10  christos 	char *buf = NULL;
    459  1.10  christos 	int error;
    460  1.10  christos 
    461  1.10  christos 	switch (error = (first ? cgetfirst : cgetnext)(&buf, db_array)) {
    462  1.10  christos 	case -2:
    463  1.10  christos 		warnx("tc= loop in `%s'", db_array[0]);
    464  1.10  christos 		break;
    465  1.10  christos 	case -1:
    466  1.10  christos 		warn("system error fetching record in `%s'", db_array[0]);
    467  1.10  christos 		break;
    468  1.10  christos 	case 0:
    469  1.10  christos 	case 1:
    470  1.10  christos 		break;
    471  1.10  christos 	case 2:
    472  1.10  christos 		warnx("tc= reference not found in `%s'", db_array[0]);
    473  1.10  christos 		break;
    474  1.10  christos 	default:
    475  1.10  christos 		warnx("unknown error %d in `%s'", error, db_array[0]);
    476  1.10  christos 		break;
    477  1.10  christos 	}
    478  1.10  christos 	return buf;
    479  1.10  christos }
    480  1.10  christos 
    481  1.10  christos static void
    482  1.10  christos capprint(const char *cap)
    483  1.10  christos {
    484  1.10  christos 	char *c = strchr(cap, ':');
    485  1.10  christos 	if (c)
    486  1.10  christos 		if (c == cap)
    487  1.10  christos 			(void)printf("true\n");
    488  1.10  christos 		else {
    489  1.10  christos 			int l = (int)(c - cap);
    490  1.10  christos 			(void)printf("%*.*s\n", l, l, cap);
    491  1.10  christos 		}
    492  1.10  christos 	else
    493  1.10  christos 		(void)printf("%s\n", cap);
    494  1.10  christos }
    495  1.11  christos 
    496  1.11  christos static void
    497  1.11  christos prettyprint(char *b)
    498  1.11  christos {
    499  1.11  christos #define TERMWIDTH 65
    500  1.11  christos 	int did = 0;
    501  1.11  christos 	size_t len;
    502  1.11  christos 	char *s, c;
    503  1.11  christos 
    504  1.11  christos 	for (;;) {
    505  1.11  christos 		len = strlen(b);
    506  1.11  christos 		if (len <= TERMWIDTH) {
    507  1.11  christos done:
    508  1.11  christos 			if (did)
    509  1.11  christos 				printf("\t:");
    510  1.11  christos 			printf("%s\n", b);
    511  1.11  christos 			return;
    512  1.11  christos 		}
    513  1.11  christos 		for (s = b + TERMWIDTH; s > b && *s != ':'; s--)
    514  1.11  christos 			continue;
    515  1.11  christos 		if (*s++ != ':')
    516  1.11  christos 			goto done;
    517  1.11  christos 		c = *s;
    518  1.11  christos 		*s = '\0';
    519  1.11  christos 		if (did)
    520  1.11  christos 			printf("\t:");
    521  1.11  christos 		did++;
    522  1.11  christos 		printf("%s\\\n", b);
    523  1.11  christos 		*s = c;
    524  1.11  christos 		b = s;
    525  1.11  christos 	}
    526  1.11  christos }
    527  1.11  christos 
    528  1.11  christos static void
    529  1.11  christos handleone(const char * const *db_array, char *b, int recurse, int pretty,
    530  1.11  christos     int level)
    531  1.11  christos {
    532  1.11  christos 	char *tc;
    533  1.11  christos 
    534  1.11  christos 	if (level && pretty)
    535  1.11  christos 		printf("\n");
    536  1.11  christos 	if (pretty)
    537  1.11  christos 		prettyprint(b);
    538  1.11  christos 	else
    539  1.11  christos 		printf("%s\n", b);
    540  1.11  christos 	if (!recurse || cgetstr(b, "tc", &tc) <= 0)
    541  1.11  christos 		return;
    542  1.11  christos 
    543  1.11  christos 	b = mygetent(db_array, tc);
    544  1.11  christos 	free(tc);
    545  1.11  christos 
    546  1.11  christos 	if (b == NULL)
    547  1.11  christos 		return;
    548  1.11  christos 
    549  1.11  christos 	handleone(db_array, b, recurse, pretty, ++level);
    550  1.11  christos 	free(b);
    551  1.11  christos }
    552  1.11  christos 
    553  1.10  christos static int
    554  1.10  christos handlecap(const char *db, int argc, char *argv[])
    555  1.10  christos {
    556  1.10  christos 	static const char sfx[] = "=#:";
    557  1.10  christos 	const char *db_array[] = { db, NULL };
    558  1.10  christos 	char	*b, *cap;
    559  1.11  christos 	int	i, j, rv, c;
    560  1.11  christos 	int	expand = 1, recurse = 0, pretty = 0;
    561  1.10  christos 
    562  1.10  christos 	assert(argc > 1);
    563  1.10  christos 	assert(argv != NULL);
    564  1.10  christos 
    565  1.11  christos 	argc--;
    566  1.11  christos 	argv++;
    567  1.11  christos 	while ((c = getopt(argc, argv, "pnr")) != -1)
    568  1.11  christos 		switch (c) {
    569  1.11  christos 		case 'n':
    570  1.11  christos 			expand = 0;
    571  1.11  christos 			break;
    572  1.11  christos 		case 'r':
    573  1.11  christos 			expand = 0;
    574  1.11  christos 			recurse = 1;
    575  1.11  christos 			break;
    576  1.11  christos 		case 'p':
    577  1.11  christos 			pretty = 1;
    578  1.11  christos 			break;
    579  1.11  christos 		default:
    580  1.11  christos 			usage();
    581  1.11  christos 			break;
    582  1.11  christos 		}
    583  1.11  christos 
    584  1.11  christos 	argc -= optind;
    585  1.11  christos 	argv += optind;
    586  1.11  christos 	csetexpandtc(expand);
    587  1.10  christos 	rv = RV_OK;
    588  1.11  christos 	if (argc == 0) {
    589  1.10  christos 		for (b = mygetone(db_array, 1); b; b = mygetone(db_array, 0)) {
    590  1.11  christos 			handleone(db_array, b, recurse, pretty, 0);
    591  1.10  christos 			free(b);
    592  1.10  christos 		}
    593  1.10  christos 	} else {
    594  1.11  christos 		if ((b = mygetent(db_array, argv[0])) == NULL)
    595  1.10  christos 			return RV_NOTFOUND;
    596  1.11  christos 		if (argc == 1)
    597  1.11  christos 			handleone(db_array, b, recurse, pretty, 0);
    598  1.10  christos 		else {
    599  1.11  christos 			for (i = 2; i < argc; i++) {
    600  1.10  christos 				for (j = 0; j < sizeof(sfx) - 1; j++) {
    601  1.10  christos 					cap = cgetcap(b, argv[i], sfx[j]);
    602  1.10  christos 					if (cap) {
    603  1.10  christos 						capprint(cap);
    604  1.10  christos 						break;
    605  1.10  christos 					}
    606  1.10  christos 				}
    607  1.10  christos 				if (j == sizeof(sfx) - 1)
    608  1.10  christos 					printf("false\n");
    609  1.10  christos 			}
    610  1.10  christos 		}
    611  1.10  christos 		free(b);
    612  1.10  christos 	}
    613  1.10  christos 	return rv;
    614  1.10  christos }
    615  1.10  christos 
    616  1.10  christos 		/*
    617  1.12  christos 		 * gettytab
    618  1.12  christos 		 */
    619  1.12  christos 
    620  1.12  christos static int
    621  1.12  christos gettytab(int argc, char *argv[])
    622  1.12  christos {
    623  1.12  christos 	return handlecap(_PATH_GETTYTAB, argc, argv);
    624  1.12  christos }
    625  1.12  christos 
    626  1.12  christos 		/*
    627  1.10  christos 		 * printcap
    628  1.10  christos 		 */
    629  1.10  christos 
    630  1.10  christos static int
    631  1.10  christos printcap(int argc, char *argv[])
    632  1.10  christos {
    633  1.10  christos 	return handlecap(_PATH_PRINTCAP, argc, argv);
    634  1.10  christos }
    635   1.3     lukem 
    636   1.3     lukem 		/*
    637  1.10  christos 		 * disktab
    638  1.10  christos 		 */
    639  1.10  christos 
    640  1.10  christos static int
    641  1.10  christos disktab(int argc, char *argv[])
    642  1.10  christos {
    643  1.10  christos 	return handlecap(_PATH_DISKTAB, argc, argv);
    644  1.10  christos }
    645  1.10  christos 
    646  1.10  christos 		/*
    647  1.10  christos 		 * termcap
    648  1.10  christos 		 */
    649  1.10  christos 
    650  1.10  christos static int
    651  1.10  christos termcap(int argc, char *argv[])
    652  1.10  christos {
    653  1.10  christos 	return handlecap(_PATH_TERMCAP, argc, argv);
    654  1.10  christos }
    655  1.10  christos 		/*
    656   1.3     lukem 		 * protocols
    657   1.3     lukem 		 */
    658   1.3     lukem 
    659   1.3     lukem static int
    660   1.3     lukem protocols(int argc, char *argv[])
    661   1.3     lukem {
    662   1.3     lukem 	struct protoent	*pe;
    663   1.3     lukem 	unsigned long	id;
    664   1.3     lukem 	int		i, rv;
    665   1.3     lukem 
    666   1.3     lukem 	assert(argc > 1);
    667   1.3     lukem 	assert(argv != NULL);
    668   1.3     lukem 
    669   1.5     lukem #define PROTOCOLSPRINT	printfmtstrings(pe->p_aliases, "  ", " ", \
    670   1.5     lukem 			    "%-16s  %5d", pe->p_name, pe->p_proto)
    671   1.5     lukem 
    672   1.3     lukem 	setprotoent(1);
    673   1.3     lukem 	rv = RV_OK;
    674   1.3     lukem 	if (argc == 2) {
    675   1.3     lukem 		while ((pe = getprotoent()) != NULL)
    676   1.5     lukem 			PROTOCOLSPRINT;
    677   1.3     lukem 	} else {
    678   1.3     lukem 		for (i = 2; i < argc; i++) {
    679   1.3     lukem 			if (parsenum(argv[i], &id))
    680  1.10  christos 				pe = getprotobynumber((int)id);
    681   1.3     lukem 			else
    682   1.3     lukem 				pe = getprotobyname(argv[i]);
    683   1.3     lukem 			if (pe != NULL)
    684   1.5     lukem 				PROTOCOLSPRINT;
    685   1.3     lukem 			else {
    686   1.3     lukem 				rv = RV_NOTFOUND;
    687   1.3     lukem 				break;
    688   1.3     lukem 			}
    689   1.3     lukem 		}
    690   1.3     lukem 	}
    691   1.3     lukem 	endprotoent();
    692   1.3     lukem 	return rv;
    693   1.3     lukem }
    694   1.3     lukem 
    695   1.6  ginsbach 		/*
    696   1.6  ginsbach 		 * rpc
    697   1.6  ginsbach 		 */
    698   1.6  ginsbach 
    699   1.6  ginsbach static int
    700   1.6  ginsbach rpc(int argc, char *argv[])
    701   1.6  ginsbach {
    702   1.6  ginsbach 	struct rpcent	*re;
    703   1.6  ginsbach 	unsigned long	id;
    704   1.6  ginsbach 	int		i, rv;
    705   1.6  ginsbach 
    706   1.6  ginsbach 	assert(argc > 1);
    707   1.6  ginsbach 	assert(argv != NULL);
    708   1.6  ginsbach 
    709   1.6  ginsbach #define RPCPRINT	printfmtstrings(re->r_aliases, "  ", " ", \
    710   1.6  ginsbach 				"%-16s  %6d", \
    711   1.6  ginsbach 				re->r_name, re->r_number)
    712   1.6  ginsbach 
    713   1.6  ginsbach 	setrpcent(1);
    714   1.6  ginsbach 	rv = RV_OK;
    715   1.6  ginsbach 	if (argc == 2) {
    716   1.6  ginsbach 		while ((re = getrpcent()) != NULL)
    717   1.6  ginsbach 			RPCPRINT;
    718   1.6  ginsbach 	} else {
    719   1.6  ginsbach 		for (i = 2; i < argc; i++) {
    720   1.6  ginsbach 			if (parsenum(argv[i], &id))
    721  1.10  christos 				re = getrpcbynumber((int)id);
    722   1.6  ginsbach 			else
    723   1.6  ginsbach 				re = getrpcbyname(argv[i]);
    724   1.6  ginsbach 			if (re != NULL)
    725   1.6  ginsbach 				RPCPRINT;
    726   1.6  ginsbach 			else {
    727   1.6  ginsbach 				rv = RV_NOTFOUND;
    728   1.6  ginsbach 				break;
    729   1.6  ginsbach 			}
    730   1.6  ginsbach 		}
    731   1.6  ginsbach 	}
    732   1.6  ginsbach 	endrpcent();
    733   1.6  ginsbach 	return rv;
    734   1.6  ginsbach }
    735   1.3     lukem 
    736   1.1     lukem 		/*
    737   1.4     lukem 		 * services
    738   1.4     lukem 		 */
    739   1.4     lukem 
    740   1.4     lukem static int
    741   1.4     lukem services(int argc, char *argv[])
    742   1.4     lukem {
    743   1.4     lukem 	struct servent	*se;
    744   1.4     lukem 	unsigned long	id;
    745   1.4     lukem 	char		*proto;
    746   1.4     lukem 	int		i, rv;
    747   1.4     lukem 
    748   1.4     lukem 	assert(argc > 1);
    749   1.4     lukem 	assert(argv != NULL);
    750   1.4     lukem 
    751   1.5     lukem #define SERVICESPRINT	printfmtstrings(se->s_aliases, "  ", " ", \
    752   1.5     lukem 			    "%-16s  %5d/%s", \
    753   1.5     lukem 			    se->s_name, ntohs(se->s_port), se->s_proto)
    754   1.5     lukem 
    755   1.4     lukem 	setservent(1);
    756   1.4     lukem 	rv = RV_OK;
    757   1.4     lukem 	if (argc == 2) {
    758   1.4     lukem 		while ((se = getservent()) != NULL)
    759   1.5     lukem 			SERVICESPRINT;
    760   1.4     lukem 	} else {
    761   1.4     lukem 		for (i = 2; i < argc; i++) {
    762   1.4     lukem 			proto = strchr(argv[i], '/');
    763   1.4     lukem 			if (proto != NULL)
    764   1.4     lukem 				*proto++ = '\0';
    765   1.4     lukem 			if (parsenum(argv[i], &id))
    766   1.9    simonb 				se = getservbyport(htons(id), proto);
    767   1.4     lukem 			else
    768   1.4     lukem 				se = getservbyname(argv[i], proto);
    769   1.4     lukem 			if (se != NULL)
    770   1.5     lukem 				SERVICESPRINT;
    771   1.4     lukem 			else {
    772   1.4     lukem 				rv = RV_NOTFOUND;
    773   1.4     lukem 				break;
    774   1.4     lukem 			}
    775   1.4     lukem 		}
    776   1.4     lukem 	}
    777   1.4     lukem 	endservent();
    778   1.4     lukem 	return rv;
    779   1.4     lukem }
    780   1.4     lukem 
    781   1.4     lukem 
    782   1.4     lukem 		/*
    783   1.1     lukem 		 * shells
    784   1.1     lukem 		 */
    785   1.1     lukem 
    786   1.1     lukem static int
    787   1.1     lukem shells(int argc, char *argv[])
    788   1.1     lukem {
    789   1.1     lukem 	const char	*sh;
    790   1.1     lukem 	int		i, rv;
    791   1.1     lukem 
    792   1.1     lukem 	assert(argc > 1);
    793   1.1     lukem 	assert(argv != NULL);
    794   1.1     lukem 
    795  1.10  christos #define SHELLSPRINT	(void)printf("%s\n", sh)
    796   1.5     lukem 
    797   1.1     lukem 	setusershell();
    798   1.1     lukem 	rv = RV_OK;
    799   1.1     lukem 	if (argc == 2) {
    800   1.1     lukem 		while ((sh = getusershell()) != NULL)
    801   1.5     lukem 			SHELLSPRINT;
    802   1.1     lukem 	} else {
    803   1.1     lukem 		for (i = 2; i < argc; i++) {
    804   1.1     lukem 			setusershell();
    805   1.1     lukem 			while ((sh = getusershell()) != NULL) {
    806   1.1     lukem 				if (strcmp(sh, argv[i]) == 0) {
    807   1.5     lukem 					SHELLSPRINT;
    808   1.1     lukem 					break;
    809   1.1     lukem 				}
    810   1.1     lukem 			}
    811   1.1     lukem 			if (sh == NULL) {
    812   1.1     lukem 				rv = RV_NOTFOUND;
    813   1.1     lukem 				break;
    814   1.1     lukem 			}
    815   1.1     lukem 		}
    816   1.1     lukem 	}
    817   1.1     lukem 	endusershell();
    818   1.1     lukem 	return rv;
    819   1.1     lukem }
    820