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