11590Srgrimes/*-
21590Srgrimes * Copyright (c) 1992, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 4. Neither the name of the University nor the names of its contributors
141590Srgrimes *    may be used to endorse or promote products derived from this software
151590Srgrimes *    without specific prior written permission.
161590Srgrimes *
171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271590Srgrimes * SUCH DAMAGE.
281590Srgrimes */
291590Srgrimes
301590Srgrimes#ifndef lint
3141568Sarchiestatic const char copyright[] =
321590Srgrimes"@(#) Copyright (c) 1992, 1993\n\
331590Srgrimes	The Regents of the University of California.  All rights reserved.\n";
3487236Smarkm#endif
351590Srgrimes
3687628Sdwmalone#if 0
371590Srgrimes#ifndef lint
38142109Srustatic char sccsid[] = "@(#)cap_mkdb.c	8.2 (Berkeley) 4/27/95";
3953508Scharnier#endif
4087628Sdwmalone#endif
411590Srgrimes
4287628Sdwmalone#include <sys/cdefs.h>
4387628Sdwmalone__FBSDID("$FreeBSD$");
4487628Sdwmalone
451590Srgrimes#include <sys/param.h>
461590Srgrimes#include <sys/stat.h>
471590Srgrimes
481590Srgrimes#include <db.h>
491590Srgrimes#include <err.h>
501590Srgrimes#include <fcntl.h>
511590Srgrimes#include <stdio.h>
521590Srgrimes#include <stdlib.h>
531590Srgrimes#include <string.h>
541590Srgrimes#include <unistd.h>
551590Srgrimes
56227154Sedstatic void	 db_build(char **);
57227154Sedstatic void	 dounlink(void);
58227154Sedstatic void	 usage(void);
591590Srgrimes
60227154Sedstatic DB	*capdbp;
61227154Sedstatic int	 verbose;
62227154Sedstatic char	*capname, buf[8 * 1024];
631590Srgrimes
64227154Sedstatic HASHINFO openinfo = {
65142109Sru	4096,		/* bsize */
66142109Sru	0,		/* ffactor */
67142109Sru	0,		/* nelem */
68142109Sru	0,		/* cachesize */
69142109Sru	NULL,		/* hash() */
70142109Sru	0		/* lorder */
71142109Sru};
72142109Sru
731590Srgrimes/*
741590Srgrimes * Mkcapdb creates a capability hash database for quick retrieval of capability
751590Srgrimes * records.  The database contains 2 types of entries: records and references
761590Srgrimes * marked by the first byte in the data.  A record entry contains the actual
771590Srgrimes * capability record whereas a reference contains the name (key) under which
781590Srgrimes * the correct record is stored.
791590Srgrimes */
801590Srgrimesint
81100812Sdwmalonemain(int argc, char *argv[])
821590Srgrimes{
83142262Sru	int byteorder, c;
841590Srgrimes
851590Srgrimes	capname = NULL;
86142262Sru	byteorder = 0;
87142262Sru	while ((c = getopt(argc, argv, "bf:lv")) != -1) {
881590Srgrimes		switch(c) {
89142262Sru		case 'b':
90142262Sru		case 'l':
91142262Sru			if (byteorder != 0)
92142262Sru				usage();
93142262Sru			byteorder = c == 'b' ? 4321 : 1234;
94142262Sru			break;
951590Srgrimes		case 'f':
961590Srgrimes			capname = optarg;
971590Srgrimes			break;
981590Srgrimes		case 'v':
991590Srgrimes			verbose = 1;
1001590Srgrimes			break;
1011590Srgrimes		case '?':
1021590Srgrimes		default:
1031590Srgrimes			usage();
1041590Srgrimes		}
1051590Srgrimes	}
1061590Srgrimes	argc -= optind;
1071590Srgrimes	argv += optind;
1081590Srgrimes
1091590Srgrimes	if (*argv == NULL)
1101590Srgrimes		usage();
1111590Srgrimes
112142262Sru	/* Set byte order. */
113142262Sru	openinfo.lorder = byteorder;
114142262Sru
1151590Srgrimes	/*
1161590Srgrimes	 * The database file is the first argument if no name is specified.
1171590Srgrimes	 * Make arrangements to unlink it if exit badly.
1181590Srgrimes	 */
1191590Srgrimes	(void)snprintf(buf, sizeof(buf), "%s.db", capname ? capname : *argv);
1201590Srgrimes	if ((capname = strdup(buf)) == NULL)
12153508Scharnier		errx(1, "strdup failed");
122296424Sdwmalone	if ((capdbp = dbopen(capname, O_CREAT | O_TRUNC | O_RDWR,
123142109Sru	    DEFFILEMODE, DB_HASH, &openinfo)) == NULL)
1241590Srgrimes		err(1, "%s", buf);
1251590Srgrimes
1261590Srgrimes	if (atexit(dounlink))
1271590Srgrimes		err(1, "atexit");
1281590Srgrimes
1291590Srgrimes	db_build(argv);
1301590Srgrimes
1311590Srgrimes	if (capdbp->close(capdbp) < 0)
1321590Srgrimes		err(1, "%s", capname);
1331590Srgrimes	capname = NULL;
1341590Srgrimes	exit(0);
1351590Srgrimes}
1361590Srgrimes
137227154Sedstatic void
138100812Sdwmalonedounlink(void)
1391590Srgrimes{
1401590Srgrimes	if (capname != NULL)
1411590Srgrimes		(void)unlink(capname);
1421590Srgrimes}
1431590Srgrimes
1441590Srgrimes/*
1451590Srgrimes * Any changes to these definitions should be made also in the getcap(3)
1461590Srgrimes * library routines.
1471590Srgrimes */
1481590Srgrimes#define RECOK	(char)0
1491590Srgrimes#define TCERR	(char)1
1501590Srgrimes#define SHADOW	(char)2
1511590Srgrimes
1521590Srgrimes/*
15377586Sru * Db_build() builds the name and capability databases according to the
1541590Srgrimes * details above.
1551590Srgrimes */
156227154Sedstatic void
157100812Sdwmalonedb_build(char **ifiles)
1581590Srgrimes{
1591590Srgrimes	DBT key, data;
1601590Srgrimes	recno_t reccnt;
1611590Srgrimes	size_t len, bplen;
1621590Srgrimes	int st;
1631590Srgrimes	char *bp, *p, *t;
1641590Srgrimes
1651590Srgrimes	data.data = NULL;
1661590Srgrimes	key.data = NULL;
1671590Srgrimes	for (reccnt = 0, bplen = 0; (st = cgetnext(&bp, ifiles)) > 0;) {
1681590Srgrimes
1691590Srgrimes		/*
1701590Srgrimes		 * Allocate enough memory to store record, terminating
1711590Srgrimes		 * NULL and one extra byte.
1721590Srgrimes		 */
1731590Srgrimes		len = strlen(bp);
1741590Srgrimes		if (bplen <= len + 2) {
1751590Srgrimes			bplen += MAX(256, len + 2);
1761590Srgrimes			if ((data.data = realloc(data.data, bplen)) == NULL)
17753508Scharnier				errx(1, "malloc failed");
1781590Srgrimes		}
1791590Srgrimes
1801590Srgrimes		/* Find the end of the name field. */
1811590Srgrimes		if ((p = strchr(bp, ':')) == NULL) {
18237453Sbde			warnx("no name field: %.*s", (int)MIN(len, 20), bp);
1831590Srgrimes			continue;
1841590Srgrimes		}
1851590Srgrimes
1861590Srgrimes		/* First byte of stored record indicates status. */
1871590Srgrimes		switch(st) {
1881590Srgrimes		case 1:
1891590Srgrimes			((char *)(data.data))[0] = RECOK;
1901590Srgrimes			break;
1911590Srgrimes		case 2:
1921590Srgrimes			((char *)(data.data))[0] = TCERR;
19379010Sdd			warnx("record not tc expanded: %.*s", (int)(p - bp),
19479010Sdd			    bp);
1951590Srgrimes			break;
1961590Srgrimes		}
1971590Srgrimes
1981590Srgrimes		/* Create the stored record. */
1991590Srgrimes		memmove(&((u_char *)(data.data))[1], bp, len + 1);
2001590Srgrimes		data.size = len + 2;
2011590Srgrimes
2021590Srgrimes		/* Store the record under the name field. */
2031590Srgrimes		key.data = bp;
2041590Srgrimes		key.size = p - bp;
2051590Srgrimes
2061590Srgrimes		switch(capdbp->put(capdbp, &key, &data, R_NOOVERWRITE)) {
2071590Srgrimes		case -1:
2081590Srgrimes			err(1, "put");
2091590Srgrimes			/* NOTREACHED */
2101590Srgrimes		case 1:
2111590Srgrimes			warnx("ignored duplicate: %.*s",
21237453Sbde			    (int)key.size, (char *)key.data);
2131590Srgrimes			continue;
2141590Srgrimes		}
2151590Srgrimes		++reccnt;
2161590Srgrimes
2171590Srgrimes		/* If only one name, ignore the rest. */
21877586Sru		*p = '\0';
21977586Sru		if (strchr(bp, '|') == NULL)
2201590Srgrimes			continue;
22177586Sru		*p = ':';
2221590Srgrimes
2231590Srgrimes		/* The rest of the names reference the entire name. */
2241590Srgrimes		((char *)(data.data))[0] = SHADOW;
2251590Srgrimes		memmove(&((u_char *)(data.data))[1], key.data, key.size);
2261590Srgrimes		data.size = key.size + 1;
2271590Srgrimes
2281590Srgrimes		/* Store references for other names. */
2291590Srgrimes		for (p = t = bp;; ++p) {
2301590Srgrimes			if (p > t && (*p == ':' || *p == '|')) {
2311590Srgrimes				key.size = p - t;
2321590Srgrimes				key.data = t;
2331590Srgrimes				switch(capdbp->put(capdbp,
2341590Srgrimes				    &key, &data, R_NOOVERWRITE)) {
2351590Srgrimes				case -1:
2361590Srgrimes					err(1, "put");
2371590Srgrimes					/* NOTREACHED */
2381590Srgrimes				case 1:
2391590Srgrimes					warnx("ignored duplicate: %.*s",
24037453Sbde					    (int)key.size, (char *)key.data);
2411590Srgrimes				}
2421590Srgrimes				t = p + 1;
2431590Srgrimes			}
2441590Srgrimes			if (*p == ':')
2451590Srgrimes				break;
2461590Srgrimes		}
2471590Srgrimes	}
2481590Srgrimes
2491590Srgrimes	switch(st) {
2501590Srgrimes	case -1:
2511590Srgrimes		err(1, "file argument");
2521590Srgrimes		/* NOTREACHED */
2531590Srgrimes	case -2:
2541590Srgrimes		errx(1, "potential reference loop detected");
2551590Srgrimes		/* NOTREACHED */
2561590Srgrimes	}
2571590Srgrimes
2581590Srgrimes	if (verbose)
2591590Srgrimes		(void)printf("cap_mkdb: %d capability records\n", reccnt);
2601590Srgrimes}
2611590Srgrimes
262227154Sedstatic void
263100812Sdwmaloneusage(void)
2641590Srgrimes{
2651590Srgrimes	(void)fprintf(stderr,
266142262Sru	    "usage: cap_mkdb [-b | -l] [-v] [-f outfile] file ...\n");
2671590Srgrimes	exit(1);
2681590Srgrimes}
269