xref: /original-bsd/usr.bin/cap_mkdb/cap_mkdb.c (revision 942cfc3b)
1 /*-
2  * Copyright (c) 1992 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1992 The Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)cap_mkdb.c	5.1 (Berkeley) 10/17/92";
16 #endif /* not lint */
17 
18 #include <sys/param.h>
19 #include <sys/stat.h>
20 
21 #include <db.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <limits.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 
30 static void	 db_build __P((char **));
31 static void	 err __P((int, const char *, ...));
32 static void	 getnamefield __P((char **, char *));
33 static void	 usage __P((void));
34 
35 int docapdbunlink, printnl;
36 char *capdb, **inputfiles;
37 
38 /*
39  * Mkcapdb creates a capability hash database for quick retrieval of capability
40  * records.  The database contains 2 types of entries: records and references
41  * marked by the first byte in the data.  A record entry contains the actual
42  * capability record whereas a reference contains the name (key) under which
43  * the correct record is stored.
44  */
45 int
46 main(argc, argv)
47 	int argc;
48 	char *argv[];
49 {
50 	int c, fd;
51 	char *outname, buf[MAXPATHLEN + 1], **f;
52 
53 	outname = NULL;
54 	while ((c = getopt(argc, argv, "f:")) != EOF) {
55 		switch(c) {
56 		case 'f':
57 			outname = optarg;
58 			break;
59 		case '?':
60 		default:
61 			usage();
62 		}
63 	}
64 	argc -= optind;
65 	argv += optind;
66 
67 	if (*argv == NULL)
68 		usage();
69 
70 	inputfiles = argv;
71 
72 	if (outname == NULL)
73 		outname = *inputfiles;
74 
75 #define CAPDBNAMEEXTLEN		3	/* ".db" */
76 	if ((capdb = malloc(strlen(outname) + CAPDBNAMEEXTLEN + 1)) == NULL)
77 		err(1, "%s", strerror(errno));
78 	(void)sprintf(capdb, "%s.db", outname);
79 
80 	/*
81 	 * We want to avoid the confusion of where the capability record
82 	 * is being read from.  Since the user probably intends to read the
83 	 * ascii file, we should make sure that user knows that the
84 	 * corresponding .db file will override.
85 	 */
86 	for (f = inputfiles; *f != NULL; f++) {
87 		(void)sprintf(buf, "%s.db", *f);
88 		fd = open(buf, O_RDONLY, 0444);
89 		if (fd == -1 && errno != ENOENT)
90 			err(1, "%s: %s", buf, strerror(errno));
91 		if (fd >= 0) {
92 			err(0, "Warning -- %s.db will override %s.", *f, *f);
93 			(void)close(fd);
94 		}
95 	}
96 
97 	db_build(inputfiles);
98 	exit(0);
99 }
100 
101 /*
102  * Any changes to these definitions should be made also in the getcap(3)
103  * library routines.
104  */
105 
106 #define RECOK	(char)0
107 #define TCERR	(char)1
108 
109 #define NBUFSIZ		(8 * 1024)
110 
111 /*
112  * Db_build() builds the name and capabilty databases according to the
113  * details above.
114  */
115 void
116 db_build(inputfiles)
117 	char **inputfiles;
118 {
119 	DB *capdbp;
120 	DBT key, data;
121 	recno_t reccnt;
122 	size_t lastlen, bplen;
123 	int st, stdb;
124 	char *cp, *np, *bp, *nf, namebuf[NBUFSIZ];
125 
126 	if ((capdbp = dbopen(capdb, O_CREAT | O_TRUNC | O_RDWR,
127 	    DEFFILEMODE, DB_HASH, NULL)) == NULL)
128 		err(1, "%s: %s", capdb, strerror(errno));
129 	docapdbunlink = 1;
130 
131 	lastlen = 0;
132 	nf = NULL;
133 	data.data = NULL;
134 	key.data = NULL;
135 	for (reccnt = 0; (st = cgetnext(&bp, inputfiles)) > 0;) {
136 		getnamefield(&nf, bp);
137 		if ((bplen = strlen(bp)) > lastlen) {
138 			if ((data.data = realloc(data.data, bplen + 2)) == NULL)
139 				err(1, "%s", strerror(errno));
140 			lastlen = bplen;
141 		}
142 
143 		/* Store record under name field. */
144 		if (st == 2)
145 			((char *)(data.data))[0] = TCERR;
146 		else
147 			((char *)(data.data))[0] = RECOK;
148 
149 		(void)strcpy(&((char *)(data.data))[1], bp);
150 		data.size = bplen + 2;
151 		key.data = nf;
152 		key.size = strlen(nf) + 1;
153 		if ((stdb =
154 		    capdbp->put(capdbp, &key, &data, R_NOOVERWRITE)) < 0)
155 			err(1, "put: %s", strerror(errno));
156 		if (stdb == 1) {
157 			err(0, "ignored duplicate: %s", nf);
158 			continue;
159 		}
160 		++reccnt;
161 
162 		/* Store references for other names. */
163 		(void)strcpy((char *)(data.data), nf);
164 
165 		data.size = key.size;
166 		key.data = namebuf;
167 		np = namebuf;
168 		for (cp = nf; *cp != '\0'; *np++ = *cp++)
169 			if (*cp == ':' || *cp == '|') {
170 				*np = '\0';
171 				key.size = strlen(namebuf) + 1;
172 				if ((stdb = capdbp->put(capdbp, &key, &data,
173 				    R_NOOVERWRITE)) < 0)
174 					err(1, "put: %s", strerror(errno));
175 				if (stdb == 1)
176 					err(0,
177 					    "ignored duplicate: %s", namebuf);
178 				np = namebuf;
179 				continue;
180 			}
181 	}
182 	if (capdbp->close(capdbp) < 0)
183 		err(1, "%s", strerror(errno));
184 
185 	if (st == -1)
186 		err(1, "%s", strerror(errno));
187 	if (st == -2)
188 		err(1, "potential reference loop detected");
189 
190 	free(data.data);
191 	free(nf);
192 	free(bp);
193 
194 	(void)printf("cap_mkdb: %d capability records\n", reccnt);
195 }
196 
197 void
198 getnamefield(nf, bp)
199 	char **nf, *bp;
200 {
201 	static size_t nfsize;
202 	size_t newsize;
203 	char *cp, tmp;
204 
205 	for (cp = bp; *cp != ':'; cp++);
206 
207 	tmp = *(cp + 1);
208 	*(cp + 1) = '\0';
209 
210 	if ((newsize = cp - bp + 1) > nfsize) {
211 		if ((*nf = realloc(*nf, newsize)) == NULL)
212 			err(1, "%s", strerror(errno));
213 		nfsize = newsize;
214 	}
215 	(void)strcpy(*nf, bp);
216 	*(cp + 1) = tmp;
217 }
218 
219 void
220 usage()
221 {
222 	(void)fprintf(stderr,
223 	    "usage: cap_mkdb [-f outfile] file1 [file2 ...]\n");
224 	exit(1);
225 }
226 
227 #if __STDC__
228 #include <stdarg.h>
229 #else
230 #include <varargs.h>
231 #endif
232 
233 void
234 #if __STDC__
235 err(int fatal, const char *fmt, ...)
236 #else
237 err(fmt, va_alist)
238 	char *fmt;
239 	va_dcl
240 #endif
241 {
242 	va_list ap;
243 #if __STDC__
244 	va_start(ap, fmt);
245 #else
246 	va_start(ap);
247 #endif
248 
249 	if (printnl)
250 		(void)fprintf(stderr, "\n");
251 	(void)fprintf(stderr, "cap_mkdb: ");
252 	(void)vfprintf(stderr, fmt, ap);
253 	va_end(ap);
254 	(void)fprintf(stderr, "\n");
255 	if (fatal) {
256 		if (docapdbunlink)
257 			(void)unlink(capdb);
258 		exit(1);
259 	}
260 }
261