138494Sobrien/* 2310490Scy * Copyright (c) 1997-2014 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. 19310490Scy * 3. Neither the name of the University nor the names of its contributors 2038494Sobrien * may be used to endorse or promote products derived from this software 2138494Sobrien * without specific prior written permission. 2238494Sobrien * 2338494Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2438494Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2538494Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2638494Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2738494Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2838494Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2938494Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3038494Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3138494Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3238494Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3338494Sobrien * SUCH DAMAGE. 3438494Sobrien * 3538494Sobrien * 36174313Sobrien * File: am-utils/mk-amd-map/mk-amd-map.c 3738494Sobrien */ 3838494Sobrien 3938494Sobrien/* 4038494Sobrien * Convert a file map into an ndbm map 4138494Sobrien */ 4238494Sobrien 4338494Sobrien#ifdef HAVE_CONFIG_H 4438494Sobrien# include <config.h> 4538494Sobrien#endif /* HAVE_CONFIG_H */ 4638494Sobrien#include <am_defs.h> 4738494Sobrien 4841145Sobrien/* (libdb version 2) uses .db extensions but an old dbm API */ 4941145Sobrien/* check for libgdbm to distinguish it from linux systems */ 5041145Sobrien#if defined(DBM_SUFFIX) && !defined(HAVE_LIBGDBM) 5141145Sobrien# define HAVE_DB_SUFFIX 5241145Sobrien#endif /* not defined(DBM_SUFFIX) && !defined(HAVE_LIBGDBM) */ 5338494Sobrien 5438494Sobrien#ifdef HAVE_MAP_NDBM 5538494Sobrien 5638494Sobrienstatic int 5738494Sobrienstore_data(voidp db, char *k, char *v) 5838494Sobrien{ 5938494Sobrien datum key, val; 6038494Sobrien 6138494Sobrien key.dptr = k; 6238494Sobrien val.dptr = v; 6338494Sobrien key.dsize = strlen(k) + 1; 6438494Sobrien val.dsize = strlen(v) + 1; 6538494Sobrien return dbm_store((DBM *) db, key, val, DBM_INSERT); 6638494Sobrien} 6738494Sobrien 6838494Sobrien 6938494Sobrien/* 7038494Sobrien * Read one line from file. 7138494Sobrien */ 7238494Sobrienstatic int 7338494Sobrienread_line(char *buf, int size, FILE *fp) 7438494Sobrien{ 7538494Sobrien int done = 0; 7638494Sobrien 7738494Sobrien do { 7838494Sobrien while (fgets(buf, size, fp)) { 7938494Sobrien int len = strlen(buf); 8038494Sobrien 8138494Sobrien done += len; 8238494Sobrien if (len > 1 && buf[len - 2] == '\\' && buf[len - 1] == '\n') { 8338494Sobrien int ch; 8438494Sobrien buf += len - 2; 8538494Sobrien size -= len - 2; 8638494Sobrien *buf = '\n'; 8738494Sobrien buf[1] = '\0'; 8838494Sobrien 8938494Sobrien /* 9038494Sobrien * Skip leading white space on next line 9138494Sobrien */ 92310490Scy while ((ch = getc(fp)) != EOF && isascii((unsigned char)ch) && isspace((unsigned char)ch)) ; 9338494Sobrien (void) ungetc(ch, fp); 9438494Sobrien } else { 9538494Sobrien return done; 9638494Sobrien } 9738494Sobrien } 9838494Sobrien } while (size > 0 && !feof(fp)); 9938494Sobrien 10038494Sobrien return done; 10138494Sobrien} 10238494Sobrien 10338494Sobrien 10438494Sobrien/* 10538494Sobrien * Read through a map. 10638494Sobrien */ 10738494Sobrienstatic int 10838494Sobrienread_file(FILE *fp, char *map, voidp db) 10938494Sobrien{ 11038494Sobrien char key_val[2048]; 11138494Sobrien int chuck = 0; 11238494Sobrien int line_no = 0; 11338494Sobrien int errs = 0; 11438494Sobrien 11541145Sobrien while (read_line(key_val, 2048, fp)) { 11638494Sobrien char *kp; 11738494Sobrien char *cp; 11838494Sobrien char *hash; 11938494Sobrien int len = strlen(key_val); 12038494Sobrien 12138494Sobrien line_no++; 12238494Sobrien 12338494Sobrien /* 12438494Sobrien * Make sure we got the whole line 12538494Sobrien */ 12638494Sobrien if (key_val[len - 1] != '\n') { 12738494Sobrien fprintf(stderr, "line %d in \"%s\" is too long", line_no, map); 12838494Sobrien chuck = 1; 12938494Sobrien } else { 13038494Sobrien key_val[len - 1] = '\0'; 13138494Sobrien } 13238494Sobrien 13338494Sobrien /* 13438494Sobrien * Strip comments 13538494Sobrien */ 13638494Sobrien hash = strchr(key_val, '#'); 13738494Sobrien if (hash) 13838494Sobrien *hash = '\0'; 13938494Sobrien 14038494Sobrien /* 14138494Sobrien * Find start of key 14238494Sobrien */ 143310490Scy for (kp = key_val; *kp && isascii((unsigned char)*kp) && isspace((unsigned char)*kp); kp++) ; 14438494Sobrien 14538494Sobrien /* 14638494Sobrien * Ignore blank lines 14738494Sobrien */ 14838494Sobrien if (!*kp) 14938494Sobrien goto again; 15038494Sobrien 15138494Sobrien /* 15238494Sobrien * Find end of key 15338494Sobrien */ 154310490Scy for (cp = kp; *cp && (!isascii((unsigned char)*cp) || !isspace((unsigned char)*cp)); cp++) ; 15538494Sobrien 15638494Sobrien /* 15738494Sobrien * Check whether key matches, or whether 15838494Sobrien * the entry is a wildcard entry. 15938494Sobrien */ 16038494Sobrien if (*cp) 16138494Sobrien *cp++ = '\0'; 162310490Scy while (*cp && isascii((unsigned char)*cp) && isspace((unsigned char)*cp)) 16338494Sobrien cp++; 16438494Sobrien if (*kp == '+') { 16538494Sobrien fprintf(stderr, "Can't interpolate %s\n", kp); 16638494Sobrien errs++; 16738494Sobrien } else if (*cp) { 16838494Sobrien if (db) { 16938494Sobrien if (store_data(db, kp, cp) < 0) { 17038494Sobrien fprintf(stderr, "Could store %s -> %s\n", kp, cp); 17138494Sobrien errs++; 17238494Sobrien } 17338494Sobrien } else { 17438494Sobrien printf("%s\t%s\n", kp, cp); 17538494Sobrien } 17638494Sobrien } else { 17738494Sobrien fprintf(stderr, "%s: line %d has no value field", map, line_no); 17838494Sobrien errs++; 17938494Sobrien } 18038494Sobrien 18138494Sobrien again: 18238494Sobrien /* 18338494Sobrien * If the last read didn't get a whole line then 18438494Sobrien * throw away the remainder before continuing... 18538494Sobrien */ 18638494Sobrien if (chuck) { 18738494Sobrien while (fgets(key_val, sizeof(key_val), fp) && 18838494Sobrien !strchr(key_val, '\n')) ; 18938494Sobrien chuck = 0; 19038494Sobrien } 19138494Sobrien } 19238494Sobrien return errs; 19338494Sobrien} 19438494Sobrien 19538494Sobrien 19638494Sobrienstatic int 19738494Sobrienremove_file(char *f) 19838494Sobrien{ 19938494Sobrien if (unlink(f) < 0 && errno != ENOENT) 20038494Sobrien return -1; 20138494Sobrien 20238494Sobrien return 0; 20338494Sobrien} 20438494Sobrien 20538494Sobrien 20638494Sobrienint 20738494Sobrienmain(int argc, char *argv[]) 20838494Sobrien{ 20941145Sobrien FILE *mapf; /* the input file to read from */ 21041145Sobrien int error; 21141145Sobrien char *mapsrc; 21241145Sobrien DBM *db = NULL; 21338494Sobrien static char maptmp[] = "dbmXXXXXX"; 21441145Sobrien#ifdef HAVE_DB_SUFFIX 21538575Sobrien char maptdb[16]; 21641145Sobrien char *map_name_db = (char *) NULL; 21741145Sobrien#else /* not HAVE_DB_SUFFIX */ 21841145Sobrien char maptpag[16], maptdir[16]; 21941145Sobrien char *map_name_pag = (char *) NULL, *map_name_dir = (char *) NULL; 22041145Sobrien#endif /* not HAVE_DB_SUFFIX */ 221174313Sobrien size_t l = 0; 22238494Sobrien char *sl; 22338494Sobrien int printit = 0; 22438494Sobrien int usage = 0; 22538494Sobrien int ch; 22638494Sobrien extern int optind; 22738494Sobrien 22838494Sobrien /* test options */ 22938500Sobrien while ((ch = getopt(argc, argv, "p")) != -1) 23038494Sobrien switch (ch) { 23138494Sobrien case 'p': 23238494Sobrien printit = 1; 23338494Sobrien break; 23438494Sobrien default: 23538494Sobrien usage++; 23638494Sobrien break; 23738494Sobrien } 23838494Sobrien 23938494Sobrien if (usage || optind != (argc - 1)) { 24038494Sobrien fputs("Usage: mk-amd-map [-p] file-map\n", stderr); 24138494Sobrien exit(1); 24238494Sobrien } 24341145Sobrien mapsrc = argv[optind]; 24438494Sobrien 24538494Sobrien /* test if can get to the map directory */ 24641145Sobrien sl = strrchr(mapsrc, '/'); 24738494Sobrien if (sl) { 24838494Sobrien *sl = '\0'; 24941145Sobrien if (chdir(mapsrc) < 0) { 25038494Sobrien fputs("Can't chdir to ", stderr); 25141145Sobrien perror(mapsrc); 25238494Sobrien exit(1); 25338494Sobrien } 25441145Sobrien mapsrc = sl + 1; 25538494Sobrien } 25638494Sobrien 25741145Sobrien /* open source file */ 25841145Sobrien mapf = fopen(mapsrc, "r"); 25941145Sobrien if (!mapf) { 26041145Sobrien fprintf(stderr, "cannot open source file "); 26141145Sobrien perror(mapsrc); 26241145Sobrien exit(1); 26341145Sobrien } 26441145Sobrien 26541145Sobrien#ifndef DEBUG 26641145Sobrien signal(SIGINT, SIG_IGN); 26741145Sobrien#endif /* DEBUG */ 26841145Sobrien 26938494Sobrien if (!printit) { 270174313Sobrien /* enough space for ".db" or ".pag" or ".dir" appended */ 271174313Sobrien l = strlen(mapsrc) + 5; 27241145Sobrien#ifdef HAVE_DB_SUFFIX 273174313Sobrien map_name_db = (char *) malloc(l); 27441145Sobrien error = (map_name_db == NULL); 27541145Sobrien#else /* not HAVE_DB_SUFFIX */ 276174313Sobrien map_name_pag = (char *) malloc(l); 277174313Sobrien map_name_dir = (char *) malloc(l); 27841145Sobrien error = (map_name_pag == NULL || map_name_dir == NULL); 27941145Sobrien#endif /* not HAVE_DB_SUFFIX */ 28041145Sobrien if (error) { 28138494Sobrien perror("mk-amd-map: malloc"); 28238494Sobrien exit(1); 28338494Sobrien } 28438494Sobrien 285119682Smbr#ifdef HAVE_MKSTEMP 286119682Smbr { 287119682Smbr /* 288119682Smbr * XXX: hack to avoid compiler complaints about mktemp not being 289119682Smbr * secure, since we have to do a dbm_open on this anyway. So use 290119682Smbr * mkstemp if you can, and then close the fd, but we get a safe 291119682Smbr * and unique file name. 292119682Smbr */ 293119682Smbr int dummyfd; 294119682Smbr dummyfd = mkstemp(maptmp); 295119682Smbr if (dummyfd >= 0) 296119682Smbr close(dummyfd); 297119682Smbr } 298119682Smbr#else /* not HAVE_MKSTEMP */ 29941145Sobrien mktemp(maptmp); 300119682Smbr#endif /* not HAVE_MKSTEMP */ 30141145Sobrien 30241145Sobrien /* remove existing temps (if any) */ 30341145Sobrien#ifdef HAVE_DB_SUFFIX 304174313Sobrien xsnprintf(maptdb, sizeof(maptdb), "%s.db", maptmp); 30538575Sobrien if (remove_file(maptdb) < 0) { 30641145Sobrien fprintf(stderr, "Can't remove existing temporary file; "); 30738575Sobrien perror(maptdb); 30838494Sobrien exit(1); 30938494Sobrien } 31041145Sobrien#else /* not HAVE_DB_SUFFIX */ 311174313Sobrien xsnprintf(maptpag, sizeof(maptpag), "%s.pag", maptmp); 312174313Sobrien xsnprintf(maptdir, sizeof(maptdir), "%s.dir", maptmp); 31341145Sobrien if (remove_file(maptpag) < 0 || remove_file(maptdir) < 0) { 31441145Sobrien fprintf(stderr, "Can't remove existing temporary files; %s and ", maptpag); 31541145Sobrien perror(maptdir); 31641145Sobrien exit(1); 31741145Sobrien } 31841145Sobrien#endif /* not HAVE_DB_SUFFIX */ 31941145Sobrien 320119682Smbr db = dbm_open(maptmp, O_RDWR|O_CREAT|O_EXCL, 0444); 32141145Sobrien if (!db) { 32241145Sobrien fprintf(stderr, "cannot initialize temporary database: %s", maptmp); 32341145Sobrien exit(1); 32441145Sobrien } 32538494Sobrien } 32638494Sobrien 32741145Sobrien /* print db to stdout or to temp database */ 32841145Sobrien error = read_file(mapf, mapsrc, db); 32941145Sobrien fclose(mapf); 33041145Sobrien if (error) { 33141145Sobrien if (printit) 33241145Sobrien fprintf(stderr, "Error reading source file %s\n", mapsrc); 33341145Sobrien else 33441145Sobrien fprintf(stderr, "Error creating database map for %s\n", mapsrc); 33541145Sobrien exit(1); 33641145Sobrien } 33738494Sobrien 33841145Sobrien if (printit) 33941145Sobrien exit(0); /* nothing more to do */ 34038494Sobrien 34141145Sobrien /* if gets here, we wrote to a database */ 34238494Sobrien 34341145Sobrien dbm_close(db); 34441145Sobrien /* all went well */ 34541145Sobrien 34641145Sobrien#ifdef HAVE_DB_SUFFIX 347174313Sobrien /* sizeof(map_name_db) is malloc'ed above */ 348174313Sobrien xsnprintf(map_name_db, l, "%s.db", mapsrc); 34941145Sobrien if (rename(maptdb, map_name_db) < 0) { 35041145Sobrien fprintf(stderr, "Couldn't rename %s to ", maptdb); 35141145Sobrien perror(map_name_db); 35241145Sobrien /* Throw away the temporary map */ 35341145Sobrien unlink(maptdb); 35441145Sobrien exit(1); 35538494Sobrien } 35641145Sobrien#else /* not HAVE_DB_SUFFIX */ 357174313Sobrien /* sizeof(map_name_{pag,dir}) are malloc'ed above */ 358174313Sobrien xsnprintf(map_name_pag, l, "%s.pag", mapsrc); 359174313Sobrien xsnprintf(map_name_dir, l, "%s.dir", mapsrc); 36041145Sobrien if (rename(maptpag, map_name_pag) < 0) { 36141145Sobrien fprintf(stderr, "Couldn't rename %s to ", maptpag); 36241145Sobrien perror(map_name_pag); 36341145Sobrien /* Throw away the temporary map */ 36441145Sobrien unlink(maptpag); 36541145Sobrien unlink(maptdir); 36641145Sobrien exit(1); 36741145Sobrien } 36841145Sobrien if (rename(maptdir, map_name_dir) < 0) { 36941145Sobrien fprintf(stderr, "Couldn't rename %s to ", maptdir); 37041145Sobrien perror(map_name_dir); 37141145Sobrien /* remove the (presumably bad) .pag file */ 37241145Sobrien unlink(map_name_pag); 37341145Sobrien /* throw away remaining part of original map */ 37441145Sobrien unlink(map_name_dir); 37541145Sobrien /* throw away the temporary map */ 37641145Sobrien unlink(maptdir); 37741145Sobrien fprintf(stderr, "WARNING: existing map \"%s.{dir,pag}\" destroyed\n", 37841145Sobrien mapsrc); 37941145Sobrien exit(1); 38041145Sobrien } 38141145Sobrien#endif /* not HAVE_DB_SUFFIX */ 38241145Sobrien 38341145Sobrien exit(0); 38438494Sobrien} 38538494Sobrien 38638494Sobrien#else /* not HAVE_MAP_NDBM */ 38738494Sobrien 38841145Sobrienint 38938494Sobrienmain() 39038494Sobrien{ 39138494Sobrien fputs("mk-amd-map: This system does not support hashed database files\n", stderr); 39238494Sobrien exit(1); 39338494Sobrien} 39438494Sobrien 39538494Sobrien#endif /* not HAVE_MAP_NDBM */ 396