From d15439ee765ec027db49777ebd9760be20ba3b31 Mon Sep 17 00:00:00 2001 From: kvik Date: Sun, 6 Dec 2020 21:52:01 +0100 Subject: [PATCH] ptrap: implement filtering on plumb attributes --- sys/man/4/ptrap | 42 +++++++++++++++++------------- sys/src/cmd/ptrap.c | 62 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 77 insertions(+), 27 deletions(-) diff --git a/sys/man/4/ptrap b/sys/man/4/ptrap index 5c29956ad..35238b4c9 100644 --- a/sys/man/4/ptrap +++ b/sys/man/4/ptrap @@ -7,10 +7,7 @@ filter .B ptrap .I port [\fB!\fR]\fIregexp\fR -[ -.I port -[\fB!\fR]\fIregexp\fR ... -] +[ +\fIattr\fR [\fB!\fR]\fIregexp\fR ... ] ... .SH DESCRIPTION .I Ptrap is a program that mounts itself over a @@ -20,20 +17,20 @@ service mounted at and filters incoming messages according to the rules provided on the command line. .PP .I Ptrap -accepts an arbitrary number of argument pairs; each pair consists of a port name -.I port -and a regular expression -.I regexp -(see -.IR regexp (6)). -Each incoming message that does not match -.I regexp -is discarded. -The -.I regexp -can be optionally prefixed by -.B ! -to indicate logical inversion (i.e. messages matching the regexp are discarded). +accepts an arbitrary number of filters; +each filter applies to a port, and may match over both the data and attributes of plumb messages. +.PP +A filter is formatted as a port name, a data filter, and a list of attribute filters. +.PP +The data filter is a +.IR regex (6) +that matches the plumbed data. +The attribute filter consists of the attribute name prefixed with a '+', followed by a +.IR regex (6) +that matches the contents of the attribute. +Any regex may be prefixed with a '!' in order to negate a match, +causing all matches for that regex to be discarded. +All parts of a filter must match in order for a plumb message to be forwarded. .SH EXAMPLES Start a .IR sam (1) @@ -52,6 +49,15 @@ instance for all other editing jobs: ptrap edit '!^/sys/src/9/' sam .EE +.PP +Start an +.IR acme (1) +instance instance dedicated to reading plumbed manual pages: +.IP +.EX +ptrap edit '.*' +action '^showdata' +filename '^/man/' +acme -c1 +.EE .SH SOURCE .B /sys/src/cmd/ptrap.c .SH SEE ALSO diff --git a/sys/src/cmd/ptrap.c b/sys/src/cmd/ptrap.c index 7cf60f7d4..dae3c088d 100644 --- a/sys/src/cmd/ptrap.c +++ b/sys/src/cmd/ptrap.c @@ -8,6 +8,7 @@ typedef struct IOProc IOProc; typedef struct PFilter PFilter; +typedef struct FAttr FAttr; typedef struct PFid PFid; struct IOProc { @@ -27,11 +28,19 @@ struct PFid { }; Qid rootqid = {.type QTDIR}; +struct FAttr { + char *name; + Reprog *filt; + int invert; + FAttr *next; +}; + struct PFilter { char *name; Reprog *filt; - PFilter *next; int invert; + FAttr *attr; + PFilter *next; }; PFilter *filters; @@ -161,13 +170,33 @@ ptrapopen(Req *r) respond(r, nil); } +static int +filter(PFilter *f, Plumbmsg *pm) +{ + FAttr *a; + char *value; + + if(!(regexec(f->filt, pm->data, nil, 0) ^ f->invert)) + return 0; + for(a = f->attr; a; a = a->next){ + value = plumblookup(pm->attr, a->name); + if(value == nil) + return 0; + if(!(regexec(a->filt, value, nil, 0) ^ f->attr->invert)) + return 0; + } + return 1; +} + static int filterread(Req *r, PFid *pf) { int rc, len, more; char *buf; Plumbmsg *pm; + PFilter *f; + f = pf->filter; for(;;){ if(pf->msg != nil){ rc = r->ifcall.count; @@ -194,7 +223,7 @@ filterread(Req *r, PFid *pf) len += rc; } free(buf); - if(regexec(pf->filter->filt, pm->data, nil, 0) ^ pf->filter->invert){ + if(filter(f, pm)){ pf->msg = plumbpack(pm, &pf->msgn); pf->msgp = 0; } @@ -341,7 +370,7 @@ Srv ptrapsrv = { void usage(void) { - fprint(2, "usage: %s port regex [ port regex ... ]\n", argv0); + fprint(2, "usage: %s port regex [ +attr regex ... ] ...\n", argv0); exits("usage"); } @@ -349,6 +378,7 @@ void threadmain(int argc, char **argv) { PFilter *f; + FAttr *fa; char *p; int i; @@ -357,19 +387,33 @@ threadmain(int argc, char **argv) }ARGEND; if(argc == 0 || argc % 2) usage(); - for(i = 0; i < argc; i += 2){ + for(i = 0; i+1 < argc;){ + p = argv[i]; f = emalloc9p(sizeof(PFilter)); - f->name = strdup(argv[i]); + f->name = estrdup9p(p); p = argv[i+1]; - if(*p == '!'){ + if(p[0] == '!'){ p++; f->invert = 1; } - f->filt = regcomp(p); - if(f->filt == nil) - sysfatal("%r"); + if((f->filt = regcomp(p)) == nil) + sysfatal("regcomp: %r"); f->next = filters; filters = f; + for(i += 2; p = argv[i], i+1 < argc && p[0] == '+'; i += 2){ + p++; + fa = emalloc9p(sizeof(FAttr)); + fa->name = estrdup9p(p); + p = argv[i+1]; + if(p[0] == '!'){ + p++; + fa->invert = 1; + } + if((fa->filt = regcomp(p)) == nil) + sysfatal("regcomp: %r"); + fa->next = f->attr; + f->attr = fa; + } } threadpostmountsrv(&ptrapsrv, nil, "/mnt/plumb", MREPL | MCREATE);