tmain.c - plan9port - [fork] Plan 9 from user space | |
git clone git://src.adamsgaard.dk/plan9port | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
tmain.c (16062B) | |
--- | |
1 #include <u.h> | |
2 #include <libc.h> | |
3 #include <ip.h> | |
4 #include <bio.h> | |
5 #include <fcall.h> | |
6 #include <libsec.h> | |
7 #include "dat.h" | |
8 #include "protos.h" | |
9 #include "y.tab.h" | |
10 | |
11 int Cflag; | |
12 int pflag; | |
13 int Nflag; | |
14 int sflag; | |
15 int tiflag; | |
16 int toflag; | |
17 | |
18 char *prom = "promiscuous"; | |
19 | |
20 enum | |
21 { | |
22 Pktlen= 64*1024, | |
23 Blen= 16*1024 | |
24 }; | |
25 | |
26 Filter *filter; | |
27 Proto *root; | |
28 Biobuf out; | |
29 vlong starttime, pkttime; | |
30 int pcap; | |
31 | |
32 int filterpkt(Filter *f, uchar *ps, uchar *pe, Proto *pr, int); | |
33 void printpkt(char *p, char *e, uchar *ps, uchar *pe); | |
34 void mkprotograph(void); | |
35 Proto* findproto(char *name); | |
36 Filter* compile(Filter *f); | |
37 void printfilter(Filter *f, char *tag); | |
38 void printhelp(char*); | |
39 void tracepkt(uchar*, int); | |
40 void pcaphdr(int); | |
41 | |
42 struct pcap_pkthdr { | |
43 u64int ts; /* time stamp */ | |
44 u32int caplen; /* length of portion present */ | |
45 u32int len; /* length this packet (off wire) */ | |
46 }; | |
47 | |
48 | |
49 void | |
50 printusage(void) | |
51 { | |
52 fprint(2, "usage: %s [-CDdpst] [-N n] [-f filter] [-h first-head… | |
53 fprint(2, " for protocol help: %s -? [proto]\n", argv0); | |
54 } | |
55 | |
56 void | |
57 usage(void) | |
58 { | |
59 printusage(); | |
60 exits("usage"); | |
61 } | |
62 | |
63 void | |
64 main(int argc, char **argv) | |
65 { | |
66 uchar *pkt; | |
67 char *buf, *file, *p, *e; | |
68 int fd; | |
69 int n; | |
70 | |
71 Binit(&out, 1, OWRITE); | |
72 | |
73 fmtinstall('E', eipfmt); | |
74 fmtinstall('V', eipfmt); | |
75 fmtinstall('I', eipfmt); | |
76 fmtinstall('H', encodefmt); | |
77 fmtinstall('F', fcallfmt); | |
78 | |
79 pkt = malloc(Pktlen+16); | |
80 pkt += 16; | |
81 buf = malloc(Blen); | |
82 e = buf+Blen-1; | |
83 | |
84 pflag = 1; | |
85 Nflag = 32; | |
86 sflag = 0; | |
87 | |
88 mkprotograph(); | |
89 | |
90 ARGBEGIN{ | |
91 default: | |
92 usage(); | |
93 case '?': | |
94 printusage(); | |
95 printhelp(ARGF()); | |
96 exits(0); | |
97 break; | |
98 case 'N': | |
99 p = EARGF(usage()); | |
100 Nflag = atoi(p); | |
101 break; | |
102 case 'f': | |
103 p = EARGF(usage()); | |
104 yyinit(p); | |
105 yyparse(); | |
106 break; | |
107 case 's': | |
108 sflag = 1; | |
109 break; | |
110 case 'h': | |
111 p = EARGF(usage()); | |
112 root = findproto(p); | |
113 if(root == nil) | |
114 sysfatal("unknown protocol: %s", p); | |
115 break; | |
116 case 'd': | |
117 toflag = 1; | |
118 break; | |
119 case 'D': | |
120 toflag = 1; | |
121 pcap = 1; | |
122 break; | |
123 case 't': | |
124 tiflag = 1; | |
125 break; | |
126 case 'T': | |
127 tiflag = 1; | |
128 pcap = 1; | |
129 break; | |
130 case 'C': | |
131 Cflag = 1; | |
132 break; | |
133 case 'p': | |
134 pflag = 0; | |
135 break; | |
136 }ARGEND; | |
137 | |
138 if(argc > 1) | |
139 usage(); | |
140 | |
141 if(argc == 0) | |
142 file = nil; | |
143 else | |
144 file = argv[0]; | |
145 | |
146 if(tiflag){ | |
147 if(file == nil) | |
148 sysfatal("must specify file with -t"); | |
149 fd = open(file, OREAD); | |
150 if(fd < 0) | |
151 sysfatal("opening %s: %r", file); | |
152 }else{ | |
153 fd = opendevice(file, pflag); | |
154 if(fd < 0) | |
155 sysfatal("opening device %s: %r", file); | |
156 } | |
157 if(root == nil) | |
158 root = ðer; | |
159 | |
160 if(pcap) | |
161 pcaphdr(fd); | |
162 | |
163 filter = compile(filter); | |
164 | |
165 if(tiflag){ | |
166 /* read a trace file */ | |
167 for(;;){ | |
168 if(pcap){ | |
169 struct pcap_pkthdr *goo; | |
170 n = read(fd, pkt, 16); | |
171 if(n != 16) | |
172 break; | |
173 goo = (struct pcap_pkthdr*)pkt; | |
174 pkttime = goo->ts; | |
175 n = goo->caplen; | |
176 }else{ | |
177 n = read(fd, pkt, 10); | |
178 if(n != 10) | |
179 break; | |
180 pkttime = NetL(pkt+2); | |
181 pkttime = (pkttime<<32) | NetL(pkt+6); | |
182 if(starttime == 0LL) | |
183 starttime = pkttime; | |
184 n = NetS(pkt); | |
185 } | |
186 if(readn(fd, pkt, n) != n) | |
187 break; | |
188 if(filterpkt(filter, pkt, pkt+n, root, 1)) | |
189 if(toflag) | |
190 tracepkt(pkt, n); | |
191 else | |
192 printpkt(buf, e, pkt, pkt+n); | |
193 } | |
194 } else { | |
195 /* read a real time stream */ | |
196 starttime = nsec(); | |
197 for(;;){ | |
198 n = root->framer(fd, pkt, Pktlen); | |
199 if(n <= 0) | |
200 break; | |
201 pkttime = nsec(); | |
202 if(filterpkt(filter, pkt, pkt+n, root, 1)) | |
203 if(toflag) | |
204 tracepkt(pkt, n); | |
205 else | |
206 printpkt(buf, e, pkt, pkt+n); | |
207 } | |
208 } | |
209 } | |
210 | |
211 /* create a new filter node */ | |
212 Filter* | |
213 newfilter(void) | |
214 { | |
215 Filter *f; | |
216 | |
217 f = mallocz(sizeof(*f), 1); | |
218 if(f == nil) | |
219 sysfatal("newfilter: %r"); | |
220 return f; | |
221 } | |
222 | |
223 /* | |
224 * apply filter to packet | |
225 */ | |
226 int | |
227 _filterpkt(Filter *f, Msg *m) | |
228 { | |
229 Msg ma; | |
230 | |
231 if(f == nil) | |
232 return 1; | |
233 | |
234 switch(f->op){ | |
235 case '!': | |
236 return !_filterpkt(f->l, m); | |
237 case LAND: | |
238 ma = *m; | |
239 return _filterpkt(f->l, &ma) && _filterpkt(f->r, m); | |
240 case LOR: | |
241 ma = *m; | |
242 return _filterpkt(f->l, &ma) || _filterpkt(f->r, m); | |
243 case WORD: | |
244 if(m->needroot){ | |
245 if(m->pr != f->pr) | |
246 return 0; | |
247 m->needroot = 0; | |
248 }else{ | |
249 if(m->pr && (m->pr->filter==nil || !(m->pr->filt… | |
250 return 0; | |
251 } | |
252 if(f->l == nil) | |
253 return 1; | |
254 m->pr = f->pr; | |
255 return _filterpkt(f->l, m); | |
256 } | |
257 sysfatal("internal error: filterpkt op: %d", f->op); | |
258 return 0; | |
259 } | |
260 int | |
261 filterpkt(Filter *f, uchar *ps, uchar *pe, Proto *pr, int needroot) | |
262 { | |
263 Msg m; | |
264 | |
265 if(f == nil) | |
266 return 1; | |
267 | |
268 m.needroot = needroot; | |
269 m.ps = ps; | |
270 m.pe = pe; | |
271 m.pr = pr; | |
272 return _filterpkt(f, &m); | |
273 } | |
274 | |
275 /* | |
276 * from the Unix world | |
277 */ | |
278 #define PCAP_VERSION_MAJOR 2 | |
279 #define PCAP_VERSION_MINOR 4 | |
280 #define TCPDUMP_MAGIC 0xa1b2c3d4 | |
281 | |
282 struct pcap_file_header { | |
283 u32int magic; | |
284 u16int version_major; | |
285 u16int version_minor; | |
286 s32int thiszone; /* gmt to local correction */ | |
287 u32int sigfigs; /* accuracy of timestamps */ | |
288 u32int snaplen; /* max length saved portion of… | |
289 u32int linktype; /* data link type (DLT_*) */ | |
290 }; | |
291 | |
292 /* | |
293 * pcap trace header | |
294 */ | |
295 void | |
296 pcaphdr(int fd) | |
297 { | |
298 if(tiflag){ | |
299 struct pcap_file_header hdr; | |
300 | |
301 if(readn(fd, &hdr, sizeof hdr) != sizeof hdr) | |
302 sysfatal("short header"); | |
303 if(hdr.magic != TCPDUMP_MAGIC) | |
304 sysfatal("packet header %ux != %ux", hdr.magic, … | |
305 if(hdr.version_major != PCAP_VERSION_MAJOR || hdr.versio… | |
306 sysfatal("version %d.%d != %d.%d", hdr.version_m… | |
307 if(hdr.linktype != 1) | |
308 sysfatal("unknown linktype %d != 1 (ethernet)", … | |
309 } | |
310 if(toflag){ | |
311 struct pcap_file_header hdr; | |
312 | |
313 hdr.magic = TCPDUMP_MAGIC; | |
314 hdr.version_major = PCAP_VERSION_MAJOR; | |
315 hdr.version_minor = PCAP_VERSION_MINOR; | |
316 | |
317 hdr.thiszone = 0; | |
318 hdr.snaplen = 1500; | |
319 hdr.sigfigs = 0; | |
320 hdr.linktype = 1; | |
321 | |
322 write(1, &hdr, sizeof(hdr)); | |
323 } | |
324 } | |
325 | |
326 /* | |
327 * write out a packet trace | |
328 */ | |
329 void | |
330 tracepkt(uchar *ps, int len) | |
331 { | |
332 struct pcap_pkthdr *goo; | |
333 | |
334 if(pcap){ | |
335 goo = (struct pcap_pkthdr*)(ps-16); | |
336 goo->ts = pkttime; | |
337 goo->caplen = len; | |
338 goo->len = len; | |
339 write(1, goo, len+16); | |
340 } else { | |
341 hnputs(ps-10, len); | |
342 hnputl(ps-8, pkttime>>32); | |
343 hnputl(ps-4, pkttime); | |
344 write(1, ps-10, len+10); | |
345 } | |
346 } | |
347 | |
348 /* | |
349 * format and print a packet | |
350 */ | |
351 void | |
352 printpkt(char *p, char *e, uchar *ps, uchar *pe) | |
353 { | |
354 Msg m; | |
355 ulong dt; | |
356 | |
357 dt = (pkttime-starttime)/1000000LL; | |
358 m.p = seprint(p, e, "%6.6uld ms ", dt); | |
359 m.ps = ps; | |
360 m.pe = pe; | |
361 m.e = e; | |
362 m.pr = root; | |
363 while(m.p < m.e){ | |
364 if(!sflag) | |
365 m.p = seprint(m.p, m.e, "\n\t"); | |
366 m.p = seprint(m.p, m.e, "%s(", m.pr->name); | |
367 if((*m.pr->seprint)(&m) < 0){ | |
368 m.p = seprint(m.p, m.e, "TOO SHORT"); | |
369 m.ps = m.pe; | |
370 } | |
371 m.p = seprint(m.p, m.e, ")"); | |
372 if(m.pr == nil || m.ps >= m.pe) | |
373 break; | |
374 } | |
375 *m.p++ = '\n'; | |
376 | |
377 if(write(1, p, m.p - p) < 0) | |
378 sysfatal("stdout: %r"); | |
379 } | |
380 | |
381 Proto **xprotos; | |
382 int nprotos; | |
383 | |
384 /* look up a protocol by its name */ | |
385 Proto* | |
386 findproto(char *name) | |
387 { | |
388 int i; | |
389 | |
390 for(i = 0; i < nprotos; i++) | |
391 if(strcmp(xprotos[i]->name, name) == 0) | |
392 return xprotos[i]; | |
393 return nil; | |
394 } | |
395 | |
396 /* | |
397 * add an undefined protocol to protos[] | |
398 */ | |
399 Proto* | |
400 addproto(char *name) | |
401 { | |
402 Proto *pr; | |
403 | |
404 xprotos = realloc(xprotos, (nprotos+1)*sizeof(Proto*)); | |
405 pr = malloc(sizeof *pr); | |
406 *pr = dump; | |
407 pr->name = name; | |
408 xprotos[nprotos++] = pr; | |
409 return pr; | |
410 } | |
411 | |
412 /* | |
413 * build a graph of protocols, this could easily be circular. This | |
414 * links together all the multiplexing in the protocol modules. | |
415 */ | |
416 void | |
417 mkprotograph(void) | |
418 { | |
419 Proto **l; | |
420 Proto *pr; | |
421 Mux *m; | |
422 | |
423 /* copy protos into a reallocable area */ | |
424 for(nprotos = 0; protos[nprotos] != nil; nprotos++) | |
425 ; | |
426 xprotos = malloc(nprotos*sizeof(Proto*)); | |
427 memmove(xprotos, protos, nprotos*sizeof(Proto*)); | |
428 | |
429 for(l = protos; *l != nil; l++){ | |
430 pr = *l; | |
431 for(m = pr->mux; m != nil && m->name != nil; m++){ | |
432 m->pr = findproto(m->name); | |
433 if(m->pr == nil) | |
434 m->pr = addproto(m->name); | |
435 } | |
436 } | |
437 } | |
438 | |
439 /* | |
440 * add in a protocol node | |
441 */ | |
442 static Filter* | |
443 addnode(Filter *f, Proto *pr) | |
444 { | |
445 Filter *nf; | |
446 nf = newfilter(); | |
447 nf->pr = pr; | |
448 nf->s = pr->name; | |
449 nf->l = f; | |
450 nf->op = WORD; | |
451 return nf; | |
452 } | |
453 | |
454 /* | |
455 * recurse through the protocol graph adding missing nodes | |
456 * to the filter if we reach the filter's protocol | |
457 */ | |
458 static Filter* | |
459 _fillin(Filter *f, Proto *last, int depth) | |
460 { | |
461 Mux *m; | |
462 Filter *nf; | |
463 | |
464 if(depth-- <= 0) | |
465 return nil; | |
466 | |
467 for(m = last->mux; m != nil && m->name != nil; m++){ | |
468 if(m->pr == nil) | |
469 continue; | |
470 if(f->pr == m->pr) | |
471 return f; | |
472 nf = _fillin(f, m->pr, depth); | |
473 if(nf != nil) | |
474 return addnode(nf, m->pr); | |
475 } | |
476 return nil; | |
477 } | |
478 | |
479 static Filter* | |
480 fillin(Filter *f, Proto *last) | |
481 { | |
482 int i; | |
483 Filter *nf; | |
484 | |
485 /* hack to make sure top level node is the root */ | |
486 if(last == nil){ | |
487 if(f->pr == root) | |
488 return f; | |
489 f = fillin(f, root); | |
490 if(f == nil) | |
491 return nil; | |
492 return addnode(f, root); | |
493 } | |
494 | |
495 /* breadth first search though the protocol graph */ | |
496 nf = f; | |
497 for(i = 1; i < 20; i++){ | |
498 nf = _fillin(f, last, i); | |
499 if(nf != nil) | |
500 break; | |
501 } | |
502 return nf; | |
503 } | |
504 | |
505 /* | |
506 * massage tree so that all paths from the root to a leaf | |
507 * contain a filter node for each header. | |
508 * | |
509 * also, set f->pr where possible | |
510 */ | |
511 Filter* | |
512 complete(Filter *f, Proto *last) | |
513 { | |
514 Proto *pr; | |
515 | |
516 if(f == nil) | |
517 return f; | |
518 | |
519 /* do a depth first traversal of the filter tree */ | |
520 switch(f->op){ | |
521 case '!': | |
522 f->l = complete(f->l, last); | |
523 break; | |
524 case LAND: | |
525 case LOR: | |
526 f->l = complete(f->l, last); | |
527 f->r = complete(f->r, last); | |
528 break; | |
529 case '=': | |
530 break; | |
531 case WORD: | |
532 pr = findproto(f->s); | |
533 f->pr = pr; | |
534 if(pr == nil){ | |
535 if(f->l != nil){ | |
536 fprint(2, "%s unknown proto, ignoring pa… | |
537 f->s); | |
538 f->l = nil; | |
539 } | |
540 } else { | |
541 f->l = complete(f->l, pr); | |
542 f = fillin(f, last); | |
543 if(f == nil) | |
544 sysfatal("internal error: can't get to %… | |
545 } | |
546 break; | |
547 } | |
548 return f; | |
549 } | |
550 | |
551 /* | |
552 * merge common nodes under | and & moving the merged node | |
553 * above the | or &. | |
554 * | |
555 * do some constant foldong, e.g. `true & x' becomes x and | |
556 * 'true | x' becomes true. | |
557 */ | |
558 static int changed; | |
559 | |
560 static Filter* | |
561 _optimize(Filter *f) | |
562 { | |
563 Filter *l; | |
564 | |
565 if(f == nil) | |
566 return f; | |
567 | |
568 switch(f->op){ | |
569 case '!': | |
570 /* is child also a not */ | |
571 if(f->l->op == '!'){ | |
572 changed = 1; | |
573 return f->l->l; | |
574 } | |
575 break; | |
576 case LOR: | |
577 /* are two children the same protocol? */ | |
578 if(f->l->op != f->r->op || f->r->op != WORD | |
579 || f->l->pr != f->r->pr || f->l->pr == nil) | |
580 break; /* no optimization */ | |
581 | |
582 changed = 1; | |
583 | |
584 /* constant folding */ | |
585 /* if either child is childless, just return that */ | |
586 if(f->l->l == nil) | |
587 return f->l; | |
588 else if(f->r->l == nil) | |
589 return f->r; | |
590 | |
591 /* move the common node up, thow away one node */ | |
592 l = f->l; | |
593 f->l = l->l; | |
594 f->r = f->r->l; | |
595 l->l = f; | |
596 return l; | |
597 case LAND: | |
598 /* are two children the same protocol? */ | |
599 if(f->l->op != f->r->op || f->r->op != WORD | |
600 || f->l->pr != f->r->pr || f->l->pr == nil) | |
601 break; /* no optimization */ | |
602 | |
603 changed = 1; | |
604 | |
605 /* constant folding */ | |
606 /* if either child is childless, ignore it */ | |
607 if(f->l->l == nil) | |
608 return f->r; | |
609 else if(f->r->l == nil) | |
610 return f->l; | |
611 | |
612 /* move the common node up, thow away one node */ | |
613 l = f->l; | |
614 f->l = _optimize(l->l); | |
615 f->r = _optimize(f->r->l); | |
616 l->l = f; | |
617 return l; | |
618 } | |
619 f->l = _optimize(f->l); | |
620 f->r = _optimize(f->r); | |
621 return f; | |
622 } | |
623 | |
624 Filter* | |
625 optimize(Filter *f) | |
626 { | |
627 do{ | |
628 changed = 0; | |
629 f = _optimize(f); | |
630 }while(changed); | |
631 | |
632 return f; | |
633 } | |
634 | |
635 /* | |
636 * find any top level nodes that aren't the root | |
637 */ | |
638 int | |
639 findbogus(Filter *f) | |
640 { | |
641 int rv; | |
642 | |
643 if(f->op != WORD){ | |
644 rv = findbogus(f->l); | |
645 if(f->r) | |
646 rv |= findbogus(f->r); | |
647 return rv; | |
648 } else if(f->pr != root){ | |
649 fprint(2, "bad top-level protocol: %s\n", f->s); | |
650 return 1; | |
651 } | |
652 return 0; | |
653 } | |
654 | |
655 /* | |
656 * compile the filter | |
657 */ | |
658 static void | |
659 _compile(Filter *f, Proto *last) | |
660 { | |
661 if(f == nil) | |
662 return; | |
663 | |
664 switch(f->op){ | |
665 case '!': | |
666 _compile(f->l, last); | |
667 break; | |
668 case LOR: | |
669 case LAND: | |
670 _compile(f->l, last); | |
671 _compile(f->r, last); | |
672 break; | |
673 case WORD: | |
674 if(last != nil){ | |
675 if(last->compile == nil) | |
676 sysfatal("unknown %s subprotocol: %s", f… | |
677 (*last->compile)(f); | |
678 } | |
679 if(f->l) | |
680 _compile(f->l, f->pr); | |
681 break; | |
682 case '=': | |
683 if(last == nil) | |
684 sysfatal("internal error: compilewalk: badly for… | |
685 | |
686 if(last->compile == nil) | |
687 sysfatal("unknown %s field: %s", f->pr->name, f-… | |
688 (*last->compile)(f); | |
689 break; | |
690 default: | |
691 sysfatal("internal error: compilewalk op: %d", f->op); | |
692 } | |
693 } | |
694 | |
695 Filter* | |
696 compile(Filter *f) | |
697 { | |
698 if(f == nil) | |
699 return f; | |
700 | |
701 /* fill in the missing header filters */ | |
702 f = complete(f, nil); | |
703 | |
704 /* constant folding */ | |
705 f = optimize(f); | |
706 if(!toflag) | |
707 printfilter(f, "after optimize"); | |
708 | |
709 /* protocol specific compilations */ | |
710 _compile(f, nil); | |
711 | |
712 /* at this point, the root had better be the root proto */ | |
713 if(findbogus(f)){ | |
714 fprint(2, "bogus filter\n"); | |
715 exits("bad filter"); | |
716 } | |
717 | |
718 return f; | |
719 } | |
720 | |
721 /* | |
722 * parse a byte array | |
723 */ | |
724 int | |
725 parseba(uchar *to, char *from) | |
726 { | |
727 char nip[4]; | |
728 char *p; | |
729 int i; | |
730 | |
731 p = from; | |
732 for(i = 0; i < 16; i++){ | |
733 if(*p == 0) | |
734 return -1; | |
735 nip[0] = *p++; | |
736 if(*p == 0) | |
737 return -1; | |
738 nip[1] = *p++; | |
739 nip[2] = 0; | |
740 to[i] = strtoul(nip, 0, 16); | |
741 } | |
742 return i; | |
743 } | |
744 | |
745 /* | |
746 * compile WORD = WORD, becomes a single node with a subop | |
747 */ | |
748 void | |
749 compile_cmp(char *proto, Filter *f, Field *fld) | |
750 { | |
751 uchar x[IPaddrlen]; | |
752 | |
753 if(f->op != '=') | |
754 sysfatal("internal error: compile_cmp %s: not a cmp", pr… | |
755 | |
756 for(; fld->name != nil; fld++){ | |
757 if(strcmp(f->l->s, fld->name) == 0){ | |
758 f->op = WORD; | |
759 f->subop = fld->subop; | |
760 switch(fld->ftype){ | |
761 case Fnum: | |
762 f->ulv = atoi(f->r->s); | |
763 break; | |
764 case Fether: | |
765 parseether(f->a, f->r->s); | |
766 break; | |
767 case Fv4ip: | |
768 f->ulv = parseip(x, f->r->s); | |
769 break; | |
770 case Fv6ip: | |
771 parseip(f->a, f->r->s); | |
772 break; | |
773 case Fba: | |
774 parseba(f->a, f->r->s); | |
775 break; | |
776 default: | |
777 sysfatal("internal error: compile_cmp %s… | |
778 proto, fld->ftype); | |
779 } | |
780 f->l = f->r = nil; | |
781 return; | |
782 } | |
783 } | |
784 sysfatal("unknown %s field in: %s = %s", proto, f->l->s, f->r->s… | |
785 } | |
786 | |
787 void | |
788 _pf(Filter *f) | |
789 { | |
790 char *s; | |
791 | |
792 if(f == nil) | |
793 return; | |
794 | |
795 s = nil; | |
796 switch(f->op){ | |
797 case '!': | |
798 fprint(2, "!"); | |
799 _pf(f->l); | |
800 break; | |
801 case WORD: | |
802 fprint(2, "%s", f->s); | |
803 if(f->l != nil){ | |
804 fprint(2, "("); | |
805 _pf(f->l); | |
806 fprint(2, ")"); | |
807 } | |
808 break; | |
809 case LAND: | |
810 s = "&&"; | |
811 goto print; | |
812 case LOR: | |
813 s = "||"; | |
814 goto print; | |
815 case '=': | |
816 print: | |
817 _pf(f->l); | |
818 if(s) | |
819 fprint(2, " %s ", s); | |
820 else | |
821 fprint(2, " %c ", f->op); | |
822 _pf(f->r); | |
823 break; | |
824 default: | |
825 fprint(2, "???"); | |
826 break; | |
827 } | |
828 } | |
829 | |
830 void | |
831 printfilter(Filter *f, char *tag) | |
832 { | |
833 fprint(2, "%s: ", tag); | |
834 _pf(f); | |
835 fprint(2, "\n"); | |
836 } | |
837 | |
838 void | |
839 cat(void) | |
840 { | |
841 char buf[1024]; | |
842 int n; | |
843 | |
844 while((n = read(0, buf, sizeof buf)) > 0) | |
845 write(1, buf, n); | |
846 } | |
847 | |
848 static int fd1 = -1; | |
849 void | |
850 startmc(void) | |
851 { | |
852 int p[2]; | |
853 | |
854 if(fd1 == -1) | |
855 fd1 = dup(1, -1); | |
856 | |
857 if(pipe(p) < 0) | |
858 return; | |
859 switch(fork()){ | |
860 case -1: | |
861 return; | |
862 default: | |
863 close(p[0]); | |
864 dup(p[1], 1); | |
865 if(p[1] != 1) | |
866 close(p[1]); | |
867 return; | |
868 case 0: | |
869 close(p[1]); | |
870 dup(p[0], 0); | |
871 if(p[0] != 0) | |
872 close(p[0]); | |
873 execl("/bin/mc", "mc", nil); | |
874 cat(); | |
875 _exits(0); | |
876 } | |
877 } | |
878 | |
879 void | |
880 stopmc(void) | |
881 { | |
882 close(1); | |
883 dup(fd1, 1); | |
884 waitpid(); | |
885 } | |
886 | |
887 void | |
888 printhelp(char *name) | |
889 { | |
890 int len; | |
891 Proto *pr, **l; | |
892 Mux *m; | |
893 Field *f; | |
894 char fmt[40]; | |
895 | |
896 if(name == nil){ | |
897 print("protocols:\n"); | |
898 startmc(); | |
899 for(l=protos; (pr=*l) != nil; l++) | |
900 print(" %s\n", pr->name); | |
901 stopmc(); | |
902 return; | |
903 } | |
904 | |
905 pr = findproto(name); | |
906 if(pr == nil){ | |
907 print("unknown protocol %s\n", name); | |
908 return; | |
909 } | |
910 | |
911 if(pr->field){ | |
912 print("%s's filter attributes:\n", pr->name); | |
913 len = 0; | |
914 for(f=pr->field; f->name; f++) | |
915 if(len < strlen(f->name)) | |
916 len = strlen(f->name); | |
917 startmc(); | |
918 for(f=pr->field; f->name; f++) | |
919 print(" %-*s - %s\n", len, f->name, f->help); | |
920 stopmc(); | |
921 } | |
922 if(pr->mux){ | |
923 print("%s's subprotos:\n", pr->name); | |
924 startmc(); | |
925 snprint(fmt, sizeof fmt, " %s %%s\n", pr->valfmt); | |
926 for(m=pr->mux; m->name != nil; m++) | |
927 print(fmt, m->val, m->name); | |
928 stopmc(); | |
929 } | |
930 } | |
931 | |
932 /* | |
933 * demultiplex to next prototol header | |
934 */ | |
935 void | |
936 demux(Mux *mx, ulong val1, ulong val2, Msg *m, Proto *def) | |
937 { | |
938 m->pr = def; | |
939 for(mx = mx; mx->name != nil; mx++){ | |
940 if(val1 == mx->val || val2 == mx->val){ | |
941 m->pr = mx->pr; | |
942 break; | |
943 } | |
944 } | |
945 } | |
946 | |
947 /* | |
948 * default framer just assumes the input packet is | |
949 * a single read | |
950 */ | |
951 int | |
952 defaultframer(int fd, uchar *pkt, int pktlen) | |
953 { | |
954 return read(fd, pkt, pktlen); | |
955 } |