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"); >