138494Sobrien/* 2174313Sobrien * Copyright (c) 1997-2006 Erez Zadok 338494Sobrien * Copyright (c) 1990 Jan-Simon Pendry 438494Sobrien * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 538494Sobrien * Copyright (c) 1990 The Regents of the University of California. 638494Sobrien * All rights reserved. 738494Sobrien * 838494Sobrien * This code is derived from software contributed to Berkeley by 938494Sobrien * Jan-Simon Pendry at Imperial College, London. 1038494Sobrien * 1138494Sobrien * Redistribution and use in source and binary forms, with or without 1238494Sobrien * modification, are permitted provided that the following conditions 1338494Sobrien * are met: 1438494Sobrien * 1. Redistributions of source code must retain the above copyright 1538494Sobrien * notice, this list of conditions and the following disclaimer. 1638494Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1738494Sobrien * notice, this list of conditions and the following disclaimer in the 1838494Sobrien * documentation and/or other materials provided with the distribution. 1938494Sobrien * 3. All advertising materials mentioning features or use of this software 2042633Sobrien * must display the following acknowledgment: 2138494Sobrien * This product includes software developed by the University of 2238494Sobrien * California, Berkeley and its contributors. 2338494Sobrien * 4. Neither the name of the University nor the names of its contributors 2438494Sobrien * may be used to endorse or promote products derived from this software 2538494Sobrien * without specific prior written permission. 2638494Sobrien * 2738494Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2838494Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2938494Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3038494Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3138494Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3238494Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3338494Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3438494Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3538494Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3638494Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3738494Sobrien * SUCH DAMAGE. 3838494Sobrien * 3938494Sobrien * 40174313Sobrien * File: am-utils/mk-amd-map/mk-amd-map.c 4138494Sobrien */ 4238494Sobrien 4338494Sobrien/* 4438494Sobrien * Convert a file map into an ndbm map 4538494Sobrien */ 4638494Sobrien 4738494Sobrien#ifdef HAVE_CONFIG_H 4838494Sobrien# include <config.h> 4938494Sobrien#endif /* HAVE_CONFIG_H */ 5038494Sobrien#include <am_defs.h> 5138494Sobrien 5241145Sobrien/* (libdb version 2) uses .db extensions but an old dbm API */ 5341145Sobrien/* check for libgdbm to distinguish it from linux systems */ 5441145Sobrien#if defined(DBM_SUFFIX) && !defined(HAVE_LIBGDBM) 5541145Sobrien# define HAVE_DB_SUFFIX 5641145Sobrien#endif /* not defined(DBM_SUFFIX) && !defined(HAVE_LIBGDBM) */ 5738494Sobrien 5838494Sobrien#ifdef HAVE_MAP_NDBM 5938494Sobrien 6038494Sobrienstatic int 6138494Sobrienstore_data(voidp db, char *k, char *v) 6238494Sobrien{ 6338494Sobrien datum key, val; 6438494Sobrien 6538494Sobrien key.dptr = k; 6638494Sobrien val.dptr = v; 6738494Sobrien key.dsize = strlen(k) + 1; 6838494Sobrien val.dsize = strlen(v) + 1; 6938494Sobrien return dbm_store((DBM *) db, key, val, DBM_INSERT); 7038494Sobrien} 7138494Sobrien 7238494Sobrien 7338494Sobrien/* 7438494Sobrien * Read one line from file. 7538494Sobrien */ 7638494Sobrienstatic int 7738494Sobrienread_line(char *buf, int size, FILE *fp) 7838494Sobrien{ 7938494Sobrien int done = 0; 8038494Sobrien 8138494Sobrien do { 8238494Sobrien while (fgets(buf, size, fp)) { 8338494Sobrien int len = strlen(buf); 8438494Sobrien 8538494Sobrien done += len; 8638494Sobrien if (len > 1 && buf[len - 2] == '\\' && buf[len - 1] == '\n') { 8738494Sobrien int ch; 8838494Sobrien buf += len - 2; 8938494Sobrien size -= len - 2; 9038494Sobrien *buf = '\n'; 9138494Sobrien buf[1] = '\0'; 9238494Sobrien 9338494Sobrien /* 9438494Sobrien * Skip leading white space on next line 9538494Sobrien */ 9638494Sobrien while ((ch = getc(fp)) != EOF && isascii(ch) && isspace(ch)) ; 9738494Sobrien (void) ungetc(ch, fp); 9838494Sobrien } else { 9938494Sobrien return done; 10038494Sobrien } 10138494Sobrien } 10238494Sobrien } while (size > 0 && !feof(fp)); 10338494Sobrien 10438494Sobrien return done; 10538494Sobrien} 10638494Sobrien 10738494Sobrien 10838494Sobrien/* 10938494Sobrien * Read through a map. 11038494Sobrien */ 11138494Sobrienstatic int 11238494Sobrienread_file(FILE *fp, char *map, voidp db) 11338494Sobrien{ 11438494Sobrien char key_val[2048]; 11538494Sobrien int chuck = 0; 11638494Sobrien int line_no = 0; 11738494Sobrien int errs = 0; 11838494Sobrien 11941145Sobrien while (read_line(key_val, 2048, fp)) { 12038494Sobrien char *kp; 12138494Sobrien char *cp; 12238494Sobrien char *hash; 12338494Sobrien int len = strlen(key_val); 12438494Sobrien 12538494Sobrien line_no++; 12638494Sobrien 12738494Sobrien /* 12838494Sobrien * Make sure we got the whole line 12938494Sobrien */ 13038494Sobrien if (key_val[len - 1] != '\n') { 13138494Sobrien fprintf(stderr, "line %d in \"%s\" is too long", line_no, map); 13238494Sobrien chuck = 1; 13338494Sobrien } else { 13438494Sobrien key_val[len - 1] = '\0'; 13538494Sobrien } 13638494Sobrien 13738494Sobrien /* 13838494Sobrien * Strip comments 13938494Sobrien */ 14038494Sobrien hash = strchr(key_val, '#'); 14138494Sobrien if (hash) 14238494Sobrien *hash = '\0'; 14338494Sobrien 14438494Sobrien /* 14538494Sobrien * Find start of key 14638494Sobrien */ 14738494Sobrien for (kp = key_val; *kp && isascii(*kp) && isspace((int)*kp); kp++) ; 14838494Sobrien 14938494Sobrien /* 15038494Sobrien * Ignore blank lines 15138494Sobrien */ 15238494Sobrien if (!*kp) 15338494Sobrien goto again; 15438494Sobrien 15538494Sobrien /* 15638494Sobrien * Find end of key 15738494Sobrien */ 15838494Sobrien for (cp = kp; *cp && (!isascii(*cp) || !isspace((int)*cp)); cp++) ; 15938494Sobrien 16038494Sobrien /* 16138494Sobrien * Check whether key matches, or whether 16238494Sobrien * the entry is a wildcard entry. 16338494Sobrien */ 16438494Sobrien if (*cp) 16538494Sobrien *cp++ = '\0'; 16638494Sobrien while (*cp && isascii(*cp) && isspace((int)*cp)) 16738494Sobrien cp++; 16838494Sobrien if (*kp == '+') { 16938494Sobrien fprintf(stderr, "Can't interpolate %s\n", kp); 17038494Sobrien errs++; 17138494Sobrien } else if (*cp) { 17238494Sobrien if (db) { 17338494Sobrien if (store_data(db, kp, cp) < 0) { 17438494Sobrien fprintf(stderr, "Could store %s -> %s\n", kp, cp); 17538494Sobrien errs++; 17638494Sobrien } 17738494Sobrien } else { 17838494Sobrien printf("%s\t%s\n", kp, cp); 17938494Sobrien } 18038494Sobrien } else { 18138494Sobrien fprintf(stderr, "%s: line %d has no value field", map, line_no); 18238494Sobrien errs++; 18338494Sobrien } 18438494Sobrien 18538494Sobrien again: 18638494Sobrien /* 18738494Sobrien * If the last read didn't get a whole line then 18838494Sobrien * throw away the remainder before continuing... 18938494Sobrien */ 19038494Sobrien if (chuck) { 19138494Sobrien while (fgets(key_val, sizeof(key_val), fp) && 19238494Sobrien !strchr(key_val, '\n')) ; 19338494Sobrien chuck = 0; 19438494Sobrien } 19538494Sobrien } 19638494Sobrien return errs; 19738494Sobrien} 19838494Sobrien 19938494Sobrien 20038494Sobrienstatic int 20138494Sobrienremove_file(char *f) 20238494Sobrien{ 20338494Sobrien if (unlink(f) < 0 && errno != ENOENT) 20438494Sobrien return -1; 20538494Sobrien 20638494Sobrien return 0; 20738494Sobrien} 20838494Sobrien 20938494Sobrien 21038494Sobrienint 21138494Sobrienmain(int argc, char *argv[]) 21238494Sobrien{ 21341145Sobrien FILE *mapf; /* the input file to read from */ 21441145Sobrien int error; 21541145Sobrien char *mapsrc; 21641145Sobrien DBM *db = NULL; 21738494Sobrien static char maptmp[] = "dbmXXXXXX"; 21841145Sobrien#ifdef HAVE_DB_SUFFIX 21938575Sobrien char maptdb[16]; 22041145Sobrien char *map_name_db = (char *) NULL; 22141145Sobrien#else /* not HAVE_DB_SUFFIX */ 22241145Sobrien char maptpag[16], maptdir[16]; 22341145Sobrien char *map_name_pag = (char *) NULL, *map_name_dir = (char *) NULL; 22441145Sobrien#endif /* not HAVE_DB_SUFFIX */ 225174313Sobrien size_t l = 0; 22638494Sobrien char *sl; 22738494Sobrien int printit = 0; 22838494Sobrien int usage = 0; 22938494Sobrien int ch; 23038494Sobrien extern int optind; 23138494Sobrien 23238494Sobrien /* test options */ 23338500Sobrien while ((ch = getopt(argc, argv, "p")) != -1) 23438494Sobrien switch (ch) { 23538494Sobrien case 'p': 23638494Sobrien printit = 1; 23738494Sobrien break; 23838494Sobrien default: 23938494Sobrien usage++; 24038494Sobrien break; 24138494Sobrien } 24238494Sobrien 24338494Sobrien if (usage || optind != (argc - 1)) { 24438494Sobrien fputs("Usage: mk-amd-map [-p] file-map\n", stderr); 24538494Sobrien exit(1); 24638494Sobrien } 24741145Sobrien mapsrc = argv[optind]; 24838494Sobrien 24938494Sobrien /* test if can get to the map directory */ 25041145Sobrien sl = strrchr(mapsrc, '/'); 25138494Sobrien if (sl) { 25238494Sobrien *sl = '\0'; 25341145Sobrien if (chdir(mapsrc) < 0) { 25438494Sobrien fputs("Can't chdir to ", stderr); 25541145Sobrien perror(mapsrc); 25638494Sobrien exit(1); 25738494Sobrien } 25841145Sobrien mapsrc = sl + 1; 25938494Sobrien } 26038494Sobrien 26141145Sobrien /* open source file */ 26241145Sobrien mapf = fopen(mapsrc, "r"); 26341145Sobrien if (!mapf) { 26441145Sobrien fprintf(stderr, "cannot open source file "); 26541145Sobrien perror(mapsrc); 26641145Sobrien exit(1); 26741145Sobrien } 26841145Sobrien 26941145Sobrien#ifndef DEBUG 27041145Sobrien signal(SIGINT, SIG_IGN); 27141145Sobrien#endif /* DEBUG */ 27241145Sobrien 27338494Sobrien if (!printit) { 274174313Sobrien /* enough space for ".db" or ".pag" or ".dir" appended */ 275174313Sobrien l = strlen(mapsrc) + 5; 27641145Sobrien#ifdef HAVE_DB_SUFFIX 277174313Sobrien map_name_db = (char *) malloc(l); 27841145Sobrien error = (map_name_db == NULL); 27941145Sobrien#else /* not HAVE_DB_SUFFIX */ 280174313Sobrien map_name_pag = (char *) malloc(l); 281174313Sobrien map_name_dir = (char *) malloc(l); 28241145Sobrien error = (map_name_pag == NULL || map_name_dir == NULL); 28341145Sobrien#endif /* not HAVE_DB_SUFFIX */ 28441145Sobrien if (error) { 28538494Sobrien perror("mk-amd-map: malloc"); 28638494Sobrien exit(1); 28738494Sobrien } 28838494Sobrien 289119682Smbr#ifdef HAVE_MKSTEMP 290119682Smbr { 291119682Smbr /* 292119682Smbr * XXX: hack to avoid compiler complaints about mktemp not being 293119682Smbr * secure, since we have to do a dbm_open on this anyway. So use 294119682Smbr * mkstemp if you can, and then close the fd, but we get a safe 295119682Smbr * and unique file name. 296119682Smbr */ 297119682Smbr int dummyfd; 298119682Smbr dummyfd = mkstemp(maptmp); 299119682Smbr if (dummyfd >= 0) 300119682Smbr close(dummyfd); 301119682Smbr } 302119682Smbr#else /* not HAVE_MKSTEMP */ 30341145Sobrien mktemp(maptmp); 304119682Smbr#endif /* not HAVE_MKSTEMP */ 30541145Sobrien 30641145Sobrien /* remove existing temps (if any) */ 30741145Sobrien#ifdef HAVE_DB_SUFFIX 308174313Sobrien xsnprintf(maptdb, sizeof(maptdb), "%s.db", maptmp); 30938575Sobrien if (remove_file(maptdb) < 0) { 31041145Sobrien fprintf(stderr, "Can't remove existing temporary file; "); 31138575Sobrien perror(maptdb); 31238494Sobrien exit(1); 31338494Sobrien } 31441145Sobrien#else /* not HAVE_DB_SUFFIX */ 315174313Sobrien xsnprintf(maptpag, sizeof(maptpag), "%s.pag", maptmp); 316174313Sobrien xsnprintf(maptdir, sizeof(maptdir), "%s.dir", maptmp); 31741145Sobrien if (remove_file(maptpag) < 0 || remove_file(maptdir) < 0) { 31841145Sobrien fprintf(stderr, "Can't remove existing temporary files; %s and ", maptpag); 31941145Sobrien perror(maptdir); 32041145Sobrien exit(1); 32141145Sobrien } 32241145Sobrien#endif /* not HAVE_DB_SUFFIX */ 32341145Sobrien 324119682Smbr db = dbm_open(maptmp, O_RDWR|O_CREAT|O_EXCL, 0444); 32541145Sobrien if (!db) { 32641145Sobrien fprintf(stderr, "cannot initialize temporary database: %s", maptmp); 32741145Sobrien exit(1); 32841145Sobrien } 32938494Sobrien } 33038494Sobrien 33141145Sobrien /* print db to stdout or to temp database */ 33241145Sobrien error = read_file(mapf, mapsrc, db); 33341145Sobrien fclose(mapf); 33441145Sobrien if (error) { 33541145Sobrien if (printit) 33641145Sobrien fprintf(stderr, "Error reading source file %s\n", mapsrc); 33741145Sobrien else 33841145Sobrien fprintf(stderr, "Error creating database map for %s\n", mapsrc); 33941145Sobrien exit(1); 34041145Sobrien } 34138494Sobrien 34241145Sobrien if (printit) 34341145Sobrien exit(0); /* nothing more to do */ 34438494Sobrien 34541145Sobrien /* if gets here, we wrote to a database */ 34638494Sobrien 34741145Sobrien dbm_close(db); 34841145Sobrien /* all went well */ 34941145Sobrien 35041145Sobrien#ifdef HAVE_DB_SUFFIX 351174313Sobrien /* sizeof(map_name_db) is malloc'ed above */ 352174313Sobrien xsnprintf(map_name_db, l, "%s.db", mapsrc); 35341145Sobrien if (rename(maptdb, map_name_db) < 0) { 35441145Sobrien fprintf(stderr, "Couldn't rename %s to ", maptdb); 35541145Sobrien perror(map_name_db); 35641145Sobrien /* Throw away the temporary map */ 35741145Sobrien unlink(maptdb); 35841145Sobrien exit(1); 35938494Sobrien } 36041145Sobrien#else /* not HAVE_DB_SUFFIX */ 361174313Sobrien /* sizeof(map_name_{pag,dir}) are malloc'ed above */ 362174313Sobrien xsnprintf(map_name_pag, l, "%s.pag", mapsrc); 363174313Sobrien xsnprintf(map_name_dir, l, "%s.dir", mapsrc); 36441145Sobrien if (rename(maptpag, map_name_pag) < 0) { 36541145Sobrien fprintf(stderr, "Couldn't rename %s to ", maptpag); 36641145Sobrien perror(map_name_pag); 36741145Sobrien /* Throw away the temporary map */ 36841145Sobrien unlink(maptpag); 36941145Sobrien unlink(maptdir); 37041145Sobrien exit(1); 37141145Sobrien } 37241145Sobrien if (rename(maptdir, map_name_dir) < 0) { 37341145Sobrien fprintf(stderr, "Couldn't rename %s to ", maptdir); 37441145Sobrien perror(map_name_dir); 37541145Sobrien /* remove the (presumably bad) .pag file */ 37641145Sobrien unlink(map_name_pag); 37741145Sobrien /* throw away remaining part of original map */ 37841145Sobrien unlink(map_name_dir); 37941145Sobrien /* throw away the temporary map */ 38041145Sobrien unlink(maptdir); 38141145Sobrien fprintf(stderr, "WARNING: existing map \"%s.{dir,pag}\" destroyed\n", 38241145Sobrien mapsrc); 38341145Sobrien exit(1); 38441145Sobrien } 38541145Sobrien#endif /* not HAVE_DB_SUFFIX */ 38641145Sobrien 38741145Sobrien exit(0); 38838494Sobrien} 38938494Sobrien 39038494Sobrien#else /* not HAVE_MAP_NDBM */ 39138494Sobrien 39241145Sobrienint 39338494Sobrienmain() 39438494Sobrien{ 39538494Sobrien fputs("mk-amd-map: This system does not support hashed database files\n", stderr); 39638494Sobrien exit(1); 39738494Sobrien} 39838494Sobrien 39938494Sobrien#endif /* not HAVE_MAP_NDBM */ 400