mk-amd-map.c revision 310490
1/* 2 * Copyright (c) 1997-2014 Erez Zadok 3 * Copyright (c) 1990 Jan-Simon Pendry 4 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 5 * Copyright (c) 1990 The Regents of the University of California. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Jan-Simon Pendry at Imperial College, London. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * 36 * File: am-utils/mk-amd-map/mk-amd-map.c 37 */ 38 39/* 40 * Convert a file map into an ndbm map 41 */ 42 43#ifdef HAVE_CONFIG_H 44# include <config.h> 45#endif /* HAVE_CONFIG_H */ 46#include <am_defs.h> 47 48/* (libdb version 2) uses .db extensions but an old dbm API */ 49/* check for libgdbm to distinguish it from linux systems */ 50#if defined(DBM_SUFFIX) && !defined(HAVE_LIBGDBM) 51# define HAVE_DB_SUFFIX 52#endif /* not defined(DBM_SUFFIX) && !defined(HAVE_LIBGDBM) */ 53 54#ifdef HAVE_MAP_NDBM 55 56static int 57store_data(voidp db, char *k, char *v) 58{ 59 datum key, val; 60 61 key.dptr = k; 62 val.dptr = v; 63 key.dsize = strlen(k) + 1; 64 val.dsize = strlen(v) + 1; 65 return dbm_store((DBM *) db, key, val, DBM_INSERT); 66} 67 68 69/* 70 * Read one line from file. 71 */ 72static int 73read_line(char *buf, int size, FILE *fp) 74{ 75 int done = 0; 76 77 do { 78 while (fgets(buf, size, fp)) { 79 int len = strlen(buf); 80 81 done += len; 82 if (len > 1 && buf[len - 2] == '\\' && buf[len - 1] == '\n') { 83 int ch; 84 buf += len - 2; 85 size -= len - 2; 86 *buf = '\n'; 87 buf[1] = '\0'; 88 89 /* 90 * Skip leading white space on next line 91 */ 92 while ((ch = getc(fp)) != EOF && isascii((unsigned char)ch) && isspace((unsigned char)ch)) ; 93 (void) ungetc(ch, fp); 94 } else { 95 return done; 96 } 97 } 98 } while (size > 0 && !feof(fp)); 99 100 return done; 101} 102 103 104/* 105 * Read through a map. 106 */ 107static int 108read_file(FILE *fp, char *map, voidp db) 109{ 110 char key_val[2048]; 111 int chuck = 0; 112 int line_no = 0; 113 int errs = 0; 114 115 while (read_line(key_val, 2048, fp)) { 116 char *kp; 117 char *cp; 118 char *hash; 119 int len = strlen(key_val); 120 121 line_no++; 122 123 /* 124 * Make sure we got the whole line 125 */ 126 if (key_val[len - 1] != '\n') { 127 fprintf(stderr, "line %d in \"%s\" is too long", line_no, map); 128 chuck = 1; 129 } else { 130 key_val[len - 1] = '\0'; 131 } 132 133 /* 134 * Strip comments 135 */ 136 hash = strchr(key_val, '#'); 137 if (hash) 138 *hash = '\0'; 139 140 /* 141 * Find start of key 142 */ 143 for (kp = key_val; *kp && isascii((unsigned char)*kp) && isspace((unsigned char)*kp); kp++) ; 144 145 /* 146 * Ignore blank lines 147 */ 148 if (!*kp) 149 goto again; 150 151 /* 152 * Find end of key 153 */ 154 for (cp = kp; *cp && (!isascii((unsigned char)*cp) || !isspace((unsigned char)*cp)); cp++) ; 155 156 /* 157 * Check whether key matches, or whether 158 * the entry is a wildcard entry. 159 */ 160 if (*cp) 161 *cp++ = '\0'; 162 while (*cp && isascii((unsigned char)*cp) && isspace((unsigned char)*cp)) 163 cp++; 164 if (*kp == '+') { 165 fprintf(stderr, "Can't interpolate %s\n", kp); 166 errs++; 167 } else if (*cp) { 168 if (db) { 169 if (store_data(db, kp, cp) < 0) { 170 fprintf(stderr, "Could store %s -> %s\n", kp, cp); 171 errs++; 172 } 173 } else { 174 printf("%s\t%s\n", kp, cp); 175 } 176 } else { 177 fprintf(stderr, "%s: line %d has no value field", map, line_no); 178 errs++; 179 } 180 181 again: 182 /* 183 * If the last read didn't get a whole line then 184 * throw away the remainder before continuing... 185 */ 186 if (chuck) { 187 while (fgets(key_val, sizeof(key_val), fp) && 188 !strchr(key_val, '\n')) ; 189 chuck = 0; 190 } 191 } 192 return errs; 193} 194 195 196static int 197remove_file(char *f) 198{ 199 if (unlink(f) < 0 && errno != ENOENT) 200 return -1; 201 202 return 0; 203} 204 205 206int 207main(int argc, char *argv[]) 208{ 209 FILE *mapf; /* the input file to read from */ 210 int error; 211 char *mapsrc; 212 DBM *db = NULL; 213 static char maptmp[] = "dbmXXXXXX"; 214#ifdef HAVE_DB_SUFFIX 215 char maptdb[16]; 216 char *map_name_db = (char *) NULL; 217#else /* not HAVE_DB_SUFFIX */ 218 char maptpag[16], maptdir[16]; 219 char *map_name_pag = (char *) NULL, *map_name_dir = (char *) NULL; 220#endif /* not HAVE_DB_SUFFIX */ 221 size_t l = 0; 222 char *sl; 223 int printit = 0; 224 int usage = 0; 225 int ch; 226 extern int optind; 227 228 /* test options */ 229 while ((ch = getopt(argc, argv, "p")) != -1) 230 switch (ch) { 231 case 'p': 232 printit = 1; 233 break; 234 default: 235 usage++; 236 break; 237 } 238 239 if (usage || optind != (argc - 1)) { 240 fputs("Usage: mk-amd-map [-p] file-map\n", stderr); 241 exit(1); 242 } 243 mapsrc = argv[optind]; 244 245 /* test if can get to the map directory */ 246 sl = strrchr(mapsrc, '/'); 247 if (sl) { 248 *sl = '\0'; 249 if (chdir(mapsrc) < 0) { 250 fputs("Can't chdir to ", stderr); 251 perror(mapsrc); 252 exit(1); 253 } 254 mapsrc = sl + 1; 255 } 256 257 /* open source file */ 258 mapf = fopen(mapsrc, "r"); 259 if (!mapf) { 260 fprintf(stderr, "cannot open source file "); 261 perror(mapsrc); 262 exit(1); 263 } 264 265#ifndef DEBUG 266 signal(SIGINT, SIG_IGN); 267#endif /* DEBUG */ 268 269 if (!printit) { 270 /* enough space for ".db" or ".pag" or ".dir" appended */ 271 l = strlen(mapsrc) + 5; 272#ifdef HAVE_DB_SUFFIX 273 map_name_db = (char *) malloc(l); 274 error = (map_name_db == NULL); 275#else /* not HAVE_DB_SUFFIX */ 276 map_name_pag = (char *) malloc(l); 277 map_name_dir = (char *) malloc(l); 278 error = (map_name_pag == NULL || map_name_dir == NULL); 279#endif /* not HAVE_DB_SUFFIX */ 280 if (error) { 281 perror("mk-amd-map: malloc"); 282 exit(1); 283 } 284 285#ifdef HAVE_MKSTEMP 286 { 287 /* 288 * XXX: hack to avoid compiler complaints about mktemp not being 289 * secure, since we have to do a dbm_open on this anyway. So use 290 * mkstemp if you can, and then close the fd, but we get a safe 291 * and unique file name. 292 */ 293 int dummyfd; 294 dummyfd = mkstemp(maptmp); 295 if (dummyfd >= 0) 296 close(dummyfd); 297 } 298#else /* not HAVE_MKSTEMP */ 299 mktemp(maptmp); 300#endif /* not HAVE_MKSTEMP */ 301 302 /* remove existing temps (if any) */ 303#ifdef HAVE_DB_SUFFIX 304 xsnprintf(maptdb, sizeof(maptdb), "%s.db", maptmp); 305 if (remove_file(maptdb) < 0) { 306 fprintf(stderr, "Can't remove existing temporary file; "); 307 perror(maptdb); 308 exit(1); 309 } 310#else /* not HAVE_DB_SUFFIX */ 311 xsnprintf(maptpag, sizeof(maptpag), "%s.pag", maptmp); 312 xsnprintf(maptdir, sizeof(maptdir), "%s.dir", maptmp); 313 if (remove_file(maptpag) < 0 || remove_file(maptdir) < 0) { 314 fprintf(stderr, "Can't remove existing temporary files; %s and ", maptpag); 315 perror(maptdir); 316 exit(1); 317 } 318#endif /* not HAVE_DB_SUFFIX */ 319 320 db = dbm_open(maptmp, O_RDWR|O_CREAT|O_EXCL, 0444); 321 if (!db) { 322 fprintf(stderr, "cannot initialize temporary database: %s", maptmp); 323 exit(1); 324 } 325 } 326 327 /* print db to stdout or to temp database */ 328 error = read_file(mapf, mapsrc, db); 329 fclose(mapf); 330 if (error) { 331 if (printit) 332 fprintf(stderr, "Error reading source file %s\n", mapsrc); 333 else 334 fprintf(stderr, "Error creating database map for %s\n", mapsrc); 335 exit(1); 336 } 337 338 if (printit) 339 exit(0); /* nothing more to do */ 340 341 /* if gets here, we wrote to a database */ 342 343 dbm_close(db); 344 /* all went well */ 345 346#ifdef HAVE_DB_SUFFIX 347 /* sizeof(map_name_db) is malloc'ed above */ 348 xsnprintf(map_name_db, l, "%s.db", mapsrc); 349 if (rename(maptdb, map_name_db) < 0) { 350 fprintf(stderr, "Couldn't rename %s to ", maptdb); 351 perror(map_name_db); 352 /* Throw away the temporary map */ 353 unlink(maptdb); 354 exit(1); 355 } 356#else /* not HAVE_DB_SUFFIX */ 357 /* sizeof(map_name_{pag,dir}) are malloc'ed above */ 358 xsnprintf(map_name_pag, l, "%s.pag", mapsrc); 359 xsnprintf(map_name_dir, l, "%s.dir", mapsrc); 360 if (rename(maptpag, map_name_pag) < 0) { 361 fprintf(stderr, "Couldn't rename %s to ", maptpag); 362 perror(map_name_pag); 363 /* Throw away the temporary map */ 364 unlink(maptpag); 365 unlink(maptdir); 366 exit(1); 367 } 368 if (rename(maptdir, map_name_dir) < 0) { 369 fprintf(stderr, "Couldn't rename %s to ", maptdir); 370 perror(map_name_dir); 371 /* remove the (presumably bad) .pag file */ 372 unlink(map_name_pag); 373 /* throw away remaining part of original map */ 374 unlink(map_name_dir); 375 /* throw away the temporary map */ 376 unlink(maptdir); 377 fprintf(stderr, "WARNING: existing map \"%s.{dir,pag}\" destroyed\n", 378 mapsrc); 379 exit(1); 380 } 381#endif /* not HAVE_DB_SUFFIX */ 382 383 exit(0); 384} 385 386#else /* not HAVE_MAP_NDBM */ 387 388int 389main() 390{ 391 fputs("mk-amd-map: This system does not support hashed database files\n", stderr); 392 exit(1); 393} 394 395#endif /* not HAVE_MAP_NDBM */ 396