shithub: riscv

Download patch

ref: d15439ee765ec027db49777ebd9760be20ba3b31
parent: cd38d4135633fd2dd9ce544aa3c2c86cf5078f8d
author: kvik <[email protected]>
date: Sun Dec 6 16:52:01 EST 2020

ptrap: implement filtering on plumb attributes

--- a/sys/man/4/ptrap
+++ b/sys/man/4/ptrap
@@ -7,10 +7,7 @@
 .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 @@
 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)
@@ -51,6 +48,15 @@
 .EX
 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
--- 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 @@
 };
 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;
 
@@ -162,12 +171,32 @@
 }
 
 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 @@
 			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 @@
 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 @@
 threadmain(int argc, char **argv)
 {
 	PFilter *f;
+	FAttr *fa;
 	char *p;
 	int i;
 
@@ -357,19 +387,33 @@
 	}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);