home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / sendmail / sendmail-5.65c+IDA-1.4.4.1 / ida / aux / dbm.c next >
Encoding:
C/C++ Source or Header  |  1991-07-01  |  12.6 KB  |  637 lines

  1. /*
  2. **  DBM -- General dbm management tool.
  3. **  Copyright (c) 1987 Lennart Lovstrand
  4. **  CIS Dept, Univ of Linkoping, Sweden
  5. **
  6. **  Use it, abuse it, but don't sell it.
  7. */
  8.  
  9. #include "sendmail.h"
  10.  
  11. #define DB_DIREXT    ".dir"
  12. #define DB_PAGEXT    ".pag"
  13.  
  14. #ifndef lint
  15. static char    SccsId[] = "@(#)dbm.c 2.2 (lel@ida.liu.se) 10/24/88";
  16. static char    Rcsid[] = "@(#)$Id: dbm.c,v 1.12 1991/07/01 17:28:32 paul Exp $";
  17. #endif /* !lint */
  18.  
  19. #define    SAMECASE    0
  20. #define LOWERCASE    1
  21. #define UPPERCASE    2
  22.  
  23. #define COMMENTCHAR    '#'
  24. #define SENTENIEL    "@@@"
  25.  
  26. #define streq(s, t)    (strcmp(s, t) == 0)
  27. #define MAKEDATUM(d, s)    {(d).dptr = s; (d).dsize = strlen(s) + 1;}
  28. #define CHECKDATUM(d)    if (Nullwarn && ((d).dsize == 0 || \
  29.                      (d).dptr[(d).dsize - 1] != '\0')) \
  30.         fprintf(stderr, "[Warning: Entry not NULL terminated]\n");
  31.  
  32. #ifdef __STDC__
  33. void opendbm(int, int);
  34. FILE * openfile(const char *, const char *);
  35. void closefile(FILE *);
  36. void parsefile(FILE *, FILE *);
  37. void loadfile(FILE *);
  38. char * scantoken(const char *);
  39. void casify(char *, int);
  40. #else /* !__STDC__ */
  41. # define    const
  42. void opendbm();
  43. FILE * openfile();
  44. void closefile();
  45. void parsefile();
  46. void loadfile();
  47. char * scantoken();
  48. void casify();
  49. #endif /* __STDC__ */
  50. void closedbm();
  51. void do_clear();
  52. void do_delete();
  53. void do_dump();
  54. void do_fetch();
  55. void do_store();
  56. void do_parse();
  57. void do_make();
  58. void do_load();
  59. char * index();
  60.  
  61. struct comtab {
  62.     char *c_name;
  63.     void (*c_func)();
  64.     int LockType;
  65. } CommandTable[] = {
  66.     {"clear",    do_clear},
  67.     {"delete",    do_delete},
  68.     {"dump",    do_dump},
  69.     {"fetch",    do_fetch},
  70.     {"load",    do_load},
  71.     {"make",    do_make},
  72.     {"parse",    do_parse},
  73.     {"store",    do_store}
  74. };
  75.     
  76. /* global arguments */
  77. int    Argc;
  78. char    **Argv;
  79.  
  80. /* options */
  81. int    Appending = FALSE;
  82. int    Casing = SAMECASE;
  83. bool    Debug = FALSE;
  84. char    *Outfile = NULL;
  85. int    Mode = 0644;
  86. char    *Progname;
  87. char    *Senteniel = NULL;
  88. int    Storeflag = DBM_INSERT;
  89. bool    Storewarn = TRUE;
  90. bool    Nullwarn = FALSE;
  91. bool    Valueonly = FALSE;
  92.  
  93. /* Dbm globals */
  94. DBMFILE    *Dbm;
  95. char    *Dbmfile = NULL;
  96. int    Dbmaccess;
  97. datum    key, val;
  98.  
  99. main(argc, argv)
  100.      int argc;
  101.      char **argv;
  102. {
  103.     extern int optind;
  104.     extern char *optarg;
  105.     struct comtab *cmd;
  106.     int c;
  107.  
  108.     Argc = argc;
  109.     Argv = argv;
  110.  
  111.     Progname = Argv[0];
  112.  
  113.     while ((c = getopt(Argc, Argv, "ADILNRSUd:m:o:s:v")) != EOF)
  114.     switch (c) {
  115.       case 'A':
  116.         Appending = TRUE;
  117.         break;
  118.       case 'D':
  119.         Debug = TRUE;
  120.         break;
  121.       case 'I':
  122.         Storeflag = DBM_INSERT;
  123.         Storewarn = FALSE;
  124.         break;
  125.       case 'L':
  126.         Casing = LOWERCASE;
  127.         break;
  128.       case 'N':
  129.         Nullwarn = TRUE;
  130.         break;
  131.       case 'R':
  132.         Storeflag = DBM_REPLACE;
  133.         break;
  134.       case 'S':
  135.         if (Senteniel == NULL)
  136.         Senteniel = SENTENIEL;
  137.         break;
  138.       case 'U':
  139.         Casing = UPPERCASE;
  140.         break;
  141.       case 'd':
  142.         Dbmfile = optarg;
  143.         break;
  144.       case 'm':
  145.         if (optarg[0] == '0')
  146.         (void) sscanf(optarg, "%o", &Mode);
  147.         else {
  148.         (void) sscanf(optarg, "%d", &Mode);
  149.         if (Mode == 0) {
  150.             (void) fprintf(stderr, "%s: non-numeric mode: %s\n",
  151.                    Progname, optarg);
  152.             exit(1);
  153.         }
  154.         }
  155.         break;
  156.       case 'o':
  157.         Outfile = optarg;
  158.         break;
  159.       case 's':
  160.         Senteniel = optarg;
  161.         break;
  162.       case 'v':
  163.         Valueonly = TRUE;
  164.         break;
  165.       default:
  166.         (void) fprintf(stderr,
  167.                "usage: %s [-ADILNRSU] [-d dbm_file] [-m mode] %s", 
  168.                Progname, "[-o output_file] [-v] command [args]\n");
  169.         exit(1);
  170.     }
  171.  
  172.     Argc -= optind;
  173.     Argv += optind;
  174.  
  175.     if (Argc > 0) {
  176.     for (cmd = CommandTable; cmd < &CommandTable[sizeof(CommandTable) /
  177.                              sizeof(*CommandTable)];
  178.          cmd++)
  179.         if (streq(*Argv, cmd->c_name)) {
  180.         (*cmd->c_func)();
  181.         exit(0);
  182.         }
  183.     (void) fprintf(stderr, "%s: unknown dbm command %s", Progname, *Argv);
  184.     } else
  185.     (void) fprintf(stderr, "%s: missing dbm command", Progname);
  186.     (void) fprintf(stderr, ", use one of the following:\n");
  187.     for (cmd = CommandTable; cmd < &CommandTable[sizeof(CommandTable) /
  188.                          sizeof(*CommandTable)]; cmd++)
  189.     (void) fprintf(stderr, "%s%s", cmd == CommandTable ? "" : "\t",
  190.                cmd->c_name);
  191.     (void) fprintf(stderr, "\n");
  192.     exit(3);
  193. }
  194.  
  195. void
  196. opendbm(access, LockType)
  197.      int access, LockType;
  198. {
  199.     if (Dbmfile == NULL) {
  200.     if (Argc > 1) {
  201.         /* use last argument */
  202.         Dbmfile = Argv[Argc-1];
  203.         Argc--;
  204.     } else {
  205.         (void) fprintf(stderr, "%s: dbm file not specified\n", Progname);
  206.         exit(3);
  207.     }
  208.     }
  209.     Dbm = dbm_open(Dbmfile, access, Mode);
  210.     if (Dbm == NULL) {
  211.     char *filename = (char *) malloc((unsigned) strlen(Dbmfile) + 20);
  212.     (void) sprintf(filename, "%s{%s,%s}", Dbmfile, DB_DIREXT, DB_PAGEXT);
  213.     perror(filename);
  214.     exit(4);
  215.     }
  216. #ifndef GDBM
  217.     if (flock(dbm_dirfno(Dbm), LockType) < 0) {
  218.         (void) fprintf(stderr, "%s: cannot lock %s\n",
  219.         Progname, Dbmfile);
  220.         exit(3);
  221.     }
  222. #endif /* !GDBM */
  223.     Dbmaccess = access;
  224. }
  225.  
  226. void
  227. closedbm()
  228. {
  229.     if ((Dbmaccess & O_RDONLY) == 0 && Senteniel != NULL) {
  230.     MAKEDATUM(key, Senteniel);
  231.     if (dbm_store(Dbm, key, key, DBM_REPLACE) != 0) {
  232.         (void) fprintf(stderr, "%s: could not store senteniel \"%s\"\n",
  233.                Progname, Senteniel);
  234.         perror(Progname);
  235.         exit(5);
  236.     }
  237.     }
  238. #ifndef GDBM
  239.     (void) flock(dbm_dirfno(Dbm), LOCK_UN);
  240. #endif /* !GDBM */
  241.     dbm_close(Dbm);
  242. }
  243.  
  244. FILE *
  245. openfile(filename, access)
  246.      const char *filename;
  247.      const char *access;
  248. {
  249.     FILE *f;
  250.  
  251.     if (streq(filename, "-"))
  252.     if (streq(access, "r"))
  253.         return stdin;
  254.     else
  255.         return stdout;
  256.     else {
  257.     f = fopen(filename, access);
  258.     if (f == NULL) {
  259.         perror(filename);
  260.         exit(4);
  261.     }
  262.     return f;
  263.     }
  264. }
  265.  
  266. void
  267. closefile(f)
  268.      FILE *f;
  269. {
  270.     if (f != stdin && f != stdout)
  271.     (void) fclose(f);
  272. }
  273. /*
  274. **    DO_CLEAR -- Clear out database leaving it emtpy.
  275. */
  276.  
  277. void
  278. do_clear()
  279. {
  280.     if (Dbmfile != NULL) {
  281.     opendbm(O_RDWR | O_CREAT | O_TRUNC, LOCK_EX);
  282.     closedbm();
  283.     }
  284.     while (Argc > 1) {
  285.     opendbm(O_RDWR | O_CREAT | O_TRUNC, LOCK_EX);
  286.     closedbm();
  287.     }
  288. }
  289.  
  290.    
  291. /*
  292. **    DO_DELETE -- Delete individual entries from the database.
  293. */
  294.  
  295. void
  296. do_delete()
  297. {
  298.     opendbm(O_RDWR | O_CREAT, LOCK_EX);
  299.  
  300.     for (Argc--, Argv++; Argc > 0; Argc--, Argv++) {
  301.     casify(*Argv, Casing);
  302.     MAKEDATUM(key, *Argv);
  303.     if (dbm_delete(Dbm, key) != 0) {
  304.         perror(*Argv);
  305.         exit(5);
  306.     }
  307.     }
  308.  
  309.     closedbm();
  310. }
  311.  
  312. /*
  313. **    DO_DUMP -- List all entries in the database.
  314. */
  315.  
  316. void
  317. do_dump()
  318. {
  319.     FILE *output;
  320.     
  321.     opendbm(O_RDONLY, LOCK_SH);
  322.  
  323.     if (Outfile == NULL)
  324.     output = stdout;
  325.     else
  326.     output = openfile(Outfile, "w");
  327.  
  328.     for (key = dbm_firstkey(Dbm); key.dptr != NULL; key = dbm_nextkey(Dbm)) {
  329.     val = dbm_fetch(Dbm, key);
  330.     CHECKDATUM(key);
  331.     CHECKDATUM(val);
  332.     if (val.dptr == NULL)
  333.         perror(key.dptr);
  334.     else if (Valueonly)
  335.         (void) fprintf(output, "%.*s\n", val.dsize, val.dptr);
  336.     else
  337.         (void) fprintf(output, "%.*s\t%.*s\n", key.dsize, key.dptr,
  338.                val.dsize, val.dptr);
  339.     }
  340. }
  341. /*
  342. **    DO_FETCH -- Lookup individual keys in the database.
  343. */
  344.  
  345. void
  346. do_fetch()
  347. {
  348.     char buf[BUFSIZ];
  349.     register char *nl;
  350.  
  351.     opendbm(O_RDONLY, LOCK_SH);
  352.  
  353.     if (Argc == 1) {
  354.     while (fgets(buf, sizeof(buf), stdin) != NULL) {
  355.         if ((nl = index(buf, '\n')) != NULL)
  356.         *nl = '\0';
  357.         casify(buf, Casing);
  358.         MAKEDATUM(key, buf);
  359.         val = dbm_fetch(Dbm, key);
  360.         CHECKDATUM(val);
  361.         if (val.dptr == NULL)
  362.         (void) printf("%s\t[NOT FOUND]\n", buf);
  363.         else if (Valueonly)
  364.         (void) printf("%.*s\n", val.dsize, val.dptr);
  365.         else
  366.         (void) printf("%s\t%.*s\n", buf, val.dsize, val.dptr);
  367.     }
  368.     }
  369.     else
  370.     for (Argc--, Argv++; Argc > 0; Argc--, Argv++) {
  371.     casify(*Argv, Casing);
  372.     MAKEDATUM(key, *Argv);
  373.     val = dbm_fetch(Dbm, key);
  374.     CHECKDATUM(val);
  375.     if (val.dptr == NULL)
  376.         (void) printf("%s\t[NOT FOUND]\n", *Argv);
  377.     else if (Valueonly)
  378.         (void) printf("%.*s\n", val.dsize, val.dptr);
  379.     else
  380.         (void) printf("%s\t%.*s\n", *Argv, val.dsize, val.dptr);
  381.     }
  382.  
  383.     closedbm();
  384. }
  385.  
  386. /*
  387. **    DO_STORE -- Insert individual entries into the database.
  388. */
  389.  
  390. void
  391. do_store()
  392. {
  393.     /* barf if # of args - 1 is even and no dbm file has been specified */
  394.     if ((Argc & 1) == 1 && Dbmfile == NULL) {
  395.     (void) fprintf(stderr, "%s: no dbm file specified\n", Progname);
  396.     exit(3);
  397.     }
  398.  
  399.     opendbm(O_RDWR | O_CREAT, LOCK_EX);
  400.  
  401.     for (Argc--, Argv++; Argc > 1; Argc -= 2, Argv += 2) {
  402.     casify(Argv[0], Casing);
  403.     MAKEDATUM(key, Argv[0]);
  404.     MAKEDATUM(val, Argv[1]);
  405.     if (dbm_store(Dbm, key, val, Storeflag) != 0) {
  406.         extern int errno;
  407.  
  408.         if (errno != 0) {
  409.         perror(Argv[0]);
  410.         exit(5);
  411.         } else if (Storewarn)
  412.         (void) fprintf(stderr,
  413.                    "%s: duplicate key \"%s\" => \"%s\" ignored\n",
  414.                    Progname, Argv[0], Argv[1]);
  415.     }
  416.     }
  417.     if (Argc > 0)
  418.     (void) fprintf(stderr, "%s: no value for last key \"%s\"--ignored\n",
  419.                Progname, Argv[0]);
  420.  
  421.     closedbm();
  422. }
  423.  
  424. /*
  425. **    DO_PARSE -- Parse a textual database file and produce key-value
  426. **        pairs separated by a tab (suitable for input to the ``load''
  427. **        function).
  428. */
  429.  
  430. void
  431. do_parse()
  432. {
  433.     FILE *input, *output;
  434.     
  435.     if (Outfile == NULL)
  436.     output = stdout;
  437.     else
  438.     output = openfile(Outfile, "w");
  439.  
  440.     if (Argc == 1)
  441.     parsefile(stdin, output);
  442.     else
  443.     for (Argc--, Argv++; Argc > 0; Argc--, Argv++) {
  444.         input = openfile(*Argv, "r");
  445.         parsefile(input, output);
  446.         closefile(input);
  447.     }
  448. }
  449.  
  450. /*
  451. **    DO_MAKE -- Parse the textual input and load the result into
  452. **        the database.
  453. */
  454.  
  455. void
  456. do_make()
  457. {
  458.     FILE *input, *pipin, *pipout;
  459.     int pipes[2];
  460.  
  461.     opendbm(O_RDWR | O_CREAT | (Appending ? 0 : O_TRUNC), LOCK_EX);
  462.  
  463.     if (pipe(pipes) != 0) {
  464.     perror("pipe");
  465.     exit(9);
  466.     }
  467.     pipin = fdopen(pipes[0], "r");
  468.     pipout = fdopen(pipes[1], "w");
  469.  
  470.     if (fork() == 0) {
  471.     /* child process */
  472.     (void) fclose(pipout);
  473.  
  474.     loadfile(pipin);
  475.     } else {
  476.     /* parent process */
  477.     (void) fclose(pipin);
  478.  
  479.     if (Argc == 1)
  480.         parsefile(stdin, pipout);
  481.     else
  482.         for (Argc--, Argv++; Argc > 0; Argc--, Argv++) {
  483.         input = openfile(*Argv, "r");
  484.         parsefile(input, pipout);
  485.         closefile(input);
  486.         }
  487.     }
  488.     closedbm();
  489. }
  490.  
  491. /*
  492. **    DO_LOAD -- Load the dbm database from a text file.  The input should
  493. **        be key-value pairs separated by a tab, each on a single line.
  494. */
  495.  
  496. void
  497. do_load()
  498. {
  499.     FILE *input;
  500.  
  501.     opendbm(O_RDWR | O_CREAT | (Appending ? 0 : O_TRUNC), LOCK_EX);
  502.  
  503.     if (Argc == 1)
  504.     loadfile(stdin);
  505.     else
  506.     for (Argc--, Argv++; Argc > 0; Argc--, Argv++) {
  507.         input = openfile(*Argv, "r");
  508.         loadfile(input);
  509.         closefile(input);
  510.     }
  511.     closedbm();
  512. }    
  513.  
  514. /*
  515. **    PARSEFILE, LOADFILE
  516. */ 
  517.  
  518. void
  519. parsefile(input, output)
  520.      FILE *input, *output;
  521. {
  522.     char buf[BUFSIZ], *key, *val = NULL;
  523.     register char *p;
  524.  
  525.     while (fgets(buf, sizeof(buf), input) != NULL) {
  526.     if (buf[0] == COMMENTCHAR || buf[0] == '\n' || buf[0] == '\0')
  527.         continue;
  528.     p=buf;
  529.     if (!isspace(buf[0])) {
  530.         /* extract value */
  531.         p = scantoken(buf);
  532.         if (val != NULL)
  533.         free(val);
  534.         val = (char *) malloc((unsigned) (p - buf + 1));
  535.         (void) strncpy(val, buf, p - buf);
  536.         val[p - buf] = '\0';
  537.         p++;
  538.     }
  539.     casify(buf, Casing);
  540.     while ( *p != '\0') {
  541.         while (*p != '\0' && isspace(*p)) p++;
  542.         if (*p == '\0' || *p == COMMENTCHAR)
  543.         break;
  544.         key = p;
  545.         p = scantoken(p);
  546.         if (*p == COMMENTCHAR)
  547.         *p = '\0';
  548.         else if (*p != '\0')
  549.         *p++ = '\0';
  550.         (void) fprintf(output, "%s\t%s\n", key, val);
  551.     }
  552.     }
  553. }
  554.  
  555. void
  556. loadfile(input)
  557.      FILE *input;
  558. {
  559.     char buf[BUFSIZ];
  560.     register char *tab, *nl;
  561.  
  562.     while (fgets(buf, sizeof(buf), input) != NULL) {
  563.     nl = index(buf, '\n');
  564.     if (nl != NULL)
  565.         *nl = '\0';
  566.  
  567.     tab = index(buf, '\t');
  568.     if (tab == NULL) {
  569.         (void) fprintf(stderr, "%s: missing tab in \"%s\"--ignored\n",
  570.                Progname, buf);
  571.         continue;
  572.     }
  573.     *tab++ = '\0';
  574.     casify(buf, Casing);
  575.     MAKEDATUM(key, buf);
  576.     MAKEDATUM(val, tab);
  577.     if (dbm_store(Dbm, key, val, Storeflag) != 0 && Storewarn) {
  578.         extern int errno;
  579.  
  580.         if (errno != 0) {
  581.         perror(buf);
  582.         exit(5);
  583.         } else if (Storewarn)
  584.         (void) fprintf(stderr,
  585.                    "%s: duplicate key \"%s\" => \"%s\" ignored\n",
  586.                    Progname, buf, tab);
  587.     }
  588.     }
  589. }
  590.  
  591. char *
  592. scantoken(p)
  593.      register const char *p;
  594. {
  595.   register bool quotedchar = FALSE, insidestring = FALSE, insideroute = FALSE;
  596.  
  597.   /* hidious address scanner */
  598.   while (*p != '\0' && (quotedchar || insidestring || insideroute || 
  599.             (*p != COMMENTCHAR && !isspace(*p)))) {
  600.     /* special quote character handling */
  601.     if (quotedchar)
  602.       quotedchar = FALSE;
  603.     else {
  604.       quotedchar = (*p == '\\');
  605.       if (!insidestring)
  606.     if (*p == '<')
  607.       insideroute = TRUE;
  608.     else if (*p == '>')
  609.       insideroute = FALSE;
  610.       if (*p == '"')
  611.     insidestring = !insidestring;
  612.     }
  613.     p++;
  614.   }
  615.  
  616.   return (char *)p;
  617. }
  618.  
  619. void
  620. casify(p, c)
  621.      register char *p;
  622.      int c;
  623. {
  624.     switch (c) {
  625.       case LOWERCASE:
  626.     for (; *p != '\0'; p++)
  627.         if (isupper(*p))
  628.         *p = tolower(*p);
  629.     break;
  630.       case UPPERCASE:
  631.     for (; *p != '\0'; p++)
  632.         if (islower(*p))
  633.         *p = toupper(*p);
  634.     break;
  635.     }
  636. }
  637.