home *** CD-ROM | disk | FTP | other *** search
/ Unix System Administration Handbook 1997 October / usah_oct97.iso / news / cnews.tar / libdbz / dbzmain.c < prev    next >
C/C++ Source or Header  |  1995-04-27  |  12KB  |  599 lines

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