From: David van Moolenbroek Date: Thu, 9 Mar 2017 18:58:26 +0000 (+0000) Subject: Import NetBSD getent(1) X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/zlib_tech.html?a=commitdiff_plain;h=refs%2Fchanges%2F15%2F3415%2F1;p=minix.git Import NetBSD getent(1) Disable RPC support for now. Change-Id: I5ccb435220bf20cd9089cdd7aacb7d126f62f119 --- diff --git a/distrib/sets/lists/minix-base/mi b/distrib/sets/lists/minix-base/mi index d99fbcaf3..e2ee8526a 100644 --- a/distrib/sets/lists/minix-base/mi +++ b/distrib/sets/lists/minix-base/mi @@ -362,6 +362,8 @@ ./usr/bin/gcov-pull minix-base ./usr/bin/genassym minix-base ./usr/bin/gencat minix-base +./usr/bin/getcap minix-base +./usr/bin/getent minix-base ./usr/bin/getopt minix-base ./usr/bin/grep minix-base ./usr/bin/groups minix-base diff --git a/distrib/sets/lists/minix-debug/mi b/distrib/sets/lists/minix-debug/mi index 632d09118..18baf7ae5 100644 --- a/distrib/sets/lists/minix-debug/mi +++ b/distrib/sets/lists/minix-debug/mi @@ -282,6 +282,7 @@ ./usr/libdata/debug/usr/bin/gcov.debug minix-debug gcc=5,gcccmds,debug ./usr/libdata/debug/usr/bin/gcpp.debug minix-debug gcc=5,gcccmds,debug ./usr/libdata/debug/usr/bin/gencat.debug minix-debug debug +./usr/libdata/debug/usr/bin/getent.debug minix-debug debug ./usr/libdata/debug/usr/bin/getopt.debug minix-debug debug ./usr/libdata/debug/usr/bin/gprof.debug minix-debug debug ./usr/libdata/debug/usr/bin/grep.debug minix-debug debug diff --git a/distrib/sets/lists/minix-man/mi b/distrib/sets/lists/minix-man/mi index 9e9b08236..9c80534db 100644 --- a/distrib/sets/lists/minix-man/mi +++ b/distrib/sets/lists/minix-man/mi @@ -124,6 +124,8 @@ ./usr/man/man1/ftp.1 minix-man ./usr/man/man1/genassym.1 minix-man ./usr/man/man1/gencat.1 minix-man +./usr/man/man1/getcap.1 minix-man +./usr/man/man1/getent.1 minix-man ./usr/man/man1/getopt.1 minix-man ./usr/man/man1/getopts.1 minix-man obsolete ./usr/man/man1/gprof.1 minix-man binutils diff --git a/usr.bin/Makefile b/usr.bin/Makefile index e9528ee53..2cd2ad802 100644 --- a/usr.bin/Makefile +++ b/usr.bin/Makefile @@ -11,7 +11,7 @@ SUBDIR= asa \ deroff dirname du \ env expand \ false find finger flock fold fmt fpr from \ - fsplit ftp genassym gencat \ + fsplit ftp genassym gencat getent \ getopt \ head hexdump id indent infocmp ipcrm ipcs join jot \ lam last ldd leave \ diff --git a/usr.bin/getent/Makefile b/usr.bin/getent/Makefile new file mode 100644 index 000000000..3daefac45 --- /dev/null +++ b/usr.bin/getent/Makefile @@ -0,0 +1,9 @@ +# $NetBSD: Makefile,v 1.5 2011/10/11 19:25:07 christos Exp $ + +USE_FORT?= yes # XXX network client? + +PROG= getent +LINKS= ${BINDIR}/getent ${BINDIR}/getcap +MLINKS= getent.1 getcap.1 + +.include diff --git a/usr.bin/getent/getent.1 b/usr.bin/getent/getent.1 new file mode 100644 index 000000000..0e07058e7 --- /dev/null +++ b/usr.bin/getent/getent.1 @@ -0,0 +1,145 @@ +.\" $NetBSD: getent.1,v 1.23 2011/10/11 20:39:40 wiz Exp $ +.\" +.\" Copyright (c) 2004 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Luke Mewburn. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd October 11, 2011 +.Dt GETENT 1 +.Os +.Sh NAME +.Nm getent +.Nd get entries from administrative databases +.Sh SYNOPSIS +.Nm getent +.Ar database +.Op Ar key ... +.Nm getcap +.Ar database +.Op Ar key ... +.Sh DESCRIPTION +The +.Nm +program retrieves and displays entries from the administrative +database specified by +.Ar database , +using the lookup order specified in +.Xr nsswitch.conf 5 . +The display format for a given +.Ar database +is as per the +.Dq traditional +file format for that database. +.Pp +.Ar database +may be one of: +.Bl -column "protocols" "user:passwd:uid:gid:gecos:home_dir:shell" -offset indent -compact +.It Sy Database Ta Sy Display format +.It disktab Ta entry +.It ethers Ta address name +.It gettytab Ta entry +.It group Ta group:passwd:gid:[member[,member]...] +.It hosts Ta address name [alias ...] +.It netgroup Ta (host,user,domain) [...] +.It networks Ta name network [alias ...] +.It passwd Ta user:passwd:uid:gid:gecos:home_dir:shell +.It printcap Ta entry +.It protocols Ta name protocol [alias ...] +.It rpc Ta name number [alias ...] +.It services Ta name port/protocol [alias ...] +.It shells Ta /path/to/shell +.El +.Pp +If one or more +.Ar key +arguments are provided, they will be looked up in +.Ar database +using the appropriate function. +For example, +.Sy passwd +supports a numeric UID or user name; +.Sy hosts +supports an IPv4 address, IPv6 address, or host name; +and +.Sy services +supports a service name, service name/protocol name, numeric port, or +numeric port/protocol name. +.Pp +If no +.Ar key +is provided and +.Ar database +supports enumeration, all entries for +.Ar database +will be retrieved using the appropriate enumeration function and printed. +.Pp +For +.Xr cgetcap 3 +style databases +.Sy ( disktab , +.Sy printcap ) +specifying a key, lists the entry for that key, and specifying more arguments +after the key are used as fields in that key, and only the values of the keys +are returned. +For boolean keys +.Dv true +is returned if the key is found. +If a key is not found, then +.Dv false +is always +returned. +.Sh DIAGNOSTICS +.Nm +exits 0 on success, +1 if there was an error in the command syntax, +2 if one of the specified key names was not found in +.Ar database , +or 3 if there is no support for enumeration on +.Ar database . +.Sh SEE ALSO +.Xr cgetcap 3 , +.Xr disktab 5 , +.Xr ethers 5 , +.Xr gettytab 5 , +.Xr group 5 , +.Xr hosts 5 , +.Xr networks 5 , +.Xr nsswitch.conf 5 , +.Xr passwd 5 , +.Xr printcap 5 , +.Xr protocols 5 , +.Xr rpc 5 , +.Xr services 5 , +.Xr shells 5 +.Sh HISTORY +A +.Nm +command appeared in +.Nx 3.0 . +It was based on the command of the same name in +.Tn Solaris +and +.Tn Linux . diff --git a/usr.bin/getent/getent.c b/usr.bin/getent/getent.c new file mode 100644 index 000000000..bb0d80f36 --- /dev/null +++ b/usr.bin/getent/getent.c @@ -0,0 +1,860 @@ +/* $NetBSD: getent.c,v 1.19 2012/03/15 02:02:23 joerg Exp $ */ + +/*- + * Copyright (c) 2004-2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#ifndef lint +__RCSID("$NetBSD: getent.c,v 1.19 2012/03/15 02:02:23 joerg Exp $"); +#endif /* not lint */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include /* for INET6_ADDRSTRLEN */ + +#if !defined(__minix) +#include +#endif /* !defined(__minix) */ + +#include + +static int usage(void) __attribute__((__noreturn__)); +static int parsenum(const char *, unsigned long *); +static int disktab(int, char *[]); +static int gettytab(int, char *[]); +static int ethers(int, char *[]); +static int group(int, char *[]); +static int hosts(int, char *[]); +static int netgroup(int, char *[]); +static int networks(int, char *[]); +static int passwd(int, char *[]); +static int printcap(int, char *[]); +static int protocols(int, char *[]); +#if !defined(__minix) +static int rpc(int, char *[]); +#endif /* !defined(__minix) */ +static int services(int, char *[]); +static int shells(int, char *[]); + +enum { + RV_OK = 0, + RV_USAGE = 1, + RV_NOTFOUND = 2, + RV_NOENUM = 3 +}; + +static struct getentdb { + const char *name; + int (*callback)(int, char *[]); +} databases[] = { + { "disktab", disktab, }, + { "ethers", ethers, }, + { "gettytab", gettytab, }, + { "group", group, }, + { "hosts", hosts, }, + { "netgroup", netgroup, }, + { "networks", networks, }, + { "passwd", passwd, }, + { "printcap", printcap, }, + { "protocols", protocols, }, +#if !defined(__minix) + { "rpc", rpc, }, +#endif /* !defined(__minix) */ + { "services", services, }, + { "shells", shells, }, + + { NULL, NULL, }, +}; + + +int +main(int argc, char *argv[]) +{ + struct getentdb *curdb; + + setprogname(argv[0]); + + if (argc < 2) + usage(); + for (curdb = databases; curdb->name != NULL; curdb++) + if (strcmp(curdb->name, argv[1]) == 0) + return (*curdb->callback)(argc, argv); + + warn("Unknown database `%s'", argv[1]); + usage(); + /* NOTREACHED */ +} + +static int +usage(void) +{ + struct getentdb *curdb; + size_t i; + + (void)fprintf(stderr, "Usage: %s database [key ...]\n", + getprogname()); + (void)fprintf(stderr, "\tdatabase may be one of:"); + for (i = 0, curdb = databases; curdb->name != NULL; curdb++, i++) { + if (i % 7 == 0) + (void)fputs("\n\t\t", stderr); + (void)fprintf(stderr, "%s%s", i % 7 == 0 ? "" : " ", + curdb->name); + } + (void)fprintf(stderr, "\n"); + exit(RV_USAGE); + /* NOTREACHED */ +} + +static int +parsenum(const char *word, unsigned long *result) +{ + unsigned long num; + char *ep; + + assert(word != NULL); + assert(result != NULL); + + if (!isdigit((unsigned char)word[0])) + return 0; + errno = 0; + num = strtoul(word, &ep, 10); + if (num == ULONG_MAX && errno == ERANGE) + return 0; + if (*ep != '\0') + return 0; + *result = num; + return 1; +} + +/* + * printfmtstrings -- + * vprintf(format, ...), + * then the aliases (beginning with prefix, separated by sep), + * then a newline + */ +static __printflike(4, 5) void +printfmtstrings(char *strings[], const char *prefix, const char *sep, + const char *fmt, ...) +{ + va_list ap; + const char *curpref; + size_t i; + + va_start(ap, fmt); + (void)vprintf(fmt, ap); + va_end(ap); + + curpref = prefix; + for (i = 0; strings[i] != NULL; i++) { + (void)printf("%s%s", curpref, strings[i]); + curpref = sep; + } + (void)printf("\n"); +} + + + /* + * ethers + */ + +static int +ethers(int argc, char *argv[]) +{ + char hostname[MAXHOSTNAMELEN + 1], *hp; + struct ether_addr ea, *eap; + int i, rv; + + assert(argc > 1); + assert(argv != NULL); + +#define ETHERSPRINT (void)printf("%-17s %s\n", ether_ntoa(eap), hp) + + rv = RV_OK; + if (argc == 2) { + warnx("Enumeration not supported on ethers"); + rv = RV_NOENUM; + } else { + for (i = 2; i < argc; i++) { + if ((eap = ether_aton(argv[i])) == NULL) { + eap = &ea; + hp = argv[i]; + if (ether_hostton(hp, eap) != 0) { + rv = RV_NOTFOUND; + break; + } + } else { + hp = hostname; + if (ether_ntohost(hp, eap) != 0) { + rv = RV_NOTFOUND; + break; + } + } + ETHERSPRINT; + } + } + return rv; +} + + /* + * group + */ + +static int +group(int argc, char *argv[]) +{ + struct group *gr; + unsigned long id; + int i, rv; + + assert(argc > 1); + assert(argv != NULL); + +#define GROUPPRINT printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u", \ + gr->gr_name, gr->gr_passwd, gr->gr_gid) + + (void)setgroupent(1); + rv = RV_OK; + if (argc == 2) { + while ((gr = getgrent()) != NULL) + GROUPPRINT; + } else { + for (i = 2; i < argc; i++) { + if (parsenum(argv[i], &id)) + gr = getgrgid((gid_t)id); + else + gr = getgrnam(argv[i]); + if (gr != NULL) + GROUPPRINT; + else { + rv = RV_NOTFOUND; + break; + } + } + } + endgrent(); + return rv; +} + + + /* + * hosts + */ + +static void +hostsprint(const struct hostent *he) +{ + char buf[INET6_ADDRSTRLEN]; + + assert(he != NULL); + if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL) + (void)strlcpy(buf, "# unknown", sizeof(buf)); + printfmtstrings(he->h_aliases, " ", " ", "%-16s %s", buf, he->h_name); +} + +static int +hosts(int argc, char *argv[]) +{ + struct hostent *he; + char addr[IN6ADDRSZ]; + int i, rv; + + assert(argc > 1); + assert(argv != NULL); + + sethostent(1); + rv = RV_OK; + if (argc == 2) { + while ((he = gethostent()) != NULL) + hostsprint(he); + } else { + for (i = 2; i < argc; i++) { + if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0) + he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6); + else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0) + he = gethostbyaddr(addr, INADDRSZ, AF_INET); + else + he = gethostbyname(argv[i]); + if (he != NULL) + hostsprint(he); + else { + rv = RV_NOTFOUND; + break; + } + } + } + endhostent(); + return rv; +} + + /* + * netgroup + */ +static int +netgroup(int argc, char *argv[]) +{ + int rv, i; + bool first; + const char *host, *user, *domain; + + assert(argc > 1); + assert(argv != NULL); + +#define NETGROUPPRINT(s) (((s) != NULL) ? (s) : "") + + rv = RV_OK; + if (argc == 2) { + warnx("Enumeration not supported on netgroup"); + rv = RV_NOENUM; + } else { + for (i = 2; i < argc; i++) { + setnetgrent(argv[i]); + first = true; + while (getnetgrent(&host, &user, &domain) != 0) { + if (first) { + first = false; + (void)fputs(argv[i], stdout); + } + (void)printf(" (%s,%s,%s)", + NETGROUPPRINT(host), + NETGROUPPRINT(user), + NETGROUPPRINT(domain)); + } + if (!first) + (void)putchar('\n'); + endnetgrent(); + } + } + + return rv; +} + + /* + * networks + */ + +static void +networksprint(const struct netent *ne) +{ + char buf[INET6_ADDRSTRLEN]; + struct in_addr ianet; + + assert(ne != NULL); + ianet = inet_makeaddr(ne->n_net, 0); + if (inet_ntop(ne->n_addrtype, &ianet, buf, sizeof(buf)) == NULL) + (void)strlcpy(buf, "# unknown", sizeof(buf)); + printfmtstrings(ne->n_aliases, " ", " ", "%-16s %s", ne->n_name, buf); +} + +static int +networks(int argc, char *argv[]) +{ + struct netent *ne; + in_addr_t net; + int i, rv; + + assert(argc > 1); + assert(argv != NULL); + + setnetent(1); + rv = RV_OK; + if (argc == 2) { + while ((ne = getnetent()) != NULL) + networksprint(ne); + } else { + for (i = 2; i < argc; i++) { + net = inet_network(argv[i]); + if (net != INADDR_NONE) + ne = getnetbyaddr(net, AF_INET); + else + ne = getnetbyname(argv[i]); + if (ne != NULL) + networksprint(ne); + else { + rv = RV_NOTFOUND; + break; + } + } + } + endnetent(); + return rv; +} + + + /* + * passwd + */ + +static int +passwd(int argc, char *argv[]) +{ + struct passwd *pw; + unsigned long id; + int i, rv; + + assert(argc > 1); + assert(argv != NULL); + +#define PASSWDPRINT (void)printf("%s:%s:%u:%u:%s:%s:%s\n", \ + pw->pw_name, pw->pw_passwd, pw->pw_uid, \ + pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell) + + (void)setpassent(1); + rv = RV_OK; + if (argc == 2) { + while ((pw = getpwent()) != NULL) + PASSWDPRINT; + } else { + for (i = 2; i < argc; i++) { + if (parsenum(argv[i], &id)) + pw = getpwuid((uid_t)id); + else + pw = getpwnam(argv[i]); + if (pw != NULL) + PASSWDPRINT; + else { + rv = RV_NOTFOUND; + break; + } + } + } + endpwent(); + return rv; +} + +static char * +mygetent(const char * const * db_array, const char *name) +{ + char *buf = NULL; + int error; + + switch (error = cgetent(&buf, db_array, name)) { + case -3: + warnx("tc= loop in record `%s' in `%s'", name, db_array[0]); + break; + case -2: + warn("system error fetching record `%s' in `%s'", name, + db_array[0]); + break; + case -1: + case 0: + break; + case 1: + warnx("tc= reference not found in record for `%s' in `%s'", + name, db_array[0]); + break; + default: + warnx("unknown error %d in record `%s' in `%s'", error, name, + db_array[0]); + break; + } + return buf; +} + +static char * +mygetone(const char * const * db_array, int first) +{ + char *buf = NULL; + int error; + + switch (error = (first ? cgetfirst : cgetnext)(&buf, db_array)) { + case -2: + warnx("tc= loop in `%s'", db_array[0]); + break; + case -1: + warn("system error fetching record in `%s'", db_array[0]); + break; + case 0: + case 1: + break; + case 2: + warnx("tc= reference not found in `%s'", db_array[0]); + break; + default: + warnx("unknown error %d in `%s'", error, db_array[0]); + break; + } + return buf; +} + +static void +capprint(const char *cap) +{ + char *c = strchr(cap, ':'); + if (c) + if (c == cap) + (void)printf("true\n"); + else { + int l = (int)(c - cap); + (void)printf("%*.*s\n", l, l, cap); + } + else + (void)printf("%s\n", cap); +} + +static void +prettyprint(char *b) +{ +#define TERMWIDTH 65 + int did = 0; + size_t len; + char *s, c; + + for (;;) { + len = strlen(b); + if (len <= TERMWIDTH) { +done: + if (did) + printf("\t:"); + printf("%s\n", b); + return; + } + for (s = b + TERMWIDTH; s > b && *s != ':'; s--) + continue; + if (*s++ != ':') + goto done; + c = *s; + *s = '\0'; + if (did) + printf("\t:"); + did++; + printf("%s\\\n", b); + *s = c; + b = s; + } +} + +static void +handleone(const char * const *db_array, char *b, int recurse, int pretty, + int level) +{ + char *tc; + + if (level && pretty) + printf("\n"); + if (pretty) + prettyprint(b); + else + printf("%s\n", b); + if (!recurse || cgetstr(b, "tc", &tc) <= 0) + return; + + b = mygetent(db_array, tc); + free(tc); + + if (b == NULL) + return; + + handleone(db_array, b, recurse, pretty, ++level); + free(b); +} + +static int +handlecap(const char *db, int argc, char *argv[]) +{ + static const char sfx[] = "=#:"; + const char *db_array[] = { db, NULL }; + char *b, *cap; + int i, rv, c; + size_t j; + int expand = 1, recurse = 0, pretty = 0; + + assert(argc > 1); + assert(argv != NULL); + + argc--; + argv++; + while ((c = getopt(argc, argv, "pnr")) != -1) + switch (c) { + case 'n': + expand = 0; + break; + case 'r': + expand = 0; + recurse = 1; + break; + case 'p': + pretty = 1; + break; + default: + usage(); + break; + } + + argc -= optind; + argv += optind; + csetexpandtc(expand); + rv = RV_OK; + if (argc == 0) { + for (b = mygetone(db_array, 1); b; b = mygetone(db_array, 0)) { + handleone(db_array, b, recurse, pretty, 0); + free(b); + } + } else { + if ((b = mygetent(db_array, argv[0])) == NULL) + return RV_NOTFOUND; + if (argc == 1) + handleone(db_array, b, recurse, pretty, 0); + else { + for (i = 2; i < argc; i++) { + for (j = 0; j < sizeof(sfx) - 1; j++) { + cap = cgetcap(b, argv[i], sfx[j]); + if (cap) { + capprint(cap); + break; + } + } + if (j == sizeof(sfx) - 1) + printf("false\n"); + } + } + free(b); + } + return rv; +} + + /* + * gettytab + */ + +static int +gettytab(int argc, char *argv[]) +{ + return handlecap(_PATH_GETTYTAB, argc, argv); +} + + /* + * printcap + */ + +static int +printcap(int argc, char *argv[]) +{ + return handlecap(_PATH_PRINTCAP, argc, argv); +} + + /* + * disktab + */ + +static int +disktab(int argc, char *argv[]) +{ + return handlecap(_PATH_DISKTAB, argc, argv); +} + + /* + * protocols + */ + +static int +protocols(int argc, char *argv[]) +{ + struct protoent *pe; + unsigned long id; + int i, rv; + + assert(argc > 1); + assert(argv != NULL); + +#define PROTOCOLSPRINT printfmtstrings(pe->p_aliases, " ", " ", \ + "%-16s %5d", pe->p_name, pe->p_proto) + + setprotoent(1); + rv = RV_OK; + if (argc == 2) { + while ((pe = getprotoent()) != NULL) + PROTOCOLSPRINT; + } else { + for (i = 2; i < argc; i++) { + if (parsenum(argv[i], &id)) + pe = getprotobynumber((int)id); + else + pe = getprotobyname(argv[i]); + if (pe != NULL) + PROTOCOLSPRINT; + else { + rv = RV_NOTFOUND; + break; + } + } + } + endprotoent(); + return rv; +} + +#if !defined(__minix) + /* + * rpc + */ + +static int +rpc(int argc, char *argv[]) +{ + struct rpcent *re; + unsigned long id; + int i, rv; + + assert(argc > 1); + assert(argv != NULL); + +#define RPCPRINT printfmtstrings(re->r_aliases, " ", " ", \ + "%-16s %6d", \ + re->r_name, re->r_number) + + setrpcent(1); + rv = RV_OK; + if (argc == 2) { + while ((re = getrpcent()) != NULL) + RPCPRINT; + } else { + for (i = 2; i < argc; i++) { + if (parsenum(argv[i], &id)) + re = getrpcbynumber((int)id); + else + re = getrpcbyname(argv[i]); + if (re != NULL) + RPCPRINT; + else { + rv = RV_NOTFOUND; + break; + } + } + } + endrpcent(); + return rv; +} +#endif /* !defined(__minix) */ + + /* + * services + */ + +static int +services(int argc, char *argv[]) +{ + struct servent *se; + unsigned long id; + char *proto; + int i, rv; + + assert(argc > 1); + assert(argv != NULL); + +#define SERVICESPRINT printfmtstrings(se->s_aliases, " ", " ", \ + "%-16s %5d/%s", \ + se->s_name, ntohs(se->s_port), se->s_proto) + + setservent(1); + rv = RV_OK; + if (argc == 2) { + while ((se = getservent()) != NULL) + SERVICESPRINT; + } else { + for (i = 2; i < argc; i++) { + proto = strchr(argv[i], '/'); + if (proto != NULL) + *proto++ = '\0'; + if (parsenum(argv[i], &id)) + se = getservbyport(htons(id), proto); + else + se = getservbyname(argv[i], proto); + if (se != NULL) + SERVICESPRINT; + else { + rv = RV_NOTFOUND; + break; + } + } + } + endservent(); + return rv; +} + + + /* + * shells + */ + +static int +shells(int argc, char *argv[]) +{ + const char *sh; + int i, rv; + + assert(argc > 1); + assert(argv != NULL); + +#define SHELLSPRINT (void)printf("%s\n", sh) + + setusershell(); + rv = RV_OK; + if (argc == 2) { + while ((sh = getusershell()) != NULL) + SHELLSPRINT; + } else { + for (i = 2; i < argc; i++) { + setusershell(); + while ((sh = getusershell()) != NULL) { + if (strcmp(sh, argv[i]) == 0) { + SHELLSPRINT; + break; + } + } + if (sh == NULL) { + rv = RV_NOTFOUND; + break; + } + } + } + endusershell(); + return rv; +}