I have an OK on the man page bits.  Anyone else want to chime in?

 - todd

On Wed, 18 Oct 2017 10:22:00 -0600, "Todd C. Miller" wrote:

> I often want to query a specific key instead of dumping out the
> entire database.  This lets you do things like:
> 
> $ spamdb 180.124.41.143
> TRAPPED|180.124.41.143|1508373987
> 
> or:
> 
> $ spamdb 74.125.198.26 180.124.41.143 107.161.26.205
> WHITE|74.125.198.26|||1506223558|1506223558|1509333958|1|0
> TRAPPED|180.124.41.143|1508373987
> 
> No error is displayed for missing addresses but the exit value will
> be 1 instead of 0 in this case.
> 
>  - todd
> 
> Index: usr.sbin/spamdb/spamdb.8
> ===================================================================
> RCS file: /cvs/src/usr.sbin/spamdb/spamdb.8,v
> retrieving revision 1.19
> diff -u -p -u -r1.19 spamdb.8
> --- usr.sbin/spamdb/spamdb.8  11 Oct 2017 18:25:07 -0000      1.19
> +++ usr.sbin/spamdb/spamdb.8  18 Oct 2017 16:17:41 -0000
> @@ -22,10 +22,8 @@
>  .Nd spamd database tool
>  .Sh SYNOPSIS
>  .Nm spamdb
> -.Oo Oo Fl Tt Oc
> -.Fl a Ar keys Oc
> -.Oo Oo Fl GTt Oc
> -.Fl d Ar keys Oc
> +.Op Fl adGTt
> +.Op Ar keys ...
>  .Sh DESCRIPTION
>  .Nm
>  manipulates the spamd database in
> @@ -35,7 +33,7 @@ used for
>  .Pp
>  The options are as follows:
>  .Bl -tag -width Ds
> -.It Fl a Ar keys
> +.It Fl a
>  Add or update the entries for
>  .Ar keys .
>  This can be used to whitelist one or more IP addresses
> @@ -46,7 +44,7 @@ If any
>  specified match entries already in the spamd database,
>  .Nm
>  updates the entry's time last seen to now.
> -.It Fl d Ar keys
> +.It Fl d
>  Delete entries for
>  .Ar keys .
>  .It Fl G
> @@ -90,9 +88,12 @@ Otherwise
>  .Ar keys
>  must be numerical IP addresses.
>  .Ss DATABASE OUTPUT FORMAT
> -If invoked without any arguments,
> +If invoked without any options,
>  .Nm
>  lists the contents of the database in a text format.
> +If one or more
> +.Ar keys
> +are specified, only matching entries will be printed.
>  .Pp
>  For SPAMTRAP entries the format is:
>  .Pp
> Index: usr.sbin/spamdb/spamdb.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/spamdb/spamdb.c,v
> retrieving revision 1.33
> diff -u -p -u -r1.33 spamdb.c
> --- usr.sbin/spamdb/spamdb.c  12 Oct 2017 09:28:56 -0000      1.33
> +++ usr.sbin/spamdb/spamdb.c  18 Oct 2017 16:21:21 -0000
> @@ -186,10 +186,81 @@ dbupdate(DB *db, char *ip, int add, int 
>  }
>  
>  int
> +print_entry(DBT *dbk, DBT *dbd)
> +{
> +     struct gdata gd;
> +     char *a, *cp;
> +
> +     if ((dbk->size < 1) || gdcopyin(dbd, &gd) == -1) {
> +             warnx("bogus size db entry - bad db file?");
> +             return (1);
> +     }
> +     a = malloc(dbk->size + 1);
> +     if (a == NULL)
> +             err(1, "malloc");
> +     memcpy(a, dbk->data, dbk->size);
> +     a[dbk->size]='\0';
> +     cp = strchr(a, '\n');
> +     if (cp == NULL) {
> +             /* this is a non-greylist entry */
> +             switch (gd.pcount) {
> +             case -1: /* spamtrap hit, with expiry time */
> +                     printf("TRAPPED|%s|%lld\n", a,
> +                         (long long)gd.expire);
> +                     break;
> +             case -2: /* spamtrap address */
> +                     printf("SPAMTRAP|%s\n", a);
> +                     break;
> +             default: /* whitelist */
> +                     printf("WHITE|%s|||%lld|%lld|%lld|%d|%d\n", a,
> +                         (long long)gd.first, (long long)gd.pass,
> +                         (long long)gd.expire, gd.bcount,
> +                         gd.pcount);
> +                     break;
> +             }
> +     } else {
> +             char *helo, *from, *to;
> +
> +             /* greylist entry */
> +             *cp = '\0';
> +             helo = cp + 1;
> +             from = strchr(helo, '\n');
> +             if (from == NULL) {
> +                     warnx("No from part in grey key %s", a);
> +                     free(a);
> +                     return (1);
> +             }
> +             *from = '\0';
> +             from++;
> +             to = strchr(from, '\n');
> +             if (to == NULL) {
> +                     /* probably old format - print it the
> +                      * with an empty HELO field instead 
> +                      * of erroring out.
> +                      */                       
> +                     printf("GREY|%s|%s|%s|%s|%lld|%lld|%lld|%d|%d\n",
> +                         a, "", helo, from, (long long)gd.first,
> +                         (long long)gd.pass, (long long)gd.expire,
> +                         gd.bcount, gd.pcount);
> +             
> +             } else {
> +                     *to = '\0';
> +                     to++;
> +                     printf("GREY|%s|%s|%s|%s|%lld|%lld|%lld|%d|%d\n",
> +                         a, helo, from, to, (long long)gd.first,
> +                         (long long)gd.pass, (long long)gd.expire,
> +                         gd.bcount, gd.pcount);
> +             }
> +     }
> +     free(a);
> +
> +     return (0);
> +}
> +
> +int
>  dblist(DB *db)
>  {
>       DBT             dbk, dbd;
> -     struct gdata    gd;
>       int             r;
>  
>       /* walk db, list in text format */
> @@ -197,80 +268,52 @@ dblist(DB *db)
>       memset(&dbd, 0, sizeof(dbd));
>       for (r = db->seq(db, &dbk, &dbd, R_FIRST); !r;
>           r = db->seq(db, &dbk, &dbd, R_NEXT)) {
> -             char *a, *cp;
> -
> -             if ((dbk.size < 1) || gdcopyin(&dbd, &gd) == -1) {
> -                     db->close(db);
> -                     errx(1, "bogus size db entry - bad db file?");
> -             }
> -             a = malloc(dbk.size + 1);
> -             if (a == NULL)
> -                     err(1, "malloc");
> -             memcpy(a, dbk.data, dbk.size);
> -             a[dbk.size]='\0';
> -             cp = strchr(a, '\n');
> -             if (cp == NULL) {
> -                     /* this is a non-greylist entry */
> -                     switch (gd.pcount) {
> -                     case -1: /* spamtrap hit, with expiry time */
> -                             printf("TRAPPED|%s|%lld\n", a,
> -                                 (long long)gd.expire);
> -                             break;
> -                     case -2: /* spamtrap address */
> -                             printf("SPAMTRAP|%s\n", a);
> -                             break;
> -                     default: /* whitelist */
> -                             printf("WHITE|%s|||%lld|%lld|%lld|%d|%d\n", a,
> -                                 (long long)gd.first, (long long)gd.pass,
> -                                 (long long)gd.expire, gd.bcount,
> -                                 gd.pcount);
> -                             break;
> -                     }
> -             } else {
> -                     char *helo, *from, *to;
> -
> -                     /* greylist entry */
> -                     *cp = '\0';
> -                     helo = cp + 1;
> -                     from = strchr(helo, '\n');
> -                     if (from == NULL) {
> -                             warnx("No from part in grey key %s", a);
> -                             free(a);
> -                             goto bad;
> -                     }
> -                     *from = '\0';
> -                     from++;
> -                     to = strchr(from, '\n');
> -                     if (to == NULL) {
> -                             /* probably old format - print it the
> -                              * with an empty HELO field instead 
> -                              * of erroring out.
> -                              */                       
> -                             printf("GREY|%s|%s|%s|%s|%lld|%lld|%lld|%d|%d\n
> ",
> -                                 a, "", helo, from, (long long)gd.first,
> -                                 (long long)gd.pass, (long long)gd.expire,
> -                                 gd.bcount, gd.pcount);
> -                     
> -                     } else {
> -                             *to = '\0';
> -                             to++;
> -                             printf("GREY|%s|%s|%s|%s|%lld|%lld|%lld|%d|%d\n
> ",
> -                                 a, helo, from, to, (long long)gd.first,
> -                                 (long long)gd.pass, (long long)gd.expire,
> -                                 gd.bcount, gd.pcount);
> -                     }
> +             if (print_entry(&dbk, &dbd) != 0) {
> +                     r = -1;
> +                     break;
>               }
> -             free(a);
>       }
>       db->close(db);
>       db = NULL;
> -     return (0);
> - bad:
> +     return (r == -1);
> +}
> +
> +int
> +dbshow(DB *db, char **addrs)
> +{
> +     DBT dbk, dbd;
> +     int errors = 0;
> +     char *a;
> +
> +     /* look up each addr */
> +     while ((a = *addrs) != NULL) {
> +             memset(&dbk, 0, sizeof(dbk));
> +             dbk.size = strlen(a);
> +             dbk.data = a;
> +             memset(&dbd, 0, sizeof(dbd));
> +             switch (db->get(db, &dbk, &dbd, 0)) {
> +             case -1:
> +                     warn("db->get failed");
> +                     errors++;
> +                     goto done;
> +             case 0:
> +                     if (print_entry(&dbk, &dbd) != 0) {
> +                             errors++;
> +                             goto done;
> +                     }
> +                     break;
> +             case 1:
> +             default:
> +                     /* not found */
> +                     errors++;
> +                     break;
> +             }
> +             addrs++;
> +     }
> + done:
>       db->close(db);
>       db = NULL;
> -     errx(1, "incorrect db format entry");
> -     /* NOTREACHED */
> -     return (1);
> +     return (errors);
>  }
>  
>  extern char *__progname;
> @@ -278,7 +321,7 @@ extern char *__progname;
>  static int
>  usage(void)
>  {
> -     fprintf(stderr, "usage: %s [[-Tt] -a keys] [[-GTt] -d keys]\n", __progn
> ame);
> +     fprintf(stderr, "usage: %s [-adGTt] [keys ...]\n", __progname);
>       exit(1);
>       /* NOTREACHED */
>  }
> @@ -335,7 +378,10 @@ main(int argc, char **argv)
>  
>       switch (action) {
>       case 0:
> -             return dblist(db);
> +             if (argc)
> +                     return dbshow(db, argv);
> +             else
> +                     return dblist(db);
>       case 1:
>               if (type == GREY)
>                       errx(2, "cannot add GREY entries");
> 

Reply via email to