ptrap: implement filtering on plumb attributes
This commit is contained in:
parent
cd38d41356
commit
d15439ee76
2 changed files with 77 additions and 27 deletions
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue