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