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