void printhelp(char *name) { int len; Proto *pr, **l; Mux *m; Field *f; char fmt[40]; if(name == nil){ print("protocols:\n"); startmc(); for(l=protos; (pr=*l) != nil; l++) print(" %s\n", pr->name); stopmc(); return; } pr = findproto(name); if(pr == nil){ print("unknown protocol %s\n", name); return; } if(pr->field){ print("%s's filter attributes:\n", pr->name); len = 0; for(f=pr->field; f->name; f++) if(len < strlen(f->name)) len = strlen(f->name); startmc(); for(f=pr->field; f->name; f++) print(" %-*s - %s\n", len, f->name, f->help); stopmc(); } if(pr->mux){ print("%s's subprotos:\n", pr->name); startmc(); snprint(fmt, sizeof fmt, " %s %%s\n", pr->valfmt); for(m=pr->mux; m->name != nil; m++) print(fmt, m->val, m->name); stopmc(); } }
/* * massage tree so that all paths from the root to a leaf * contain a filter node for each header. * * also, set f->pr where possible */ Filter* complete(Filter *f, Proto *last) { Proto *pr; if(f == nil) return f; /* do a depth first traversal of the filter tree */ switch(f->op){ case '!': f->l = complete(f->l, last); break; case LAND: case LOR: f->l = complete(f->l, last); f->r = complete(f->r, last); break; case '=': break; case WORD: pr = findproto(f->s); f->pr = pr; if(pr == nil){ if(f->l != nil){ fprint(2, "%s unknown proto, ignoring params\n", f->s); f->l = nil; } } else { f->l = complete(f->l, pr); f = fillin(f, last); if(f == nil) sysfatal("internal error: can't get to %s", pr->name); } break; } return f; }
/* * build a graph of protocols, this could easily be circular. This * links together all the multiplexing in the protocol modules. */ void mkprotograph(void) { Proto **l; Proto *pr; Mux *m; /* copy protos into a reallocable area */ for(nprotos = 0; protos[nprotos] != nil; nprotos++) ; xprotos = malloc(nprotos*sizeof(Proto*)); memmove(xprotos, protos, nprotos*sizeof(Proto*)); for(l = protos; *l != nil; l++){ pr = *l; for(m = pr->mux; m != nil && m->name != nil; m++){ m->pr = findproto(m->name); if(m->pr == nil) m->pr = addproto(m->name); } } }
// compilation d'une fonction // [name] -> 0 int Compiler::parsefun() { int k; int* type_result; // PRINTF(m)(LOG_DEVCORE,"fonction %s\n",STRSTART(VALTOPNT(STACKGET(m,0)))); char* name=STRSTART(VALTOPNT(STACKGET(m,0))); // création des variables de travail if (k=STACKPUSH(m,NIL)) return k; // LOCALS locals=STACKREF(m); if (k=createnodetype(TYPENAME_FUN)) return k; // recherche des arguments int narg=0; do { if (!parser->next(0)) { PRINTF(m)(LOG_COMPILER,"Compiler : argument or '=' expected (found EOF)\n"); return MTLERR_SN; } if (islabel(parser->token)) { if (k=createnodetype(TYPENAME_UNDEF)) return k; if (k=addlabel(locals,parser->token,INTTOVAL(narg++),STACKGET(m,0))) return k; } else if (strcmp(parser->token,"=")) { PRINTF(m)(LOG_COMPILER,"Compiler : argument or '=' expected (found '%s')\n",parser->token); return MTLERR_SN; } } while(strcmp(parser->token,"=")); // construction du type initial de la fonction if (k=createnodetuple(narg)) return k; TABSET(m,VALTOPNT(STACKGET(m,1)),TYPEHEADER_LENGTH,STACKGET(m,0)); // attachement du noeud tuple au noeud fun STACKDROP(m); if (k=createnodetype(TYPENAME_UNDEF)) return k; // noeud résultat TABSET(m,VALTOPNT(STACKGET(m,1)),TYPEHEADER_LENGTH+1,STACKGET(m,0)); // attachement du noeud resultat au noeud fun type_result=VALTOPNT(STACKPULL(m)); // on garde en mémoire le type du résultat // ici : [type local global name] // on crée le bloc fonction newref=MALLOCCLEAR(m,REF_LENGTH); if (!newref) return MTLERR_OM; TABSET(m,newref,REF_TYPE,STACKPULL(m)); TABSET(m,newref,REF_NAME,STACKGET(m,1)); TABSET(m,newref,REF_CODE,INTTOVAL(narg)); // vient d'être déclarée, pas encore utilisée TABSET(m,newref,REF_USED,INTTOVAL(0)); k=findproto(PNTTOVAL(newpackage),newref); TABSET(m,newref,REF_PACKAGE,(k!=NIL)?k:INTTOVAL(ifuns++)); if (k=STACKPUSH(m,PNTTOVAL(newref))) return MTLERR_OM; // [newref local global name] addreftopackage(newref,newpackage); STACKDROP(m); // [local global name] // on poursuit la compilation vers le corps de la fonction nblocals=narg; bc->reinit(); // initialisation de la production de bytecode // [locals globals] // parsing if (k=parseprogram()) return k; // [type locals globals] // la pile contient le type du résultat de la fonction if (k=parser->parsekeyword(";;")) return k; // unifier le type résultat if (k=unif(type_result,VALTOPNT(STACKGET(m,0)))) return k; STACKDROP(m); // [locals globals name] // créer le bloc programme int* fun=MALLOCCLEAR(m,FUN_LENGTH); if (!fun) return MTLERR_OM; TABSET(m,newref,REF_VAL,PNTTOVAL(fun)); TABSET(m,fun,FUN_NBARGS,INTTOVAL(narg)); TABSET(m,fun,FUN_NBLOCALS,INTTOVAL(nblocals)); // stocker le bytecode bc->addchar(OPret); if (k=STRPUSHBINARY(m,bc->getstart(),bc->getsize())) return k; TABSET(m,fun,FUN_BC,STACKPULL(m)); if (!strcmp(name,"awcConnect")) displaybc(m,STRSTART(VALTOPNT(TABGET(fun,FUN_BC)))); // construire le tuple des références globales // int* globalstuple=tuplefromlabels(globals); // if (!globalstuple) return MTLERR_OM; // TABSET(m,fun,FUN_REF,PNTTOVAL(globalstuple)); TABSET(m,fun,FUN_REFERENCE,PNTTOVAL(newref)); STACKDROPN(m,2); // [] // chercher d'éventuels prototypes if (k=fillproto(PNTTOVAL(newpackage),newref)) return k; outputbuf->reinit(); outputbuf->printf("Compiler : %s : ",STRSTART(VALTOPNT(TABGET(newref,REF_NAME)))); echograph(outputbuf,VALTOPNT(TABGET(newref,REF_TYPE))); PRINTF(m)(LOG_COMPILER,"%s\n",outputbuf->getstart()); return 0; }
void main(int argc, char **argv) { uchar *pkt; char *buf, *file, *p, *e; int fd, cfd; int n; Binit(&out, 1, OWRITE); fmtinstall('E', eipfmt); fmtinstall('V', eipfmt); fmtinstall('I', eipfmt); fmtinstall('H', encodefmt); fmtinstall('F', fcallfmt); pkt = malloc(Pktlen+16); pkt += 16; buf = malloc(Blen); e = buf+Blen-1; pflag = 1; Nflag = 32; sflag = 0; mkprotograph(); ARGBEGIN{ default: usage(); case '?': printusage(); printhelp(ARGF()); exits(0); break; case 'M': p = EARGF(usage()); Mflag = atoi(p); break; case 'N': p = EARGF(usage()); Nflag = atoi(p); break; case 'f': p = EARGF(usage()); yyinit(p); yyparse(); break; case 's': sflag = 1; break; case 'h': p = EARGF(usage()); root = findproto(p); if(root == nil) sysfatal("unknown protocol: %s", p); break; case 'd': toflag = 1; break; case 'D': toflag = 1; pcap = 1; break; case 't': tiflag = 1; break; case 'C': Cflag = 1; break; case 'p': pflag = 0; break; }ARGEND; if(pcap) pcaphdr(); if(argc == 0){ file = "/net/ether0"; if(root != nil) root = ðer; } else file = argv[0]; if((!tiflag) && strstr(file, "ether")){ if(root == nil) root = ðer; snprint(buf, Blen, "%s!-1", file); fd = dial(buf, 0, 0, &cfd); if(fd < 0) sysfatal("dialing %s: %r", buf); if(pflag && fprint(cfd, prom, strlen(prom)) < 0) sysfatal("setting %s", prom); } else if((!tiflag) && strstr(file, "ipifc")){ if(root == nil) root = &ip; snprint(buf, Blen, "%s/snoop", file); fd = open(buf, OREAD); if(fd < 0) sysfatal("opening %s: %r", buf); } else { if(root == nil) root = ðer; fd = open(file, OREAD); if(fd < 0) sysfatal("opening %s: %r", file); } filter = compile(filter); if(tiflag){ /* read a trace file */ for(;;){ n = read(fd, pkt, 10); if(n != 10) break; pkttime = NetL(pkt+2); pkttime = (pkttime<<32) | NetL(pkt+6); if(starttime == 0LL) starttime = pkttime; n = NetS(pkt); if(readn(fd, pkt, n) != n) break; if(filterpkt(filter, pkt, pkt+n, root, 1)) if(toflag) tracepkt(pkt, n); else printpkt(buf, e, pkt, pkt+n); } } else { /* read a real time stream */ starttime = nsec(); for(;;){ n = root->framer(fd, pkt, Pktlen); if(n <= 0) break; pkttime = nsec(); if(filterpkt(filter, pkt, pkt+n, root, 1)) if(toflag) tracepkt(pkt, n); else printpkt(buf, e, pkt, pkt+n); } } }
int ctlwrite(char *a, int atzero) { char *p; int i, nmatch, ret; Attr *attr, **l, **lpriv, **lprotos, *pa, *priv, *protos; Key *k; Proto *proto; if(a[0] == '#' || a[0] == '\0') return 0; /* * it would be nice to emit a warning of some sort here. * we ignore all but the first line of the write. this helps * both with things like "echo delkey >/mnt/factotum/ctl" * and writes that (incorrectly) contain multiple key lines. */ if((p = strchr(a, '\n')) != nil){ if(p[1] != '\0'){ werrstr("multiline write not allowed"); return -1; } *p = '\0'; } if((p = strchr(a, ' ')) == nil) p = ""; else *p++ = '\0'; switch(classify(a, ctltab, nelem(ctltab))){ default: case Vunknown: werrstr("unknown verb"); return -1; case Vdebug: debug ^= 1; return 0; case Vdelkey: nmatch = 0; attr = _parseattr(p); for(pa=attr; pa; pa=pa->next){ if(pa->type != AttrQuery && pa->name[0]=='!'){ werrstr("only !private? patterns are allowed for private fields"); _freeattr(attr); return -1; } } for(i=0; i<ring->nkey; ){ if(matchattr(attr, ring->key[i]->attr, ring->key[i]->privattr)){ nmatch++; closekey(ring->key[i]); ring->nkey--; memmove(&ring->key[i], &ring->key[i+1], (ring->nkey-i)*sizeof(ring->key[0])); }else i++; } _freeattr(attr); if(nmatch == 0){ werrstr("found no keys to delete"); return -1; } return 0; case Vaddkey: attr = _parseattr(p); /* separate out proto= attributes */ lprotos = &protos; for(l=&attr; (*l); ){ if(strcmp((*l)->name, "proto") == 0){ *lprotos = *l; lprotos = &(*l)->next; *l = (*l)->next; }else l = &(*l)->next; } *lprotos = nil; if(protos == nil){ werrstr("key without protos"); _freeattr(attr); return -1; } /* separate out private attributes */ lpriv = &priv; for(l=&attr; (*l); ){ if((*l)->name[0] == '!'){ *lpriv = *l; lpriv = &(*l)->next; *l = (*l)->next; }else l = &(*l)->next; } *lpriv = nil; /* add keys */ ret = 0; for(pa=protos; pa; pa=pa->next){ if((proto = findproto(pa->val)) == nil){ werrstr("unknown proto %s", pa->val); ret = -1; continue; } if(proto->addkey == nil){ werrstr("proto %s doesn't take keys", proto->name); ret = -1; continue; } k = emalloc(sizeof(Key)); k->attr = _mkattr(AttrNameval, "proto", proto->name, _copyattr(attr)); k->privattr = _copyattr(priv); k->ref = 1; k->proto = proto; if(proto->addkey(k, atzero) < 0){ ret = -1; closekey(k); continue; } closekey(k); } _freeattr(attr); _freeattr(priv); _freeattr(protos); return ret; } }
void rpcread(Req *r) { Attr *attr; char *p; int ophase, ret; uint8_t *e; uint count; Fsstate *fss; Proto *proto; if(r->ifcall.count < 64){ respond(r, "rpc read too small"); return; } fss = r->fid->aux; if(!fss->pending){ respond(r, "no rpc pending"); return; } switch(fss->rpc.iverb){ default: case Vunknown: retstring(r, fss, "error unknown verb"); break; case Vstart: if(fss->phase != Notstarted){ flog("%d: implicit close due to second start; old attr '%A'", fss->seqnum, fss->attr); if(fss->proto && fss->ps) (*fss->proto->close)(fss); fss->ps = nil; fss->proto = nil; _freeattr(fss->attr); fss->attr = nil; fss->phase = Notstarted; } attr = _parseattr(fss->rpc.arg); if((p = _strfindattr(attr, "proto")) == nil){ retstring(r, fss, "error did not specify proto"); _freeattr(attr); break; } if((proto = findproto(p)) == nil){ snprint(fss->rpc.buf, Maxrpc, "error unknown protocol %q", p); retstring(r, fss, fss->rpc.buf); _freeattr(attr); break; } fss->attr = attr; fss->proto = proto; fss->seqnum = ++seqnum; ret = (*proto->init)(proto, fss); rpcstartlog(attr, fss, ret); if(ret != RpcOk){ _freeattr(fss->attr); fss->attr = nil; fss->phase = Notstarted; } retrpc(r, ret, fss); break; case Vread: if(fss->rpc.arg && fss->rpc.arg[0]){ retstring(r, fss, "error read needs no parameters"); break; } if(rdwrcheck(r, fss) < 0) break; count = r->ifcall.count - 3; ophase = fss->phase; ret = fss->proto->read(fss, (uint8_t*)r->ofcall.data+3, &count); rpcrdwrlog(fss, "read", count, ophase, ret); if(ret == RpcOk){ memmove(r->ofcall.data, "ok ", 3); if(count == 0) r->ofcall.count = 2; else r->ofcall.count = 3+count; fss->pending = 0; respond(r, nil); }else retrpc(r, ret, fss); break; case Vwrite: if(rdwrcheck(r, fss) < 0) break; ophase = fss->phase; ret = fss->proto->write(fss, fss->rpc.arg, fss->rpc.narg); rpcrdwrlog(fss, "write", fss->rpc.narg, ophase, ret); retrpc(r, ret, fss); break; case Vauthinfo: if(fss->phase != Established){ retstring(r, fss, "error authentication unfinished"); break; } if(!fss->haveai){ retstring(r, fss, "error no authinfo available"); break; } memmove(r->ofcall.data, "ok ", 3); fss->ai.cap = mkcap(r->fid->uid, fss->ai.suid); e = convAI2M(&fss->ai, (uint8_t*)r->ofcall.data+3, r->ifcall.count-3); free(fss->ai.cap); fss->ai.cap = nil; if(e == nil){ retstring(r, fss, "error read too small"); break; } r->ofcall.count = e - (uint8_t*)r->ofcall.data; fss->pending = 0; respond(r, nil); break; case Vattr: snprint(fss->rpc.buf, Maxrpc, "ok %A", fss->attr); retstring(r, fss, fss->rpc.buf); break; } }