ptrap: implement filtering on plumb attributes

This commit is contained in:
kvik 2020-12-06 21:52:01 +01:00
parent cd38d41356
commit d15439ee76
2 changed files with 77 additions and 27 deletions

View file

@ -7,10 +7,7 @@ filter
.B ptrap .B ptrap
.I port .I port
[\fB!\fR]\fIregexp\fR [\fB!\fR]\fIregexp\fR
[ [ +\fIattr\fR [\fB!\fR]\fIregexp\fR ... ] ...
.I port
[\fB!\fR]\fIregexp\fR ...
]
.SH DESCRIPTION .SH DESCRIPTION
.I Ptrap .I Ptrap
is a program that mounts itself over a 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. and filters incoming messages according to the rules provided on the command line.
.PP .PP
.I Ptrap .I Ptrap
accepts an arbitrary number of argument pairs; each pair consists of a port name accepts an arbitrary number of filters;
.I port each filter applies to a port, and may match over both the data and attributes of plumb messages.
and a regular expression .PP
.I regexp A filter is formatted as a port name, a data filter, and a list of attribute filters.
(see .PP
.IR regexp (6)). The data filter is a
Each incoming message that does not match .IR regex (6)
.I regexp that matches the plumbed data.
is discarded. The attribute filter consists of the attribute name prefixed with a '+', followed by a
The .IR regex (6)
.I regexp that matches the contents of the attribute.
can be optionally prefixed by Any regex may be prefixed with a '!' in order to negate a match,
.B ! causing all matches for that regex to be discarded.
to indicate logical inversion (i.e. messages matching the regexp are discarded). All parts of a filter must match in order for a plumb message to be forwarded.
.SH EXAMPLES .SH EXAMPLES
Start a Start a
.IR sam (1) .IR sam (1)
@ -52,6 +49,15 @@ instance for all other editing jobs:
ptrap edit '!^/sys/src/9/' ptrap edit '!^/sys/src/9/'
sam sam
.EE .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 .SH SOURCE
.B /sys/src/cmd/ptrap.c .B /sys/src/cmd/ptrap.c
.SH SEE ALSO .SH SEE ALSO

View file

@ -8,6 +8,7 @@
typedef struct IOProc IOProc; typedef struct IOProc IOProc;
typedef struct PFilter PFilter; typedef struct PFilter PFilter;
typedef struct FAttr FAttr;
typedef struct PFid PFid; typedef struct PFid PFid;
struct IOProc { struct IOProc {
@ -27,11 +28,19 @@ struct PFid {
}; };
Qid rootqid = {.type QTDIR}; Qid rootqid = {.type QTDIR};
struct FAttr {
char *name;
Reprog *filt;
int invert;
FAttr *next;
};
struct PFilter { struct PFilter {
char *name; char *name;
Reprog *filt; Reprog *filt;
PFilter *next;
int invert; int invert;
FAttr *attr;
PFilter *next;
}; };
PFilter *filters; PFilter *filters;
@ -161,13 +170,33 @@ ptrapopen(Req *r)
respond(r, nil); 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 static int
filterread(Req *r, PFid *pf) filterread(Req *r, PFid *pf)
{ {
int rc, len, more; int rc, len, more;
char *buf; char *buf;
Plumbmsg *pm; Plumbmsg *pm;
PFilter *f;
f = pf->filter;
for(;;){ for(;;){
if(pf->msg != nil){ if(pf->msg != nil){
rc = r->ifcall.count; rc = r->ifcall.count;
@ -194,7 +223,7 @@ filterread(Req *r, PFid *pf)
len += rc; len += rc;
} }
free(buf); 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->msg = plumbpack(pm, &pf->msgn);
pf->msgp = 0; pf->msgp = 0;
} }
@ -341,7 +370,7 @@ Srv ptrapsrv = {
void void
usage(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"); exits("usage");
} }
@ -349,6 +378,7 @@ void
threadmain(int argc, char **argv) threadmain(int argc, char **argv)
{ {
PFilter *f; PFilter *f;
FAttr *fa;
char *p; char *p;
int i; int i;
@ -357,19 +387,33 @@ threadmain(int argc, char **argv)
}ARGEND; }ARGEND;
if(argc == 0 || argc % 2) usage(); 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 = emalloc9p(sizeof(PFilter));
f->name = strdup(argv[i]); f->name = estrdup9p(p);
p = argv[i+1]; p = argv[i+1];
if(*p == '!'){ if(p[0] == '!'){
p++; p++;
f->invert = 1; f->invert = 1;
} }
f->filt = regcomp(p); if((f->filt = regcomp(p)) == nil)
if(f->filt == nil) sysfatal("regcomp: %r");
sysfatal("%r");
f->next = filters; f->next = filters;
filters = f; 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); threadpostmountsrv(&ptrapsrv, nil, "/mnt/plumb", MREPL | MCREATE);