xref: /original-bsd/usr.bin/cap_mkdb/cap_mkdb.c (revision 00695d63)
1 /*-
2  * Copyright (c) 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1992, 1993\n\
11 	The Regents of the University of California.  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)cap_mkdb.c	8.2 (Berkeley) 04/27/95";
16 #endif /* not lint */
17 
18 #include <sys/param.h>
19 #include <sys/stat.h>
20 
21 #include <db.h>
22 #include <err.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <limits.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 
31 void	 db_build __P((char **));
32 void	 dounlink __P((void));
33 void	 usage __P((void));
34 
35 DB *capdbp;
36 int verbose;
37 char *capdb, *capname, buf[8 * 1024];
38 
39 HASHINFO openinfo = {
40 	4096,		/* bsize */
41 	16,		/* ffactor */
42 	256,		/* nelem */
43 	2048 * 1024,	/* cachesize */
44 	NULL,		/* hash() */
45 	0		/* lorder */
46 };
47 
48 /*
49  * Mkcapdb creates a capability hash database for quick retrieval of capability
50  * records.  The database contains 2 types of entries: records and references
51  * marked by the first byte in the data.  A record entry contains the actual
52  * capability record whereas a reference contains the name (key) under which
53  * the correct record is stored.
54  */
55 int
56 main(argc, argv)
57 	int argc;
58 	char *argv[];
59 {
60 	int c;
61 
62 	capname = NULL;
63 	while ((c = getopt(argc, argv, "f:v")) != EOF) {
64 		switch(c) {
65 		case 'f':
66 			capname = optarg;
67 			break;
68 		case 'v':
69 			verbose = 1;
70 			break;
71 		case '?':
72 		default:
73 			usage();
74 		}
75 	}
76 	argc -= optind;
77 	argv += optind;
78 
79 	if (*argv == NULL)
80 		usage();
81 
82 	/*
83 	 * The database file is the first argument if no name is specified.
84 	 * Make arrangements to unlink it if exit badly.
85 	 */
86 	(void)snprintf(buf, sizeof(buf), "%s.db", capname ? capname : *argv);
87 	if ((capname = strdup(buf)) == NULL)
88 		err(1, "");
89 	if ((capdbp = dbopen(capname, O_CREAT | O_TRUNC | O_RDWR,
90 	    DEFFILEMODE, DB_HASH, &openinfo)) == NULL)
91 		err(1, "%s", buf);
92 
93 	if (atexit(dounlink))
94 		err(1, "atexit");
95 
96 	db_build(argv);
97 
98 	if (capdbp->close(capdbp) < 0)
99 		err(1, "%s", capname);
100 	capname = NULL;
101 	exit(0);
102 }
103 
104 void
105 dounlink()
106 {
107 	if (capname != NULL)
108 		(void)unlink(capname);
109 }
110 
111 /*
112  * Any changes to these definitions should be made also in the getcap(3)
113  * library routines.
114  */
115 #define RECOK	(char)0
116 #define TCERR	(char)1
117 #define SHADOW	(char)2
118 
119 /*
120  * Db_build() builds the name and capabilty databases according to the
121  * details above.
122  */
123 void
124 db_build(ifiles)
125 	char **ifiles;
126 {
127 	DBT key, data;
128 	recno_t reccnt;
129 	size_t len, bplen;
130 	int st;
131 	char *bp, *p, *t;
132 
133 	data.data = NULL;
134 	key.data = NULL;
135 	for (reccnt = 0, bplen = 0; (st = cgetnext(&bp, ifiles)) > 0;) {
136 
137 		/*
138 		 * Allocate enough memory to store record, terminating
139 		 * NULL and one extra byte.
140 		 */
141 		len = strlen(bp);
142 		if (bplen <= len + 2) {
143 			bplen += MAX(256, len + 2);
144 			if ((data.data = realloc(data.data, bplen)) == NULL)
145 				err(1, "");
146 		}
147 
148 		/* Find the end of the name field. */
149 		if ((p = strchr(bp, ':')) == NULL) {
150 			warnx("no name field: %.*s", MIN(len, 20), bp);
151 			continue;
152 		}
153 
154 		/* First byte of stored record indicates status. */
155 		switch(st) {
156 		case 1:
157 			((char *)(data.data))[0] = RECOK;
158 			break;
159 		case 2:
160 			((char *)(data.data))[0] = TCERR;
161 			warnx("Record not tc expanded: %.*s", p - bp, bp);
162 			break;
163 		}
164 
165 		/* Create the stored record. */
166 		memmove(&((u_char *)(data.data))[1], bp, len + 1);
167 		data.size = len + 2;
168 
169 		/* Store the record under the name field. */
170 		key.data = bp;
171 		key.size = p - bp;
172 
173 		switch(capdbp->put(capdbp, &key, &data, R_NOOVERWRITE)) {
174 		case -1:
175 			err(1, "put");
176 			/* NOTREACHED */
177 		case 1:
178 			warnx("ignored duplicate: %.*s",
179 			    key.size, (char *)key.data);
180 			continue;
181 		}
182 		++reccnt;
183 
184 		/* If only one name, ignore the rest. */
185 		if ((p = strchr(bp, '|')) == NULL)
186 			continue;
187 
188 		/* The rest of the names reference the entire name. */
189 		((char *)(data.data))[0] = SHADOW;
190 		memmove(&((u_char *)(data.data))[1], key.data, key.size);
191 		data.size = key.size + 1;
192 
193 		/* Store references for other names. */
194 		for (p = t = bp;; ++p) {
195 			if (p > t && (*p == ':' || *p == '|')) {
196 				key.size = p - t;
197 				key.data = t;
198 				switch(capdbp->put(capdbp,
199 				    &key, &data, R_NOOVERWRITE)) {
200 				case -1:
201 					err(1, "put");
202 					/* NOTREACHED */
203 				case 1:
204 					warnx("ignored duplicate: %.*s",
205 					    key.size, (char *)key.data);
206 				}
207 				t = p + 1;
208 			}
209 			if (*p == ':')
210 				break;
211 		}
212 	}
213 
214 	switch(st) {
215 	case -1:
216 		err(1, "file argument");
217 		/* NOTREACHED */
218 	case -2:
219 		errx(1, "potential reference loop detected");
220 		/* NOTREACHED */
221 	}
222 
223 	if (verbose)
224 		(void)printf("cap_mkdb: %d capability records\n", reccnt);
225 }
226 
227 void
228 usage()
229 {
230 	(void)fprintf(stderr,
231 	    "usage: cap_mkdb [-v] [-f outfile] file1 [file2 ...]\n");
232 	exit(1);
233 }
234