1 /* 2 * Copyright (c) 1992 Eric P. Allman. 3 * Copyright (c) 1992, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)makemap.c 8.9 (Berkeley) 02/03/95"; 11 #endif /* not lint */ 12 13 #include <stdio.h> 14 #include <sysexits.h> 15 #include <sys/types.h> 16 #include <sys/file.h> 17 #include <ctype.h> 18 #include <string.h> 19 #include <sys/errno.h> 20 #include "useful.h" 21 #include "conf.h" 22 23 #ifdef NDBM 24 #include <ndbm.h> 25 #endif 26 27 #ifdef NEWDB 28 #include <db.h> 29 #endif 30 31 enum type { T_DBM, T_BTREE, T_HASH, T_ERR, T_UNKNOWN }; 32 33 union dbent 34 { 35 #ifdef NDBM 36 datum dbm; 37 #endif 38 #ifdef NEWDB 39 DBT db; 40 #endif 41 struct 42 { 43 char *data; 44 size_t size; 45 } xx; 46 }; 47 48 #define BUFSIZE 1024 49 50 main(argc, argv) 51 int argc; 52 char **argv; 53 { 54 char *progname; 55 bool inclnull = FALSE; 56 bool notrunc = FALSE; 57 bool allowreplace = FALSE; 58 bool allowdups = FALSE; 59 bool verbose = FALSE; 60 bool foldcase = TRUE; 61 int exitstat; 62 int opt; 63 char *typename; 64 char *mapname; 65 char *ext; 66 int lineno; 67 int st; 68 int mode; 69 enum type type; 70 int fd; 71 union 72 { 73 #ifdef NDBM 74 DBM *dbm; 75 #endif 76 #ifdef NEWDB 77 DB *db; 78 #endif 79 void *dbx; 80 } dbp; 81 union dbent key, val; 82 #ifdef NEWDB 83 BTREEINFO bti; 84 #endif 85 char ibuf[BUFSIZE]; 86 char fbuf[MAXNAME]; 87 extern char *optarg; 88 extern int optind; 89 extern bool lockfile(); 90 91 progname = argv[0]; 92 93 while ((opt = getopt(argc, argv, "Ndforv")) != EOF) 94 { 95 switch (opt) 96 { 97 case 'N': 98 inclnull = TRUE; 99 break; 100 101 case 'd': 102 allowdups = TRUE; 103 break; 104 105 case 'f': 106 foldcase = FALSE; 107 break; 108 109 case 'o': 110 notrunc = TRUE; 111 break; 112 113 case 'r': 114 allowreplace = TRUE; 115 break; 116 117 case 'v': 118 verbose = TRUE; 119 break; 120 121 default: 122 type = T_ERR; 123 break; 124 } 125 } 126 127 argc -= optind; 128 argv += optind; 129 if (argc != 2) 130 type = T_ERR; 131 else 132 { 133 typename = argv[0]; 134 mapname = argv[1]; 135 ext = NULL; 136 137 if (strcmp(typename, "dbm") == 0) 138 { 139 type = T_DBM; 140 } 141 else if (strcmp(typename, "btree") == 0) 142 { 143 type = T_BTREE; 144 ext = ".db"; 145 } 146 else if (strcmp(typename, "hash") == 0) 147 { 148 type = T_HASH; 149 ext = ".db"; 150 } 151 else 152 type = T_UNKNOWN; 153 } 154 155 switch (type) 156 { 157 case T_ERR: 158 fprintf(stderr, "Usage: %s [-N] [-d] [-f] [-o] [-r] [-v] type mapname\n", progname); 159 exit(EX_USAGE); 160 161 case T_UNKNOWN: 162 fprintf(stderr, "%s: Unknown database type %s\n", 163 progname, typename); 164 exit(EX_USAGE); 165 166 #ifndef NDBM 167 case T_DBM: 168 #endif 169 #ifndef NEWDB 170 case T_BTREE: 171 case T_HASH: 172 #endif 173 fprintf(stderr, "%s: Type %s not supported in this version\n", 174 progname, typename); 175 exit(EX_UNAVAILABLE); 176 177 #ifdef NEWDB 178 case T_BTREE: 179 bzero(&bti, sizeof bti); 180 if (allowdups) 181 bti.flags |= R_DUP; 182 break; 183 184 case T_HASH: 185 #endif 186 #ifdef NDBM 187 case T_DBM: 188 #endif 189 if (allowdups) 190 { 191 fprintf(stderr, "%s: Type %s does not support -d (allow dups)\n", 192 progname, typename); 193 exit(EX_UNAVAILABLE); 194 } 195 break; 196 } 197 198 /* 199 ** Adjust file names. 200 */ 201 202 if (ext != NULL) 203 { 204 int el, fl; 205 206 el = strlen(ext); 207 fl = strlen(mapname); 208 if (fl < el || strcmp(&mapname[fl - el], ext) != 0) 209 { 210 strcpy(fbuf, mapname); 211 strcat(fbuf, ext); 212 mapname = fbuf; 213 } 214 } 215 216 /* 217 ** Create the database. 218 */ 219 220 mode = O_RDWR; 221 #ifdef O_EXLOCK 222 mode |= O_EXLOCK; 223 #endif 224 if (!notrunc) 225 mode |= O_CREAT|O_TRUNC; 226 switch (type) 227 { 228 #ifdef NDBM 229 case T_DBM: 230 dbp.dbm = dbm_open(mapname, mode, 0644); 231 break; 232 #endif 233 234 #ifdef NEWDB 235 case T_HASH: 236 dbp.db = dbopen(mapname, mode, 0644, DB_HASH, NULL); 237 break; 238 239 case T_BTREE: 240 dbp.db = dbopen(mapname, mode, 0644, DB_BTREE, &bti); 241 break; 242 #endif 243 244 default: 245 fprintf(stderr, "%s: internal error: type %d\n", progname, type); 246 exit(EX_SOFTWARE); 247 } 248 249 if (dbp.dbx == NULL) 250 { 251 fprintf(stderr, "%s: cannot create type %s map %s\n", 252 progname, typename, mapname); 253 exit(EX_CANTCREAT); 254 } 255 256 #ifndef O_EXLOCK 257 switch (type) 258 { 259 # ifdef NDBM 260 case T_DBM: 261 fd = dbm_dirfno(dbp.dbm); 262 if (fd >= 0) 263 lockfile(fd); 264 break; 265 # endif 266 # ifdef NEWDB 267 case T_HASH: 268 case T_BTREE: 269 fd = dbp.db->fd(dbp.db); 270 if (fd >= 0) 271 lockfile(fd); 272 break; 273 # endif 274 } 275 #endif 276 277 /* 278 ** Copy the data 279 */ 280 281 lineno = 0; 282 exitstat = EX_OK; 283 while (fgets(ibuf, sizeof ibuf, stdin) != NULL) 284 { 285 register char *p; 286 287 lineno++; 288 289 /* 290 ** Parse the line. 291 */ 292 293 p = strchr(ibuf, '\n'); 294 if (p != NULL) 295 *p = '\0'; 296 else if (!feof(stdin)) 297 { 298 fprintf(stderr, "%s: %s: line %d: line too long (%d bytes max)\n", 299 progname, mapname, lineno, sizeof ibuf); 300 continue; 301 } 302 303 if (ibuf[0] == '\0' || ibuf[0] == '#') 304 continue; 305 if (isspace(ibuf[0])) 306 { 307 fprintf(stderr, "%s: %s: line %d: syntax error (leading space)\n", 308 progname, mapname, lineno); 309 continue; 310 } 311 key.xx.data = ibuf; 312 for (p = ibuf; *p != '\0' && !isspace(*p); p++) 313 { 314 if (foldcase && isupper(*p)) 315 *p = tolower(*p); 316 } 317 key.xx.size = p - key.xx.data; 318 if (inclnull) 319 key.xx.size++; 320 if (*p != '\0') 321 *p++ = '\0'; 322 while (isspace(*p)) 323 p++; 324 if (*p == '\0') 325 { 326 fprintf(stderr, "%s: %s: line %d: no RHS for LHS %s\n", 327 progname, mapname, lineno, key.xx.data); 328 continue; 329 } 330 val.xx.data = p; 331 val.xx.size = strlen(p); 332 if (inclnull) 333 val.xx.size++; 334 335 /* 336 ** Do the database insert. 337 */ 338 339 if (verbose) 340 { 341 printf("key=`%s', val=`%s'\n", key.xx.data, val.xx.data); 342 } 343 344 switch (type) 345 { 346 #ifdef NDBM 347 case T_DBM: 348 st = dbm_store(dbp.dbm, key.dbm, val.dbm, 349 allowreplace ? DBM_REPLACE : DBM_INSERT); 350 break; 351 #endif 352 353 #ifdef NEWDB 354 case T_BTREE: 355 case T_HASH: 356 st = (*dbp.db->put)(dbp.db, &key.db, &val.db, 357 allowreplace ? 0 : R_NOOVERWRITE); 358 break; 359 #endif 360 } 361 362 if (st < 0) 363 { 364 fprintf(stderr, "%s: %s: line %d: key %s: put error\n", 365 progname, mapname, lineno, key.xx.data); 366 perror(mapname); 367 exitstat = EX_IOERR; 368 } 369 else if (st > 0) 370 { 371 fprintf(stderr, "%s: %s: line %d: key %s: duplicate key\n", 372 progname, mapname, lineno, key.xx.data); 373 } 374 } 375 376 /* 377 ** Now close the database. 378 */ 379 380 switch (type) 381 { 382 #ifdef NDBM 383 case T_DBM: 384 dbm_close(dbp.dbm); 385 break; 386 #endif 387 388 #ifdef NEWDB 389 case T_HASH: 390 case T_BTREE: 391 if ((*dbp.db->close)(dbp.db) < 0) 392 { 393 fprintf(stderr, "%s: %s: error on close\n", 394 progname, mapname); 395 perror(mapname); 396 exitstat = EX_IOERR; 397 } 398 #endif 399 } 400 401 exit (exitstat); 402 } 403 /* 404 ** LOCKFILE -- lock a file using flock or (shudder) fcntl locking 405 ** 406 ** Parameters: 407 ** fd -- the file descriptor of the file. 408 ** 409 ** Returns: 410 ** TRUE if the lock was acquired. 411 ** FALSE otherwise. 412 */ 413 414 bool 415 lockfile(fd) 416 int fd; 417 { 418 # if !HASFLOCK 419 int action; 420 struct flock lfd; 421 extern int errno; 422 423 bzero(&lfd, sizeof lfd); 424 lfd.l_type = F_WRLCK; 425 action = F_SETLKW; 426 427 if (fcntl(fd, action, &lfd) >= 0) 428 return TRUE; 429 430 /* 431 ** On SunOS, if you are testing using -oQ/tmp/mqueue or 432 ** -oA/tmp/aliases or anything like that, and /tmp is mounted 433 ** as type "tmp" (that is, served from swap space), the 434 ** previous fcntl will fail with "Invalid argument" errors. 435 ** Since this is fairly common during testing, we will assume 436 ** that this indicates that the lock is successfully grabbed. 437 */ 438 439 if (errno == EINVAL) 440 return TRUE; 441 442 # else /* HASFLOCK */ 443 444 if (flock(fd, LOCK_EX) >= 0) 445 return TRUE; 446 447 # endif 448 449 return FALSE; 450 } 451