156811Seric /* 256811Seric * Copyright (c) 1992 Eric P. Allman. 362514Sbostic * Copyright (c) 1992, 1993 462514Sbostic * The Regents of the University of California. All rights reserved. 556811Seric * 656811Seric * %sccs.include.redist.c% 756811Seric */ 856811Seric 956811Seric #ifndef lint 10*68182Seric static char sccsid[] = "@(#)makemap.c 8.8 (Berkeley) 01/10/95"; 1156811Seric #endif /* not lint */ 1256811Seric 1356811Seric #include <stdio.h> 1456811Seric #include <sysexits.h> 1564343Seric #include <sys/types.h> 1656811Seric #include <sys/file.h> 1756811Seric #include <ctype.h> 1856811Seric #include <string.h> 19*68182Seric #include <sys/errno.h> 2056811Seric #include "useful.h" 2156811Seric #include "conf.h" 2256811Seric 2360558Seric #ifdef NDBM 2456811Seric #include <ndbm.h> 2556811Seric #endif 2656811Seric 2760558Seric #ifdef NEWDB 2856811Seric #include <db.h> 2956811Seric #endif 3056811Seric 3156811Seric enum type { T_DBM, T_BTREE, T_HASH, T_ERR, T_UNKNOWN }; 3256811Seric 3356811Seric union dbent 3456811Seric { 3560558Seric #ifdef NDBM 3656811Seric datum dbm; 3756811Seric #endif 3860558Seric #ifdef NEWDB 3956811Seric DBT db; 4056811Seric #endif 4156811Seric struct 4256811Seric { 4356811Seric char *data; 4456811Seric int size; 4556811Seric } xx; 4656811Seric }; 4756811Seric 4856811Seric #define BUFSIZE 1024 4956811Seric 5056811Seric main(argc, argv) 5156811Seric int argc; 5256811Seric char **argv; 5356811Seric { 5456811Seric char *progname; 5556811Seric bool inclnull = FALSE; 5656811Seric bool notrunc = FALSE; 5756811Seric bool allowreplace = FALSE; 5867557Seric bool allowdups = FALSE; 5956811Seric bool verbose = FALSE; 6064557Seric bool foldcase = TRUE; 6156811Seric int exitstat; 6256811Seric int opt; 6356811Seric char *typename; 6456811Seric char *mapname; 6564152Seric char *ext; 6656811Seric int lineno; 6756811Seric int st; 6856811Seric int mode; 6956811Seric enum type type; 70*68182Seric int fd; 7156811Seric union 7256811Seric { 7360558Seric #ifdef NDBM 7456811Seric DBM *dbm; 7556811Seric #endif 7660558Seric #ifdef NEWDB 7756811Seric DB *db; 7856811Seric #endif 7956811Seric void *dbx; 8056811Seric } dbp; 8156811Seric union dbent key, val; 8267557Seric #ifdef NEWDB 8367557Seric BTREEINFO bti; 8467557Seric #endif 8556811Seric char ibuf[BUFSIZE]; 8664151Seric char fbuf[MAXNAME]; 8756811Seric extern char *optarg; 8856811Seric extern int optind; 89*68182Seric extern bool lockfile(); 9056811Seric 9156811Seric progname = argv[0]; 9256811Seric 9367557Seric while ((opt = getopt(argc, argv, "Ndforv")) != EOF) 9456811Seric { 9556811Seric switch (opt) 9656811Seric { 9756811Seric case 'N': 9856811Seric inclnull = TRUE; 9956811Seric break; 10056811Seric 10167557Seric case 'd': 10267557Seric allowdups = TRUE; 10367557Seric break; 10467557Seric 10557078Seric case 'f': 10664557Seric foldcase = FALSE; 10757078Seric break; 10857078Seric 10956811Seric case 'o': 11056811Seric notrunc = TRUE; 11156811Seric break; 11256811Seric 11356811Seric case 'r': 11456811Seric allowreplace = TRUE; 11556811Seric break; 11656811Seric 11756811Seric case 'v': 11856811Seric verbose = TRUE; 11956811Seric break; 12056811Seric 12156811Seric default: 12256811Seric type = T_ERR; 12356811Seric break; 12456811Seric } 12556811Seric } 12656811Seric 12756811Seric argc -= optind; 12856811Seric argv += optind; 12956811Seric if (argc != 2) 13056811Seric type = T_ERR; 13156811Seric else 13256811Seric { 13356811Seric typename = argv[0]; 13456811Seric mapname = argv[1]; 13564151Seric ext = NULL; 13656811Seric 13756811Seric if (strcmp(typename, "dbm") == 0) 13864151Seric { 13956811Seric type = T_DBM; 14064151Seric } 14156811Seric else if (strcmp(typename, "btree") == 0) 14264151Seric { 14356811Seric type = T_BTREE; 14464151Seric ext = ".db"; 14564151Seric } 14656811Seric else if (strcmp(typename, "hash") == 0) 14764151Seric { 14856811Seric type = T_HASH; 14964151Seric ext = ".db"; 15064151Seric } 15156811Seric else 15256811Seric type = T_UNKNOWN; 15356811Seric } 15456811Seric 15556811Seric switch (type) 15656811Seric { 15756811Seric case T_ERR: 15867557Seric fprintf(stderr, "Usage: %s [-N] [-d] [-f] [-o] [-r] [-v] type mapname\n", progname); 15956811Seric exit(EX_USAGE); 16056811Seric 16156811Seric case T_UNKNOWN: 16256811Seric fprintf(stderr, "%s: Unknown database type %s\n", 16356811Seric progname, typename); 16456811Seric exit(EX_USAGE); 16556811Seric 16660558Seric #ifndef NDBM 16756811Seric case T_DBM: 16856811Seric #endif 16960558Seric #ifndef NEWDB 17056811Seric case T_BTREE: 17156811Seric case T_HASH: 17256811Seric #endif 17356811Seric fprintf(stderr, "%s: Type %s not supported in this version\n", 17456811Seric progname, typename); 17556811Seric exit(EX_UNAVAILABLE); 17667557Seric 17767557Seric #ifdef NEWDB 17867557Seric case T_BTREE: 17967557Seric bzero(&bti, sizeof bti); 18067557Seric if (allowdups) 18167557Seric bti.flags |= R_DUP; 18267557Seric break; 18367557Seric 18467557Seric case T_HASH: 18567557Seric #endif 18667557Seric #ifdef NDBM 18767557Seric case T_DBM: 18867557Seric #endif 18967557Seric if (allowdups) 19067557Seric { 19167557Seric fprintf(stderr, "%s: Type %s does not support -d (allow dups)\n", 19267557Seric progname, typename); 19367557Seric exit(EX_UNAVAILABLE); 19467557Seric } 19567557Seric break; 19656811Seric } 19756811Seric 19856811Seric /* 19964151Seric ** Adjust file names. 20064151Seric */ 20164151Seric 20264151Seric if (ext != NULL) 20364151Seric { 20464151Seric int el, fl; 20564151Seric 20664151Seric el = strlen(ext); 20764151Seric fl = strlen(mapname); 20864151Seric if (fl < el || strcmp(&mapname[fl - el], ext) != 0) 20964151Seric { 21064151Seric strcpy(fbuf, mapname); 21164151Seric strcat(fbuf, ext); 21264151Seric mapname = fbuf; 21364151Seric } 21464151Seric } 21564151Seric 21664151Seric /* 21756811Seric ** Create the database. 21856811Seric */ 21956811Seric 22056811Seric mode = O_RDWR; 221*68182Seric #ifdef O_EXLOCK 222*68182Seric mode |= O_EXLOCK; 223*68182Seric #endif 22456811Seric if (!notrunc) 22556811Seric mode |= O_CREAT|O_TRUNC; 22656811Seric switch (type) 22756811Seric { 22860558Seric #ifdef NDBM 22956811Seric case T_DBM: 23056811Seric dbp.dbm = dbm_open(mapname, mode, 0644); 23156811Seric break; 23256811Seric #endif 23356811Seric 23460558Seric #ifdef NEWDB 23556811Seric case T_HASH: 23656811Seric dbp.db = dbopen(mapname, mode, 0644, DB_HASH, NULL); 23756811Seric break; 23856811Seric 23956811Seric case T_BTREE: 24067557Seric dbp.db = dbopen(mapname, mode, 0644, DB_BTREE, &bti); 24156811Seric break; 24256811Seric #endif 24356811Seric 24456811Seric default: 24556811Seric fprintf(stderr, "%s: internal error: type %d\n", progname, type); 24656811Seric exit(EX_SOFTWARE); 24756811Seric } 24856811Seric 24956811Seric if (dbp.dbx == NULL) 25056811Seric { 25156811Seric fprintf(stderr, "%s: cannot create type %s map %s\n", 25256811Seric progname, typename, mapname); 25356811Seric exit(EX_CANTCREAT); 25456811Seric } 25556811Seric 256*68182Seric #ifndef O_EXLOCK 257*68182Seric switch (type) 258*68182Seric { 259*68182Seric # ifdef NDBM 260*68182Seric case T_DBM: 261*68182Seric fd = dbm_dirfno(dbp.dbm); 262*68182Seric if (fd >= 0) 263*68182Seric lockfile(fd); 264*68182Seric break; 265*68182Seric # endif 266*68182Seric # ifdef NEWDB 267*68182Seric case T_HASH: 268*68182Seric case T_BTREE: 269*68182Seric fd = dbp.db->fd(dbp.db); 270*68182Seric if (fd >= 0) 271*68182Seric lockfile(fd); 272*68182Seric break; 273*68182Seric # endif 274*68182Seric } 275*68182Seric #endif 276*68182Seric 27756811Seric /* 27856811Seric ** Copy the data 27956811Seric */ 28056811Seric 28156811Seric lineno = 0; 28256811Seric exitstat = EX_OK; 28356811Seric while (fgets(ibuf, sizeof ibuf, stdin) != NULL) 28456811Seric { 28556811Seric register char *p; 28656811Seric 28756811Seric lineno++; 28856811Seric 28956811Seric /* 29056811Seric ** Parse the line. 29156811Seric */ 29256811Seric 29356811Seric p = strchr(ibuf, '\n'); 29464934Seric if (p != NULL) 29556811Seric *p = '\0'; 29664934Seric else if (!feof(stdin)) 29764934Seric { 29864934Seric fprintf(stderr, "%s: %s: line %d: line too long (%d bytes max)\n", 29964934Seric progname, mapname, lineno, sizeof ibuf); 30064934Seric continue; 30164934Seric } 30264934Seric 30356811Seric if (ibuf[0] == '\0' || ibuf[0] == '#') 30456811Seric continue; 30556811Seric if (isspace(ibuf[0])) 30656811Seric { 30756811Seric fprintf(stderr, "%s: %s: line %d: syntax error (leading space)\n", 30856811Seric progname, mapname, lineno); 30956811Seric continue; 31056811Seric } 31156811Seric key.xx.data = ibuf; 31256811Seric for (p = ibuf; *p != '\0' && !isspace(*p); p++) 31357078Seric { 31457078Seric if (foldcase && isupper(*p)) 31557078Seric *p = tolower(*p); 31657078Seric } 31756811Seric key.xx.size = p - key.xx.data; 31856811Seric if (inclnull) 31956811Seric key.xx.size++; 32056811Seric if (*p != '\0') 32156811Seric *p++ = '\0'; 32256811Seric while (isspace(*p)) 32356811Seric p++; 32456811Seric if (*p == '\0') 32556811Seric { 32656811Seric fprintf(stderr, "%s: %s: line %d: no RHS for LHS %s\n", 32756811Seric progname, mapname, lineno, key.xx.data); 32856811Seric continue; 32956811Seric } 33056811Seric val.xx.data = p; 33156811Seric val.xx.size = strlen(p); 33256811Seric if (inclnull) 33356811Seric val.xx.size++; 33456811Seric 33556811Seric /* 33656811Seric ** Do the database insert. 33756811Seric */ 33856811Seric 33956811Seric if (verbose) 34056811Seric { 34156811Seric printf("key=`%s', val=`%s'\n", key.xx.data, val.xx.data); 34256811Seric } 34356811Seric 34456811Seric switch (type) 34556811Seric { 34660558Seric #ifdef NDBM 34756811Seric case T_DBM: 34856811Seric st = dbm_store(dbp.dbm, key.dbm, val.dbm, 34956811Seric allowreplace ? DBM_REPLACE : DBM_INSERT); 35056811Seric break; 35156811Seric #endif 35256811Seric 35360558Seric #ifdef NEWDB 35456811Seric case T_BTREE: 35556811Seric case T_HASH: 35656811Seric st = (*dbp.db->put)(dbp.db, &key.db, &val.db, 35756811Seric allowreplace ? 0 : R_NOOVERWRITE); 35856811Seric break; 35956811Seric #endif 36056811Seric } 36156811Seric 36256811Seric if (st < 0) 36356811Seric { 36456811Seric fprintf(stderr, "%s: %s: line %d: key %s: put error\n", 36556811Seric progname, mapname, lineno, key.xx.data); 36656811Seric perror(mapname); 36756811Seric exitstat = EX_IOERR; 36856811Seric } 36956811Seric else if (st > 0) 37056811Seric { 37156811Seric fprintf(stderr, "%s: %s: line %d: key %s: duplicate key\n", 37256811Seric progname, mapname, lineno, key.xx.data); 37356811Seric } 37456811Seric } 37556811Seric 37656811Seric /* 37756811Seric ** Now close the database. 37856811Seric */ 37956811Seric 38056811Seric switch (type) 38156811Seric { 38260558Seric #ifdef NDBM 38356811Seric case T_DBM: 38456811Seric dbm_close(dbp.dbm); 38556811Seric break; 38656811Seric #endif 38756811Seric 38860558Seric #ifdef NEWDB 38956811Seric case T_HASH: 39056811Seric case T_BTREE: 39156811Seric if ((*dbp.db->close)(dbp.db) < 0) 39256811Seric { 39356811Seric fprintf(stderr, "%s: %s: error on close\n", 39456811Seric progname, mapname); 39556811Seric perror(mapname); 39656811Seric exitstat = EX_IOERR; 39756811Seric } 39856811Seric #endif 39956811Seric } 40056811Seric 40156811Seric exit (exitstat); 40256811Seric } 403*68182Seric /* 404*68182Seric ** LOCKFILE -- lock a file using flock or (shudder) fcntl locking 405*68182Seric ** 406*68182Seric ** Parameters: 407*68182Seric ** fd -- the file descriptor of the file. 408*68182Seric ** 409*68182Seric ** Returns: 410*68182Seric ** TRUE if the lock was acquired. 411*68182Seric ** FALSE otherwise. 412*68182Seric */ 413*68182Seric 414*68182Seric bool 415*68182Seric lockfile(fd) 416*68182Seric int fd; 417*68182Seric { 418*68182Seric # if !HASFLOCK 419*68182Seric int action; 420*68182Seric struct flock lfd; 421*68182Seric extern int errno; 422*68182Seric 423*68182Seric bzero(&lfd, sizeof lfd); 424*68182Seric lfd.l_type = F_WRLCK; 425*68182Seric action = F_SETLKW; 426*68182Seric 427*68182Seric if (fcntl(fd, action, &lfd) >= 0) 428*68182Seric return TRUE; 429*68182Seric 430*68182Seric /* 431*68182Seric ** On SunOS, if you are testing using -oQ/tmp/mqueue or 432*68182Seric ** -oA/tmp/aliases or anything like that, and /tmp is mounted 433*68182Seric ** as type "tmp" (that is, served from swap space), the 434*68182Seric ** previous fcntl will fail with "Invalid argument" errors. 435*68182Seric ** Since this is fairly common during testing, we will assume 436*68182Seric ** that this indicates that the lock is successfully grabbed. 437*68182Seric */ 438*68182Seric 439*68182Seric if (errno == EINVAL) 440*68182Seric return TRUE; 441*68182Seric 442*68182Seric # else /* HASFLOCK */ 443*68182Seric 444*68182Seric if (flock(fd, LOCK_EX) >= 0) 445*68182Seric return TRUE; 446*68182Seric 447*68182Seric # endif 448*68182Seric 449*68182Seric return FALSE; 450*68182Seric } 451