+int
+filter(int fd, char *host)
+{
+ char addr[128], buf[256], *s, *file, *argv[16];
+ int p[2], lfd, flags, len, argc;
+
+ if(filterp == nil)
+ return fd;
+ procsetname("filter %s", filterp);
+ flags = RFNOWAIT|RFPROC|RFMEM|RFFDG;
+ if(host == nil){
+ /* remote side */
+ if(announce(anstring, addr) < 0)
+ fatal("filter: Cannot announce %s: %r", anstring);
+ snprint(buf, sizeof(buf), "%s/local", addr);
+ if((lfd = open(buf, OREAD)) < 0)
+ fatal("filter: Cannot open %s: %r", buf);
+ if((len = read(lfd, buf, sizeof buf - 1)) < 0)
+ fatal("filter: Cannot read %s: %r", buf);
+ close(lfd);
+ buf[len] = 0;
+ if(s = strchr(buf, '\n'))
+ len = s - buf;
+ if(write(fd, buf, len) != len)
+ fatal("filter: cannot write port; %r");
+ } else {
+ /* client side */
+ flags |= RFNOTEG;
+ if((len = read(fd, buf, sizeof buf - 1)) < 0)
+ fatal("filter: cannot read port; %r");
+ buf[len] = '\0';
+ if((s = strrchr(buf, '!')) == nil)
+ fatal("filter: malformed remote port: %s", buf);
+ snprint(addr, sizeof(addr), "%s", netmkaddr(host, "tcp", s+1));
+ }
+
+ snprint(buf, sizeof(buf), "%s", filterp);
+ if((argc = tokenize(buf, argv, nelem(argv)-3)) <= 0)
+ fatal("filter: empty command");
+ if(host)
+ argv[argc++] = "-c";
+ argv[argc++] = addr;
+ argv[argc] = nil;
+ file = argv[0];
+ if(s = strrchr(argv[0], '/'))
+ argv[0] = s+1;
+
+ if(pipe(p) < 0)
+ fatal("filter: pipe; %r");
+
+ switch(rfork(flags)) {
+ case -1:
+ fatal("filter: rfork; %r\n");
+ case 0:
+ if (dup(p[0], 1) < 0)
+ fatal("filter: Cannot dup to 1; %r");
+ if (dup(p[0], 0) < 0)
+ fatal("filter: Cannot dup to 0; %r");
+ close(p[0]);
+ close(p[1]);
+ exec(file, argv);
+ fatal("filter: exec; %r");
+ default:
+ close(fd);
+ close(p[0]);
+ }
+ return p[1];
+}
+