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*68450Seric static char sccsid[] = "@(#)makemap.c 8.10 (Berkeley) 02/24/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> 1868182Seric #include <sys/errno.h> 19*68450Seric #ifndef ISC_UNIX 20*68450Seric # include <sys/file.h> 21*68450Seric #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; 6067557Seric 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; 7268182Seric 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; 8467557Seric #ifdef NEWDB 8567557Seric BTREEINFO bti; 8667557Seric #endif 8756811Seric char ibuf[BUFSIZE]; 8864151Seric char fbuf[MAXNAME]; 8956811Seric extern char *optarg; 9056811Seric extern int optind; 9168182Seric extern bool lockfile(); 9256811Seric 9356811Seric progname = argv[0]; 9456811Seric 9567557Seric while ((opt = getopt(argc, argv, "Ndforv")) != EOF) 9656811Seric { 9756811Seric switch (opt) 9856811Seric { 9956811Seric case 'N': 10056811Seric inclnull = TRUE; 10156811Seric break; 10256811Seric 10367557Seric case 'd': 10467557Seric allowdups = TRUE; 10567557Seric break; 10667557Seric 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: 16067557Seric 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); 17867557Seric 17967557Seric #ifdef NEWDB 18067557Seric case T_BTREE: 18167557Seric bzero(&bti, sizeof bti); 18267557Seric if (allowdups) 18367557Seric bti.flags |= R_DUP; 18467557Seric break; 18567557Seric 18667557Seric case T_HASH: 18767557Seric #endif 18867557Seric #ifdef NDBM 18967557Seric case T_DBM: 19067557Seric #endif 19167557Seric if (allowdups) 19267557Seric { 19367557Seric fprintf(stderr, "%s: Type %s does not support -d (allow dups)\n", 19467557Seric progname, typename); 19567557Seric exit(EX_UNAVAILABLE); 19667557Seric } 19767557Seric 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; 22368182Seric #ifdef O_EXLOCK 22468182Seric mode |= O_EXLOCK; 22568182Seric #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); 23956811Seric break; 24056811Seric 24156811Seric case T_BTREE: 24267557Seric dbp.db = dbopen(mapname, mode, 0644, DB_BTREE, &bti); 24356811Seric break; 24456811Seric #endif 24556811Seric 24656811Seric default: 24756811Seric fprintf(stderr, "%s: internal error: type %d\n", progname, type); 24856811Seric exit(EX_SOFTWARE); 24956811Seric } 25056811Seric 25156811Seric if (dbp.dbx == NULL) 25256811Seric { 25356811Seric fprintf(stderr, "%s: cannot create type %s map %s\n", 25456811Seric progname, typename, mapname); 25556811Seric exit(EX_CANTCREAT); 25656811Seric } 25756811Seric 25868182Seric #ifndef O_EXLOCK 25968182Seric switch (type) 26068182Seric { 26168182Seric # ifdef NDBM 26268182Seric case T_DBM: 26368182Seric fd = dbm_dirfno(dbp.dbm); 26468182Seric if (fd >= 0) 26568182Seric lockfile(fd); 26668182Seric break; 26768182Seric # endif 26868182Seric # ifdef NEWDB 26968182Seric case T_HASH: 27068182Seric case T_BTREE: 27168182Seric fd = dbp.db->fd(dbp.db); 27268182Seric if (fd >= 0) 27368182Seric lockfile(fd); 27468182Seric break; 27568182Seric # endif 27668182Seric } 27768182Seric #endif 27868182Seric 27956811Seric /* 28056811Seric ** Copy the data 28156811Seric */ 28256811Seric 28356811Seric lineno = 0; 28456811Seric exitstat = EX_OK; 28556811Seric while (fgets(ibuf, sizeof ibuf, stdin) != NULL) 28656811Seric { 28756811Seric register char *p; 28856811Seric 28956811Seric lineno++; 29056811Seric 29156811Seric /* 29256811Seric ** Parse the line. 29356811Seric */ 29456811Seric 29556811Seric p = strchr(ibuf, '\n'); 29664934Seric if (p != NULL) 29756811Seric *p = '\0'; 29864934Seric else if (!feof(stdin)) 29964934Seric { 30064934Seric fprintf(stderr, "%s: %s: line %d: line too long (%d bytes max)\n", 30164934Seric progname, mapname, lineno, sizeof ibuf); 30264934Seric continue; 30364934Seric } 30464934Seric 30556811Seric if (ibuf[0] == '\0' || ibuf[0] == '#') 30656811Seric continue; 30756811Seric if (isspace(ibuf[0])) 30856811Seric { 30956811Seric fprintf(stderr, "%s: %s: line %d: syntax error (leading space)\n", 31056811Seric progname, mapname, lineno); 31156811Seric continue; 31256811Seric } 31356811Seric key.xx.data = ibuf; 31456811Seric for (p = ibuf; *p != '\0' && !isspace(*p); p++) 31557078Seric { 31657078Seric if (foldcase && isupper(*p)) 31757078Seric *p = tolower(*p); 31857078Seric } 31956811Seric key.xx.size = p - key.xx.data; 32056811Seric if (inclnull) 32156811Seric key.xx.size++; 32256811Seric if (*p != '\0') 32356811Seric *p++ = '\0'; 32456811Seric while (isspace(*p)) 32556811Seric p++; 32656811Seric if (*p == '\0') 32756811Seric { 32856811Seric fprintf(stderr, "%s: %s: line %d: no RHS for LHS %s\n", 32956811Seric progname, mapname, lineno, key.xx.data); 33056811Seric continue; 33156811Seric } 33256811Seric val.xx.data = p; 33356811Seric val.xx.size = strlen(p); 33456811Seric if (inclnull) 33556811Seric val.xx.size++; 33656811Seric 33756811Seric /* 33856811Seric ** Do the database insert. 33956811Seric */ 34056811Seric 34156811Seric if (verbose) 34256811Seric { 34356811Seric printf("key=`%s', val=`%s'\n", key.xx.data, val.xx.data); 34456811Seric } 34556811Seric 34656811Seric switch (type) 34756811Seric { 34860558Seric #ifdef NDBM 34956811Seric case T_DBM: 35056811Seric st = dbm_store(dbp.dbm, key.dbm, val.dbm, 35156811Seric allowreplace ? DBM_REPLACE : DBM_INSERT); 35256811Seric break; 35356811Seric #endif 35456811Seric 35560558Seric #ifdef NEWDB 35656811Seric case T_BTREE: 35756811Seric case T_HASH: 35856811Seric st = (*dbp.db->put)(dbp.db, &key.db, &val.db, 35956811Seric allowreplace ? 0 : R_NOOVERWRITE); 36056811Seric break; 36156811Seric #endif 36256811Seric } 36356811Seric 36456811Seric if (st < 0) 36556811Seric { 36656811Seric fprintf(stderr, "%s: %s: line %d: key %s: put error\n", 36756811Seric progname, mapname, lineno, key.xx.data); 36856811Seric perror(mapname); 36956811Seric exitstat = EX_IOERR; 37056811Seric } 37156811Seric else if (st > 0) 37256811Seric { 37356811Seric fprintf(stderr, "%s: %s: line %d: key %s: duplicate key\n", 37456811Seric progname, mapname, lineno, key.xx.data); 37556811Seric } 37656811Seric } 37756811Seric 37856811Seric /* 37956811Seric ** Now close the database. 38056811Seric */ 38156811Seric 38256811Seric switch (type) 38356811Seric { 38460558Seric #ifdef NDBM 38556811Seric case T_DBM: 38656811Seric dbm_close(dbp.dbm); 38756811Seric break; 38856811Seric #endif 38956811Seric 39060558Seric #ifdef NEWDB 39156811Seric case T_HASH: 39256811Seric case T_BTREE: 39356811Seric if ((*dbp.db->close)(dbp.db) < 0) 39456811Seric { 39556811Seric fprintf(stderr, "%s: %s: error on close\n", 39656811Seric progname, mapname); 39756811Seric perror(mapname); 39856811Seric exitstat = EX_IOERR; 39956811Seric } 40056811Seric #endif 40156811Seric } 40256811Seric 40356811Seric exit (exitstat); 40456811Seric } 40568182Seric /* 40668182Seric ** LOCKFILE -- lock a file using flock or (shudder) fcntl locking 40768182Seric ** 40868182Seric ** Parameters: 40968182Seric ** fd -- the file descriptor of the file. 41068182Seric ** 41168182Seric ** Returns: 41268182Seric ** TRUE if the lock was acquired. 41368182Seric ** FALSE otherwise. 41468182Seric */ 41568182Seric 41668182Seric bool 41768182Seric lockfile(fd) 41868182Seric int fd; 41968182Seric { 42068182Seric # if !HASFLOCK 42168182Seric int action; 42268182Seric struct flock lfd; 42368182Seric extern int errno; 42468182Seric 42568182Seric bzero(&lfd, sizeof lfd); 42668182Seric lfd.l_type = F_WRLCK; 42768182Seric action = F_SETLKW; 42868182Seric 42968182Seric if (fcntl(fd, action, &lfd) >= 0) 43068182Seric return TRUE; 43168182Seric 43268182Seric /* 43368182Seric ** On SunOS, if you are testing using -oQ/tmp/mqueue or 43468182Seric ** -oA/tmp/aliases or anything like that, and /tmp is mounted 43568182Seric ** as type "tmp" (that is, served from swap space), the 43668182Seric ** previous fcntl will fail with "Invalid argument" errors. 43768182Seric ** Since this is fairly common during testing, we will assume 43868182Seric ** that this indicates that the lock is successfully grabbed. 43968182Seric */ 44068182Seric 44168182Seric if (errno == EINVAL) 44268182Seric return TRUE; 44368182Seric 44468182Seric # else /* HASFLOCK */ 44568182Seric 44668182Seric if (flock(fd, LOCK_EX) >= 0) 44768182Seric return TRUE; 44868182Seric 44968182Seric # endif 45068182Seric 45168182Seric return FALSE; 45268182Seric } 453