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