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