1/* 2 * dbz - use and test dbz in various ways 3 * 4 * -Log- 5 */ 6 7#include <stdio.h> 8#include <sys/types.h> 9#include <sys/stat.h> 10#include <string.h> 11#include <dbz.h> 12 13#ifdef FUNNYSEEKS 14#include <unistd.h> 15#else 16#define SEEK_SET 0 17#endif 18 19#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) 20 21#ifndef lint 22static char RCSid[] = "$Header: /tmp/bonefish/open-beos/buildtools/gcc/libio/dbz/dbzmain.c,v 1.1 2004/10/28 18:14:04 zooey Exp $"; 23#endif 24 25char *progname; 26 27char *inname = "(no file)"; /* filename for messages etc. */ 28long lineno; /* line number for messages etc. */ 29 30char *my_basename; 31char *pagname; 32char *dir_name; 33char *str2dup(); 34FILE *base; 35 36int op = 'b'; /* what to do, default build a new table */ 37int baseinput = 1; /* is the base file also the input? */ 38 39char *from = NULL; /* old table to use for dbzagain() */ 40int omitzero = 0; /* omit lines tagged with 0 */ 41long every = 0; /* report every n lines */ 42int syncs = 0; /* dbzsync() on each report */ 43int quick = 0; /* quick checking, not too thorough */ 44int sweep = 0; /* sweep file checking all offsets */ 45int useincore = 1; /* should we use incore facility? */ 46long xxx = 0; /* debugging variable */ 47int printx = 0; /* print xxx after all is done */ 48int unique = 1; /* before store(), check with fetch() */ 49int usefresh = 0; /* use dbzfresh? */ 50long siz = 0; /* -p size */ 51char map = 'C'; /* -p map */ 52long tag = 0; /* -p tag mask */ 53int exact = 0; /* do not run dbzsize(siz) */ 54int dbzint = 1; /* use new interface? */ 55char fs = '\t'; /* field separator, default tab */ 56int unopen = 0; /* make base unopenable during dbminit? */ 57char *change = NULL; /* chdir here before dbmclose */ 58 59#define DEFBUF 1024 /* default line-buffer size */ 60int buflen = DEFBUF; /* line length limit */ 61char lbuf[DEFBUF]; 62char *line = lbuf; 63char cbuf[DEFBUF]; 64char *cmp = cbuf; 65 66void fail(); 67void dofile(); 68void runs(); 69void dosweep(); 70void mkfiles(); 71void crfile(); 72void doline(); 73void process(); 74 75#ifdef HAVERFCIZE 76extern char *rfc822ize(); 77#else 78#define rfc822ize(n) (n) 79#endif 80 81extern char *malloc(); 82 83/* 84 - main - parse arguments and handle options 85 */ 86int 87main(argc, argv) 88int argc; 89char *argv[]; 90{ 91 int c; 92 int errflg = 0; 93 extern int optind; 94 extern char *optarg; 95 int doruns = 0; 96 extern long atol(); 97 98 progname = argv[0]; 99 100 while ((c = getopt(argc, argv, "axcmt:l:R0E:SqOiX:Yuf:p:eMUC:d")) != EOF) 101 switch (c) { 102 case 'a': /* append to existing table */ 103 if (op != 'b') 104 fail("only one of -a -x -c -m can be given", ""); 105 op = 'a'; 106 baseinput = 0; 107 break; 108 case 'x': /* extract from existing table */ 109 if (op != 'b') 110 fail("only one of -a -x -c -m can be given", ""); 111 op = 'x'; 112 baseinput = 0; 113 break; 114 case 'c': /* check existing table */ 115 if (op != 'b') 116 fail("only one of -a -x -c -m can be given", ""); 117 op = 'c'; 118 break; 119 case 'm': /* extract missing (complement of -x) */ 120 if (op != 'b') 121 fail("only one of -a -x -c -m can be given", ""); 122 op = 'm'; 123 baseinput = 0; 124 break; 125 case 't': /* set field separator */ 126 if (strlen(optarg) > 1) 127 fail("only one field separator allowed", ""); 128 fs = *optarg; 129 break; 130 case 'l': /* override line-length limit */ 131 buflen = atoi(optarg) + 1; 132 if (buflen <= 2) 133 fail("bad -l value `%s'", optarg); 134 line = malloc(buflen); 135 cmp = malloc(buflen); 136 if (line == NULL || cmp == NULL) 137 fail("cannot allocate %s-byte buffers", optarg); 138 break; 139 case 'R': /* print run statistics */ 140 doruns = 1; 141 break; 142 case '0': /* omit lines tagged (by fake -t) with 0 */ 143 omitzero = 1; 144 break; 145 case 'E': /* report every n items */ 146 every = atol(optarg); 147 break; 148 case 'S': /* dbzsync() on each -E report */ 149 syncs = 1; 150 break; 151 case 'q': /* quick check or extract */ 152 quick = 1; 153 break; 154 case 'O': /* sweep file checking all offsets */ 155 sweep = 1; 156 break; 157 case 'i': /* don't use incore */ 158 useincore = 0; 159 break; 160 case 'X': /* set xxx */ 161 xxx = atoi(optarg); 162 break; 163 case 'Y': /* print xxx afterward */ 164 printx = 1; 165 break; 166 case 'u': /* don't check uniqueness */ 167 unique = 0; 168 break; 169 case 'f': /* init from existing table's parameters */ 170 from = optarg; 171 break; 172 case 'p': /* parameters for dbzfresh */ 173 if (sscanf(optarg, "%ld %1s %lx", &siz, &map, &tag) != 3) { 174 map = '?'; 175 tag = 0; 176 if (sscanf(optarg, "%ld", &siz) != 1) 177 fail("bad -n value `%s'", optarg); 178 } 179 usefresh = 1; 180 break; 181 case 'e': /* -p size is exact, don't dbzsize() it */ 182 exact = 1; 183 break; 184 case 'M': /* use old dbm interface + rfc822ize */ 185 dbzint = 0; 186 break; 187 case 'U': /* make base unopenable during init */ 188 unopen = 1; 189 break; 190 case 'C': /* change directories before dbmclose */ 191 change = optarg; 192 break; 193 case 'd': /* Debugging. */ 194 if (dbzdebug(1) < 0) 195 fail("dbz debugging not available", ""); 196 break; 197 case '?': 198 default: 199 errflg++; 200 break; 201 } 202 if (errflg || optind >= argc || (optind+1 < argc && baseinput)) { 203 fprintf(stderr, "usage: %s ", progname); 204 fprintf(stderr, "[-a] [-x] [-c] database [file] ...\n"); 205 exit(2); 206 } 207 208 (void) dbzincore(useincore); 209 my_basename = argv[optind]; 210 pagname = str2dup(my_basename, ".pag"); 211 dir_name = str2dup(my_basename, ".dir"); 212 mkfiles(); 213 optind++; 214 215 if (baseinput) /* implies no further arguments */ 216 process(base, my_basename); 217 else if (optind >= argc) 218 process(stdin, "stdin"); 219 else 220 for (; optind < argc; optind++) 221 dofile(argv[optind]); 222 223 if (change != NULL) 224 (void) chdir(change); 225 if (dbmclose() < 0) 226 fail("dbmclose failed", ""); 227 if (doruns) 228 runs(pagname); 229 if (sweep) 230 dosweep(my_basename, pagname); 231 if (printx) 232 printf("%ld\n", xxx); 233#ifdef DBZ_FINISH 234 DBZ_FINISH; 235#endif 236 exit(0); 237} 238 239/* 240 - dofile - open a file and invoke process() 241 */ 242void 243dofile(name) 244char *name; 245{ 246 register FILE *in; 247 248 if (STREQ(name, "-")) 249 process(stdin, "-"); 250 else { 251 in = fopen(name, "r"); 252 if (in == NULL) 253 fail("cannot open `%s'", name); 254 process(in, name); 255 (void) fclose(in); 256 } 257} 258 259/* 260 - mkfiles - create empty files and open them up 261 */ 262void 263mkfiles() 264{ 265 if (op == 'b' && !dbzint) { 266 crfile(dir_name); 267 crfile(pagname); 268 } 269 270 base = fopen(my_basename, (op == 'a') ? "a" : "r"); 271 if (base == NULL) 272 fail("cannot open `%s'", my_basename); 273 if (unopen) 274 (void) chmod(my_basename, 0); 275 if (from != NULL) { 276 if (dbzagain(my_basename, from) < 0) 277 fail("dbzagain(`%s'...) failed", my_basename); 278 } else if (op == 'b' && dbzint) { 279 if (!exact) 280 siz = dbzsize(siz); 281 if (dbzfresh(my_basename, siz, (int)fs, map, (off_t)tag) < 0) 282 fail("dbzfresh(`%s'...) failed", my_basename); 283 } else if (dbminit(my_basename) < 0) 284 fail("dbminit(`%s') failed", my_basename); 285 if (unopen) 286 (void) chmod(my_basename, 0600); /* hard to restore original */ 287} 288 289/* 290 - crfile - create a file 291 */ 292void 293crfile(name) 294char *name; 295{ 296 register int f; 297 298 f = creat(name, 0666); 299 if (f < 0) 300 fail("cannot create `%s'", name); 301 (void) close(f); 302} 303 304/* 305 - process - process input file 306 */ 307void 308process(in, name) 309FILE *in; 310char *name; 311{ 312 register off_t place; 313 314 inname = name; 315 lineno = 0; 316 317 for (;;) { 318 place = ftell(in); 319 if (fgets(line, buflen, in) == NULL) 320 return; 321 lineno++; 322 if (every > 0 && lineno%every == 0) { 323 fprintf(stderr, "%ld\n", lineno); 324 if (dbzsync() < 0) 325 fail("dbzsync failed", ""); 326 } 327 doline(line, place); 328 } 329 /* NOTREACHED */ 330} 331 332/* 333 - doline - process input line 334 */ 335void 336doline(lp, inoffset) 337char *lp; 338off_t inoffset; 339{ 340 register char *p; 341 register char pc; 342 datum key, value; 343 off_t place = inoffset; 344 register int shouldfind; 345 register int llen; 346 char keytext[DBZMAXKEY+1]; 347 348 p = NULL; 349 if (fs != '\0') 350 p = strchr(lp, fs); 351 if (p == NULL) 352 p = lp + strlen(lp); 353 if (p > lp && *(p-1) == '\n') 354 p--; 355 if (p - lp > DBZMAXKEY) 356 fail("key of `%.40s...' too long", lp); 357 pc = *p; 358 *p = '\0'; 359 (void) strcpy(keytext, lp); 360 *p = pc; 361 key.dptr = (dbzint) ? keytext : rfc822ize(keytext); 362 key.dsize = strlen(keytext)+1; 363 364 switch (op) { 365 case 'a': 366 place = ftell(base); 367 llen = strlen(lp); 368 if (fwrite(lp, 1, llen, base) != llen) 369 fail("write error in `%s'", my_basename); 370 /* FALLTHROUGH */ 371 case 'b': 372 if (omitzero && p != NULL && *(p+1) == '0') 373 return; 374 if (unique) { 375 value = (dbzint) ? dbzfetch(key) : fetch(key); 376 if (value.dptr != NULL) 377 fail("`%.40s...' already present", lp); 378 } 379 value.dptr = (char *)&place; 380 value.dsize = (int)sizeof(off_t); 381 if (((dbzint) ? dbzstore(key, value) : store(key, value)) < 0) 382 fail("store failed on `%.40s...'", lp); 383 break; 384 case 'c': 385 value = (dbzint) ? dbzfetch(key) : fetch(key); 386 shouldfind = (omitzero && p != NULL && *(p+1) == '0') ? 0 : 1; 387 if (!shouldfind && (value.dptr != NULL || value.dsize != 0)) 388 fail("`%.40s...' found, shouldn't be", lp); 389 if (shouldfind && (value.dptr == NULL || 390 value.dsize != sizeof(off_t))) 391 fail("can't find `%.40s...'", lp); 392 if (shouldfind && !quick) { 393 (void) memcpy((char *)&place, value.dptr, sizeof(off_t)); 394 if (place != inoffset) 395 fail("offset mismatch on `%.40s...'", lp); 396 if (fseek(base, place, SEEK_SET) == -1) 397 fail("fseek failed on `%.40s...'", lp); 398 if (fgets(cmp, buflen, base) == NULL) 399 fail("can't read line for `%.40s...'", lp); 400 if (!STREQ(lp, cmp)) 401 fail("compare failed on `%.40s...'", lp); 402 } 403 break; 404 case 'x': 405 value = (dbzint) ? dbzfetch(key) : fetch(key); 406 if (value.dptr != NULL && !quick) { 407 (void) memcpy((char *)&place, value.dptr, sizeof(off_t)); 408 if (fseek(base, place, SEEK_SET) == -1) 409 fail("fseek failed on `%.40s...'", lp); 410 if (fgets(cmp, buflen, base) == NULL) 411 fail("can't read line for `%.40s...'", lp); 412 fputs(cmp, stdout); 413 } else if (value.dptr != NULL) 414 fputs(lp, stdout); 415 break; 416 case 'm': 417 value = (dbzint) ? dbzfetch(key) : fetch(key); 418 if (value.dptr == NULL) { 419 fputs(keytext, stdout); 420 putchar('\n'); 421 } 422 break; 423 default: 424 fail("unknown operator -- can't happen", ""); 425 break; 426 } 427} 428 429/* 430 - runs - print run statistics 431 */ 432void 433runs(file) 434char *file; 435{ 436 register FILE *fd; 437 off_t it; 438 register long run; 439 440 fd = fopen(file, "r"); 441 if (fd == NULL) 442 fail("cannot reopen `%s'", file); 443 run = 0; 444 while (fread((char *)&it, sizeof(off_t), 1, fd) == 1) { 445 if (it != 0) 446 run++; 447 else if (run > 0) { 448 printf("%ld\n", run); 449 run = 0; 450 } 451 } 452 (void) fclose(fd); 453} 454 455/* 456 - dosweep - sweep pag file checking for valid offsets 457 */ 458void 459dosweep(fn, pn) 460char *fn; 461char *pn; 462{ 463 register FILE *pf; 464 off_t it; 465 char nl; 466 register FILE *hf; 467 468 hf = fopen(fn, "r"); 469 if (hf == NULL) 470 fail("cannot reopen `%s'", fn); 471 pf = fopen(pn, "r"); 472 if (pf == NULL) 473 fail("cannot reopen `%s'", pn); 474 while (fread((char *)&it, sizeof(off_t), 1, pf) == 1) { 475 it = (it & ((off_t)0x80000000)) ? (it&~((off_t)0xff000000)) : it; 476 if (it != 0 && it != 1) { /* 0 empty, 1 known okay */ 477 it--; /* get rid of bias */ 478 (void) fseek(hf, it-1, SEEK_SET); 479 nl = getc(hf); 480 if (nl != '\n') 481 fprintf(stderr, "offset 0%lo does not point to line\n", 482 (long)it); 483 } 484 } 485 (void) fclose(hf); 486 (void) fclose(pf); 487} 488 489/* 490 - fail - complain and die 491 */ 492void 493fail(s1, s2) 494char *s1; 495char *s2; 496{ 497 fprintf(stderr, "%s: (file `%s', line %ld) ", progname, inname, lineno); 498 fprintf(stderr, s1, s2); 499 fprintf(stderr, "\n"); 500 exit(1); 501} 502 503/* 504 - str2dup - concatenate strings and malloc result 505 */ 506char * 507str2dup(s1, s2) 508char *s1; 509char *s2; 510{ 511 register char *p; 512 513 p = malloc((size_t)strlen(s1) + strlen(s2) + 1); 514 if (p == NULL) 515 fail("can't allocate space for strings", ""); 516 (void) strcpy(p, s1); 517 (void) strcat(p, s2); 518 return(p); 519} 520