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", 
__progname);
+       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