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*68492Seric static char sccsid[] = "@(#)makemap.c 8.11 (Berkeley) 03/06/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> 1968450Seric #ifndef ISC_UNIX 2068450Seric # include <sys/file.h> 2168450Seric #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); 239*68492Seric if (dbp.db != NULL) 240*68492Seric (void) (*dbp.db->sync)(dbp.db, 0); 24156811Seric break; 24256811Seric 24356811Seric case T_BTREE: 24467557Seric dbp.db = dbopen(mapname, mode, 0644, DB_BTREE, &bti); 245*68492Seric if (dbp.db != NULL) 246*68492Seric (void) (*dbp.db->sync)(dbp.db, 0); 24756811Seric break; 24856811Seric #endif 24956811Seric 25056811Seric default: 25156811Seric fprintf(stderr, "%s: internal error: type %d\n", progname, type); 25256811Seric exit(EX_SOFTWARE); 25356811Seric } 25456811Seric 25556811Seric if (dbp.dbx == NULL) 25656811Seric { 25756811Seric fprintf(stderr, "%s: cannot create type %s map %s\n", 25856811Seric progname, typename, mapname); 25956811Seric exit(EX_CANTCREAT); 26056811Seric } 26156811Seric 26268182Seric #ifndef O_EXLOCK 26368182Seric switch (type) 26468182Seric { 26568182Seric # ifdef NDBM 26668182Seric case T_DBM: 26768182Seric fd = dbm_dirfno(dbp.dbm); 26868182Seric if (fd >= 0) 26968182Seric lockfile(fd); 27068182Seric break; 27168182Seric # endif 27268182Seric # ifdef NEWDB 27368182Seric case T_HASH: 27468182Seric case T_BTREE: 27568182Seric fd = dbp.db->fd(dbp.db); 27668182Seric if (fd >= 0) 27768182Seric lockfile(fd); 27868182Seric break; 27968182Seric # endif 28068182Seric } 28168182Seric #endif 28268182Seric 28356811Seric /* 28456811Seric ** Copy the data 28556811Seric */ 28656811Seric 28756811Seric lineno = 0; 28856811Seric exitstat = EX_OK; 28956811Seric while (fgets(ibuf, sizeof ibuf, stdin) != NULL) 29056811Seric { 29156811Seric register char *p; 29256811Seric 29356811Seric lineno++; 29456811Seric 29556811Seric /* 29656811Seric ** Parse the line. 29756811Seric */ 29856811Seric 29956811Seric p = strchr(ibuf, '\n'); 30064934Seric if (p != NULL) 30156811Seric *p = '\0'; 30264934Seric else if (!feof(stdin)) 30364934Seric { 30464934Seric fprintf(stderr, "%s: %s: line %d: line too long (%d bytes max)\n", 30564934Seric progname, mapname, lineno, sizeof ibuf); 30664934Seric continue; 30764934Seric } 30864934Seric 30956811Seric if (ibuf[0] == '\0' || ibuf[0] == '#') 31056811Seric continue; 31156811Seric if (isspace(ibuf[0])) 31256811Seric { 31356811Seric fprintf(stderr, "%s: %s: line %d: syntax error (leading space)\n", 31456811Seric progname, mapname, lineno); 31556811Seric continue; 31656811Seric } 31756811Seric key.xx.data = ibuf; 31856811Seric for (p = ibuf; *p != '\0' && !isspace(*p); p++) 31957078Seric { 32057078Seric if (foldcase && isupper(*p)) 32157078Seric *p = tolower(*p); 32257078Seric } 32356811Seric key.xx.size = p - key.xx.data; 32456811Seric if (inclnull) 32556811Seric key.xx.size++; 32656811Seric if (*p != '\0') 32756811Seric *p++ = '\0'; 32856811Seric while (isspace(*p)) 32956811Seric p++; 33056811Seric if (*p == '\0') 33156811Seric { 33256811Seric fprintf(stderr, "%s: %s: line %d: no RHS for LHS %s\n", 33356811Seric progname, mapname, lineno, key.xx.data); 33456811Seric continue; 33556811Seric } 33656811Seric val.xx.data = p; 33756811Seric val.xx.size = strlen(p); 33856811Seric if (inclnull) 33956811Seric val.xx.size++; 34056811Seric 34156811Seric /* 34256811Seric ** Do the database insert. 34356811Seric */ 34456811Seric 34556811Seric if (verbose) 34656811Seric { 34756811Seric printf("key=`%s', val=`%s'\n", key.xx.data, val.xx.data); 34856811Seric } 34956811Seric 35056811Seric switch (type) 35156811Seric { 35260558Seric #ifdef NDBM 35356811Seric case T_DBM: 35456811Seric st = dbm_store(dbp.dbm, key.dbm, val.dbm, 35556811Seric allowreplace ? DBM_REPLACE : DBM_INSERT); 35656811Seric break; 35756811Seric #endif 35856811Seric 35960558Seric #ifdef NEWDB 36056811Seric case T_BTREE: 36156811Seric case T_HASH: 36256811Seric st = (*dbp.db->put)(dbp.db, &key.db, &val.db, 36356811Seric allowreplace ? 0 : R_NOOVERWRITE); 36456811Seric break; 36556811Seric #endif 36656811Seric } 36756811Seric 36856811Seric if (st < 0) 36956811Seric { 37056811Seric fprintf(stderr, "%s: %s: line %d: key %s: put error\n", 37156811Seric progname, mapname, lineno, key.xx.data); 37256811Seric perror(mapname); 37356811Seric exitstat = EX_IOERR; 37456811Seric } 37556811Seric else if (st > 0) 37656811Seric { 37756811Seric fprintf(stderr, "%s: %s: line %d: key %s: duplicate key\n", 37856811Seric progname, mapname, lineno, key.xx.data); 37956811Seric } 38056811Seric } 38156811Seric 38256811Seric /* 38356811Seric ** Now close the database. 38456811Seric */ 38556811Seric 38656811Seric switch (type) 38756811Seric { 38860558Seric #ifdef NDBM 38956811Seric case T_DBM: 39056811Seric dbm_close(dbp.dbm); 39156811Seric break; 39256811Seric #endif 39356811Seric 39460558Seric #ifdef NEWDB 39556811Seric case T_HASH: 39656811Seric case T_BTREE: 39756811Seric if ((*dbp.db->close)(dbp.db) < 0) 39856811Seric { 39956811Seric fprintf(stderr, "%s: %s: error on close\n", 40056811Seric progname, mapname); 40156811Seric perror(mapname); 40256811Seric exitstat = EX_IOERR; 40356811Seric } 40456811Seric #endif 40556811Seric } 40656811Seric 40756811Seric exit (exitstat); 40856811Seric } 40968182Seric /* 41068182Seric ** LOCKFILE -- lock a file using flock or (shudder) fcntl locking 41168182Seric ** 41268182Seric ** Parameters: 41368182Seric ** fd -- the file descriptor of the file. 41468182Seric ** 41568182Seric ** Returns: 41668182Seric ** TRUE if the lock was acquired. 41768182Seric ** FALSE otherwise. 41868182Seric */ 41968182Seric 42068182Seric bool 42168182Seric lockfile(fd) 42268182Seric int fd; 42368182Seric { 42468182Seric # if !HASFLOCK 42568182Seric int action; 42668182Seric struct flock lfd; 42768182Seric extern int errno; 42868182Seric 42968182Seric bzero(&lfd, sizeof lfd); 43068182Seric lfd.l_type = F_WRLCK; 43168182Seric action = F_SETLKW; 43268182Seric 43368182Seric if (fcntl(fd, action, &lfd) >= 0) 43468182Seric return TRUE; 43568182Seric 43668182Seric /* 43768182Seric ** On SunOS, if you are testing using -oQ/tmp/mqueue or 43868182Seric ** -oA/tmp/aliases or anything like that, and /tmp is mounted 43968182Seric ** as type "tmp" (that is, served from swap space), the 44068182Seric ** previous fcntl will fail with "Invalid argument" errors. 44168182Seric ** Since this is fairly common during testing, we will assume 44268182Seric ** that this indicates that the lock is successfully grabbed. 44368182Seric */ 44468182Seric 44568182Seric if (errno == EINVAL) 44668182Seric return TRUE; 44768182Seric 44868182Seric # else /* HASFLOCK */ 44968182Seric 45068182Seric if (flock(fd, LOCK_EX) >= 0) 45168182Seric return TRUE; 45268182Seric 45368182Seric # endif 45468182Seric 45568182Seric return FALSE; 45668182Seric } 457