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*69394Seric static char sccsid[] = "@(#)makemap.c 8.12 (Berkeley) 05/12/95"; 1156811Seric #endif /* not lint */ 1256811Seric 1356811Seric #include <stdio.h> 1456811Seric #include <sysexits.h> 1564343Seric #include <sys/types.h> 1656811Seric #include <ctype.h> 1756811Seric #include <string.h> 18*69394Seric #include <sys/errno.h> 19*69394Seric #ifndef ISC_UNIX 20*69394Seric # include <sys/file.h> 21*69394Seric #endif 2256811Seric #include "useful.h" 2356811Seric #include "conf.h" 2456811Seric 2560558Seric #ifdef NDBM 2656811Seric #include <ndbm.h> 2756811Seric #endif 2856811Seric 2960558Seric #ifdef NEWDB 3056811Seric #include <db.h> 3156811Seric #endif 3256811Seric 3356811Seric enum type { T_DBM, T_BTREE, T_HASH, T_ERR, T_UNKNOWN }; 3456811Seric 3556811Seric union dbent 3656811Seric { 3760558Seric #ifdef NDBM 3856811Seric datum dbm; 3956811Seric #endif 4060558Seric #ifdef NEWDB 4156811Seric DBT db; 4256811Seric #endif 4356811Seric struct 4456811Seric { 4556811Seric char *data; 4668221Seric size_t size; 4756811Seric } xx; 4856811Seric }; 4956811Seric 5056811Seric #define BUFSIZE 1024 5156811Seric 5256811Seric main(argc, argv) 5356811Seric int argc; 5456811Seric char **argv; 5556811Seric { 5656811Seric char *progname; 5756811Seric bool inclnull = FALSE; 5856811Seric bool notrunc = FALSE; 5956811Seric bool allowreplace = FALSE; 60*69394Seric bool allowdups = FALSE; 6156811Seric bool verbose = FALSE; 6264557Seric bool foldcase = TRUE; 6356811Seric int exitstat; 6456811Seric int opt; 6556811Seric char *typename; 6656811Seric char *mapname; 6764152Seric char *ext; 6856811Seric int lineno; 6956811Seric int st; 7056811Seric int mode; 7156811Seric enum type type; 72*69394Seric int fd; 7356811Seric union 7456811Seric { 7560558Seric #ifdef NDBM 7656811Seric DBM *dbm; 7756811Seric #endif 7860558Seric #ifdef NEWDB 7956811Seric DB *db; 8056811Seric #endif 8156811Seric void *dbx; 8256811Seric } dbp; 8356811Seric union dbent key, val; 84*69394Seric #ifdef NEWDB 85*69394Seric BTREEINFO bti; 86*69394Seric #endif 8756811Seric char ibuf[BUFSIZE]; 8864151Seric char fbuf[MAXNAME]; 8956811Seric extern char *optarg; 9056811Seric extern int optind; 91*69394Seric extern bool lockfile(); 9256811Seric 9356811Seric progname = argv[0]; 9456811Seric 95*69394Seric while ((opt = getopt(argc, argv, "Ndforv")) != EOF) 9656811Seric { 9756811Seric switch (opt) 9856811Seric { 9956811Seric case 'N': 10056811Seric inclnull = TRUE; 10156811Seric break; 10256811Seric 103*69394Seric case 'd': 104*69394Seric allowdups = TRUE; 105*69394Seric break; 106*69394Seric 10757078Seric case 'f': 10864557Seric foldcase = FALSE; 10957078Seric break; 11057078Seric 11156811Seric case 'o': 11256811Seric notrunc = TRUE; 11356811Seric break; 11456811Seric 11556811Seric case 'r': 11656811Seric allowreplace = TRUE; 11756811Seric break; 11856811Seric 11956811Seric case 'v': 12056811Seric verbose = TRUE; 12156811Seric break; 12256811Seric 12356811Seric default: 12456811Seric type = T_ERR; 12556811Seric break; 12656811Seric } 12756811Seric } 12856811Seric 12956811Seric argc -= optind; 13056811Seric argv += optind; 13156811Seric if (argc != 2) 13256811Seric type = T_ERR; 13356811Seric else 13456811Seric { 13556811Seric typename = argv[0]; 13656811Seric mapname = argv[1]; 13764151Seric ext = NULL; 13856811Seric 13956811Seric if (strcmp(typename, "dbm") == 0) 14064151Seric { 14156811Seric type = T_DBM; 14264151Seric } 14356811Seric else if (strcmp(typename, "btree") == 0) 14464151Seric { 14556811Seric type = T_BTREE; 14664151Seric ext = ".db"; 14764151Seric } 14856811Seric else if (strcmp(typename, "hash") == 0) 14964151Seric { 15056811Seric type = T_HASH; 15164151Seric ext = ".db"; 15264151Seric } 15356811Seric else 15456811Seric type = T_UNKNOWN; 15556811Seric } 15656811Seric 15756811Seric switch (type) 15856811Seric { 15956811Seric case T_ERR: 160*69394Seric fprintf(stderr, "Usage: %s [-N] [-d] [-f] [-o] [-r] [-v] type mapname\n", progname); 16156811Seric exit(EX_USAGE); 16256811Seric 16356811Seric case T_UNKNOWN: 16456811Seric fprintf(stderr, "%s: Unknown database type %s\n", 16556811Seric progname, typename); 16656811Seric exit(EX_USAGE); 16756811Seric 16860558Seric #ifndef NDBM 16956811Seric case T_DBM: 17056811Seric #endif 17160558Seric #ifndef NEWDB 17256811Seric case T_BTREE: 17356811Seric case T_HASH: 17456811Seric #endif 17556811Seric fprintf(stderr, "%s: Type %s not supported in this version\n", 17656811Seric progname, typename); 17756811Seric exit(EX_UNAVAILABLE); 178*69394Seric 179*69394Seric #ifdef NEWDB 180*69394Seric case T_BTREE: 181*69394Seric bzero(&bti, sizeof bti); 182*69394Seric if (allowdups) 183*69394Seric bti.flags |= R_DUP; 184*69394Seric break; 185*69394Seric 186*69394Seric case T_HASH: 187*69394Seric #endif 188*69394Seric #ifdef NDBM 189*69394Seric case T_DBM: 190*69394Seric #endif 191*69394Seric if (allowdups) 192*69394Seric { 193*69394Seric fprintf(stderr, "%s: Type %s does not support -d (allow dups)\n", 194*69394Seric progname, typename); 195*69394Seric exit(EX_UNAVAILABLE); 196*69394Seric } 197*69394Seric break; 19856811Seric } 19956811Seric 20056811Seric /* 20164151Seric ** Adjust file names. 20264151Seric */ 20364151Seric 20464151Seric if (ext != NULL) 20564151Seric { 20664151Seric int el, fl; 20764151Seric 20864151Seric el = strlen(ext); 20964151Seric fl = strlen(mapname); 21064151Seric if (fl < el || strcmp(&mapname[fl - el], ext) != 0) 21164151Seric { 21264151Seric strcpy(fbuf, mapname); 21364151Seric strcat(fbuf, ext); 21464151Seric mapname = fbuf; 21564151Seric } 21664151Seric } 21764151Seric 21864151Seric /* 21956811Seric ** Create the database. 22056811Seric */ 22156811Seric 22256811Seric mode = O_RDWR; 223*69394Seric #ifdef O_EXLOCK 224*69394Seric mode |= O_EXLOCK; 225*69394Seric #endif 22656811Seric if (!notrunc) 22756811Seric mode |= O_CREAT|O_TRUNC; 22856811Seric switch (type) 22956811Seric { 23060558Seric #ifdef NDBM 23156811Seric case T_DBM: 23256811Seric dbp.dbm = dbm_open(mapname, mode, 0644); 23356811Seric break; 23456811Seric #endif 23556811Seric 23660558Seric #ifdef NEWDB 23756811Seric case T_HASH: 23856811Seric dbp.db = dbopen(mapname, mode, 0644, DB_HASH, NULL); 23968492Seric if (dbp.db != NULL) 240*69394Seric { 241*69394Seric # ifdef OLD_NEWDB 242*69394Seric (void) (*dbp.db->sync)(dbp.db); 243*69394Seric # else 24468492Seric (void) (*dbp.db->sync)(dbp.db, 0); 245*69394Seric # endif 246*69394Seric } 24756811Seric break; 24856811Seric 24956811Seric case T_BTREE: 250*69394Seric dbp.db = dbopen(mapname, mode, 0644, DB_BTREE, &bti); 25168492Seric if (dbp.db != NULL) 252*69394Seric { 253*69394Seric # ifdef OLD_NEWDB 254*69394Seric (void) (*dbp.db->sync)(dbp.db); 255*69394Seric # else 25668492Seric (void) (*dbp.db->sync)(dbp.db, 0); 257*69394Seric # endif 258*69394Seric } 25956811Seric break; 26056811Seric #endif 26156811Seric 26256811Seric default: 26356811Seric fprintf(stderr, "%s: internal error: type %d\n", progname, type); 26456811Seric exit(EX_SOFTWARE); 26556811Seric } 26656811Seric 26756811Seric if (dbp.dbx == NULL) 26856811Seric { 26956811Seric fprintf(stderr, "%s: cannot create type %s map %s\n", 27056811Seric progname, typename, mapname); 27156811Seric exit(EX_CANTCREAT); 27256811Seric } 27356811Seric 274*69394Seric #ifndef O_EXLOCK 275*69394Seric switch (type) 276*69394Seric { 277*69394Seric # ifdef NDBM 278*69394Seric case T_DBM: 279*69394Seric fd = dbm_dirfno(dbp.dbm); 280*69394Seric if (fd >= 0) 281*69394Seric lockfile(fd); 282*69394Seric break; 283*69394Seric # endif 284*69394Seric # ifdef NEWDB 285*69394Seric case T_HASH: 286*69394Seric case T_BTREE: 287*69394Seric fd = dbp.db->fd(dbp.db); 288*69394Seric if (fd >= 0) 289*69394Seric lockfile(fd); 290*69394Seric break; 291*69394Seric # endif 292*69394Seric } 293*69394Seric #endif 294*69394Seric 29556811Seric /* 29656811Seric ** Copy the data 29756811Seric */ 29856811Seric 29956811Seric lineno = 0; 30056811Seric exitstat = EX_OK; 30156811Seric while (fgets(ibuf, sizeof ibuf, stdin) != NULL) 30256811Seric { 30356811Seric register char *p; 30456811Seric 30556811Seric lineno++; 30656811Seric 30756811Seric /* 30856811Seric ** Parse the line. 30956811Seric */ 31056811Seric 31156811Seric p = strchr(ibuf, '\n'); 31264934Seric if (p != NULL) 31356811Seric *p = '\0'; 31464934Seric else if (!feof(stdin)) 31564934Seric { 31664934Seric fprintf(stderr, "%s: %s: line %d: line too long (%d bytes max)\n", 31764934Seric progname, mapname, lineno, sizeof ibuf); 31864934Seric continue; 31964934Seric } 32064934Seric 32156811Seric if (ibuf[0] == '\0' || ibuf[0] == '#') 32256811Seric continue; 32356811Seric if (isspace(ibuf[0])) 32456811Seric { 32556811Seric fprintf(stderr, "%s: %s: line %d: syntax error (leading space)\n", 32656811Seric progname, mapname, lineno); 32756811Seric continue; 32856811Seric } 32956811Seric key.xx.data = ibuf; 33056811Seric for (p = ibuf; *p != '\0' && !isspace(*p); p++) 33157078Seric { 33257078Seric if (foldcase && isupper(*p)) 33357078Seric *p = tolower(*p); 33457078Seric } 33556811Seric key.xx.size = p - key.xx.data; 33656811Seric if (inclnull) 33756811Seric key.xx.size++; 33856811Seric if (*p != '\0') 33956811Seric *p++ = '\0'; 34056811Seric while (isspace(*p)) 34156811Seric p++; 34256811Seric if (*p == '\0') 34356811Seric { 34456811Seric fprintf(stderr, "%s: %s: line %d: no RHS for LHS %s\n", 34556811Seric progname, mapname, lineno, key.xx.data); 34656811Seric continue; 34756811Seric } 34856811Seric val.xx.data = p; 34956811Seric val.xx.size = strlen(p); 35056811Seric if (inclnull) 35156811Seric val.xx.size++; 35256811Seric 35356811Seric /* 35456811Seric ** Do the database insert. 35556811Seric */ 35656811Seric 35756811Seric if (verbose) 35856811Seric { 35956811Seric printf("key=`%s', val=`%s'\n", key.xx.data, val.xx.data); 36056811Seric } 36156811Seric 36256811Seric switch (type) 36356811Seric { 36460558Seric #ifdef NDBM 36556811Seric case T_DBM: 36656811Seric st = dbm_store(dbp.dbm, key.dbm, val.dbm, 36756811Seric allowreplace ? DBM_REPLACE : DBM_INSERT); 36856811Seric break; 36956811Seric #endif 37056811Seric 37160558Seric #ifdef NEWDB 37256811Seric case T_BTREE: 37356811Seric case T_HASH: 37456811Seric st = (*dbp.db->put)(dbp.db, &key.db, &val.db, 37556811Seric allowreplace ? 0 : R_NOOVERWRITE); 37656811Seric break; 37756811Seric #endif 37856811Seric } 37956811Seric 38056811Seric if (st < 0) 38156811Seric { 38256811Seric fprintf(stderr, "%s: %s: line %d: key %s: put error\n", 38356811Seric progname, mapname, lineno, key.xx.data); 38456811Seric perror(mapname); 38556811Seric exitstat = EX_IOERR; 38656811Seric } 38756811Seric else if (st > 0) 38856811Seric { 38956811Seric fprintf(stderr, "%s: %s: line %d: key %s: duplicate key\n", 39056811Seric progname, mapname, lineno, key.xx.data); 39156811Seric } 39256811Seric } 39356811Seric 39456811Seric /* 39556811Seric ** Now close the database. 39656811Seric */ 39756811Seric 39856811Seric switch (type) 39956811Seric { 40060558Seric #ifdef NDBM 40156811Seric case T_DBM: 40256811Seric dbm_close(dbp.dbm); 40356811Seric break; 40456811Seric #endif 40556811Seric 40660558Seric #ifdef NEWDB 40756811Seric case T_HASH: 40856811Seric case T_BTREE: 40956811Seric if ((*dbp.db->close)(dbp.db) < 0) 41056811Seric { 41156811Seric fprintf(stderr, "%s: %s: error on close\n", 41256811Seric progname, mapname); 41356811Seric perror(mapname); 41456811Seric exitstat = EX_IOERR; 41556811Seric } 41656811Seric #endif 41756811Seric } 41856811Seric 41956811Seric exit (exitstat); 42056811Seric } 421*69394Seric /* 422*69394Seric ** LOCKFILE -- lock a file using flock or (shudder) fcntl locking 423*69394Seric ** 424*69394Seric ** Parameters: 425*69394Seric ** fd -- the file descriptor of the file. 426*69394Seric ** 427*69394Seric ** Returns: 428*69394Seric ** TRUE if the lock was acquired. 429*69394Seric ** FALSE otherwise. 430*69394Seric */ 431*69394Seric 432*69394Seric bool 433*69394Seric lockfile(fd) 434*69394Seric int fd; 435*69394Seric { 436*69394Seric # if !HASFLOCK 437*69394Seric int action; 438*69394Seric struct flock lfd; 439*69394Seric extern int errno; 440*69394Seric 441*69394Seric bzero(&lfd, sizeof lfd); 442*69394Seric lfd.l_type = F_WRLCK; 443*69394Seric action = F_SETLKW; 444*69394Seric 445*69394Seric if (fcntl(fd, action, &lfd) >= 0) 446*69394Seric return TRUE; 447*69394Seric 448*69394Seric /* 449*69394Seric ** On SunOS, if you are testing using -oQ/tmp/mqueue or 450*69394Seric ** -oA/tmp/aliases or anything like that, and /tmp is mounted 451*69394Seric ** as type "tmp" (that is, served from swap space), the 452*69394Seric ** previous fcntl will fail with "Invalid argument" errors. 453*69394Seric ** Since this is fairly common during testing, we will assume 454*69394Seric ** that this indicates that the lock is successfully grabbed. 455*69394Seric */ 456*69394Seric 457*69394Seric if (errno == EINVAL) 458*69394Seric return TRUE; 459*69394Seric 460*69394Seric # else /* HASFLOCK */ 461*69394Seric 462*69394Seric if (flock(fd, LOCK_EX) >= 0) 463*69394Seric return TRUE; 464*69394Seric 465*69394Seric # endif 466*69394Seric 467*69394Seric return FALSE; 468*69394Seric } 469