From: David van Moolenbroek Date: Mon, 20 Feb 2017 14:23:24 +0000 (+0000) Subject: Import NetBSD services_mkdb(8) X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/zpipe.c?a=commitdiff_plain;h=81fc6023c221f18ce82ac48abc0f13e4e023787a;p=minix.git Import NetBSD services_mkdb(8) Change-Id: Ia3fc2479d2abb2dbe9afd1b60e0ffbaf377bcf5a --- diff --git a/distrib/sets/lists/minix-base/mi b/distrib/sets/lists/minix-base/mi index 67ae9e428..9233d541d 100644 --- a/distrib/sets/lists/minix-base/mi +++ b/distrib/sets/lists/minix-base/mi @@ -1007,6 +1007,7 @@ ./usr/sbin/postinstall minix-base ./usr/sbin/pwd_mkdb minix-base ./usr/sbin/rdate minix-base +./usr/sbin/services_mkdb minix-base ./usr/sbin/syslogd minix-base ./usr/sbin/traceroute minix-base ./usr/sbin/unlink minix-base diff --git a/distrib/sets/lists/minix-debug/mi b/distrib/sets/lists/minix-debug/mi index 99dd9fb3a..632d09118 100644 --- a/distrib/sets/lists/minix-debug/mi +++ b/distrib/sets/lists/minix-debug/mi @@ -603,6 +603,7 @@ ./usr/libdata/debug/usr/sbin/pkg_info.debug minix-debug debug ./usr/libdata/debug/usr/sbin/pwd_mkdb.debug minix-debug debug ./usr/libdata/debug/usr/sbin/rdate.debug minix-debug debug +./usr/libdata/debug/usr/sbin/services_mkdb.debug minix-debug debug ./usr/libdata/debug/usr/sbin/syslogd.debug minix-debug debug ./usr/libdata/debug/usr/sbin/traceroute.debug minix-debug debug ./usr/libdata/debug/usr/sbin/unlink.debug minix-debug debug diff --git a/distrib/sets/lists/minix-man/mi b/distrib/sets/lists/minix-man/mi index 3c349835b..edd65b20c 100644 --- a/distrib/sets/lists/minix-man/mi +++ b/distrib/sets/lists/minix-man/mi @@ -3440,6 +3440,7 @@ ./usr/man/man8/screendump.8 minix-man ./usr/man/man8/serial-ip.8 minix-man obsolete ./usr/man/man8/service.8 minix-man obsolete +./usr/man/man8/services_mkdb.8 minix-man ./usr/man/man8/setup.8 minix-man ./usr/man/man8/shutdown.8 minix-man ./usr/man/man8/slip.8 minix-man diff --git a/etc/usr/rc b/etc/usr/rc index ae391f724..029007e0d 100644 --- a/etc/usr/rc +++ b/etc/usr/rc @@ -402,6 +402,14 @@ start|autoboot) dev_mkdb fi + # Same for /etc/services. + SERVICESFILE=/etc/services + SERVICESDB=/var/db/services.cdb + if [ ! -f "$SERVICESDB" -o "$SERVICESFILE" -nt "$SERVICESDB" ] + then + services_mkdb -q + fi + if [ "$net" ] then # Get the nodename from the DNS and set it. diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index c8ee775ab..ff2002184 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -24,7 +24,7 @@ SUBDIR= \ \ rdate \ \ - \ + services_mkdb \ \ syslogd \ traceroute \ diff --git a/usr.sbin/services_mkdb/Makefile b/usr.sbin/services_mkdb/Makefile new file mode 100644 index 000000000..f86fb7b3d --- /dev/null +++ b/usr.sbin/services_mkdb/Makefile @@ -0,0 +1,11 @@ +# $NetBSD: Makefile,v 1.7 2010/04/25 00:54:46 joerg Exp $ + +PROG= services_mkdb +MAN= services_mkdb.8 +SRCS= services_mkdb.c output_cdb.c output_db.c uniq.c + +LDADD+= -lutil +DPADD+= ${LIBUTIL} +#COPTS+=-g + +.include diff --git a/usr.sbin/services_mkdb/extern.h b/usr.sbin/services_mkdb/extern.h new file mode 100644 index 000000000..004b131ab --- /dev/null +++ b/usr.sbin/services_mkdb/extern.h @@ -0,0 +1,9 @@ +#include + +int cdb_open(const char *); +void cdb_add(StringList *, size_t, const char *, size_t *, int); +int cdb_close(void); +int db_open(const char *); +void db_add(StringList *, size_t, const char *, size_t *, int); +int db_close(void); +__dead void uniq(const char *); diff --git a/usr.sbin/services_mkdb/output_cdb.c b/usr.sbin/services_mkdb/output_cdb.c new file mode 100644 index 000000000..ac12883ec --- /dev/null +++ b/usr.sbin/services_mkdb/output_cdb.c @@ -0,0 +1,163 @@ +/* $NetBSD: output_cdb.c,v 1.1 2010/04/25 00:54:46 joerg Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Joerg Sonnenberger. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "extern.h" + +static struct cdbw *cdbw; +static int cdbw_fd = -1; + +int +cdb_open(const char *tname) +{ + + if ((cdbw = cdbw_open()) == NULL) + return -1; + + if ((cdbw_fd = open(tname, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) { + cdbw_close(cdbw); + cdbw = NULL; + return -1; + } + return 0; +} + +void +cdb_add(StringList *sl, size_t port, const char *proto, size_t *cnt, + int warndup) +{ + uint8_t key[255 * 2 + 2]; + uint8_t *data, *data_iter; + size_t len, protolen, datalen, keylen; + uint32_t idx; + size_t i; + + protolen = strlen(proto); + if (protolen == 0 || protolen > 255) + errx(1, "Invalid protocol ``%s'', entry skipped", proto); + + datalen = 4 + protolen; + for (i = 0; i < sl->sl_cur; ++i) { + len = strlen(sl->sl_str[i]); + if (len == 0 || len > 255) + errx(1, "Service alias ``%s'' invalid", sl->sl_str[i]); + datalen += len + 2; + } + + data = malloc(datalen); + if (data == NULL) + err(1, "malloc failed"); + be16enc(data, port); + data[2] = protolen; + data_iter = data + 3; + memcpy(data_iter, proto, protolen + 1); + data_iter += protolen + 1; + for (i = 0; i < sl->sl_cur; ++i) { + len = strlen(sl->sl_str[i]); + *data_iter++ = len; + memcpy(data_iter, sl->sl_str[i], len + 1); + data_iter += len + 1; + } + + if (cdbw_put_data(cdbw, data, datalen, &idx)) + err(1, "cdbw_put_data failed"); + + free(data); + + key[0] = 0; + key[1] = protolen; + be16enc(key + 2, port); + memcpy(key + 4, proto, protolen); + keylen = 4 + protolen; + if (cdbw_put_key(cdbw, key, keylen, idx) && warndup) + warnx("duplicate service: `%zu/%s'", port, proto); + + key[1] = 0; + keylen = 4; + if (cdbw_put_key(cdbw, key, keylen, idx) && warndup) + warnx("duplicate service: `%zu'", port); + + /* add references for service and all aliases */ + for (i = 0; i < sl->sl_cur; i++) { + len = strlen(sl->sl_str[i]); + key[0] = len; + key[1] = protolen; + memcpy(key + 2, sl->sl_str[i], len); + memcpy(key + 2 + len, proto, protolen); + keylen = 2 + len + protolen; + if (cdbw_put_key(cdbw, key, keylen, idx) && warndup) + warnx("duplicate service: `%s/%s'", sl->sl_str[i], proto); + + key[1] = 0; + keylen = 2 + len; + if (cdbw_put_key(cdbw, key, keylen, idx) && warndup) + warnx("duplicate service: `%s'", sl->sl_str[i]); + } + + sl_free(sl, 1); +} + +int +cdb_close(void) +{ + int rv, serrno; + + rv = 0; + serrno = errno; + + if (cdbw_output(cdbw, cdbw_fd, "services(5)", NULL)) { + rv = -1; + serrno = errno; + } + + cdbw_close(cdbw); + cdbw = NULL; + + if (close(cdbw_fd)) { + if (rv == 0) + serrno = errno; + rv = -1; + } + cdbw_fd = -1; + + errno = serrno; + return rv; +} diff --git a/usr.sbin/services_mkdb/output_db.c b/usr.sbin/services_mkdb/output_db.c new file mode 100644 index 000000000..043f7630e --- /dev/null +++ b/usr.sbin/services_mkdb/output_db.c @@ -0,0 +1,189 @@ +/* $NetBSD: output_db.c,v 1.1 2010/04/25 00:54:46 joerg Exp $ */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn and Christos Zoulas. + * + * 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: output_db.c,v 1.1 2010/04/25 00:54:46 joerg Exp $"); +#endif /* not lint */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "extern.h" + +static DB *db; + +static const HASHINFO hinfo = { + .bsize = 256, + .ffactor = 4, + .nelem = 32768, + .cachesize = 1024, + .hash = NULL, + .lorder = 0 +}; + +static void store(DBT *, DBT *, int); +static void killproto(DBT *); +static const char *mkaliases(StringList *, char *, size_t); + +int +db_open(const char *tname) +{ + db = dbopen(tname, O_RDWR | O_CREAT | O_EXCL, + (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH), DB_HASH, &hinfo); + + return db != NULL ? 0 : -1; +} + +int +db_close(void) +{ + int rv; + + rv = (db->close)(db); + db = NULL; + + return rv; +} + +void +db_add(StringList *sl, size_t port, const char *proto, size_t *cnt, + int warndup) +{ + size_t i; + char keyb[BUFSIZ], datab[BUFSIZ], abuf[BUFSIZ]; + DBT data, key; + key.data = keyb; + data.data = datab; + + /* key `indirect key', data `full line' */ + data.size = snprintf(datab, sizeof(datab), "%zu", (*cnt)++) + 1; + key.size = snprintf(keyb, sizeof(keyb), "%s %zu/%s %s", + sl->sl_str[0], port, proto, mkaliases(sl, abuf, sizeof(abuf))) + 1; + store(&data, &key, warndup); + + /* key `\377port/proto', data = `indirect key' */ + key.size = snprintf(keyb, sizeof(keyb), "\377%zu/%s", + port, proto) + 1; + store(&key, &data, warndup); + + /* key `\377port', data = `indirect key' */ + killproto(&key); + store(&key, &data, warndup); + + /* add references for service and all aliases */ + for (i = 0; i < sl->sl_cur; i++) { + /* key `\376service/proto', data = `indirect key' */ + key.size = snprintf(keyb, sizeof(keyb), "\376%s/%s", + sl->sl_str[i], proto) + 1; + store(&key, &data, warndup); + + /* key `\376service', data = `indirect key' */ + killproto(&key); + store(&key, &data, warndup); + } + sl_free(sl, 1); +} + +static void +killproto(DBT *key) +{ + char *p, *d = key->data; + + if ((p = strchr(d, '/')) == NULL) + abort(); + *p++ = '\0'; + key->size = p - d; +} + +static void +store(DBT *key, DBT *data, int warndup) +{ +#ifdef DEBUG + int k = key->size - 1; + int d = data->size - 1; + (void)printf("store [%*.*s] [%*.*s]\n", + k, k, (char *)key->data + 1, + d, d, (char *)data->data + 1); +#endif + switch ((db->put)(db, key, data, R_NOOVERWRITE)) { + case 0: + break; + case 1: + if (warndup) + warnx("duplicate service `%s'", + &((char *)key->data)[1]); + break; + case -1: + err(1, "put"); + break; + default: + abort(); + break; + } +} + +static const char * +mkaliases(StringList *sl, char *buf, size_t len) +{ + size_t nc, i, pos; + + buf[0] = 0; + for (i = 1, pos = 0; i < sl->sl_cur; i++) { + nc = strlcpy(buf + pos, sl->sl_str[i], len); + if (nc >= len) + goto out; + pos += nc; + len -= nc; + nc = strlcpy(buf + pos, " ", len); + if (nc >= len) + goto out; + pos += nc; + len -= nc; + } + return buf; +out: + warn("aliases for `%s' truncated", sl->sl_str[0]); + return buf; +} diff --git a/usr.sbin/services_mkdb/services_mkdb.8 b/usr.sbin/services_mkdb/services_mkdb.8 new file mode 100644 index 000000000..b56c67ec5 --- /dev/null +++ b/usr.sbin/services_mkdb/services_mkdb.8 @@ -0,0 +1,113 @@ +.\" $NetBSD: services_mkdb.8,v 1.12 2010/05/05 22:11:19 wiz Exp $ +.\" +.\" Copyright (c) 1999 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 May 5, 2010 +.Dt SERVICES_MKDB 8 +.Os +.Sh NAME +.Nm services_mkdb +.Nd generate the services databases +.Sh SYNOPSIS +.Nm +.Op Fl qv +.Op Fl o Ar database +.Op Fl V Ar style +.Op Ar file +.Nm +.Fl u +.Op Ar file +.Sh DESCRIPTION +.Nm +creates a +.Xr db 3 +database for the specified file. +If no file is specified, then +.Pa /etc/services +is used. +The database is installed into +.Pa /var/db/services.cdb +for CDB format and into +.Pa /var/db/services.db +for DB format (see +.Fl V ) . +The file must be in the correct format (see +.Xr services 5 ) . +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl o Ar database +Put the output databases in the named file. +.It Fl q +Don't warn about duplicate services. +This is the default behavior. +.It Fl u +Print the services file to stdout, omitting duplicate entries and comments. +.It Fl V +Create a specific version of the database style. +.Ar style +can be +.Li cdb +to request the CDB format (default) or +.Li db +to request the DB format. +The DB format is useful for compatibility with old statically +linked binaries. +.It Fl v +Warn about duplicate services. +.El +.Pp +The databases are used by the C library services routines (see +.Xr getservent 3 ) . +.Pp +.Nm +exits zero on success, non-zero on failure. +.Sh FILES +.Bl -tag -width 24n -compact +.It Pa /var/db/services.db +The current services database. +.It Pa /var/db/services.db.tmp +A temporary file. +.It Pa /etc/services +The current services file. +.El +.Sh SEE ALSO +.Xr db 3 , +.Xr getservent 3 , +.Xr services 5 +.Sh BUGS +Because +.Nm +guarantees not to install a partial destination file it must +build a temporary file in the same file system and if successful use +.Xr rename 2 +to install over the destination file. +.Pp +If +.Nm +fails it will leave the previous version of the destination file intact. diff --git a/usr.sbin/services_mkdb/services_mkdb.c b/usr.sbin/services_mkdb/services_mkdb.c new file mode 100644 index 000000000..5d3ba2684 --- /dev/null +++ b/usr.sbin/services_mkdb/services_mkdb.c @@ -0,0 +1,323 @@ +/* $NetBSD: services_mkdb.c,v 1.18 2010/10/07 01:28:50 christos Exp $ */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn and Christos Zoulas. + * + * 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: services_mkdb.c,v 1.18 2010/10/07 01:28:50 christos Exp $"); +#endif /* not lint */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "extern.h" + +static char tname[MAXPATHLEN]; + +#define PMASK 0xffff +#define PROTOMAX 6 + +static StringList ***parseservices(const char *, StringList *); +static void cleanup(void); +static char *getstring(const char *, size_t, char **, const char *); +static size_t getprotoindex(StringList *, const char *); +static const char *getprotostr(StringList *, size_t); +static void usage(void) __dead; + +int +main(int argc, char *argv[]) +{ + int ch; + const char *fname = _PATH_SERVICES; + const char *dbname = NULL; + int use_db = 0; + int warndup = 0; + int unique = 0; + int otherflag = 0; + size_t cnt = 0; + StringList *sl, ***svc; + size_t port, proto; + void (*addfn)(StringList *, size_t, const char *, size_t *, int); + int (*closefn)(void); + + setprogname(argv[0]); + + while ((ch = getopt(argc, argv, "o:quV:v")) != -1) + switch (ch) { + case 'o': + otherflag = 1; + dbname = optarg; + break; + case 'q': + otherflag = 1; + warndup = 0; + break; + case 'u': + unique++; + break; + case 'V': + if (strcmp(optarg, "db") == 0) + use_db = 1; + else if (strcmp(optarg, "cdb") == 0) + use_db = 0; + else + usage(); + break; + case 'v': + otherflag = 1; + warndup = 1; + break; + default: + usage(); + } + + argc -= optind; + argv += optind; + + if (argc > 1 || (unique && otherflag)) + usage(); + if (argc == 1) + fname = argv[0]; + + if (unique) + uniq(fname); + + if (dbname == NULL) + dbname = use_db ? _PATH_SERVICES_DB : _PATH_SERVICES_CDB; + + svc = parseservices(fname, sl = sl_init()); + + if (atexit(cleanup)) + err(1, "Cannot install exit handler"); + + (void)snprintf(tname, sizeof(tname), "%s.tmp", dbname); + + if (use_db) { + if (db_open(tname)) + err(1, "Error opening temporary database `%s'", tname); + addfn = db_add; + closefn = db_close; + } else { + if (cdb_open(tname)) + err(1, "Error opening temporary database `%s'", tname); + addfn = cdb_add; + closefn = cdb_close; + } + + for (port = 0; port < PMASK + 1; port++) { + if (svc[port] == NULL) + continue; + + for (proto = 0; proto < PROTOMAX; proto++) { + StringList *s; + if ((s = svc[port][proto]) == NULL) + continue; + (addfn)(s, port, getprotostr(sl, proto), &cnt, warndup); + } + + free(svc[port]); + } + + free(svc); + sl_free(sl, 1); + + if ((closefn)()) + err(1, "Error writing temporary database `%s'", tname); + + if (rename(tname, dbname) == -1) + err(1, "Cannot rename `%s' to `%s'", tname, dbname); + + return 0; +} + +static StringList *** +parseservices(const char *fname, StringList *sl) +{ + size_t len, line, pindex; + FILE *fp; + StringList ***svc, *s; + char *p, *ep; + + if ((fp = fopen(fname, "r")) == NULL) + err(1, "Cannot open `%s'", fname); + + line = 0; + svc = ecalloc(PMASK + 1, sizeof(StringList **)); + + /* XXX: change NULL to "\0\0#" when fparseln fixed */ + for (; (p = fparseln(fp, &len, &line, NULL, 0)) != NULL; free(p)) { + char *name, *port, *proto, *aliases, *cp, *alias; + unsigned long pnum; + + if (len == 0) + continue; + + for (cp = p; *cp && isspace((unsigned char)*cp); cp++) + continue; + + if (*cp == '\0' || *cp == '#') + continue; + + if ((name = getstring(fname, line, &cp, "name")) == NULL) + continue; + + if ((port = getstring(fname, line, &cp, "port")) == NULL) + continue; + + if (cp) { + for (aliases = cp; *cp && *cp != '#'; cp++) + continue; + + if (*cp) + *cp = '\0'; + } else + aliases = NULL; + + proto = strchr(port, '/'); + if (proto == NULL || proto[1] == '\0') { + warnx("%s, %zu: no protocol found", fname, line); + continue; + } + *proto++ = '\0'; + + errno = 0; + pnum = strtoul(port, &ep, 0); + if (*port == '\0' || *ep != '\0') { + warnx("%s, %zu: invalid port `%s'", fname, line, port); + continue; + } + if ((errno == ERANGE && pnum == ULONG_MAX) || pnum > PMASK) { + warnx("%s, %zu: port too big `%s'", fname, line, port); + continue; + } + + if (svc[pnum] == NULL) + svc[pnum] = ecalloc(PROTOMAX, sizeof(StringList *)); + + pindex = getprotoindex(sl, proto); + if (svc[pnum][pindex] == NULL) + s = svc[pnum][pindex] = sl_init(); + else + s = svc[pnum][pindex]; + + if (strlen(name) > 255) { + warnx("%s, %zu: invalid name too long `%s'", fname, + line, name); + continue; + } + + /* build list of aliases */ + if (sl_find(s, name) == NULL) + (void)sl_add(s, estrdup(name)); + + if (aliases) { + while ((alias = strsep(&aliases, " \t")) != NULL) { + if (alias[0] == '\0') + continue; + if (strlen(alias) > 255) { + warnx("%s, %zu: alias name too long `%s'", + fname, line, alias); + continue; + } + if (sl_find(s, alias) == NULL) + (void)sl_add(s, estrdup(alias)); + } + } + } + (void)fclose(fp); + return svc; +} + +/* + * cleanup(): Remove temporary files upon exit + */ +static void +cleanup(void) +{ + if (tname[0]) + (void)unlink(tname); +} + +static char * +getstring(const char *fname, size_t line, char **cp, const char *tag) +{ + char *str; + + while ((str = strsep(cp, " \t")) != NULL && *str == '\0') + continue; + + if (str == NULL) + warnx("%s, %zu: no %s found", fname, line, tag); + + return str; +} + +static size_t +getprotoindex(StringList *sl, const char *str) +{ + size_t i; + + for (i= 0; i < sl->sl_cur; i++) + if (strcmp(sl->sl_str[i], str) == 0) + return i; + + if (i == PROTOMAX) + errx(1, "Ran out of protocols adding `%s';" + " recompile with larger PROTOMAX", str); + (void)sl_add(sl, estrdup(str)); + return i; +} + +static const char * +getprotostr(StringList *sl, size_t i) +{ + assert(i < sl->sl_cur); + return sl->sl_str[i]; +} + +static void +usage(void) +{ + (void)fprintf(stderr, "Usage:\t%s [-q] [-o ] [-V cdb|db] []\n" + "\t%s -u []\n", getprogname(), getprogname()); + exit(1); +} diff --git a/usr.sbin/services_mkdb/uniq.c b/usr.sbin/services_mkdb/uniq.c new file mode 100644 index 000000000..f7c32d8d3 --- /dev/null +++ b/usr.sbin/services_mkdb/uniq.c @@ -0,0 +1,166 @@ +/* $NetBSD: uniq.c,v 1.6 2014/06/21 17:48:07 christos Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 +__RCSID("$NetBSD: uniq.c,v 1.6 2014/06/21 17:48:07 christos Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "extern.h" + +static const HASHINFO hinfo = { + .bsize = 256, + .ffactor = 4, + .nelem = 32768, + .cachesize = 1024, + .hash = NULL, + .lorder = 0 +}; + +static int comp(const char *, char **, size_t *); + +/* + * Preserve only unique content lines in a file. Input lines that have + * content [alphanumeric characters before a comment] are white-space + * normalized and have their comments removed. Then they are placed + * in a hash table, and only the first instance of them is printed. + * Comment lines without any alphanumeric content are always printed + * since they are there to make the file "pretty". Comment lines with + * alphanumeric content are also placed into the hash table and only + * printed once. + */ +void +uniq(const char *fname) +{ + DB *db; + DBT key; + static const DBT data = { NULL, 0 }; + FILE *fp; + char *line; + size_t len; + + if ((db = dbopen(NULL, O_RDWR, 0, DB_HASH, &hinfo)) == NULL) + err(1, "Cannot create in memory database"); + + fp = efopen(fname, "r"); + while ((line = fgetln(fp, &len)) != NULL) { + size_t complen = len; + char *compline; + if (!comp(line, &compline, &complen)) { + (void)fprintf(stdout, "%*.*s", (int)len, (int)len, + line); + continue; + } + key.data = compline; + key.size = complen; + switch ((db->put)(db, &key, &data, R_NOOVERWRITE)) { + case 0: + (void)fprintf(stdout, "%*.*s", (int)len, (int)len, + line); + break; + case 1: + break; + case -1: + err(1, "put"); + /*NOTREACHED*/ + default: + abort(); + break; + } + } + (void)fflush(stdout); + exit(0); +} + +/* + * normalize whitespace in the original line and place a new string + * with whitespace converted to a single space in compline. If the line + * contains just comments, we preserve them. If it contains data and + * comments, we kill the comments. Return 1 if the line had actual + * contents, or 0 if it was just a comment without alphanumeric characters. + */ +static int +comp(const char *origline, char **compline, size_t *len) +{ + const unsigned char *p; + unsigned char *q; + char *cline; + size_t l = *len, complen; + int hasalnum, iscomment; + + /* Eat leading space */ + for (p = (const unsigned char *)origline; l && *p && isspace(*p); + p++, l--) + continue; + cline = emalloc(l + 1); + (void)memcpy(cline, p, l); + cline[l] = '\0'; + if (*cline == '\0') + return 0; + + complen = 0; + hasalnum = 0; + iscomment = 0; + + for (q = (unsigned char *)cline; l && *p; p++, l--) { + if (isspace(*p)) { + if (complen && isspace(q[-1])) + continue; + *q++ = ' '; + complen++; + } else { + if (!iscomment && *p == '#') { + if (hasalnum) + break; + iscomment = 1; + } else + hasalnum |= isalnum(*p); + *q++ = *p; + complen++; + } + } + + /* Eat trailing space */ + while (complen && isspace(q[-1])) { + --q; + --complen; + } + *q = '\0'; + *compline = cline; + *len = complen; + return hasalnum; +}