13e12c5d1SDavid du Colombier /* 23e12c5d1SDavid du Colombier * exportfs - Export a plan 9 name space across a network 33e12c5d1SDavid du Colombier */ 43e12c5d1SDavid du Colombier #include <u.h> 53e12c5d1SDavid du Colombier #include <libc.h> 63e12c5d1SDavid du Colombier #include <auth.h> 7219b2ee8SDavid du Colombier #include <fcall.h> 89a747e4fSDavid du Colombier #include <libsec.h> 93e12c5d1SDavid du Colombier #define Extern 103e12c5d1SDavid du Colombier #include "exportfs.h" 113e12c5d1SDavid du Colombier 129a747e4fSDavid du Colombier #define QIDPATH ((1LL<<48)-1) 139a747e4fSDavid du Colombier vlong newqid = 0; 149a747e4fSDavid du Colombier 159a747e4fSDavid du Colombier enum { 169a747e4fSDavid du Colombier Encnone, 179a747e4fSDavid du Colombier Encssl, 189a747e4fSDavid du Colombier Enctls, 199a747e4fSDavid du Colombier }; 207dd7cddfSDavid du Colombier 213e12c5d1SDavid du Colombier void (*fcalls[])(Fsrpc*) = 223e12c5d1SDavid du Colombier { 239a747e4fSDavid du Colombier [Tversion] Xversion, 249a747e4fSDavid du Colombier [Tauth] Xauth, 253e12c5d1SDavid du Colombier [Tflush] Xflush, 263e12c5d1SDavid du Colombier [Tattach] Xattach, 273e12c5d1SDavid du Colombier [Twalk] Xwalk, 283e12c5d1SDavid du Colombier [Topen] slave, 293e12c5d1SDavid du Colombier [Tcreate] Xcreate, 303e12c5d1SDavid du Colombier [Tclunk] Xclunk, 313e12c5d1SDavid du Colombier [Tread] slave, 323e12c5d1SDavid du Colombier [Twrite] slave, 333e12c5d1SDavid du Colombier [Tremove] Xremove, 343e12c5d1SDavid du Colombier [Tstat] Xstat, 353e12c5d1SDavid du Colombier [Twstat] Xwstat, 363e12c5d1SDavid du Colombier }; 373e12c5d1SDavid du Colombier 387dd7cddfSDavid du Colombier /* accounting and debugging counters */ 397dd7cddfSDavid du Colombier int filecnt; 407dd7cddfSDavid du Colombier int freecnt; 417dd7cddfSDavid du Colombier int qidcnt; 427dd7cddfSDavid du Colombier int qfreecnt; 437dd7cddfSDavid du Colombier int ncollision; 447dd7cddfSDavid du Colombier 459a747e4fSDavid du Colombier int srvfd = -1; 469a747e4fSDavid du Colombier int nonone = 1; 479a747e4fSDavid du Colombier char *filterp; 489a747e4fSDavid du Colombier char *ealgs = "rc4_256 sha1"; 499a747e4fSDavid du Colombier char *aanfilter = "/bin/aan"; 509a747e4fSDavid du Colombier int encproto = Encnone; 5124b9ac62SDavid du Colombier int readonly; 52a960ed1cSDavid du Colombier 539a747e4fSDavid du Colombier static void mksecret(char *, uchar *); 54*61b17cc6SDavid du Colombier static int localread9pmsg(int, void *, uint, void *); 55dc5a79c1SDavid du Colombier static char *anstring = "tcp!*!0"; 567ec5746aSDavid du Colombier 577ec5746aSDavid du Colombier char *netdir = "", *local = "", *remote = ""; 587ec5746aSDavid du Colombier 59*61b17cc6SDavid du Colombier void filter(int, char *, char *); 60219b2ee8SDavid du Colombier 61219b2ee8SDavid du Colombier void 62219b2ee8SDavid du Colombier usage(void) 63219b2ee8SDavid du Colombier { 647ec5746aSDavid du Colombier fprint(2, "usage: %s [-adnsR] [-f dbgfile] [-m msize] [-r root] " 657ec5746aSDavid du Colombier "[-S srvfile] [-e 'crypt hash'] [-P exclusion-file] " 667ec5746aSDavid du Colombier "[-A announce-string] [-B address]\n", argv0); 67219b2ee8SDavid du Colombier fatal("usage"); 68219b2ee8SDavid du Colombier } 69219b2ee8SDavid du Colombier 707ec5746aSDavid du Colombier static void 717ec5746aSDavid du Colombier noteconn(int fd) 727ec5746aSDavid du Colombier { 737ec5746aSDavid du Colombier NetConnInfo *nci; 747ec5746aSDavid du Colombier 757ec5746aSDavid du Colombier nci = getnetconninfo(nil, fd); 767ec5746aSDavid du Colombier if(nci == nil) 777ec5746aSDavid du Colombier return; 78*61b17cc6SDavid du Colombier netdir = estrdup(nci->dir); 79*61b17cc6SDavid du Colombier local = estrdup(nci->lsys); 80*61b17cc6SDavid du Colombier remote = estrdup(nci->rsys); 817ec5746aSDavid du Colombier freenetconninfo(nci); 827ec5746aSDavid du Colombier } 837ec5746aSDavid du Colombier 843e12c5d1SDavid du Colombier void 853e12c5d1SDavid du Colombier main(int argc, char **argv) 863e12c5d1SDavid du Colombier { 87*61b17cc6SDavid du Colombier char buf[ERRMAX], ebuf[ERRMAX], initial[4], *ini, *srvfdfile; 8883a6036fSDavid du Colombier char *dbfile, *srv, *na, *nsfile, *keyspec; 89*61b17cc6SDavid du Colombier int doauth, n, fd; 909a747e4fSDavid du Colombier AuthInfo *ai; 91*61b17cc6SDavid du Colombier Fsrpc *r; 923e12c5d1SDavid du Colombier 933e12c5d1SDavid du Colombier dbfile = "/tmp/exportdb"; 9480ee5cbfSDavid du Colombier srv = nil; 959a747e4fSDavid du Colombier srvfd = -1; 9683a6036fSDavid du Colombier srvfdfile = nil; 97e0d6d19cSDavid du Colombier na = nil; 98e0d6d19cSDavid du Colombier nsfile = nil; 99da51d93aSDavid du Colombier keyspec = ""; 10083a6036fSDavid du Colombier doauth = 0; 1013e12c5d1SDavid du Colombier 1029a747e4fSDavid du Colombier ai = nil; 1033e12c5d1SDavid du Colombier ARGBEGIN{ 1043e12c5d1SDavid du Colombier case 'a': 10583a6036fSDavid du Colombier doauth = 1; 1063e12c5d1SDavid du Colombier break; 1073e12c5d1SDavid du Colombier 108759d2aa8SDavid du Colombier case 'd': 109759d2aa8SDavid du Colombier dbg++; 110da51d93aSDavid du Colombier break; 111da51d93aSDavid du Colombier 1129a747e4fSDavid du Colombier case 'e': 11383a6036fSDavid du Colombier ealgs = EARGF(usage()); 1149a747e4fSDavid du Colombier if(*ealgs == 0 || strcmp(ealgs, "clear") == 0) 1159a747e4fSDavid du Colombier ealgs = nil; 1169a747e4fSDavid du Colombier break; 1179a747e4fSDavid du Colombier 1183e12c5d1SDavid du Colombier case 'f': 11980ee5cbfSDavid du Colombier dbfile = EARGF(usage()); 1203e12c5d1SDavid du Colombier break; 1213e12c5d1SDavid du Colombier 122759d2aa8SDavid du Colombier case 'k': 123759d2aa8SDavid du Colombier keyspec = EARGF(usage()); 1249a747e4fSDavid du Colombier break; 1259a747e4fSDavid du Colombier 1269a747e4fSDavid du Colombier case 'm': 1279a747e4fSDavid du Colombier messagesize = strtoul(EARGF(usage()), nil, 0); 1287dd7cddfSDavid du Colombier break; 1297dd7cddfSDavid du Colombier 13024b9ac62SDavid du Colombier case 'n': 13124b9ac62SDavid du Colombier nonone = 0; 13224b9ac62SDavid du Colombier break; 13324b9ac62SDavid du Colombier 13480ee5cbfSDavid du Colombier case 'r': 13580ee5cbfSDavid du Colombier srv = EARGF(usage()); 13680ee5cbfSDavid du Colombier break; 13780ee5cbfSDavid du Colombier 138bd389b36SDavid du Colombier case 's': 13980ee5cbfSDavid du Colombier srv = "/"; 140bd389b36SDavid du Colombier break; 141219b2ee8SDavid du Colombier 1429a747e4fSDavid du Colombier case 'A': 1439a747e4fSDavid du Colombier anstring = EARGF(usage()); 1449a747e4fSDavid du Colombier break; 1459a747e4fSDavid du Colombier 146759d2aa8SDavid du Colombier case 'B': 147759d2aa8SDavid du Colombier na = EARGF(usage()); 148759d2aa8SDavid du Colombier break; 149759d2aa8SDavid du Colombier 150759d2aa8SDavid du Colombier case 'F': 151759d2aa8SDavid du Colombier /* accepted but ignored, for backwards compatibility */ 152759d2aa8SDavid du Colombier break; 153759d2aa8SDavid du Colombier 154759d2aa8SDavid du Colombier case 'N': 155759d2aa8SDavid du Colombier nsfile = EARGF(usage()); 156759d2aa8SDavid du Colombier break; 157759d2aa8SDavid du Colombier 158759d2aa8SDavid du Colombier case 'P': 159759d2aa8SDavid du Colombier patternfile = EARGF(usage()); 160759d2aa8SDavid du Colombier break; 161759d2aa8SDavid du Colombier 16224b9ac62SDavid du Colombier case 'R': 16324b9ac62SDavid du Colombier readonly = 1; 16424b9ac62SDavid du Colombier break; 16524b9ac62SDavid du Colombier 166759d2aa8SDavid du Colombier case 'S': 167*61b17cc6SDavid du Colombier if(srvfdfile != nil) 168759d2aa8SDavid du Colombier usage(); 169759d2aa8SDavid du Colombier srvfdfile = EARGF(usage()); 17024b9ac62SDavid du Colombier break; 17124b9ac62SDavid du Colombier 172219b2ee8SDavid du Colombier default: 173219b2ee8SDavid du Colombier usage(); 1743e12c5d1SDavid du Colombier }ARGEND 1753e12c5d1SDavid du Colombier USED(argc, argv); 1763e12c5d1SDavid du Colombier 177*61b17cc6SDavid du Colombier if(na == nil && doauth){ 17883a6036fSDavid du Colombier /* 17983a6036fSDavid du Colombier * We use p9any so we don't have to visit this code again, with the 18083a6036fSDavid du Colombier * cost that this code is incompatible with the old world, which 18183a6036fSDavid du Colombier * requires p9sk2. (The two differ in who talks first, so compatibility 18283a6036fSDavid du Colombier * is awkward.) 18383a6036fSDavid du Colombier */ 18483a6036fSDavid du Colombier ai = auth_proxy(0, auth_getkey, "proto=p9any role=server %s", keyspec); 18583a6036fSDavid du Colombier if(ai == nil) 18683a6036fSDavid du Colombier fatal("auth_proxy: %r"); 18783a6036fSDavid du Colombier if(nonone && strcmp(ai->cuid, "none") == 0) 18883a6036fSDavid du Colombier fatal("exportfs by none disallowed"); 18983a6036fSDavid du Colombier if(auth_chuid(ai, nsfile) < 0) 19083a6036fSDavid du Colombier fatal("auth_chuid: %r"); 19183a6036fSDavid du Colombier putenv("service", "exportfs"); 19283a6036fSDavid du Colombier } 19383a6036fSDavid du Colombier 194*61b17cc6SDavid du Colombier if(srvfdfile != nil){ 19583a6036fSDavid du Colombier if((srvfd = open(srvfdfile, ORDWR)) < 0) 196*61b17cc6SDavid du Colombier fatal("open %s: %r", srvfdfile); 19783a6036fSDavid du Colombier } 19883a6036fSDavid du Colombier 199*61b17cc6SDavid du Colombier if(na != nil){ 20024b9ac62SDavid du Colombier if(srv == nil) 201*61b17cc6SDavid du Colombier fatal("-B requires -s"); 20224b9ac62SDavid du Colombier 2037ec5746aSDavid du Colombier local = "me"; 2047ec5746aSDavid du Colombier remote = na; 20524b9ac62SDavid du Colombier if((fd = dial(netmkaddr(na, 0, "importfs"), 0, 0, 0)) < 0) 206*61b17cc6SDavid du Colombier fatal("can't dial %s: %r", na); 20724b9ac62SDavid du Colombier 208da51d93aSDavid du Colombier ai = auth_proxy(fd, auth_getkey, "proto=p9any role=client %s", keyspec); 20924b9ac62SDavid du Colombier if(ai == nil) 210*61b17cc6SDavid du Colombier fatal("%r: %s", na); 21124b9ac62SDavid du Colombier 21224b9ac62SDavid du Colombier dup(fd, 0); 21324b9ac62SDavid du Colombier dup(fd, 1); 21424b9ac62SDavid du Colombier close(fd); 21524b9ac62SDavid du Colombier } 21624b9ac62SDavid du Colombier 217a960ed1cSDavid du Colombier exclusions(); 218a960ed1cSDavid du Colombier 2193e12c5d1SDavid du Colombier if(dbg) { 2203e12c5d1SDavid du Colombier n = create(dbfile, OWRITE|OTRUNC, 0666); 2217dd7cddfSDavid du Colombier dup(n, DFD); 2223e12c5d1SDavid du Colombier close(n); 2233e12c5d1SDavid du Colombier } 2243e12c5d1SDavid du Colombier 225*61b17cc6SDavid du Colombier if(srvfd >= 0 && srv != nil){ 2269a747e4fSDavid du Colombier fprint(2, "exportfs: -S cannot be used with -r or -s\n"); 2279a747e4fSDavid du Colombier usage(); 2289a747e4fSDavid du Colombier } 2299a747e4fSDavid du Colombier 2307dd7cddfSDavid du Colombier DEBUG(DFD, "exportfs: started\n"); 231219b2ee8SDavid du Colombier 232*61b17cc6SDavid du Colombier rfork(RFNOTEG|RFREND); 2333e12c5d1SDavid du Colombier 2349a747e4fSDavid du Colombier if(messagesize == 0){ 235*61b17cc6SDavid du Colombier messagesize = iounit(0); 2369a747e4fSDavid du Colombier if(messagesize == 0) 2379a747e4fSDavid du Colombier messagesize = 8192+IOHDRSZ; 2389a747e4fSDavid du Colombier } 2399a747e4fSDavid du Colombier fhash = emallocz(sizeof(Fid*)*FHASHSIZE); 2403e12c5d1SDavid du Colombier 2419a747e4fSDavid du Colombier fmtinstall('F', fcallfmt); 2423e12c5d1SDavid du Colombier 2433e12c5d1SDavid du Colombier /* 244219b2ee8SDavid du Colombier * Get tree to serve from network connection, 245219b2ee8SDavid du Colombier * check we can get there and ack the connection 2463e12c5d1SDavid du Colombier */ 2479a747e4fSDavid du Colombier if(srvfd != -1) { 2489a747e4fSDavid du Colombier /* do nothing */ 2499a747e4fSDavid du Colombier } 250*61b17cc6SDavid du Colombier else if(srv != nil) { 2517f49a7ffSDavid du Colombier if(chdir(srv) < 0) { 2527f49a7ffSDavid du Colombier errstr(ebuf, sizeof ebuf); 2537f49a7ffSDavid du Colombier fprint(0, "chdir(\"%s\"): %s\n", srv, ebuf); 2547f49a7ffSDavid du Colombier DEBUG(DFD, "chdir(\"%s\"): %s\n", srv, ebuf); 2557f49a7ffSDavid du Colombier exits(ebuf); 2567f49a7ffSDavid du Colombier } 25780ee5cbfSDavid du Colombier DEBUG(DFD, "invoked as server for %s", srv); 2589a747e4fSDavid du Colombier strncpy(buf, srv, sizeof buf); 259219b2ee8SDavid du Colombier } 260bd389b36SDavid du Colombier else { 261*61b17cc6SDavid du Colombier noteconn(0); 262bd389b36SDavid du Colombier buf[0] = 0; 2639a747e4fSDavid du Colombier n = read(0, buf, sizeof(buf)-1); 264bd389b36SDavid du Colombier if(n < 0) { 2659a747e4fSDavid du Colombier errstr(buf, sizeof buf); 2667f49a7ffSDavid du Colombier fprint(0, "read(0): %s\n", buf); 2677f49a7ffSDavid du Colombier DEBUG(DFD, "read(0): %s\n", buf); 2683e12c5d1SDavid du Colombier exits(buf); 2693e12c5d1SDavid du Colombier } 270219b2ee8SDavid du Colombier buf[n] = 0; 271bd389b36SDavid du Colombier if(chdir(buf) < 0) { 2729a747e4fSDavid du Colombier errstr(ebuf, sizeof ebuf); 2737f49a7ffSDavid du Colombier fprint(0, "chdir(%d:\"%s\"): %s\n", n, buf, ebuf); 2747f49a7ffSDavid du Colombier DEBUG(DFD, "chdir(%d:\"%s\"): %s\n", n, buf, ebuf); 275bd389b36SDavid du Colombier exits(ebuf); 276bd389b36SDavid du Colombier } 277bd389b36SDavid du Colombier } 2783e12c5d1SDavid du Colombier 27924b9ac62SDavid du Colombier DEBUG(DFD, "\niniting root\n"); 2803e12c5d1SDavid du Colombier initroot(); 2813e12c5d1SDavid du Colombier 2827dd7cddfSDavid du Colombier DEBUG(DFD, "exportfs: %s\n", buf); 2833e12c5d1SDavid du Colombier 2849a747e4fSDavid du Colombier if(srv == nil && srvfd == -1 && write(0, "OK", 2) != 2) 2853e12c5d1SDavid du Colombier fatal("open ack write"); 2863e12c5d1SDavid du Colombier 287*61b17cc6SDavid du Colombier ini = initial; 288*61b17cc6SDavid du Colombier n = readn(0, initial, sizeof(initial)); 289*61b17cc6SDavid du Colombier if(n == 0) 290*61b17cc6SDavid du Colombier fatal(nil); /* port scan or spurious open/close on exported /srv file (unmount) */ 291*61b17cc6SDavid du Colombier if(n < sizeof(initial)) 292*61b17cc6SDavid du Colombier fatal("can't read initial string: %r"); 2939a747e4fSDavid du Colombier 294*61b17cc6SDavid du Colombier if(memcmp(ini, "impo", 4) == 0) { 2959a747e4fSDavid du Colombier char buf[128], *p, *args[3]; 2969a747e4fSDavid du Colombier 297*61b17cc6SDavid du Colombier ini = nil; 2989a747e4fSDavid du Colombier p = buf; 299*61b17cc6SDavid du Colombier for(;;){ 300*61b17cc6SDavid du Colombier if((n = read(0, p, 1)) < 0) 301*61b17cc6SDavid du Colombier fatal("can't read impo arguments: %r"); 3029a747e4fSDavid du Colombier if(n == 0) 303*61b17cc6SDavid du Colombier fatal("connection closed while reading arguments"); 3049a747e4fSDavid du Colombier if(*p == '\n') 3059a747e4fSDavid du Colombier *p = '\0'; 3069a747e4fSDavid du Colombier if(*p++ == '\0') 3079a747e4fSDavid du Colombier break; 308*61b17cc6SDavid du Colombier if(p >= buf + sizeof(buf)) 309*61b17cc6SDavid du Colombier fatal("import parameters too long"); 3109a747e4fSDavid du Colombier } 3119a747e4fSDavid du Colombier 3129a747e4fSDavid du Colombier if(tokenize(buf, args, nelem(args)) != 2) 313*61b17cc6SDavid du Colombier fatal("impo arguments invalid: impo%s...", buf); 3149a747e4fSDavid du Colombier 31529e26a97SDavid du Colombier if(strcmp(args[0], "aan") == 0) 3169a747e4fSDavid du Colombier filterp = aanfilter; 31729e26a97SDavid du Colombier else if(strcmp(args[0], "nofilter") != 0) 318*61b17cc6SDavid du Colombier fatal("import filter argument unsupported: %s", args[0]); 3199a747e4fSDavid du Colombier 32029e26a97SDavid du Colombier if(strcmp(args[1], "ssl") == 0) 3219a747e4fSDavid du Colombier encproto = Encssl; 32229e26a97SDavid du Colombier else if(strcmp(args[1], "tls") == 0) 3239a747e4fSDavid du Colombier encproto = Enctls; 32429e26a97SDavid du Colombier else if(strcmp(args[1], "clear") != 0) 325*61b17cc6SDavid du Colombier fatal("import encryption proto unsupported: %s", args[1]); 3269a747e4fSDavid du Colombier 3279a747e4fSDavid du Colombier if(encproto == Enctls) 328*61b17cc6SDavid du Colombier fatal("%s: tls has not yet been implemented", argv[0]); 3299a747e4fSDavid du Colombier } 3309a747e4fSDavid du Colombier 331*61b17cc6SDavid du Colombier if(encproto != Encnone && ealgs != nil && ai != nil) { 332*61b17cc6SDavid du Colombier uchar key[16], digest[SHA1dlen]; 3339a747e4fSDavid du Colombier char fromclientsecret[21]; 3349a747e4fSDavid du Colombier char fromserversecret[21]; 3359a747e4fSDavid du Colombier int i; 3369a747e4fSDavid du Colombier 337*61b17cc6SDavid du Colombier if(ai->nsecret < 8) 338*61b17cc6SDavid du Colombier fatal("secret too small for ssl"); 339*61b17cc6SDavid du Colombier memmove(key+4, ai->secret, 8); 3409a747e4fSDavid du Colombier 3419a747e4fSDavid du Colombier /* exchange random numbers */ 3429a747e4fSDavid du Colombier srand(truerand()); 3439a747e4fSDavid du Colombier for(i = 0; i < 4; i++) 3449a747e4fSDavid du Colombier key[i+12] = rand(); 3459a747e4fSDavid du Colombier 346*61b17cc6SDavid du Colombier if(ini != nil) 347*61b17cc6SDavid du Colombier fatal("Protocol botch: old import"); 348*61b17cc6SDavid du Colombier if(readn(0, key, 4) != 4) 349*61b17cc6SDavid du Colombier fatal("can't read key part; %r"); 3509a747e4fSDavid du Colombier 351*61b17cc6SDavid du Colombier if(write(0, key+12, 4) != 4) 352*61b17cc6SDavid du Colombier fatal("can't write key part; %r"); 3539a747e4fSDavid du Colombier 3549a747e4fSDavid du Colombier /* scramble into two secrets */ 3559a747e4fSDavid du Colombier sha1(key, sizeof(key), digest, nil); 3569a747e4fSDavid du Colombier mksecret(fromclientsecret, digest); 3579a747e4fSDavid du Colombier mksecret(fromserversecret, digest+10); 3589a747e4fSDavid du Colombier 359*61b17cc6SDavid du Colombier if(filterp != nil) 360*61b17cc6SDavid du Colombier filter(0, filterp, na); 3619a747e4fSDavid du Colombier 3629a747e4fSDavid du Colombier switch(encproto) { 3639a747e4fSDavid du Colombier case Encssl: 364*61b17cc6SDavid du Colombier fd = pushssl(0, ealgs, fromserversecret, fromclientsecret, nil); 365*61b17cc6SDavid du Colombier if(fd < 0) 366*61b17cc6SDavid du Colombier fatal("can't establish ssl connection: %r"); 367*61b17cc6SDavid du Colombier if(fd != 0){ 368*61b17cc6SDavid du Colombier dup(fd, 0); 369*61b17cc6SDavid du Colombier close(fd); 370*61b17cc6SDavid du Colombier } 3719a747e4fSDavid du Colombier break; 3729a747e4fSDavid du Colombier case Enctls: 3739a747e4fSDavid du Colombier default: 374*61b17cc6SDavid du Colombier fatal("Unsupported encryption protocol"); 3759a747e4fSDavid du Colombier } 376*61b17cc6SDavid du Colombier } 377*61b17cc6SDavid du Colombier else if(filterp != nil) { 378*61b17cc6SDavid du Colombier if(ini != nil) 379*61b17cc6SDavid du Colombier fatal("Protocol botch: don't know how to deal with this"); 380*61b17cc6SDavid du Colombier filter(0, filterp, na); 381*61b17cc6SDavid du Colombier } 382*61b17cc6SDavid du Colombier dup(0, 1); 3839a747e4fSDavid du Colombier 384*61b17cc6SDavid du Colombier if(ai != nil) 385*61b17cc6SDavid du Colombier auth_freeAI(ai); 3867dd7cddfSDavid du Colombier 3877dd7cddfSDavid du Colombier /* 3883e12c5d1SDavid du Colombier * Start serving file requests from the network 3893e12c5d1SDavid du Colombier */ 3903e12c5d1SDavid du Colombier for(;;) { 3913e12c5d1SDavid du Colombier r = getsbuf(); 392*61b17cc6SDavid du Colombier while((n = localread9pmsg(0, r->buf, messagesize, ini)) == 0) 393*61b17cc6SDavid du Colombier ; 394*61b17cc6SDavid du Colombier if(n < 0) 3959a747e4fSDavid du Colombier fatal(nil); 3969a747e4fSDavid du Colombier if(convM2S(r->buf, n, &r->work) == 0) 3979a747e4fSDavid du Colombier fatal("convM2S format error"); 3983e12c5d1SDavid du Colombier 3997dd7cddfSDavid du Colombier DEBUG(DFD, "%F\n", &r->work); 4003e12c5d1SDavid du Colombier (fcalls[r->work.type])(r); 401*61b17cc6SDavid du Colombier ini = nil; 4023e12c5d1SDavid du Colombier } 4033e12c5d1SDavid du Colombier } 4043e12c5d1SDavid du Colombier 40529e26a97SDavid du Colombier /* 40629e26a97SDavid du Colombier * WARNING: Replace this with the original version as soon as all 40729e26a97SDavid du Colombier * _old_ imports have been replaced with negotiating imports. Also 40829e26a97SDavid du Colombier * cpu relies on this (which needs to be fixed!) -- pb. 40929e26a97SDavid du Colombier */ 4109a747e4fSDavid du Colombier static int 411*61b17cc6SDavid du Colombier localread9pmsg(int fd, void *abuf, uint n, void *ini) 4129a747e4fSDavid du Colombier { 4139a747e4fSDavid du Colombier int m, len; 4149a747e4fSDavid du Colombier uchar *buf; 4159a747e4fSDavid du Colombier 4169a747e4fSDavid du Colombier buf = abuf; 4179a747e4fSDavid du Colombier 4189a747e4fSDavid du Colombier /* read count */ 419*61b17cc6SDavid du Colombier if(ini != nil) 420*61b17cc6SDavid du Colombier memcpy(buf, ini, BIT32SZ); 4219a747e4fSDavid du Colombier else { 4229a747e4fSDavid du Colombier m = readn(fd, buf, BIT32SZ); 4239a747e4fSDavid du Colombier if(m != BIT32SZ){ 4249a747e4fSDavid du Colombier if(m < 0) 4259a747e4fSDavid du Colombier return -1; 4269a747e4fSDavid du Colombier return 0; 4279a747e4fSDavid du Colombier } 4289a747e4fSDavid du Colombier } 4299a747e4fSDavid du Colombier 4309a747e4fSDavid du Colombier len = GBIT32(buf); 4319a747e4fSDavid du Colombier if(len <= BIT32SZ || len > n){ 4329a747e4fSDavid du Colombier werrstr("bad length in 9P2000 message header"); 4339a747e4fSDavid du Colombier return -1; 4349a747e4fSDavid du Colombier } 4359a747e4fSDavid du Colombier len -= BIT32SZ; 4369a747e4fSDavid du Colombier m = readn(fd, buf+BIT32SZ, len); 4379a747e4fSDavid du Colombier if(m < len) 4389a747e4fSDavid du Colombier return 0; 4399a747e4fSDavid du Colombier return BIT32SZ+m; 4409a747e4fSDavid du Colombier } 4413e12c5d1SDavid du Colombier void 4423e12c5d1SDavid du Colombier reply(Fcall *r, Fcall *t, char *err) 4433e12c5d1SDavid du Colombier { 4449a747e4fSDavid du Colombier uchar *data; 4453e12c5d1SDavid du Colombier int n; 4463e12c5d1SDavid du Colombier 4473e12c5d1SDavid du Colombier t->tag = r->tag; 4483e12c5d1SDavid du Colombier t->fid = r->fid; 449*61b17cc6SDavid du Colombier if(err != nil) { 4503e12c5d1SDavid du Colombier t->type = Rerror; 4519a747e4fSDavid du Colombier t->ename = err; 4523e12c5d1SDavid du Colombier } 4533e12c5d1SDavid du Colombier else 4543e12c5d1SDavid du Colombier t->type = r->type + 1; 4553e12c5d1SDavid du Colombier 4567dd7cddfSDavid du Colombier DEBUG(DFD, "\t%F\n", t); 4573e12c5d1SDavid du Colombier 4589a747e4fSDavid du Colombier data = malloc(messagesize); /* not mallocz; no need to clear */ 4599a747e4fSDavid du Colombier if(data == nil) 4609a747e4fSDavid du Colombier fatal(Enomem); 4619a747e4fSDavid du Colombier n = convS2M(t, data, messagesize); 462*61b17cc6SDavid du Colombier if(write(0, data, n) != n){ 463*61b17cc6SDavid du Colombier /* not fatal, might have got a note due to flush */ 464*61b17cc6SDavid du Colombier fprint(2, "exportfs: short write in reply: %r\n"); 4653e12c5d1SDavid du Colombier } 4669a747e4fSDavid du Colombier free(data); 4679a747e4fSDavid du Colombier } 4683e12c5d1SDavid du Colombier 4693e12c5d1SDavid du Colombier Fid * 4703e12c5d1SDavid du Colombier getfid(int nr) 4713e12c5d1SDavid du Colombier { 4723e12c5d1SDavid du Colombier Fid *f; 4733e12c5d1SDavid du Colombier 474*61b17cc6SDavid du Colombier for(f = fidhash(nr); f != nil; f = f->next) 4753e12c5d1SDavid du Colombier if(f->nr == nr) 4763e12c5d1SDavid du Colombier return f; 4773e12c5d1SDavid du Colombier 478*61b17cc6SDavid du Colombier return nil; 4793e12c5d1SDavid du Colombier } 4803e12c5d1SDavid du Colombier 4813e12c5d1SDavid du Colombier int 4823e12c5d1SDavid du Colombier freefid(int nr) 4833e12c5d1SDavid du Colombier { 4843e12c5d1SDavid du Colombier Fid *f, **l; 485219b2ee8SDavid du Colombier char buf[128]; 4863e12c5d1SDavid du Colombier 4873e12c5d1SDavid du Colombier l = &fidhash(nr); 488*61b17cc6SDavid du Colombier for(f = *l; f != nil; f = f->next) { 4893e12c5d1SDavid du Colombier if(f->nr == nr) { 490219b2ee8SDavid du Colombier if(f->mid) { 491*61b17cc6SDavid du Colombier snprint(buf, sizeof(buf), "/mnt/exportfs/%d", f->mid); 492219b2ee8SDavid du Colombier unmount(0, buf); 493219b2ee8SDavid du Colombier psmap[f->mid] = 0; 494219b2ee8SDavid du Colombier } 495*61b17cc6SDavid du Colombier if(f->f != nil) { 4967dd7cddfSDavid du Colombier freefile(f->f); 4977dd7cddfSDavid du Colombier f->f = nil; 4989a747e4fSDavid du Colombier } 499*61b17cc6SDavid du Colombier if(f->dir != nil){ 500a960ed1cSDavid du Colombier free(f->dir); 501a960ed1cSDavid du Colombier f->dir = nil; 502a960ed1cSDavid du Colombier } 5033e12c5d1SDavid du Colombier *l = f->next; 5043e12c5d1SDavid du Colombier f->next = fidfree; 5053e12c5d1SDavid du Colombier fidfree = f; 5063e12c5d1SDavid du Colombier return 1; 5073e12c5d1SDavid du Colombier } 5083e12c5d1SDavid du Colombier l = &f->next; 5093e12c5d1SDavid du Colombier } 5103e12c5d1SDavid du Colombier 5113e12c5d1SDavid du Colombier return 0; 5123e12c5d1SDavid du Colombier } 5133e12c5d1SDavid du Colombier 5143e12c5d1SDavid du Colombier Fid * 5153e12c5d1SDavid du Colombier newfid(int nr) 5163e12c5d1SDavid du Colombier { 5173e12c5d1SDavid du Colombier Fid *new, **l; 5183e12c5d1SDavid du Colombier int i; 5193e12c5d1SDavid du Colombier 5203e12c5d1SDavid du Colombier l = &fidhash(nr); 521*61b17cc6SDavid du Colombier for(new = *l; new != nil; new = new->next) 5223e12c5d1SDavid du Colombier if(new->nr == nr) 523*61b17cc6SDavid du Colombier return nil; 5243e12c5d1SDavid du Colombier 525*61b17cc6SDavid du Colombier if(fidfree == nil) { 5269a747e4fSDavid du Colombier fidfree = emallocz(sizeof(Fid) * Fidchunk); 5273e12c5d1SDavid du Colombier 5283e12c5d1SDavid du Colombier for(i = 0; i < Fidchunk-1; i++) 5293e12c5d1SDavid du Colombier fidfree[i].next = &fidfree[i+1]; 5303e12c5d1SDavid du Colombier 531*61b17cc6SDavid du Colombier fidfree[Fidchunk-1].next = nil; 5323e12c5d1SDavid du Colombier } 5333e12c5d1SDavid du Colombier 5343e12c5d1SDavid du Colombier new = fidfree; 5353e12c5d1SDavid du Colombier fidfree = new->next; 5363e12c5d1SDavid du Colombier 5373e12c5d1SDavid du Colombier memset(new, 0, sizeof(Fid)); 5383e12c5d1SDavid du Colombier new->next = *l; 5393e12c5d1SDavid du Colombier *l = new; 5403e12c5d1SDavid du Colombier new->nr = nr; 5413e12c5d1SDavid du Colombier new->fid = -1; 542219b2ee8SDavid du Colombier new->mid = 0; 5433e12c5d1SDavid du Colombier 5443e12c5d1SDavid du Colombier return new; 5453e12c5d1SDavid du Colombier } 5463e12c5d1SDavid du Colombier 547*61b17cc6SDavid du Colombier static struct { 548*61b17cc6SDavid du Colombier Lock; 549*61b17cc6SDavid du Colombier Fsrpc *free; 550*61b17cc6SDavid du Colombier 551*61b17cc6SDavid du Colombier /* statistics */ 552*61b17cc6SDavid du Colombier int nalloc; 553*61b17cc6SDavid du Colombier int nfree; 554*61b17cc6SDavid du Colombier } sbufalloc; 555*61b17cc6SDavid du Colombier 5563e12c5d1SDavid du Colombier Fsrpc * 5573e12c5d1SDavid du Colombier getsbuf(void) 5583e12c5d1SDavid du Colombier { 559*61b17cc6SDavid du Colombier Fsrpc *w; 5609a747e4fSDavid du Colombier 561*61b17cc6SDavid du Colombier lock(&sbufalloc); 562*61b17cc6SDavid du Colombier w = sbufalloc.free; 563*61b17cc6SDavid du Colombier if(w != nil){ 564*61b17cc6SDavid du Colombier sbufalloc.free = w->next; 565*61b17cc6SDavid du Colombier w->next = nil; 566*61b17cc6SDavid du Colombier sbufalloc.nfree--; 567*61b17cc6SDavid du Colombier unlock(&sbufalloc); 568*61b17cc6SDavid du Colombier } else { 569*61b17cc6SDavid du Colombier sbufalloc.nalloc++; 570*61b17cc6SDavid du Colombier unlock(&sbufalloc); 571*61b17cc6SDavid du Colombier w = emallocz(sizeof(*w) + messagesize); 572*61b17cc6SDavid du Colombier } 573*61b17cc6SDavid du Colombier w->flushtag = NOTAG; 574*61b17cc6SDavid du Colombier return w; 5753e12c5d1SDavid du Colombier } 5763e12c5d1SDavid du Colombier 577*61b17cc6SDavid du Colombier void 578*61b17cc6SDavid du Colombier putsbuf(Fsrpc *w) 579*61b17cc6SDavid du Colombier { 580*61b17cc6SDavid du Colombier w->flushtag = NOTAG; 581*61b17cc6SDavid du Colombier lock(&sbufalloc); 582*61b17cc6SDavid du Colombier w->next = sbufalloc.free; 583*61b17cc6SDavid du Colombier sbufalloc.free = w; 584*61b17cc6SDavid du Colombier sbufalloc.nfree++; 585*61b17cc6SDavid du Colombier unlock(&sbufalloc); 5867dd7cddfSDavid du Colombier } 5873e12c5d1SDavid du Colombier 5887dd7cddfSDavid du Colombier void 5897dd7cddfSDavid du Colombier freefile(File *f) 5903e12c5d1SDavid du Colombier { 5917dd7cddfSDavid du Colombier File *parent, *child; 5923e12c5d1SDavid du Colombier 593*61b17cc6SDavid du Colombier while(--f->ref == 0){ 5947dd7cddfSDavid du Colombier freecnt++; 5957dd7cddfSDavid du Colombier DEBUG(DFD, "free %s\n", f->name); 5967dd7cddfSDavid du Colombier /* delete from parent */ 5977dd7cddfSDavid du Colombier parent = f->parent; 5987dd7cddfSDavid du Colombier if(parent->child == f) 5997dd7cddfSDavid du Colombier parent->child = f->childlist; 6007dd7cddfSDavid du Colombier else{ 601*61b17cc6SDavid du Colombier for(child = parent->child; child->childlist != f; child = child->childlist) { 6027dd7cddfSDavid du Colombier if(child->childlist == nil) 6037dd7cddfSDavid du Colombier fatal("bad child list"); 604*61b17cc6SDavid du Colombier } 6057dd7cddfSDavid du Colombier child->childlist = f->childlist; 6067dd7cddfSDavid du Colombier } 6077dd7cddfSDavid du Colombier freeqid(f->qidt); 6089a747e4fSDavid du Colombier free(f->name); 6097dd7cddfSDavid du Colombier free(f); 6107dd7cddfSDavid du Colombier f = parent; 611*61b17cc6SDavid du Colombier } 6123e12c5d1SDavid du Colombier } 6133e12c5d1SDavid du Colombier 6143e12c5d1SDavid du Colombier File * 6153e12c5d1SDavid du Colombier file(File *parent, char *name) 6163e12c5d1SDavid du Colombier { 6179a747e4fSDavid du Colombier Dir *dir; 6189a747e4fSDavid du Colombier char *path; 6197dd7cddfSDavid du Colombier File *f; 6203e12c5d1SDavid du Colombier 6217dd7cddfSDavid du Colombier DEBUG(DFD, "\tfile: 0x%p %s name %s\n", parent, parent->name, name); 6223e12c5d1SDavid du Colombier 6239a747e4fSDavid du Colombier path = makepath(parent, name); 624a960ed1cSDavid du Colombier if(patternfile != nil && excludefile(path)){ 625a960ed1cSDavid du Colombier free(path); 626a960ed1cSDavid du Colombier return nil; 627a960ed1cSDavid du Colombier } 6289a747e4fSDavid du Colombier dir = dirstat(path); 6299a747e4fSDavid du Colombier free(path); 6309a747e4fSDavid du Colombier if(dir == nil) 6317dd7cddfSDavid du Colombier return nil; 6323e12c5d1SDavid du Colombier 633*61b17cc6SDavid du Colombier for(f = parent->child; f != nil; f = f->childlist) 6347dd7cddfSDavid du Colombier if(strcmp(name, f->name) == 0) 6357dd7cddfSDavid du Colombier break; 6367dd7cddfSDavid du Colombier 6377dd7cddfSDavid du Colombier if(f == nil){ 6389a747e4fSDavid du Colombier f = emallocz(sizeof(File)); 6399a747e4fSDavid du Colombier f->name = estrdup(name); 6403e12c5d1SDavid du Colombier 6417dd7cddfSDavid du Colombier f->parent = parent; 6427dd7cddfSDavid du Colombier f->childlist = parent->child; 6437dd7cddfSDavid du Colombier parent->child = f; 6447dd7cddfSDavid du Colombier parent->ref++; 6457dd7cddfSDavid du Colombier f->ref = 0; 6467dd7cddfSDavid du Colombier filecnt++; 6477dd7cddfSDavid du Colombier } 6487dd7cddfSDavid du Colombier f->ref++; 6499a747e4fSDavid du Colombier f->qid.type = dir->qid.type; 6509a747e4fSDavid du Colombier f->qid.vers = dir->qid.vers; 6519a747e4fSDavid du Colombier f->qidt = uniqueqid(dir); 6527dd7cddfSDavid du Colombier f->qid.path = f->qidt->uniqpath; 6533e12c5d1SDavid du Colombier 6547dd7cddfSDavid du Colombier f->inval = 0; 6553e12c5d1SDavid du Colombier 6569a747e4fSDavid du Colombier free(dir); 6577dd7cddfSDavid du Colombier 6587dd7cddfSDavid du Colombier return f; 6593e12c5d1SDavid du Colombier } 6603e12c5d1SDavid du Colombier 6613e12c5d1SDavid du Colombier void 6623e12c5d1SDavid du Colombier initroot(void) 6633e12c5d1SDavid du Colombier { 6649a747e4fSDavid du Colombier Dir *dir; 6653e12c5d1SDavid du Colombier 6669a747e4fSDavid du Colombier root = emallocz(sizeof(File)); 6679a747e4fSDavid du Colombier root->name = estrdup("."); 6683e12c5d1SDavid du Colombier 6699a747e4fSDavid du Colombier dir = dirstat(root->name); 6709a747e4fSDavid du Colombier if(dir == nil) 6713e12c5d1SDavid du Colombier fatal("root stat"); 6723e12c5d1SDavid du Colombier 6737dd7cddfSDavid du Colombier root->ref = 1; 6749a747e4fSDavid du Colombier root->qid.vers = dir->qid.vers; 6759a747e4fSDavid du Colombier root->qidt = uniqueqid(dir); 6767dd7cddfSDavid du Colombier root->qid.path = root->qidt->uniqpath; 6779a747e4fSDavid du Colombier root->qid.type = QTDIR; 6789a747e4fSDavid du Colombier free(dir); 679219b2ee8SDavid du Colombier 6809a747e4fSDavid du Colombier psmpt = emallocz(sizeof(File)); 6819a747e4fSDavid du Colombier psmpt->name = estrdup("/"); 682219b2ee8SDavid du Colombier 6839a747e4fSDavid du Colombier dir = dirstat(psmpt->name); 6849a747e4fSDavid du Colombier if(dir == nil) 685219b2ee8SDavid du Colombier return; 686219b2ee8SDavid du Colombier 6877dd7cddfSDavid du Colombier psmpt->ref = 1; 6889a747e4fSDavid du Colombier psmpt->qid.vers = dir->qid.vers; 6899a747e4fSDavid du Colombier psmpt->qidt = uniqueqid(dir); 6907dd7cddfSDavid du Colombier psmpt->qid.path = psmpt->qidt->uniqpath; 6919a747e4fSDavid du Colombier free(dir); 692219b2ee8SDavid du Colombier 693219b2ee8SDavid du Colombier psmpt = file(psmpt, "mnt"); 694*61b17cc6SDavid du Colombier if(psmpt == nil) 695219b2ee8SDavid du Colombier return; 696219b2ee8SDavid du Colombier psmpt = file(psmpt, "exportfs"); 6973e12c5d1SDavid du Colombier } 6983e12c5d1SDavid du Colombier 6999a747e4fSDavid du Colombier char* 7009a747e4fSDavid du Colombier makepath(File *p, char *name) 7013e12c5d1SDavid du Colombier { 7029a747e4fSDavid du Colombier int i, n; 7039a747e4fSDavid du Colombier char *c, *s, *path, *seg[256]; 7043e12c5d1SDavid du Colombier 7053e12c5d1SDavid du Colombier seg[0] = name; 7069a747e4fSDavid du Colombier n = strlen(name)+2; 7079a747e4fSDavid du Colombier for(i = 1; i < 256 && p; i++, p = p->parent){ 7083e12c5d1SDavid du Colombier seg[i] = p->name; 7099a747e4fSDavid du Colombier n += strlen(p->name)+1; 7109a747e4fSDavid du Colombier } 711*61b17cc6SDavid du Colombier path = emallocz(n); 7129a747e4fSDavid du Colombier s = path; 7133e12c5d1SDavid du Colombier 7143e12c5d1SDavid du Colombier while(i--) { 7153e12c5d1SDavid du Colombier for(c = seg[i]; *c; c++) 7163e12c5d1SDavid du Colombier *s++ = *c; 7173e12c5d1SDavid du Colombier *s++ = '/'; 7183e12c5d1SDavid du Colombier } 7193e12c5d1SDavid du Colombier while(s[-1] == '/') 7203e12c5d1SDavid du Colombier s--; 7213e12c5d1SDavid du Colombier *s = '\0'; 7229a747e4fSDavid du Colombier 7239a747e4fSDavid du Colombier return path; 7243e12c5d1SDavid du Colombier } 7253e12c5d1SDavid du Colombier 7267dd7cddfSDavid du Colombier int 7279a747e4fSDavid du Colombier qidhash(vlong path) 7287dd7cddfSDavid du Colombier { 7297dd7cddfSDavid du Colombier int h, n; 7307dd7cddfSDavid du Colombier 7317dd7cddfSDavid du Colombier h = 0; 7329a747e4fSDavid du Colombier for(n=0; n<64; n+=Nqidbits){ 7337dd7cddfSDavid du Colombier h ^= path; 7347dd7cddfSDavid du Colombier path >>= Nqidbits; 7357dd7cddfSDavid du Colombier } 7367dd7cddfSDavid du Colombier return h & (Nqidtab-1); 7377dd7cddfSDavid du Colombier } 7387dd7cddfSDavid du Colombier 7397dd7cddfSDavid du Colombier void 7407dd7cddfSDavid du Colombier freeqid(Qidtab *q) 7417dd7cddfSDavid du Colombier { 7427dd7cddfSDavid du Colombier ulong h; 7437dd7cddfSDavid du Colombier Qidtab *l; 7447dd7cddfSDavid du Colombier 745*61b17cc6SDavid du Colombier if(--q->ref) 7467dd7cddfSDavid du Colombier return; 7477dd7cddfSDavid du Colombier qfreecnt++; 7487dd7cddfSDavid du Colombier h = qidhash(q->path); 7497dd7cddfSDavid du Colombier if(qidtab[h] == q) 7507dd7cddfSDavid du Colombier qidtab[h] = q->next; 7517dd7cddfSDavid du Colombier else{ 7527dd7cddfSDavid du Colombier for(l=qidtab[h]; l->next!=q; l=l->next) 7537dd7cddfSDavid du Colombier if(l->next == nil) 7547dd7cddfSDavid du Colombier fatal("bad qid list"); 7557dd7cddfSDavid du Colombier l->next = q->next; 7567dd7cddfSDavid du Colombier } 7577dd7cddfSDavid du Colombier free(q); 7587dd7cddfSDavid du Colombier } 7597dd7cddfSDavid du Colombier 7607dd7cddfSDavid du Colombier Qidtab* 7617dd7cddfSDavid du Colombier qidlookup(Dir *d) 7627dd7cddfSDavid du Colombier { 7637dd7cddfSDavid du Colombier ulong h; 7647dd7cddfSDavid du Colombier Qidtab *q; 7657dd7cddfSDavid du Colombier 7667dd7cddfSDavid du Colombier h = qidhash(d->qid.path); 7677dd7cddfSDavid du Colombier for(q=qidtab[h]; q!=nil; q=q->next) 7687dd7cddfSDavid du Colombier if(q->type==d->type && q->dev==d->dev && q->path==d->qid.path) 7697dd7cddfSDavid du Colombier return q; 7707dd7cddfSDavid du Colombier return nil; 7717dd7cddfSDavid du Colombier } 7727dd7cddfSDavid du Colombier 7737dd7cddfSDavid du Colombier int 7749a747e4fSDavid du Colombier qidexists(vlong path) 7757dd7cddfSDavid du Colombier { 7767dd7cddfSDavid du Colombier int h; 7777dd7cddfSDavid du Colombier Qidtab *q; 7787dd7cddfSDavid du Colombier 7797dd7cddfSDavid du Colombier for(h=0; h<Nqidtab; h++) 7807dd7cddfSDavid du Colombier for(q=qidtab[h]; q!=nil; q=q->next) 7817dd7cddfSDavid du Colombier if(q->uniqpath == path) 7827dd7cddfSDavid du Colombier return 1; 7837dd7cddfSDavid du Colombier return 0; 7847dd7cddfSDavid du Colombier } 7857dd7cddfSDavid du Colombier 7867dd7cddfSDavid du Colombier Qidtab* 7877dd7cddfSDavid du Colombier uniqueqid(Dir *d) 7887dd7cddfSDavid du Colombier { 7899a747e4fSDavid du Colombier ulong h; 7909a747e4fSDavid du Colombier vlong path; 7917dd7cddfSDavid du Colombier Qidtab *q; 7927dd7cddfSDavid du Colombier 7937dd7cddfSDavid du Colombier q = qidlookup(d); 7947dd7cddfSDavid du Colombier if(q != nil){ 7957dd7cddfSDavid du Colombier q->ref++; 7967dd7cddfSDavid du Colombier return q; 7977dd7cddfSDavid du Colombier } 7987dd7cddfSDavid du Colombier path = d->qid.path; 7997dd7cddfSDavid du Colombier while(qidexists(path)){ 8009a747e4fSDavid du Colombier DEBUG(DFD, "collision on %s\n", d->name); 8017dd7cddfSDavid du Colombier /* collision: find a new one */ 8027dd7cddfSDavid du Colombier ncollision++; 8039a747e4fSDavid du Colombier path &= QIDPATH; 8049a747e4fSDavid du Colombier ++newqid; 8059a747e4fSDavid du Colombier if(newqid >= (1<<16)){ 8069a747e4fSDavid du Colombier DEBUG(DFD, "collision wraparound\n"); 8079a747e4fSDavid du Colombier newqid = 1; 8089a747e4fSDavid du Colombier } 8099a747e4fSDavid du Colombier path |= newqid<<48; 8109a747e4fSDavid du Colombier DEBUG(DFD, "assign qid %.16llux\n", path); 8117dd7cddfSDavid du Colombier } 8127dd7cddfSDavid du Colombier qidcnt++; 813*61b17cc6SDavid du Colombier q = emallocz(sizeof(Qidtab)); 8147dd7cddfSDavid du Colombier q->ref = 1; 8157dd7cddfSDavid du Colombier q->type = d->type; 8167dd7cddfSDavid du Colombier q->dev = d->dev; 8177dd7cddfSDavid du Colombier q->path = d->qid.path; 8187dd7cddfSDavid du Colombier q->uniqpath = path; 8197dd7cddfSDavid du Colombier h = qidhash(d->qid.path); 8207dd7cddfSDavid du Colombier q->next = qidtab[h]; 8217dd7cddfSDavid du Colombier qidtab[h] = q; 8227dd7cddfSDavid du Colombier return q; 8237dd7cddfSDavid du Colombier } 8247dd7cddfSDavid du Colombier 8253e12c5d1SDavid du Colombier void 8269a747e4fSDavid du Colombier fatal(char *s, ...) 8273e12c5d1SDavid du Colombier { 8289a747e4fSDavid du Colombier char buf[ERRMAX]; 8299a747e4fSDavid du Colombier va_list arg; 8303e12c5d1SDavid du Colombier Proc *m; 8313e12c5d1SDavid du Colombier 832*61b17cc6SDavid du Colombier if(s != nil) { 8339a747e4fSDavid du Colombier va_start(arg, s); 8349a747e4fSDavid du Colombier vsnprint(buf, ERRMAX, s, arg); 8359a747e4fSDavid du Colombier va_end(arg); 8369a747e4fSDavid du Colombier } 8373e12c5d1SDavid du Colombier 8383e12c5d1SDavid du Colombier /* Clear away the slave children */ 839*61b17cc6SDavid du Colombier for(m = Proclist; m != nil; m = m->next) 840219b2ee8SDavid du Colombier postnote(PNPROC, m->pid, "kill"); 8413e12c5d1SDavid du Colombier 842*61b17cc6SDavid du Colombier if(s != nil) { 8437dd7cddfSDavid du Colombier DEBUG(DFD, "%s\n", buf); 844243ea1fbSDavid du Colombier sysfatal("%s", buf); /* caution: buf could contain '%' */ 845*61b17cc6SDavid du Colombier } else 8469a747e4fSDavid du Colombier exits(nil); 8479a747e4fSDavid du Colombier } 8489a747e4fSDavid du Colombier 8499a747e4fSDavid du Colombier void* 8509a747e4fSDavid du Colombier emallocz(uint n) 8519a747e4fSDavid du Colombier { 8529a747e4fSDavid du Colombier void *p; 8539a747e4fSDavid du Colombier 8549a747e4fSDavid du Colombier p = mallocz(n, 1); 8559a747e4fSDavid du Colombier if(p == nil) 8569a747e4fSDavid du Colombier fatal(Enomem); 857*61b17cc6SDavid du Colombier setmalloctag(p, getcallerpc(&n)); 8589a747e4fSDavid du Colombier return p; 8599a747e4fSDavid du Colombier } 8609a747e4fSDavid du Colombier 8619a747e4fSDavid du Colombier char* 8629a747e4fSDavid du Colombier estrdup(char *s) 8639a747e4fSDavid du Colombier { 8649a747e4fSDavid du Colombier char *t; 8659a747e4fSDavid du Colombier 8669a747e4fSDavid du Colombier t = strdup(s); 8679a747e4fSDavid du Colombier if(t == nil) 8689a747e4fSDavid du Colombier fatal(Enomem); 869*61b17cc6SDavid du Colombier setmalloctag(t, getcallerpc(&s)); 8709a747e4fSDavid du Colombier return t; 8713e12c5d1SDavid du Colombier } 8723e12c5d1SDavid du Colombier 873*61b17cc6SDavid du Colombier void 874*61b17cc6SDavid du Colombier filter(int fd, char *cmd, char *host) 8753e12c5d1SDavid du Colombier { 876*61b17cc6SDavid du Colombier char addr[128], buf[256], *s, *file, *argv[16]; 877*61b17cc6SDavid du Colombier int lfd, p[2], len, argc; 8789a747e4fSDavid du Colombier 879*61b17cc6SDavid du Colombier if(host == nil){ 88029e26a97SDavid du Colombier /* Get a free port and post it to the client. */ 881*61b17cc6SDavid du Colombier if (announce(anstring, addr) < 0) 882*61b17cc6SDavid du Colombier fatal("filter: Cannot announce %s: %r", anstring); 8839a747e4fSDavid du Colombier 884*61b17cc6SDavid du Colombier snprint(buf, sizeof(buf), "%s/local", addr); 8859a747e4fSDavid du Colombier if ((lfd = open(buf, OREAD)) < 0) 886*61b17cc6SDavid du Colombier fatal("filter: Cannot open %s: %r", buf); 887*61b17cc6SDavid du Colombier if ((len = read(lfd, buf, sizeof buf - 1)) < 0) 888*61b17cc6SDavid du Colombier fatal("filter: Cannot read %s: %r", buf); 8899a747e4fSDavid du Colombier close(lfd); 890*61b17cc6SDavid du Colombier buf[len] = '\0'; 891*61b17cc6SDavid du Colombier if ((s = strchr(buf, '\n')) != nil) 892*61b17cc6SDavid du Colombier len = s - buf; 893*61b17cc6SDavid du Colombier if (write(fd, buf, len) != len) 894*61b17cc6SDavid du Colombier fatal("filter: cannot write port; %r"); 895*61b17cc6SDavid du Colombier } else { 896*61b17cc6SDavid du Colombier /* Read address string from connection */ 897*61b17cc6SDavid du Colombier if ((len = read(fd, buf, sizeof buf - 1)) < 0) 898*61b17cc6SDavid du Colombier sysfatal("filter: cannot write port; %r"); 899*61b17cc6SDavid du Colombier buf[len] = '\0'; 9009a747e4fSDavid du Colombier 901*61b17cc6SDavid du Colombier if ((s = strrchr(buf, '!')) == nil) 902*61b17cc6SDavid du Colombier sysfatal("filter: illegally formatted port %s", buf); 903*61b17cc6SDavid du Colombier strecpy(addr, addr+sizeof(addr), netmkaddr(host, "tcp", s+1)); 904*61b17cc6SDavid du Colombier strecpy(strrchr(addr, '!'), addr+sizeof(addr), s); 905*61b17cc6SDavid du Colombier } 9069a747e4fSDavid du Colombier 907*61b17cc6SDavid du Colombier DEBUG(DFD, "filter: %s\n", addr); 9089a747e4fSDavid du Colombier 909*61b17cc6SDavid du Colombier snprint(buf, sizeof(buf), "%s", cmd); 910*61b17cc6SDavid du Colombier argc = tokenize(buf, argv, nelem(argv)-3); 9119a747e4fSDavid du Colombier if (argc == 0) 9129a747e4fSDavid du Colombier sysfatal("filter: empty command"); 913*61b17cc6SDavid du Colombier 914*61b17cc6SDavid du Colombier if(host != nil) 915*61b17cc6SDavid du Colombier argv[argc++] = "-c"; 916*61b17cc6SDavid du Colombier argv[argc++] = addr; 9179a747e4fSDavid du Colombier argv[argc] = nil; 918*61b17cc6SDavid du Colombier 9199a747e4fSDavid du Colombier file = argv[0]; 920*61b17cc6SDavid du Colombier if((s = strrchr(argv[0], '/')) != nil) 9219a747e4fSDavid du Colombier argv[0] = s+1; 9223e12c5d1SDavid du Colombier 9237dd7cddfSDavid du Colombier if(pipe(p) < 0) 924*61b17cc6SDavid du Colombier sysfatal("pipe: %r"); 9257dd7cddfSDavid du Colombier 926*61b17cc6SDavid du Colombier switch(rfork(RFNOWAIT|RFPROC|RFMEM|RFFDG|RFREND)) { 9277dd7cddfSDavid du Colombier case -1: 928*61b17cc6SDavid du Colombier fatal("filter: rfork; %r\n"); 9297dd7cddfSDavid du Colombier case 0: 930*61b17cc6SDavid du Colombier close(fd); 9319a747e4fSDavid du Colombier if (dup(p[0], 1) < 0) 932*61b17cc6SDavid du Colombier fatal("filter: Cannot dup to 1; %r"); 9339a747e4fSDavid du Colombier if (dup(p[0], 0) < 0) 934*61b17cc6SDavid du Colombier fatal("filter: Cannot dup to 0; %r"); 9357dd7cddfSDavid du Colombier close(p[0]); 9367dd7cddfSDavid du Colombier close(p[1]); 9379a747e4fSDavid du Colombier exec(file, argv); 938*61b17cc6SDavid du Colombier fatal("filter: exec; %r"); 9397dd7cddfSDavid du Colombier default: 940*61b17cc6SDavid du Colombier dup(p[1], fd); 9417dd7cddfSDavid du Colombier close(p[0]); 942*61b17cc6SDavid du Colombier close(p[1]); 9433e12c5d1SDavid du Colombier } 9443e12c5d1SDavid du Colombier } 9459a747e4fSDavid du Colombier 9469a747e4fSDavid du Colombier static void 9479a747e4fSDavid du Colombier mksecret(char *t, uchar *f) 9489a747e4fSDavid du Colombier { 9499a747e4fSDavid du Colombier sprint(t, "%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux", 9509a747e4fSDavid du Colombier f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9]); 9519a747e4fSDavid du Colombier } 952