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 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.9 (Berkeley) 09/09/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