Unified · Split
| @@ -0,0 +1,937 @@ | ||
| 1 | +/* | |
| 2 | + * exportfs - Export a plan 9 name space across a network | |
| 3 | + */ | |
| 4 | +#include <u.h> | |
| 5 | +#include <libc.h> | |
| 6 | +#include <auth.h> | |
| 7 | +#include <fcall.h> | |
| 8 | +#include <libsec.h> | |
| 9 | +#define Extern | |
| 10 | +#include "exportfs.h" | |
| 11 | + | |
| 12 | +#define QIDPATH ((1LL<<48)-1) | |
| 13 | +vlong newqid = 0; | |
| 14 | + | |
| 15 | +enum { | |
| 16 | + Encnone, | |
| 17 | + Encssl, | |
| 18 | + Enctls, | |
| 19 | +}; | |
| 20 | + | |
| 21 | +void (*fcalls[])(Fsrpc*) = | |
| 22 | +{ | |
| 23 | + [Tversion] Xversion, | |
| 24 | + [Tauth] Xauth, | |
| 25 | + [Tflush] Xflush, | |
| 26 | + [Tattach] Xattach, | |
| 27 | + [Twalk] Xwalk, | |
| 28 | + [Topen] slave, | |
| 29 | + [Tcreate] Xcreate, | |
| 30 | + [Tclunk] Xclunk, | |
| 31 | + [Tread] slave, | |
| 32 | + [Twrite] slave, | |
| 33 | + [Tremove] Xremove, | |
| 34 | + [Tstat] Xstat, | |
| 35 | + [Twstat] Xwstat, | |
| 36 | +}; | |
| 37 | + | |
| 38 | +/* accounting and debugging counters */ | |
| 39 | +int filecnt; | |
| 40 | +int freecnt; | |
| 41 | +int qidcnt; | |
| 42 | +int qfreecnt; | |
| 43 | +int ncollision; | |
| 44 | + | |
| 45 | +int netfd; /* initially stdin */ | |
| 46 | +int srvfd = -1; | |
| 47 | +int nonone = 1; | |
| 48 | +char *filterp; | |
| 49 | +char *ealgs = "rc4_256 sha1"; | |
| 50 | +char *aanfilter = "/bin/aan"; | |
| 51 | +int encproto = Encnone; | |
| 52 | +int readonly; | |
| 53 | + | |
| 54 | +static void mksecret(char *, uchar *); | |
| 55 | +static int localread9pmsg(int, void *, uint, ulong *); | |
| 56 | +static char *anstring = "tcp!*!0"; | |
| 57 | + | |
| 58 | +char *netdir = "", *local = "", *remote = ""; | |
| 59 | + | |
| 60 | +int filter(int, char *); | |
| 61 | + | |
| 62 | +void | |
| 63 | +usage(void) | |
| 64 | +{ | |
| 65 | + fprint(2, "usage: %s [-adnsR] [-f dbgfile] [-m msize] [-r root] " | |
| 66 | + "[-S srvfile] [-e 'crypt hash'] [-P exclusion-file] " | |
| 67 | + "[-A announce-string] [-B address]\n", argv0); | |
| 68 | + fatal("usage"); | |
| 69 | +} | |
| 70 | + | |
| 71 | +static void | |
| 72 | +noteconn(int fd) | |
| 73 | +{ | |
| 74 | + NetConnInfo *nci; | |
| 75 | + | |
| 76 | + nci = getnetconninfo(nil, fd); | |
| 77 | + if (nci == nil) | |
| 78 | + return; | |
| 79 | + netdir = strdup(nci->dir); | |
| 80 | + local = strdup(nci->lsys); | |
| 81 | + remote = strdup(nci->rsys); | |
| 82 | + freenetconninfo(nci); | |
| 83 | +} | |
| 84 | + | |
| 85 | +void | |
| 86 | +main(int argc, char **argv) | |
| 87 | +{ | |
| 88 | + char buf[ERRMAX], ebuf[ERRMAX], *srvfdfile; | |
| 89 | + Fsrpc *r; | |
| 90 | + int doauth, n, fd; | |
| 91 | + char *dbfile, *srv, *na, *nsfile, *keyspec; | |
| 92 | + AuthInfo *ai; | |
| 93 | + ulong initial; | |
| 94 | + | |
| 95 | + dbfile = "/tmp/exportdb"; | |
| 96 | + srv = nil; | |
| 97 | + srvfd = -1; | |
| 98 | + srvfdfile = nil; | |
| 99 | + na = nil; | |
| 100 | + nsfile = nil; | |
| 101 | + keyspec = ""; | |
| 102 | + doauth = 0; | |
| 103 | + | |
| 104 | + ai = nil; | |
| 105 | + ARGBEGIN{ | |
| 106 | + case 'a': | |
| 107 | + doauth = 1; | |
| 108 | + break; | |
| 109 | + | |
| 110 | + case 'd': | |
| 111 | + dbg++; | |
| 112 | + break; | |
| 113 | + | |
| 114 | + case 'e': | |
| 115 | + ealgs = EARGF(usage()); | |
| 116 | + if(*ealgs == 0 || strcmp(ealgs, "clear") == 0) | |
| 117 | + ealgs = nil; | |
| 118 | + break; | |
| 119 | + | |
| 120 | + case 'f': | |
| 121 | + dbfile = EARGF(usage()); | |
| 122 | + break; | |
| 123 | + | |
| 124 | + case 'k': | |
| 125 | + keyspec = EARGF(usage()); | |
| 126 | + break; | |
| 127 | + | |
| 128 | + case 'm': | |
| 129 | + messagesize = strtoul(EARGF(usage()), nil, 0); | |
| 130 | + break; | |
| 131 | + | |
| 132 | + case 'n': | |
| 133 | + nonone = 0; | |
| 134 | + break; | |
| 135 | + | |
| 136 | + case 'r': | |
| 137 | + srv = EARGF(usage()); | |
| 138 | + break; | |
| 139 | + | |
| 140 | + case 's': | |
| 141 | + srv = "/"; | |
| 142 | + break; | |
| 143 | + | |
| 144 | + case 'A': | |
| 145 | + anstring = EARGF(usage()); | |
| 146 | + break; | |
| 147 | + | |
| 148 | + case 'B': | |
| 149 | + na = EARGF(usage()); | |
| 150 | + break; | |
| 151 | + | |
| 152 | + case 'F': | |
| 153 | + /* accepted but ignored, for backwards compatibility */ | |
| 154 | + break; | |
| 155 | + | |
| 156 | + case 'N': | |
| 157 | + nsfile = EARGF(usage()); | |
| 158 | + break; | |
| 159 | + | |
| 160 | + case 'P': | |
| 161 | + patternfile = EARGF(usage()); | |
| 162 | + break; | |
| 163 | + | |
| 164 | + case 'R': | |
| 165 | + readonly = 1; | |
| 166 | + break; | |
| 167 | + | |
| 168 | + case 'S': | |
| 169 | + if(srvfdfile) | |
| 170 | + usage(); | |
| 171 | + srvfdfile = EARGF(usage()); | |
| 172 | + break; | |
| 173 | + | |
| 174 | + default: | |
| 175 | + usage(); | |
| 176 | + }ARGEND | |
| 177 | + USED(argc, argv); | |
| 178 | + | |
| 179 | + if(doauth){ | |
| 180 | + /* | |
| 181 | + * We use p9any so we don't have to visit this code again, with the | |
| 182 | + * cost that this code is incompatible with the old world, which | |
| 183 | + * requires p9sk2. (The two differ in who talks first, so compatibility | |
| 184 | + * is awkward.) | |
| 185 | + */ | |
| 186 | + ai = auth_proxy(0, auth_getkey, "proto=p9any role=server %s", keyspec); | |
| 187 | + if(ai == nil) | |
| 188 | + fatal("auth_proxy: %r"); | |
| 189 | + if(nonone && strcmp(ai->cuid, "none") == 0) | |
| 190 | + fatal("exportfs by none disallowed"); | |
| 191 | + if(auth_chuid(ai, nsfile) < 0) | |
| 192 | + fatal("auth_chuid: %r"); | |
| 193 | + putenv("service", "exportfs"); | |
| 194 | + } | |
| 195 | + | |
| 196 | + if(srvfdfile){ | |
| 197 | + if((srvfd = open(srvfdfile, ORDWR)) < 0) | |
| 198 | + sysfatal("open '%s': %r", srvfdfile); | |
| 199 | + } | |
| 200 | + | |
| 201 | + if(na){ | |
| 202 | + if(srv == nil) | |
| 203 | + sysfatal("-B requires -s"); | |
| 204 | + | |
| 205 | + local = "me"; | |
| 206 | + remote = na; | |
| 207 | + if((fd = dial(netmkaddr(na, 0, "importfs"), 0, 0, 0)) < 0) | |
| 208 | + sysfatal("can't dial %s: %r", na); | |
| 209 | + | |
| 210 | + ai = auth_proxy(fd, auth_getkey, "proto=p9any role=client %s", keyspec); | |
| 211 | + if(ai == nil) | |
| 212 | + sysfatal("%r: %s", na); | |
| 213 | + | |
| 214 | + dup(fd, 0); | |
| 215 | + dup(fd, 1); | |
| 216 | + close(fd); | |
| 217 | + } | |
| 218 | + | |
| 219 | + exclusions(); | |
| 220 | + | |
| 221 | + if(dbg) { | |
| 222 | + n = create(dbfile, OWRITE|OTRUNC, 0666); | |
| 223 | + dup(n, DFD); | |
| 224 | + close(n); | |
| 225 | + } | |
| 226 | + | |
| 227 | + if(srvfd >= 0 && srv){ | |
| 228 | + fprint(2, "exportfs: -S cannot be used with -r or -s\n"); | |
| 229 | + usage(); | |
| 230 | + } | |
| 231 | + | |
| 232 | + DEBUG(DFD, "exportfs: started\n"); | |
| 233 | + | |
| 234 | + rfork(RFNOTEG); | |
| 235 | + | |
| 236 | + if(messagesize == 0){ | |
| 237 | + messagesize = iounit(netfd); | |
| 238 | + if(messagesize == 0) | |
| 239 | + messagesize = 8192+IOHDRSZ; | |
| 240 | + } | |
| 241 | + | |
| 242 | + Workq = emallocz(sizeof(Fsrpc)*Nr_workbufs); | |
| 243 | +// for(i=0; i<Nr_workbufs; i++) | |
| 244 | +// Workq[i].buf = emallocz(messagesize); | |
| 245 | + fhash = emallocz(sizeof(Fid*)*FHASHSIZE); | |
| 246 | + | |
| 247 | + fmtinstall('F', fcallfmt); | |
| 248 | + | |
| 249 | + /* | |
| 250 | + * Get tree to serve from network connection, | |
| 251 | + * check we can get there and ack the connection | |
| 252 | + */ | |
| 253 | + if(srvfd != -1) { | |
| 254 | + /* do nothing */ | |
| 255 | + } | |
| 256 | + else if(srv) { | |
| 257 | + chdir(srv); | |
| 258 | + DEBUG(DFD, "invoked as server for %s", srv); | |
| 259 | + strncpy(buf, srv, sizeof buf); | |
| 260 | + } | |
| 261 | + else { | |
| 262 | + noteconn(netfd); | |
| 263 | + buf[0] = 0; | |
| 264 | + n = read(0, buf, sizeof(buf)-1); | |
| 265 | + if(n < 0) { | |
| 266 | + errstr(buf, sizeof buf); | |
| 267 | + fprint(0, "read(0): %s", buf); | |
| 268 | + DEBUG(DFD, "read(0): %s", buf); | |
| 269 | + exits(buf); | |
| 270 | + } | |
| 271 | + buf[n] = 0; | |
| 272 | + if(chdir(buf) < 0) { | |
| 273 | + errstr(ebuf, sizeof ebuf); | |
| 274 | + fprint(0, "chdir(%d:\"%s\"): %s", n, buf, ebuf); | |
| 275 | + DEBUG(DFD, "chdir(%d:\"%s\"): %s", n, buf, ebuf); | |
| 276 | + exits(ebuf); | |
| 277 | + } | |
| 278 | + } | |
| 279 | + | |
| 280 | + DEBUG(DFD, "\niniting root\n"); | |
| 281 | + initroot(); | |
| 282 | + | |
| 283 | + DEBUG(DFD, "exportfs: %s\n", buf); | |
| 284 | + | |
| 285 | + if(srv == nil && srvfd == -1 && write(0, "OK", 2) != 2) | |
| 286 | + fatal("open ack write"); | |
| 287 | + | |
| 288 | + if (readn(netfd, &initial, sizeof(ulong)) < sizeof(ulong)) | |
| 289 | + fatal("can't read initial string: %r\n"); | |
| 290 | + | |
| 291 | + if (strncmp((char *)&initial, "impo", sizeof(ulong)) == 0) { | |
| 292 | + char buf[128], *p, *args[3]; | |
| 293 | + | |
| 294 | + /* New import. Read import's parameters... */ | |
| 295 | + initial = 0; | |
| 296 | + | |
| 297 | + p = buf; | |
| 298 | + while (p - buf < sizeof buf) { | |
| 299 | + if ((n = read(netfd, p, 1)) < 0) | |
| 300 | + fatal("can't read impo arguments: %r\n"); | |
| 301 | + | |
| 302 | + if (n == 0) | |
| 303 | + fatal("connection closed while reading arguments\n"); | |
| 304 | + | |
| 305 | + if (*p == '\n') | |
| 306 | + *p = '\0'; | |
| 307 | + if (*p++ == '\0') | |
| 308 | + break; | |
| 309 | + } | |
| 310 | + | |
| 311 | + if (tokenize(buf, args, nelem(args)) != 2) | |
| 312 | + fatal("impo arguments invalid: impo%s...\n", buf); | |
| 313 | + | |
| 314 | + if (strcmp(args[0], "aan") == 0) | |
| 315 | + filterp = aanfilter; | |
| 316 | + else if (strcmp(args[0], "nofilter") != 0) | |
| 317 | + fatal("import filter argument unsupported: %s\n", args[0]); | |
| 318 | + | |
| 319 | + if (strcmp(args[1], "ssl") == 0) | |
| 320 | + encproto = Encssl; | |
| 321 | + else if (strcmp(args[1], "tls") == 0) | |
| 322 | + encproto = Enctls; | |
| 323 | + else if (strcmp(args[1], "clear") != 0) | |
| 324 | + fatal("import encryption proto unsupported: %s\n", args[1]); | |
| 325 | + | |
| 326 | + if (encproto == Enctls) | |
| 327 | + sysfatal("%s: tls has not yet been implemented", argv[0]); | |
| 328 | + } | |
| 329 | + | |
| 330 | + if (encproto != Encnone && ealgs && ai) { | |
| 331 | + uchar key[16]; | |
| 332 | + uchar digest[SHA1dlen]; | |
| 333 | + char fromclientsecret[21]; | |
| 334 | + char fromserversecret[21]; | |
| 335 | + int i; | |
| 336 | + | |
| 337 | + memmove(key+4, ai->secret, ai->nsecret); | |
| 338 | + | |
| 339 | + /* exchange random numbers */ | |
| 340 | + srand(truerand()); | |
| 341 | + for(i = 0; i < 4; i++) | |
| 342 | + key[i+12] = rand(); | |
| 343 | + | |
| 344 | + if (initial) | |
| 345 | + fatal("Protocol botch: old import\n"); | |
| 346 | + if(readn(netfd, key, 4) != 4) | |
| 347 | + fatal("can't read key part; %r\n"); | |
| 348 | + | |
| 349 | + if(write(netfd, key+12, 4) != 4) | |
| 350 | + fatal("can't write key part; %r\n"); | |
| 351 | + | |
| 352 | + /* scramble into two secrets */ | |
| 353 | + sha1(key, sizeof(key), digest, nil); | |
| 354 | + mksecret(fromclientsecret, digest); | |
| 355 | + mksecret(fromserversecret, digest+10); | |
| 356 | + | |
| 357 | + if (filterp) | |
| 358 | + netfd = filter(netfd, filterp); | |
| 359 | + | |
| 360 | + switch (encproto) { | |
| 361 | + case Encssl: | |
| 362 | + netfd = pushssl(netfd, ealgs, fromserversecret, | |
| 363 | + fromclientsecret, nil); | |
| 364 | + break; | |
| 365 | + case Enctls: | |
| 366 | + default: | |
| 367 | + fatal("Unsupported encryption protocol\n"); | |
| 368 | + } | |
| 369 | + | |
| 370 | + if(netfd < 0) | |
| 371 | + fatal("can't establish ssl connection: %r"); | |
| 372 | + } | |
| 373 | + else if (filterp) { | |
| 374 | + if (initial) | |
| 375 | + fatal("Protocol botch: don't know how to deal with this\n"); | |
| 376 | + netfd = filter(netfd, filterp); | |
| 377 | + } | |
| 378 | + | |
| 379 | + /* | |
| 380 | + * Start serving file requests from the network | |
| 381 | + */ | |
| 382 | + for(;;) { | |
| 383 | + r = getsbuf(); | |
| 384 | + if(r == 0) | |
| 385 | + fatal("Out of service buffers"); | |
| 386 | + | |
| 387 | + n = localread9pmsg(netfd, r->buf, messagesize, &initial); | |
| 388 | + if(n <= 0) | |
| 389 | + fatal(nil); | |
| 390 | + | |
| 391 | + if(convM2S(r->buf, n, &r->work) == 0) | |
| 392 | + fatal("convM2S format error"); | |
| 393 | + | |
| 394 | + DEBUG(DFD, "%F\n", &r->work); | |
| 395 | + (fcalls[r->work.type])(r); | |
| 396 | + } | |
| 397 | +} | |
| 398 | + | |
| 399 | +/* | |
| 400 | + * WARNING: Replace this with the original version as soon as all | |
| 401 | + * _old_ imports have been replaced with negotiating imports. Also | |
| 402 | + * cpu relies on this (which needs to be fixed!) -- pb. | |
| 403 | + */ | |
| 404 | +static int | |
| 405 | +localread9pmsg(int fd, void *abuf, uint n, ulong *initial) | |
| 406 | +{ | |
| 407 | + int m, len; | |
| 408 | + uchar *buf; | |
| 409 | + | |
| 410 | + buf = abuf; | |
| 411 | + | |
| 412 | + /* read count */ | |
| 413 | + assert(BIT32SZ == sizeof(ulong)); | |
| 414 | + if (*initial) { | |
| 415 | + memcpy(buf, initial, BIT32SZ); | |
| 416 | + *initial = 0; | |
| 417 | + } | |
| 418 | + else { | |
| 419 | + m = readn(fd, buf, BIT32SZ); | |
| 420 | + if(m != BIT32SZ){ | |
| 421 | + if(m < 0) | |
| 422 | + return -1; | |
| 423 | + return 0; | |
| 424 | + } | |
| 425 | + } | |
| 426 | + | |
| 427 | + len = GBIT32(buf); | |
| 428 | + if(len <= BIT32SZ || len > n){ | |
| 429 | + werrstr("bad length in 9P2000 message header"); | |
| 430 | + return -1; | |
| 431 | + } | |
| 432 | + len -= BIT32SZ; | |
| 433 | + m = readn(fd, buf+BIT32SZ, len); | |
| 434 | + if(m < len) | |
| 435 | + return 0; | |
| 436 | + return BIT32SZ+m; | |
| 437 | +} | |
| 438 | +void | |
| 439 | +reply(Fcall *r, Fcall *t, char *err) | |
| 440 | +{ | |
| 441 | + uchar *data; | |
| 442 | + int n; | |
| 443 | + | |
| 444 | + t->tag = r->tag; | |
| 445 | + t->fid = r->fid; | |
| 446 | + if(err) { | |
| 447 | + t->type = Rerror; | |
| 448 | + t->ename = err; | |
| 449 | + } | |
| 450 | + else | |
| 451 | + t->type = r->type + 1; | |
| 452 | + | |
| 453 | + DEBUG(DFD, "\t%F\n", t); | |
| 454 | + | |
| 455 | + data = malloc(messagesize); /* not mallocz; no need to clear */ | |
| 456 | + if(data == nil) | |
| 457 | + fatal(Enomem); | |
| 458 | + n = convS2M(t, data, messagesize); | |
| 459 | + if(write(netfd, data, n)!=n) | |
| 460 | +{syslog(0, "exportfs", "short write: %r"); | |
| 461 | + fatal("mount write"); | |
| 462 | +} | |
| 463 | + free(data); | |
| 464 | +} | |
| 465 | + | |
| 466 | +Fid * | |
| 467 | +getfid(int nr) | |
| 468 | +{ | |
| 469 | + Fid *f; | |
| 470 | + | |
| 471 | + for(f = fidhash(nr); f; f = f->next) | |
| 472 | + if(f->nr == nr) | |
| 473 | + return f; | |
| 474 | + | |
| 475 | + return 0; | |
| 476 | +} | |
| 477 | + | |
| 478 | +int | |
| 479 | +freefid(int nr) | |
| 480 | +{ | |
| 481 | + Fid *f, **l; | |
| 482 | + char buf[128]; | |
| 483 | + | |
| 484 | + l = &fidhash(nr); | |
| 485 | + for(f = *l; f; f = f->next) { | |
| 486 | + if(f->nr == nr) { | |
| 487 | + if(f->mid) { | |
| 488 | + sprint(buf, "/mnt/exportfs/%d", f->mid); | |
| 489 | + unmount(0, buf); | |
| 490 | + psmap[f->mid] = 0; | |
| 491 | + } | |
| 492 | + if(f->f) { | |
| 493 | + freefile(f->f); | |
| 494 | + f->f = nil; | |
| 495 | + } | |
| 496 | + if(f->dir){ | |
| 497 | + free(f->dir); | |
| 498 | + f->dir = nil; | |
| 499 | + } | |
| 500 | + *l = f->next; | |
| 501 | + f->next = fidfree; | |
| 502 | + fidfree = f; | |
| 503 | + return 1; | |
| 504 | + } | |
| 505 | + l = &f->next; | |
| 506 | + } | |
| 507 | + | |
| 508 | + return 0; | |
| 509 | +} | |
| 510 | + | |
| 511 | +Fid * | |
| 512 | +newfid(int nr) | |
| 513 | +{ | |
| 514 | + Fid *new, **l; | |
| 515 | + int i; | |
| 516 | + | |
| 517 | + l = &fidhash(nr); | |
| 518 | + for(new = *l; new; new = new->next) | |
| 519 | + if(new->nr == nr) | |
| 520 | + return 0; | |
| 521 | + | |
| 522 | + if(fidfree == 0) { | |
| 523 | + fidfree = emallocz(sizeof(Fid) * Fidchunk); | |
| 524 | + | |
| 525 | + for(i = 0; i < Fidchunk-1; i++) | |
| 526 | + fidfree[i].next = &fidfree[i+1]; | |
| 527 | + | |
| 528 | + fidfree[Fidchunk-1].next = 0; | |
| 529 | + } | |
| 530 | + | |
| 531 | + new = fidfree; | |
| 532 | + fidfree = new->next; | |
| 533 | + | |
| 534 | + memset(new, 0, sizeof(Fid)); | |
| 535 | + new->next = *l; | |
| 536 | + *l = new; | |
| 537 | + new->nr = nr; | |
| 538 | + new->fid = -1; | |
| 539 | + new->mid = 0; | |
| 540 | + | |
| 541 | + return new; | |
| 542 | +} | |
| 543 | + | |
| 544 | +Fsrpc * | |
| 545 | +getsbuf(void) | |
| 546 | +{ | |
| 547 | + static int ap; | |
| 548 | + int look, rounds; | |
| 549 | + Fsrpc *wb; | |
| 550 | + int small_instead_of_fast = 1; | |
| 551 | + | |
| 552 | + if(small_instead_of_fast) | |
| 553 | + ap = 0; /* so we always start looking at the beginning and reuse buffers */ | |
| 554 | + | |
| 555 | + for(rounds = 0; rounds < 10; rounds++) { | |
| 556 | + for(look = 0; look < Nr_workbufs; look++) { | |
| 557 | + if(++ap == Nr_workbufs) | |
| 558 | + ap = 0; | |
| 559 | + if(Workq[ap].busy == 0) | |
| 560 | + break; | |
| 561 | + } | |
| 562 | + | |
| 563 | + if(look == Nr_workbufs){ | |
| 564 | + sleep(10 * rounds); | |
| 565 | + continue; | |
| 566 | + } | |
| 567 | + | |
| 568 | + wb = &Workq[ap]; | |
| 569 | + wb->pid = 0; | |
| 570 | + wb->canint = 0; | |
| 571 | + wb->flushtag = NOTAG; | |
| 572 | + wb->busy = 1; | |
| 573 | + if(wb->buf == nil) /* allocate buffers dynamically to keep size down */ | |
| 574 | + wb->buf = emallocz(messagesize); | |
| 575 | + return wb; | |
| 576 | + } | |
| 577 | + fatal("No more work buffers"); | |
| 578 | + return nil; | |
| 579 | +} | |
| 580 | + | |
| 581 | +void | |
| 582 | +freefile(File *f) | |
| 583 | +{ | |
| 584 | + File *parent, *child; | |
| 585 | + | |
| 586 | +Loop: | |
| 587 | + f->ref--; | |
| 588 | + if(f->ref > 0) | |
| 589 | + return; | |
| 590 | + freecnt++; | |
| 591 | + if(f->ref < 0) abort(); | |
| 592 | + DEBUG(DFD, "free %s\n", f->name); | |
| 593 | + /* delete from parent */ | |
| 594 | + parent = f->parent; | |
| 595 | + if(parent->child == f) | |
| 596 | + parent->child = f->childlist; | |
| 597 | + else{ | |
| 598 | + for(child=parent->child; child->childlist!=f; child=child->childlist) | |
| 599 | + if(child->childlist == nil) | |
| 600 | + fatal("bad child list"); | |
| 601 | + child->childlist = f->childlist; | |
| 602 | + } | |
| 603 | + freeqid(f->qidt); | |
| 604 | + free(f->name); | |
| 605 | + f->name = nil; | |
| 606 | + free(f); | |
| 607 | + f = parent; | |
| 608 | + if(f != nil) | |
| 609 | + goto Loop; | |
| 610 | +} | |
| 611 | + | |
| 612 | +File * | |
| 613 | +file(File *parent, char *name) | |
| 614 | +{ | |
| 615 | + Dir *dir; | |
| 616 | + char *path; | |
| 617 | + File *f; | |
| 618 | + | |
| 619 | + DEBUG(DFD, "\tfile: 0x%p %s name %s\n", parent, parent->name, name); | |
| 620 | + | |
| 621 | + path = makepath(parent, name); | |
| 622 | + if(patternfile != nil && excludefile(path)){ | |
| 623 | + free(path); | |
| 624 | + return nil; | |
| 625 | + } | |
| 626 | + dir = dirstat(path); | |
| 627 | + free(path); | |
| 628 | + if(dir == nil) | |
| 629 | + return nil; | |
| 630 | + | |
| 631 | + for(f = parent->child; f; f = f->childlist) | |
| 632 | + if(strcmp(name, f->name) == 0) | |
| 633 | + break; | |
| 634 | + | |
| 635 | + if(f == nil){ | |
| 636 | + f = emallocz(sizeof(File)); | |
| 637 | + f->name = estrdup(name); | |
| 638 | + | |
| 639 | + f->parent = parent; | |
| 640 | + f->childlist = parent->child; | |
| 641 | + parent->child = f; | |
| 642 | + parent->ref++; | |
| 643 | + f->ref = 0; | |
| 644 | + filecnt++; | |
| 645 | + } | |
| 646 | + f->ref++; | |
| 647 | + f->qid.type = dir->qid.type; | |
| 648 | + f->qid.vers = dir->qid.vers; | |
| 649 | + f->qidt = uniqueqid(dir); | |
| 650 | + f->qid.path = f->qidt->uniqpath; | |
| 651 | + | |
| 652 | + f->inval = 0; | |
| 653 | + | |
| 654 | + free(dir); | |
| 655 | + | |
| 656 | + return f; | |
| 657 | +} | |
| 658 | + | |
| 659 | +void | |
| 660 | +initroot(void) | |
| 661 | +{ | |
| 662 | + Dir *dir; | |
| 663 | + | |
| 664 | + root = emallocz(sizeof(File)); | |
| 665 | + root->name = estrdup("."); | |
| 666 | + | |
| 667 | + dir = dirstat(root->name); | |
| 668 | + if(dir == nil) | |
| 669 | + fatal("root stat"); | |
| 670 | + | |
| 671 | + root->ref = 1; | |
| 672 | + root->qid.vers = dir->qid.vers; | |
| 673 | + root->qidt = uniqueqid(dir); | |
| 674 | + root->qid.path = root->qidt->uniqpath; | |
| 675 | + root->qid.type = QTDIR; | |
| 676 | + free(dir); | |
| 677 | + | |
| 678 | + psmpt = emallocz(sizeof(File)); | |
| 679 | + psmpt->name = estrdup("/"); | |
| 680 | + | |
| 681 | + dir = dirstat(psmpt->name); | |
| 682 | + if(dir == nil) | |
| 683 | + return; | |
| 684 | + | |
| 685 | + psmpt->ref = 1; | |
| 686 | + psmpt->qid.vers = dir->qid.vers; | |
| 687 | + psmpt->qidt = uniqueqid(dir); | |
| 688 | + psmpt->qid.path = psmpt->qidt->uniqpath; | |
| 689 | + free(dir); | |
| 690 | + | |
| 691 | + psmpt = file(psmpt, "mnt"); | |
| 692 | + if(psmpt == 0) | |
| 693 | + return; | |
| 694 | + psmpt = file(psmpt, "exportfs"); | |
| 695 | +} | |
| 696 | + | |
| 697 | +char* | |
| 698 | +makepath(File *p, char *name) | |
| 699 | +{ | |
| 700 | + int i, n; | |
| 701 | + char *c, *s, *path, *seg[256]; | |
| 702 | + | |
| 703 | + seg[0] = name; | |
| 704 | + n = strlen(name)+2; | |
| 705 | + for(i = 1; i < 256 && p; i++, p = p->parent){ | |
| 706 | + seg[i] = p->name; | |
| 707 | + n += strlen(p->name)+1; | |
| 708 | + } | |
| 709 | + path = malloc(n); | |
| 710 | + if(path == nil) | |
| 711 | + fatal("out of memory"); | |
| 712 | + s = path; | |
| 713 | + | |
| 714 | + while(i--) { | |
| 715 | + for(c = seg[i]; *c; c++) | |
| 716 | + *s++ = *c; | |
| 717 | + *s++ = '/'; | |
| 718 | + } | |
| 719 | + while(s[-1] == '/') | |
| 720 | + s--; | |
| 721 | + *s = '\0'; | |
| 722 | + | |
| 723 | + return path; | |
| 724 | +} | |
| 725 | + | |
| 726 | +int | |
| 727 | +qidhash(vlong path) | |
| 728 | +{ | |
| 729 | + int h, n; | |
| 730 | + | |
| 731 | + h = 0; | |
| 732 | + for(n=0; n<64; n+=Nqidbits){ | |
| 733 | + h ^= path; | |
| 734 | + path >>= Nqidbits; | |
| 735 | + } | |
| 736 | + return h & (Nqidtab-1); | |
| 737 | +} | |
| 738 | + | |
| 739 | +void | |
| 740 | +freeqid(Qidtab *q) | |
| 741 | +{ | |
| 742 | + ulong h; | |
| 743 | + Qidtab *l; | |
| 744 | + | |
| 745 | + q->ref--; | |
| 746 | + if(q->ref > 0) | |
| 747 | + return; | |
| 748 | + qfreecnt++; | |
| 749 | + h = qidhash(q->path); | |
| 750 | + if(qidtab[h] == q) | |
| 751 | + qidtab[h] = q->next; | |
| 752 | + else{ | |
| 753 | + for(l=qidtab[h]; l->next!=q; l=l->next) | |
| 754 | + if(l->next == nil) | |
| 755 | + fatal("bad qid list"); | |
| 756 | + l->next = q->next; | |
| 757 | + } | |
| 758 | + free(q); | |
| 759 | +} | |
| 760 | + | |
| 761 | +Qidtab* | |
| 762 | +qidlookup(Dir *d) | |
| 763 | +{ | |
| 764 | + ulong h; | |
| 765 | + Qidtab *q; | |
| 766 | + | |
| 767 | + h = qidhash(d->qid.path); | |
| 768 | + for(q=qidtab[h]; q!=nil; q=q->next) | |
| 769 | + if(q->type==d->type && q->dev==d->dev && q->path==d->qid.path) | |
| 770 | + return q; | |
| 771 | + return nil; | |
| 772 | +} | |
| 773 | + | |
| 774 | +int | |
| 775 | +qidexists(vlong path) | |
| 776 | +{ | |
| 777 | + int h; | |
| 778 | + Qidtab *q; | |
| 779 | + | |
| 780 | + for(h=0; h<Nqidtab; h++) | |
| 781 | + for(q=qidtab[h]; q!=nil; q=q->next) | |
| 782 | + if(q->uniqpath == path) | |
| 783 | + return 1; | |
| 784 | + return 0; | |
| 785 | +} | |
| 786 | + | |
| 787 | +Qidtab* | |
| 788 | +uniqueqid(Dir *d) | |
| 789 | +{ | |
| 790 | + ulong h; | |
| 791 | + vlong path; | |
| 792 | + Qidtab *q; | |
| 793 | + | |
| 794 | + q = qidlookup(d); | |
| 795 | + if(q != nil){ | |
| 796 | + q->ref++; | |
| 797 | + return q; | |
| 798 | + } | |
| 799 | + path = d->qid.path; | |
| 800 | + while(qidexists(path)){ | |
| 801 | + DEBUG(DFD, "collision on %s\n", d->name); | |
| 802 | + /* collision: find a new one */ | |
| 803 | + ncollision++; | |
| 804 | + path &= QIDPATH; | |
| 805 | + ++newqid; | |
| 806 | + if(newqid >= (1<<16)){ | |
| 807 | + DEBUG(DFD, "collision wraparound\n"); | |
| 808 | + newqid = 1; | |
| 809 | + } | |
| 810 | + path |= newqid<<48; | |
| 811 | + DEBUG(DFD, "assign qid %.16llux\n", path); | |
| 812 | + } | |
| 813 | + q = mallocz(sizeof(Qidtab), 1); | |
| 814 | + if(q == nil) | |
| 815 | + fatal("no memory for qid table"); | |
| 816 | + qidcnt++; | |
| 817 | + q->ref = 1; | |
| 818 | + q->type = d->type; | |
| 819 | + q->dev = d->dev; | |
| 820 | + q->path = d->qid.path; | |
| 821 | + q->uniqpath = path; | |
| 822 | + h = qidhash(d->qid.path); | |
| 823 | + q->next = qidtab[h]; | |
| 824 | + qidtab[h] = q; | |
| 825 | + return q; | |
| 826 | +} | |
| 827 | + | |
| 828 | +void | |
| 829 | +fatal(char *s, ...) | |
| 830 | +{ | |
| 831 | + char buf[ERRMAX]; | |
| 832 | + va_list arg; | |
| 833 | + Proc *m; | |
| 834 | + | |
| 835 | + if (s) { | |
| 836 | + va_start(arg, s); | |
| 837 | + vsnprint(buf, ERRMAX, s, arg); | |
| 838 | + va_end(arg); | |
| 839 | + } | |
| 840 | + | |
| 841 | + /* Clear away the slave children */ | |
| 842 | + for(m = Proclist; m; m = m->next) | |
| 843 | + postnote(PNPROC, m->pid, "kill"); | |
| 844 | + | |
| 845 | + DEBUG(DFD, "%s\n", buf); | |
| 846 | + if (s) | |
| 847 | + sysfatal("%s", buf); /* caution: buf could contain '%' */ | |
| 848 | + else | |
| 849 | + exits(nil); | |
| 850 | +} | |
| 851 | + | |
| 852 | +void* | |
| 853 | +emallocz(uint n) | |
| 854 | +{ | |
| 855 | + void *p; | |
| 856 | + | |
| 857 | + p = mallocz(n, 1); | |
| 858 | + if(p == nil) | |
| 859 | + fatal(Enomem); | |
| 860 | + return p; | |
| 861 | +} | |
| 862 | + | |
| 863 | +char* | |
| 864 | +estrdup(char *s) | |
| 865 | +{ | |
| 866 | + char *t; | |
| 867 | + | |
| 868 | + t = strdup(s); | |
| 869 | + if(t == nil) | |
| 870 | + fatal(Enomem); | |
| 871 | + return t; | |
| 872 | +} | |
| 873 | + | |
| 874 | +/* Network on fd1, mount driver on fd0 */ | |
| 875 | +int | |
| 876 | +filter(int fd, char *cmd) | |
| 877 | +{ | |
| 878 | + int p[2], lfd, len, nb, argc; | |
| 879 | + char newport[128], buf[128], devdir[40], *s, *file, *argv[16]; | |
| 880 | + | |
| 881 | + /* Get a free port and post it to the client. */ | |
| 882 | + if (announce(anstring, devdir) < 0) | |
| 883 | + sysfatal("filter: Cannot announce %s: %r", anstring); | |
| 884 | + | |
| 885 | + snprint(buf, sizeof(buf), "%s/local", devdir); | |
| 886 | + buf[sizeof buf - 1] = '\0'; | |
| 887 | + if ((lfd = open(buf, OREAD)) < 0) | |
| 888 | + sysfatal("filter: Cannot open %s: %r", buf); | |
| 889 | + if ((len = read(lfd, newport, sizeof newport - 1)) < 0) | |
| 890 | + sysfatal("filter: Cannot read %s: %r", buf); | |
| 891 | + close(lfd); | |
| 892 | + newport[len] = '\0'; | |
| 893 | + | |
| 894 | + if ((s = strchr(newport, '\n')) != nil) | |
| 895 | + *s = '\0'; | |
| 896 | + | |
| 897 | + if ((nb = write(fd, newport, len)) < 0) | |
| 898 | + sysfatal("getport; cannot write port; %r"); | |
| 899 | + assert(nb == len); | |
| 900 | + | |
| 901 | + argc = tokenize(cmd, argv, nelem(argv)-2); | |
| 902 | + if (argc == 0) | |
| 903 | + sysfatal("filter: empty command"); | |
| 904 | + argv[argc++] = buf; | |
| 905 | + argv[argc] = nil; | |
| 906 | + file = argv[0]; | |
| 907 | + if (s = strrchr(argv[0], '/')) | |
| 908 | + argv[0] = s+1; | |
| 909 | + | |
| 910 | + if(pipe(p) < 0) | |
| 911 | + fatal("pipe"); | |
| 912 | + | |
| 913 | + switch(rfork(RFNOWAIT|RFPROC|RFFDG)) { | |
| 914 | + case -1: | |
| 915 | + fatal("rfork record module"); | |
| 916 | + case 0: | |
| 917 | + if (dup(p[0], 1) < 0) | |
| 918 | + fatal("filter: Cannot dup to 1; %r\n"); | |
| 919 | + if (dup(p[0], 0) < 0) | |
| 920 | + fatal("filter: Cannot dup to 0; %r\n"); | |
| 921 | + close(p[0]); | |
| 922 | + close(p[1]); | |
| 923 | + exec(file, argv); | |
| 924 | + fatal("exec record module"); | |
| 925 | + default: | |
| 926 | + close(fd); | |
| 927 | + close(p[0]); | |
| 928 | + } | |
| 929 | + return p[1]; | |
| 930 | +} | |
| 931 | + | |
| 932 | +static void | |
| 933 | +mksecret(char *t, uchar *f) | |
| 934 | +{ | |
| 935 | + sprint(t, "%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux", | |
| 936 | + f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9]); | |
| 937 | +} | |
| @@ -0,0 +1,144 @@ | ||
| 1 | +/* | |
| 2 | + * exportfs.h - definitions for exporting file server | |
| 3 | + */ | |
| 4 | + | |
| 5 | +#define DEBUG if(!dbg){}else fprint | |
| 6 | +#define DFD 9 | |
| 7 | +#define fidhash(s) fhash[s%FHASHSIZE] | |
| 8 | + | |
| 9 | +typedef struct Fsrpc Fsrpc; | |
| 10 | +typedef struct Fid Fid; | |
| 11 | +typedef struct File File; | |
| 12 | +typedef struct Proc Proc; | |
| 13 | +typedef struct Qidtab Qidtab; | |
| 14 | + | |
| 15 | +struct Fsrpc | |
| 16 | +{ | |
| 17 | + int busy; /* Work buffer has pending rpc to service */ | |
| 18 | + uintptr pid; /* Pid of slave process executing the rpc */ | |
| 19 | + int canint; /* Interrupt gate */ | |
| 20 | + int flushtag; /* Tag on which to reply to flush */ | |
| 21 | + Fcall work; /* Plan 9 incoming Fcall */ | |
| 22 | + uchar *buf; /* Data buffer */ | |
| 23 | +}; | |
| 24 | + | |
| 25 | +struct Fid | |
| 26 | +{ | |
| 27 | + int fid; /* system fd for i/o */ | |
| 28 | + File *f; /* File attached to this fid */ | |
| 29 | + int mode; | |
| 30 | + int nr; /* fid number */ | |
| 31 | + int mid; /* Mount id */ | |
| 32 | + Fid *next; /* hash link */ | |
| 33 | + | |
| 34 | + /* for preaddir -- ARRGH! */ | |
| 35 | + Dir *dir; /* buffer for reading directories */ | |
| 36 | + int ndir; /* number of entries in dir */ | |
| 37 | + int cdir; /* number of consumed entries in dir */ | |
| 38 | + int gdir; /* glue index */ | |
| 39 | + vlong offset; /* offset in virtual directory */ | |
| 40 | +}; | |
| 41 | + | |
| 42 | +struct File | |
| 43 | +{ | |
| 44 | + char *name; | |
| 45 | + int ref; | |
| 46 | + Qid qid; | |
| 47 | + Qidtab *qidt; | |
| 48 | + int inval; | |
| 49 | + File *parent; | |
| 50 | + File *child; | |
| 51 | + File *childlist; | |
| 52 | +}; | |
| 53 | + | |
| 54 | +struct Proc | |
| 55 | +{ | |
| 56 | + uintptr pid; | |
| 57 | + int busy; | |
| 58 | + Proc *next; | |
| 59 | +}; | |
| 60 | + | |
| 61 | +struct Qidtab | |
| 62 | +{ | |
| 63 | + int ref; | |
| 64 | + int type; | |
| 65 | + int dev; | |
| 66 | + vlong path; | |
| 67 | + vlong uniqpath; | |
| 68 | + Qidtab *next; | |
| 69 | +}; | |
| 70 | + | |
| 71 | +enum | |
| 72 | +{ | |
| 73 | + MAXPROC = 50, | |
| 74 | + FHASHSIZE = 64, | |
| 75 | + Nr_workbufs = 50, | |
| 76 | + Fidchunk = 1000, | |
| 77 | + Npsmpt = 32, | |
| 78 | + Nqidbits = 5, | |
| 79 | + Nqidtab = (1<<Nqidbits), | |
| 80 | +}; | |
| 81 | + | |
| 82 | +char Ebadfid[]; | |
| 83 | +char Enotdir[]; | |
| 84 | +char Edupfid[]; | |
| 85 | +char Eopen[]; | |
| 86 | +char Exmnt[]; | |
| 87 | +char Enomem[]; | |
| 88 | +char Emip[]; | |
| 89 | +char Enopsmt[]; | |
| 90 | + | |
| 91 | +Extern Fsrpc *Workq; | |
| 92 | +Extern int dbg; | |
| 93 | +Extern File *root; | |
| 94 | +Extern File *psmpt; | |
| 95 | +Extern Fid **fhash; | |
| 96 | +Extern Fid *fidfree; | |
| 97 | +Extern Proc *Proclist; | |
| 98 | +Extern char psmap[Npsmpt]; | |
| 99 | +Extern Qidtab *qidtab[Nqidtab]; | |
| 100 | +Extern ulong messagesize; | |
| 101 | +Extern char Enomem[]; | |
| 102 | +Extern int srvfd; | |
| 103 | +Extern char* patternfile; | |
| 104 | + | |
| 105 | +/* File system protocol service procedures */ | |
| 106 | +void Xattach(Fsrpc*); | |
| 107 | +void Xauth(Fsrpc*); | |
| 108 | +void Xclunk(Fsrpc*); | |
| 109 | +void Xcreate(Fsrpc*); | |
| 110 | +void Xflush(Fsrpc*); | |
| 111 | +void Xnop(Fsrpc*); | |
| 112 | +void Xremove(Fsrpc*); | |
| 113 | +void Xstat(Fsrpc*); | |
| 114 | +void Xversion(Fsrpc*); | |
| 115 | +void Xwalk(Fsrpc*); | |
| 116 | +void Xwstat(Fsrpc*); | |
| 117 | +void slave(Fsrpc*); | |
| 118 | + | |
| 119 | +void reply(Fcall*, Fcall*, char*); | |
| 120 | +Fid *getfid(int); | |
| 121 | +int freefid(int); | |
| 122 | +Fid *newfid(int); | |
| 123 | +Fsrpc *getsbuf(void); | |
| 124 | +void initroot(void); | |
| 125 | +void fatal(char*, ...); | |
| 126 | +char* makepath(File*, char*); | |
| 127 | +File *file(File*, char*); | |
| 128 | +void freefile(File*); | |
| 129 | +void slaveopen(Fsrpc*); | |
| 130 | +void slaveread(Fsrpc*); | |
| 131 | +void slavewrite(Fsrpc*); | |
| 132 | +void blockingslave(void); | |
| 133 | +void reopen(Fid *f); | |
| 134 | +void noteproc(int, char*); | |
| 135 | +void flushaction(void*, char*); | |
| 136 | +void pushfcall(char*); | |
| 137 | +Qidtab* uniqueqid(Dir*); | |
| 138 | +void freeqid(Qidtab*); | |
| 139 | +char* estrdup(char*); | |
| 140 | +void* emallocz(uint); | |
| 141 | +int readmessage(int, char*, int); | |
| 142 | +void exclusions(void); | |
| 143 | +int excludefile(char*); | |
| 144 | +int preaddir(Fid*, uchar*, int, vlong); | |
| @@ -0,0 +1,764 @@ | ||
| 1 | +#include <u.h> | |
| 2 | +#include <libc.h> | |
| 3 | +#include <auth.h> | |
| 4 | +#include <fcall.h> | |
| 5 | +#define Extern extern | |
| 6 | +#include "exportfs.h" | |
| 7 | + | |
| 8 | +extern char *netdir, *local, *remote; | |
| 9 | + | |
| 10 | +char Ebadfid[] = "Bad fid"; | |
| 11 | +char Enotdir[] = "Not a directory"; | |
| 12 | +char Edupfid[] = "Fid already in use"; | |
| 13 | +char Eopen[] = "Fid already opened"; | |
| 14 | +char Exmnt[] = "Cannot .. past mount point"; | |
| 15 | +char Emip[] = "Mount in progress"; | |
| 16 | +char Enopsmt[] = "Out of pseudo mount points"; | |
| 17 | +char Enomem[] = "No memory"; | |
| 18 | +char Eversion[] = "Bad 9P2000 version"; | |
| 19 | +char Ereadonly[] = "File system read only"; | |
| 20 | + | |
| 21 | +ulong messagesize; | |
| 22 | +int readonly; | |
| 23 | + | |
| 24 | +void | |
| 25 | +Xversion(Fsrpc *t) | |
| 26 | +{ | |
| 27 | + Fcall rhdr; | |
| 28 | + | |
| 29 | + if(t->work.msize > messagesize) | |
| 30 | + t->work.msize = messagesize; | |
| 31 | + messagesize = t->work.msize; | |
| 32 | + if(strncmp(t->work.version, "9P2000", 6) != 0){ | |
| 33 | + reply(&t->work, &rhdr, Eversion); | |
| 34 | + return; | |
| 35 | + } | |
| 36 | + rhdr.version = "9P2000"; | |
| 37 | + rhdr.msize = t->work.msize; | |
| 38 | + reply(&t->work, &rhdr, 0); | |
| 39 | + t->busy = 0; | |
| 40 | +} | |
| 41 | + | |
| 42 | +void | |
| 43 | +Xauth(Fsrpc *t) | |
| 44 | +{ | |
| 45 | + Fcall rhdr; | |
| 46 | + | |
| 47 | + reply(&t->work, &rhdr, "exportfs: authentication not required"); | |
| 48 | + t->busy = 0; | |
| 49 | +} | |
| 50 | + | |
| 51 | +void | |
| 52 | +Xflush(Fsrpc *t) | |
| 53 | +{ | |
| 54 | + Fsrpc *w, *e; | |
| 55 | + Fcall rhdr; | |
| 56 | + | |
| 57 | + e = &Workq[Nr_workbufs]; | |
| 58 | + | |
| 59 | + for(w = Workq; w < e; w++) { | |
| 60 | + if(w->work.tag == t->work.oldtag) { | |
| 61 | + DEBUG(DFD, "\tQ busy %d pid %p can %d\n", w->busy, w->pid, w->canint); | |
| 62 | + if(w->busy && w->pid) { | |
| 63 | + w->flushtag = t->work.tag; | |
| 64 | + DEBUG(DFD, "\tset flushtag %d\n", t->work.tag); | |
| 65 | + if(w->canint) | |
| 66 | + postnote(PNPROC, w->pid, "flush"); | |
| 67 | + t->busy = 0; | |
| 68 | + return; | |
| 69 | + } | |
| 70 | + } | |
| 71 | + } | |
| 72 | + | |
| 73 | + reply(&t->work, &rhdr, 0); | |
| 74 | + DEBUG(DFD, "\tflush reply\n"); | |
| 75 | + t->busy = 0; | |
| 76 | +} | |
| 77 | + | |
| 78 | +void | |
| 79 | +Xattach(Fsrpc *t) | |
| 80 | +{ | |
| 81 | + int i, nfd; | |
| 82 | + Fcall rhdr; | |
| 83 | + Fid *f; | |
| 84 | + char buf[128]; | |
| 85 | + | |
| 86 | + f = newfid(t->work.fid); | |
| 87 | + if(f == 0) { | |
| 88 | + reply(&t->work, &rhdr, Ebadfid); | |
| 89 | + t->busy = 0; | |
| 90 | + return; | |
| 91 | + } | |
| 92 | + | |
| 93 | + if(srvfd >= 0){ | |
| 94 | + if(psmpt == 0){ | |
| 95 | + Nomount: | |
| 96 | + reply(&t->work, &rhdr, Enopsmt); | |
| 97 | + t->busy = 0; | |
| 98 | + freefid(t->work.fid); | |
| 99 | + return; | |
| 100 | + } | |
| 101 | + for(i=0; i<Npsmpt; i++) | |
| 102 | + if(psmap[i] == 0) | |
| 103 | + break; | |
| 104 | + if(i >= Npsmpt) | |
| 105 | + goto Nomount; | |
| 106 | + sprint(buf, "%d", i); | |
| 107 | + f->f = file(psmpt, buf); | |
| 108 | + if(f->f == nil) | |
| 109 | + goto Nomount; | |
| 110 | + sprint(buf, "/mnt/exportfs/%d", i); | |
| 111 | + nfd = dup(srvfd, -1); | |
| 112 | + if(amount(nfd, buf, MREPL|MCREATE, t->work.aname) < 0){ | |
| 113 | + errstr(buf, sizeof buf); | |
| 114 | + reply(&t->work, &rhdr, buf); | |
| 115 | + t->busy = 0; | |
| 116 | + freefid(t->work.fid); | |
| 117 | + close(nfd); | |
| 118 | + return; | |
| 119 | + } | |
| 120 | + psmap[i] = 1; | |
| 121 | + f->mid = i; | |
| 122 | + }else{ | |
| 123 | + f->f = root; | |
| 124 | + f->f->ref++; | |
| 125 | + } | |
| 126 | + | |
| 127 | + rhdr.qid = f->f->qid; | |
| 128 | + reply(&t->work, &rhdr, 0); | |
| 129 | + t->busy = 0; | |
| 130 | +} | |
| 131 | + | |
| 132 | +Fid* | |
| 133 | +clonefid(Fid *f, int new) | |
| 134 | +{ | |
| 135 | + Fid *n; | |
| 136 | + | |
| 137 | + n = newfid(new); | |
| 138 | + if(n == 0) { | |
| 139 | + n = getfid(new); | |
| 140 | + if(n == 0) | |
| 141 | + fatal("inconsistent fids"); | |
| 142 | + if(n->fid >= 0) | |
| 143 | + close(n->fid); | |
| 144 | + freefid(new); | |
| 145 | + n = newfid(new); | |
| 146 | + if(n == 0) | |
| 147 | + fatal("inconsistent fids2"); | |
| 148 | + } | |
| 149 | + n->f = f->f; | |
| 150 | + n->f->ref++; | |
| 151 | + return n; | |
| 152 | +} | |
| 153 | + | |
| 154 | +void | |
| 155 | +Xwalk(Fsrpc *t) | |
| 156 | +{ | |
| 157 | + char err[ERRMAX], *e; | |
| 158 | + Fcall rhdr; | |
| 159 | + Fid *f, *nf; | |
| 160 | + File *wf; | |
| 161 | + int i; | |
| 162 | + | |
| 163 | + f = getfid(t->work.fid); | |
| 164 | + if(f == 0) { | |
| 165 | + reply(&t->work, &rhdr, Ebadfid); | |
| 166 | + t->busy = 0; | |
| 167 | + return; | |
| 168 | + } | |
| 169 | + | |
| 170 | + nf = nil; | |
| 171 | + if(t->work.newfid != t->work.fid){ | |
| 172 | + nf = clonefid(f, t->work.newfid); | |
| 173 | + f = nf; | |
| 174 | + } | |
| 175 | + | |
| 176 | + rhdr.nwqid = 0; | |
| 177 | + e = nil; | |
| 178 | + for(i=0; i<t->work.nwname; i++){ | |
| 179 | + if(i == MAXWELEM){ | |
| 180 | + e = "Too many path elements"; | |
| 181 | + break; | |
| 182 | + } | |
| 183 | + | |
| 184 | + if(strcmp(t->work.wname[i], "..") == 0) { | |
| 185 | + if(f->f->parent == nil) { | |
| 186 | + e = Exmnt; | |
| 187 | + break; | |
| 188 | + } | |
| 189 | + wf = f->f->parent; | |
| 190 | + wf->ref++; | |
| 191 | + goto Accept; | |
| 192 | + } | |
| 193 | + | |
| 194 | + wf = file(f->f, t->work.wname[i]); | |
| 195 | + if(wf == 0){ | |
| 196 | + errstr(err, sizeof err); | |
| 197 | + e = err; | |
| 198 | + break; | |
| 199 | + } | |
| 200 | + Accept: | |
| 201 | + freefile(f->f); | |
| 202 | + rhdr.wqid[rhdr.nwqid++] = wf->qid; | |
| 203 | + f->f = wf; | |
| 204 | + continue; | |
| 205 | + } | |
| 206 | + | |
| 207 | + if(nf!=nil && (e!=nil || rhdr.nwqid!=t->work.nwname)) | |
| 208 | + freefid(t->work.newfid); | |
| 209 | + if(rhdr.nwqid > 0) | |
| 210 | + e = nil; | |
| 211 | + reply(&t->work, &rhdr, e); | |
| 212 | + t->busy = 0; | |
| 213 | +} | |
| 214 | + | |
| 215 | +void | |
| 216 | +Xclunk(Fsrpc *t) | |
| 217 | +{ | |
| 218 | + Fcall rhdr; | |
| 219 | + Fid *f; | |
| 220 | + | |
| 221 | + f = getfid(t->work.fid); | |
| 222 | + if(f == 0) { | |
| 223 | + reply(&t->work, &rhdr, Ebadfid); | |
| 224 | + t->busy = 0; | |
| 225 | + return; | |
| 226 | + } | |
| 227 | + | |
| 228 | + if(f->fid >= 0) | |
| 229 | + close(f->fid); | |
| 230 | + | |
| 231 | + freefid(t->work.fid); | |
| 232 | + reply(&t->work, &rhdr, 0); | |
| 233 | + t->busy = 0; | |
| 234 | +} | |
| 235 | + | |
| 236 | +void | |
| 237 | +Xstat(Fsrpc *t) | |
| 238 | +{ | |
| 239 | + char err[ERRMAX], *path; | |
| 240 | + Fcall rhdr; | |
| 241 | + Fid *f; | |
| 242 | + Dir *d; | |
| 243 | + int s; | |
| 244 | + uchar *statbuf; | |
| 245 | + | |
| 246 | + f = getfid(t->work.fid); | |
| 247 | + if(f == 0) { | |
| 248 | + reply(&t->work, &rhdr, Ebadfid); | |
| 249 | + t->busy = 0; | |
| 250 | + return; | |
| 251 | + } | |
| 252 | + if(f->fid >= 0) | |
| 253 | + d = dirfstat(f->fid); | |
| 254 | + else { | |
| 255 | + path = makepath(f->f, ""); | |
| 256 | + d = dirstat(path); | |
| 257 | + free(path); | |
| 258 | + } | |
| 259 | + | |
| 260 | + if(d == nil) { | |
| 261 | + errstr(err, sizeof err); | |
| 262 | + reply(&t->work, &rhdr, err); | |
| 263 | + t->busy = 0; | |
| 264 | + return; | |
| 265 | + } | |
| 266 | + | |
| 267 | + d->qid.path = f->f->qidt->uniqpath; | |
| 268 | + s = sizeD2M(d); | |
| 269 | + statbuf = emallocz(s); | |
| 270 | + s = convD2M(d, statbuf, s); | |
| 271 | + free(d); | |
| 272 | + rhdr.nstat = s; | |
| 273 | + rhdr.stat = statbuf; | |
| 274 | + reply(&t->work, &rhdr, 0); | |
| 275 | + free(statbuf); | |
| 276 | + t->busy = 0; | |
| 277 | +} | |
| 278 | + | |
| 279 | +static int | |
| 280 | +getiounit(int fd) | |
| 281 | +{ | |
| 282 | + int n; | |
| 283 | + | |
| 284 | + n = iounit(fd); | |
| 285 | + if(n > messagesize-IOHDRSZ) | |
| 286 | + n = messagesize-IOHDRSZ; | |
| 287 | + return n; | |
| 288 | +} | |
| 289 | + | |
| 290 | +void | |
| 291 | +Xcreate(Fsrpc *t) | |
| 292 | +{ | |
| 293 | + char err[ERRMAX], *path; | |
| 294 | + Fcall rhdr; | |
| 295 | + Fid *f; | |
| 296 | + File *nf; | |
| 297 | + | |
| 298 | + if(readonly) { | |
| 299 | + reply(&t->work, &rhdr, Ereadonly); | |
| 300 | + t->busy = 0; | |
| 301 | + return; | |
| 302 | + } | |
| 303 | + f = getfid(t->work.fid); | |
| 304 | + if(f == 0) { | |
| 305 | + reply(&t->work, &rhdr, Ebadfid); | |
| 306 | + t->busy = 0; | |
| 307 | + return; | |
| 308 | + } | |
| 309 | + | |
| 310 | + | |
| 311 | + path = makepath(f->f, t->work.name); | |
| 312 | + f->fid = create(path, t->work.mode, t->work.perm); | |
| 313 | + free(path); | |
| 314 | + if(f->fid < 0) { | |
| 315 | + errstr(err, sizeof err); | |
| 316 | + reply(&t->work, &rhdr, err); | |
| 317 | + t->busy = 0; | |
| 318 | + return; | |
| 319 | + } | |
| 320 | + | |
| 321 | + nf = file(f->f, t->work.name); | |
| 322 | + if(nf == 0) { | |
| 323 | + errstr(err, sizeof err); | |
| 324 | + reply(&t->work, &rhdr, err); | |
| 325 | + t->busy = 0; | |
| 326 | + return; | |
| 327 | + } | |
| 328 | + | |
| 329 | + f->mode = t->work.mode; | |
| 330 | + freefile(f->f); | |
| 331 | + f->f = nf; | |
| 332 | + rhdr.qid = f->f->qid; | |
| 333 | + rhdr.iounit = getiounit(f->fid); | |
| 334 | + reply(&t->work, &rhdr, 0); | |
| 335 | + t->busy = 0; | |
| 336 | +} | |
| 337 | + | |
| 338 | +void | |
| 339 | +Xremove(Fsrpc *t) | |
| 340 | +{ | |
| 341 | + char err[ERRMAX], *path; | |
| 342 | + Fcall rhdr; | |
| 343 | + Fid *f; | |
| 344 | + | |
| 345 | + if(readonly) { | |
| 346 | + reply(&t->work, &rhdr, Ereadonly); | |
| 347 | + t->busy = 0; | |
| 348 | + return; | |
| 349 | + } | |
| 350 | + f = getfid(t->work.fid); | |
| 351 | + if(f == 0) { | |
| 352 | + reply(&t->work, &rhdr, Ebadfid); | |
| 353 | + t->busy = 0; | |
| 354 | + return; | |
| 355 | + } | |
| 356 | + | |
| 357 | + path = makepath(f->f, ""); | |
| 358 | + DEBUG(DFD, "\tremove: %s\n", path); | |
| 359 | + if(remove(path) < 0) { | |
| 360 | + free(path); | |
| 361 | + errstr(err, sizeof err); | |
| 362 | + reply(&t->work, &rhdr, err); | |
| 363 | + t->busy = 0; | |
| 364 | + return; | |
| 365 | + } | |
| 366 | + free(path); | |
| 367 | + | |
| 368 | + f->f->inval = 1; | |
| 369 | + if(f->fid >= 0) | |
| 370 | + close(f->fid); | |
| 371 | + freefid(t->work.fid); | |
| 372 | + | |
| 373 | + reply(&t->work, &rhdr, 0); | |
| 374 | + t->busy = 0; | |
| 375 | +} | |
| 376 | + | |
| 377 | +void | |
| 378 | +Xwstat(Fsrpc *t) | |
| 379 | +{ | |
| 380 | + char err[ERRMAX], *path; | |
| 381 | + Fcall rhdr; | |
| 382 | + Fid *f; | |
| 383 | + int s; | |
| 384 | + char *strings; | |
| 385 | + Dir d; | |
| 386 | + | |
| 387 | + if(readonly) { | |
| 388 | + reply(&t->work, &rhdr, Ereadonly); | |
| 389 | + t->busy = 0; | |
| 390 | + return; | |
| 391 | + } | |
| 392 | + f = getfid(t->work.fid); | |
| 393 | + if(f == 0) { | |
| 394 | + reply(&t->work, &rhdr, Ebadfid); | |
| 395 | + t->busy = 0; | |
| 396 | + return; | |
| 397 | + } | |
| 398 | + strings = emallocz(t->work.nstat); /* ample */ | |
| 399 | + if(convM2D(t->work.stat, t->work.nstat, &d, strings) <= BIT16SZ){ | |
| 400 | + rerrstr(err, sizeof err); | |
| 401 | + reply(&t->work, &rhdr, err); | |
| 402 | + t->busy = 0; | |
| 403 | + free(strings); | |
| 404 | + return; | |
| 405 | + } | |
| 406 | + | |
| 407 | + if(f->fid >= 0) | |
| 408 | + s = dirfwstat(f->fid, &d); | |
| 409 | + else { | |
| 410 | + path = makepath(f->f, ""); | |
| 411 | + s = dirwstat(path, &d); | |
| 412 | + free(path); | |
| 413 | + } | |
| 414 | + if(s < 0) { | |
| 415 | + rerrstr(err, sizeof err); | |
| 416 | + reply(&t->work, &rhdr, err); | |
| 417 | + } | |
| 418 | + else { | |
| 419 | + /* wstat may really be rename */ | |
| 420 | + if(strcmp(d.name, f->f->name)!=0 && strcmp(d.name, "")!=0){ | |
| 421 | + free(f->f->name); | |
| 422 | + f->f->name = estrdup(d.name); | |
| 423 | + } | |
| 424 | + reply(&t->work, &rhdr, 0); | |
| 425 | + } | |
| 426 | + free(strings); | |
| 427 | + t->busy = 0; | |
| 428 | +} | |
| 429 | + | |
| 430 | +/* | |
| 431 | + * based on libthread's threadsetname, but drags in less library code. | |
| 432 | + * actually just sets the arguments displayed. | |
| 433 | + */ | |
| 434 | +void | |
| 435 | +procsetname(char *fmt, ...) | |
| 436 | +{ | |
| 437 | + int fd; | |
| 438 | + char *cmdname; | |
| 439 | + char buf[128]; | |
| 440 | + va_list arg; | |
| 441 | + | |
| 442 | + va_start(arg, fmt); | |
| 443 | + cmdname = vsmprint(fmt, arg); | |
| 444 | + va_end(arg); | |
| 445 | + if (cmdname == nil) | |
| 446 | + return; | |
| 447 | + snprint(buf, sizeof buf, "#p/%d/args", getpid()); | |
| 448 | + if((fd = open(buf, OWRITE)) >= 0){ | |
| 449 | + write(fd, cmdname, strlen(cmdname)+1); | |
| 450 | + close(fd); | |
| 451 | + } | |
| 452 | + free(cmdname); | |
| 453 | +} | |
| 454 | + | |
| 455 | +void | |
| 456 | +slave(Fsrpc *f) | |
| 457 | +{ | |
| 458 | + Proc *p; | |
| 459 | + uintptr pid; | |
| 460 | + Fcall rhdr; | |
| 461 | + static int nproc; | |
| 462 | + | |
| 463 | + if(readonly){ | |
| 464 | + switch(f->work.type){ | |
| 465 | + case Twrite: | |
| 466 | + reply(&f->work, &rhdr, Ereadonly); | |
| 467 | + f->busy = 0; | |
| 468 | + return; | |
| 469 | + case Topen: | |
| 470 | + if((f->work.mode&3) == OWRITE || (f->work.mode&OTRUNC)){ | |
| 471 | + reply(&f->work, &rhdr, Ereadonly); | |
| 472 | + f->busy = 0; | |
| 473 | + return; | |
| 474 | + } | |
| 475 | + } | |
| 476 | + } | |
| 477 | + for(;;) { | |
| 478 | + for(p = Proclist; p; p = p->next) { | |
| 479 | + if(p->busy == 0) { | |
| 480 | + f->pid = p->pid; | |
| 481 | + p->busy = 1; | |
| 482 | + pid = (uintptr)rendezvous((void*)p->pid, f); | |
| 483 | + if(pid != p->pid) | |
| 484 | + fatal("rendezvous sync fail"); | |
| 485 | + return; | |
| 486 | + } | |
| 487 | + } | |
| 488 | + | |
| 489 | + if(++nproc > MAXPROC) | |
| 490 | + fatal("too many procs"); | |
| 491 | + | |
| 492 | + pid = rfork(RFPROC|RFMEM); | |
| 493 | + switch(pid) { | |
| 494 | + case -1: | |
| 495 | + fatal("rfork"); | |
| 496 | + | |
| 497 | + case 0: | |
| 498 | + if (local[0] != '\0') | |
| 499 | + if (netdir[0] != '\0') | |
| 500 | + procsetname("%s: %s -> %s", netdir, | |
| 501 | + local, remote); | |
| 502 | + else | |
| 503 | + procsetname("%s -> %s", local, remote); | |
| 504 | + blockingslave(); | |
| 505 | + fatal("slave"); | |
| 506 | + | |
| 507 | + default: | |
| 508 | + p = malloc(sizeof(Proc)); | |
| 509 | + if(p == 0) | |
| 510 | + fatal("out of memory"); | |
| 511 | + | |
| 512 | + p->busy = 0; | |
| 513 | + p->pid = pid; | |
| 514 | + p->next = Proclist; | |
| 515 | + Proclist = p; | |
| 516 | + | |
| 517 | + rendezvous((void*)pid, p); | |
| 518 | + } | |
| 519 | + } | |
| 520 | +} | |
| 521 | + | |
| 522 | +void | |
| 523 | +blockingslave(void) | |
| 524 | +{ | |
| 525 | + Fsrpc *p; | |
| 526 | + Fcall rhdr; | |
| 527 | + Proc *m; | |
| 528 | + uintptr pid; | |
| 529 | + | |
| 530 | + notify(flushaction); | |
| 531 | + | |
| 532 | + pid = getpid(); | |
| 533 | + | |
| 534 | + m = rendezvous((void*)pid, 0); | |
| 535 | + | |
| 536 | + for(;;) { | |
| 537 | + p = rendezvous((void*)pid, (void*)pid); | |
| 538 | + if(p == (void*)~0) /* Interrupted */ | |
| 539 | + continue; | |
| 540 | + | |
| 541 | + DEBUG(DFD, "\tslave: %p %F b %d p %p\n", pid, &p->work, p->busy, p->pid); | |
| 542 | + if(p->flushtag != NOTAG) | |
| 543 | + goto flushme; | |
| 544 | + | |
| 545 | + switch(p->work.type) { | |
| 546 | + case Tread: | |
| 547 | + slaveread(p); | |
| 548 | + break; | |
| 549 | + | |
| 550 | + case Twrite: | |
| 551 | + slavewrite(p); | |
| 552 | + break; | |
| 553 | + | |
| 554 | + case Topen: | |
| 555 | + slaveopen(p); | |
| 556 | + break; | |
| 557 | + | |
| 558 | + default: | |
| 559 | + reply(&p->work, &rhdr, "exportfs: slave type error"); | |
| 560 | + } | |
| 561 | + if(p->flushtag != NOTAG) { | |
| 562 | +flushme: | |
| 563 | + p->work.type = Tflush; | |
| 564 | + p->work.tag = p->flushtag; | |
| 565 | + reply(&p->work, &rhdr, 0); | |
| 566 | + } | |
| 567 | + p->busy = 0; | |
| 568 | + m->busy = 0; | |
| 569 | + } | |
| 570 | +} | |
| 571 | + | |
| 572 | +int | |
| 573 | +openmount(int sfd) | |
| 574 | +{ | |
| 575 | + int p[2]; | |
| 576 | + char *arg[10], fdbuf[20], mbuf[20]; | |
| 577 | + | |
| 578 | + if(pipe(p) < 0) | |
| 579 | + return -1; | |
| 580 | + | |
| 581 | + switch(rfork(RFPROC|RFMEM|RFNOWAIT|RFNAMEG|RFFDG)){ | |
| 582 | + case -1: | |
| 583 | + return -1; | |
| 584 | + | |
| 585 | + default: | |
| 586 | + close(sfd); | |
| 587 | + close(p[0]); | |
| 588 | + return p[1]; | |
| 589 | + | |
| 590 | + case 0: | |
| 591 | + break; | |
| 592 | + } | |
| 593 | + | |
| 594 | + close(p[1]); | |
| 595 | + | |
| 596 | + arg[0] = "exportfs"; | |
| 597 | + snprint(fdbuf, sizeof fdbuf, "-S/fd/%d", sfd); | |
| 598 | + arg[1] = fdbuf; | |
| 599 | + snprint(mbuf, sizeof mbuf, "-m%lud", messagesize-IOHDRSZ); | |
| 600 | + arg[2] = mbuf; | |
| 601 | + arg[3] = nil; | |
| 602 | + | |
| 603 | + close(0); | |
| 604 | + close(1); | |
| 605 | + dup(p[0], 0); | |
| 606 | + dup(p[0], 1); | |
| 607 | + exec("/bin/exportfs", arg); | |
| 608 | + _exits("whoops: exec failed"); | |
| 609 | + return -1; | |
| 610 | +} | |
| 611 | + | |
| 612 | +void | |
| 613 | +slaveopen(Fsrpc *p) | |
| 614 | +{ | |
| 615 | + char err[ERRMAX], *path; | |
| 616 | + Fcall *work, rhdr; | |
| 617 | + Fid *f; | |
| 618 | + Dir *d; | |
| 619 | + | |
| 620 | + work = &p->work; | |
| 621 | + | |
| 622 | + f = getfid(work->fid); | |
| 623 | + if(f == 0) { | |
| 624 | + reply(work, &rhdr, Ebadfid); | |
| 625 | + return; | |
| 626 | + } | |
| 627 | + if(f->fid >= 0) { | |
| 628 | + close(f->fid); | |
| 629 | + f->fid = -1; | |
| 630 | + } | |
| 631 | + | |
| 632 | + path = makepath(f->f, ""); | |
| 633 | + DEBUG(DFD, "\topen: %s %d\n", path, work->mode); | |
| 634 | + | |
| 635 | + p->canint = 1; | |
| 636 | + if(p->flushtag != NOTAG){ | |
| 637 | + free(path); | |
| 638 | + return; | |
| 639 | + } | |
| 640 | + /* There is a race here I ignore because there are no locks */ | |
| 641 | + f->fid = open(path, work->mode); | |
| 642 | + free(path); | |
| 643 | + p->canint = 0; | |
| 644 | + if(f->fid < 0 || (d = dirfstat(f->fid)) == nil) { | |
| 645 | + Error: | |
| 646 | + errstr(err, sizeof err); | |
| 647 | + reply(work, &rhdr, err); | |
| 648 | + return; | |
| 649 | + } | |
| 650 | + f->f->qid = d->qid; | |
| 651 | + free(d); | |
| 652 | + if(f->f->qid.type & QTMOUNT){ /* fork new exportfs for this */ | |
| 653 | + f->fid = openmount(f->fid); | |
| 654 | + if(f->fid < 0) | |
| 655 | + goto Error; | |
| 656 | + } | |
| 657 | + | |
| 658 | + DEBUG(DFD, "\topen: fd %d\n", f->fid); | |
| 659 | + f->mode = work->mode; | |
| 660 | + f->offset = 0; | |
| 661 | + rhdr.iounit = getiounit(f->fid); | |
| 662 | + rhdr.qid = f->f->qid; | |
| 663 | + reply(work, &rhdr, 0); | |
| 664 | +} | |
| 665 | + | |
| 666 | +void | |
| 667 | +slaveread(Fsrpc *p) | |
| 668 | +{ | |
| 669 | + Fid *f; | |
| 670 | + int n, r; | |
| 671 | + Fcall *work, rhdr; | |
| 672 | + char *data, err[ERRMAX]; | |
| 673 | + | |
| 674 | + work = &p->work; | |
| 675 | + | |
| 676 | + f = getfid(work->fid); | |
| 677 | + if(f == 0) { | |
| 678 | + reply(work, &rhdr, Ebadfid); | |
| 679 | + return; | |
| 680 | + } | |
| 681 | + | |
| 682 | + n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count; | |
| 683 | + p->canint = 1; | |
| 684 | + if(p->flushtag != NOTAG) | |
| 685 | + return; | |
| 686 | + data = malloc(n); | |
| 687 | + if(data == nil) | |
| 688 | + fatal(Enomem); | |
| 689 | + | |
| 690 | + /* can't just call pread, since directories must update the offset */ | |
| 691 | + if(patternfile != nil && (f->f->qid.type&QTDIR)) | |
| 692 | + r = preaddir(f, (uchar*)data, n, work->offset); | |
| 693 | + else | |
| 694 | + r = pread(f->fid, data, n, work->offset); | |
| 695 | + p->canint = 0; | |
| 696 | + if(r < 0) { | |
| 697 | + free(data); | |
| 698 | + errstr(err, sizeof err); | |
| 699 | + reply(work, &rhdr, err); | |
| 700 | + return; | |
| 701 | + } | |
| 702 | + | |
| 703 | + DEBUG(DFD, "\tread: fd=%d %d bytes\n", f->fid, r); | |
| 704 | + | |
| 705 | + rhdr.data = data; | |
| 706 | + rhdr.count = r; | |
| 707 | + reply(work, &rhdr, 0); | |
| 708 | + free(data); | |
| 709 | +} | |
| 710 | + | |
| 711 | +void | |
| 712 | +slavewrite(Fsrpc *p) | |
| 713 | +{ | |
| 714 | + char err[ERRMAX]; | |
| 715 | + Fcall *work, rhdr; | |
| 716 | + Fid *f; | |
| 717 | + int n; | |
| 718 | + | |
| 719 | + work = &p->work; | |
| 720 | + | |
| 721 | + f = getfid(work->fid); | |
| 722 | + if(f == 0) { | |
| 723 | + reply(work, &rhdr, Ebadfid); | |
| 724 | + return; | |
| 725 | + } | |
| 726 | + | |
| 727 | + n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count; | |
| 728 | + p->canint = 1; | |
| 729 | + if(p->flushtag != NOTAG) | |
| 730 | + return; | |
| 731 | + n = pwrite(f->fid, work->data, n, work->offset); | |
| 732 | + p->canint = 0; | |
| 733 | + if(n < 0) { | |
| 734 | + errstr(err, sizeof err); | |
| 735 | + reply(work, &rhdr, err); | |
| 736 | + return; | |
| 737 | + } | |
| 738 | + | |
| 739 | + DEBUG(DFD, "\twrite: %d bytes fd=%d\n", n, f->fid); | |
| 740 | + | |
| 741 | + rhdr.count = n; | |
| 742 | + reply(work, &rhdr, 0); | |
| 743 | +} | |
| 744 | + | |
| 745 | +void | |
| 746 | +reopen(Fid *f) | |
| 747 | +{ | |
| 748 | + USED(f); | |
| 749 | + fatal("reopen"); | |
| 750 | +} | |
| 751 | + | |
| 752 | +void | |
| 753 | +flushaction(void *a, char *cause) | |
| 754 | +{ | |
| 755 | + USED(a); | |
| 756 | + if(strncmp(cause, "sys:", 4) == 0 && !strstr(cause, "pipe")) { | |
| 757 | + fprint(2, "exportsrv: note: %s\n", cause); | |
| 758 | + exits("noted"); | |
| 759 | + } | |
| 760 | + if(strncmp(cause, "kill", 4) == 0) | |
| 761 | + noted(NDFLT); | |
| 762 | + | |
| 763 | + noted(NCONT); | |
| 764 | +} | |
| @@ -0,0 +1,18 @@ | ||
| 1 | +</$objtype/mkfile | |
| 2 | + | |
| 3 | +TARG=exportfs | |
| 4 | +OFILES=\ | |
| 5 | + exportfs.$O\ | |
| 6 | + exportsrv.$O\ | |
| 7 | + pattern.$O\ | |
| 8 | + | |
| 9 | +HFILES=exportfs.h\ | |
| 10 | + | |
| 11 | +BIN=/$objtype/bin | |
| 12 | + | |
| 13 | +UPDATE=\ | |
| 14 | + mkfile\ | |
| 15 | + $HFILES\ | |
| 16 | + ${OFILES:%.$O=%.c}\ | |
| 17 | + | |
| 18 | +</sys/src/cmd/mkone | |
| @@ -0,0 +1,154 @@ | ||
| 1 | +#include <u.h> | |
| 2 | +#include <libc.h> | |
| 3 | +#include <fcall.h> | |
| 4 | +#include <bio.h> | |
| 5 | +#include <regexp.h> | |
| 6 | +#define Extern | |
| 7 | +#include "exportfs.h" | |
| 8 | + | |
| 9 | +Reprog **exclude, **include; | |
| 10 | +char *patternfile; | |
| 11 | + | |
| 12 | +void | |
| 13 | +exclusions(void) | |
| 14 | +{ | |
| 15 | + Biobuf *f; | |
| 16 | + int ni, nmaxi, ne, nmaxe; | |
| 17 | + char *line; | |
| 18 | + | |
| 19 | + if(patternfile == nil) | |
| 20 | + return; | |
| 21 | + | |
| 22 | + f = Bopen(patternfile, OREAD); | |
| 23 | + if(f == nil) | |
| 24 | + fatal("cannot open patternfile"); | |
| 25 | + ni = 0; | |
| 26 | + nmaxi = 100; | |
| 27 | + include = malloc(nmaxi*sizeof(*include)); | |
| 28 | + if(include == nil) | |
| 29 | + fatal("out of memory"); | |
| 30 | + include[0] = nil; | |
| 31 | + ne = 0; | |
| 32 | + nmaxe = 100; | |
| 33 | + exclude = malloc(nmaxe*sizeof(*exclude)); | |
| 34 | + if(exclude == nil) | |
| 35 | + fatal("out of memory"); | |
| 36 | + exclude[0] = nil; | |
| 37 | + while(line = Brdline(f, '\n')){ | |
| 38 | + line[Blinelen(f) - 1] = 0; | |
| 39 | + if(strlen(line) < 2 || line[1] != ' ') | |
| 40 | + continue; | |
| 41 | + switch(line[0]){ | |
| 42 | + case '+': | |
| 43 | + if(ni+1 >= nmaxi){ | |
| 44 | + nmaxi = 2*nmaxi; | |
| 45 | + include = realloc(include, nmaxi*sizeof(*include)); | |
| 46 | + if(include == nil) | |
| 47 | + fatal("out of memory"); | |
| 48 | + } | |
| 49 | + DEBUG(DFD, "\tinclude %s\n", line+2); | |
| 50 | + include[ni] = regcomp(line+2); | |
| 51 | + include[++ni] = nil; | |
| 52 | + break; | |
| 53 | + case '-': | |
| 54 | + if(ne+1 >= nmaxe){ | |
| 55 | + nmaxe = 2*nmaxe; | |
| 56 | + exclude = realloc(exclude, nmaxe*sizeof(*exclude)); | |
| 57 | + if(exclude == nil) | |
| 58 | + fatal("out of memory"); | |
| 59 | + } | |
| 60 | + DEBUG(DFD, "\texclude %s\n", line+2); | |
| 61 | + exclude[ne] = regcomp(line+2); | |
| 62 | + exclude[++ne] = nil; | |
| 63 | + break; | |
| 64 | + default: | |
| 65 | + DEBUG(DFD, "ignoring pattern %s\n", line); | |
| 66 | + break; | |
| 67 | + } | |
| 68 | + } | |
| 69 | + Bterm(f); | |
| 70 | +} | |
| 71 | + | |
| 72 | +int | |
| 73 | +excludefile(char *path) | |
| 74 | +{ | |
| 75 | + Reprog **re; | |
| 76 | + char *p; | |
| 77 | + | |
| 78 | + if(*(path+1) == 0) | |
| 79 | + p = "/"; | |
| 80 | + else | |
| 81 | + p = path+1; | |
| 82 | + | |
| 83 | + DEBUG(DFD, "checking %s\n", path); | |
| 84 | + for(re = include; *re != nil; re++){ | |
| 85 | + if(regexec(*re, p, nil, 0) != 1){ | |
| 86 | + DEBUG(DFD, "excluded+ %s\n", path); | |
| 87 | + return -1; | |
| 88 | + } | |
| 89 | + } | |
| 90 | + for(re = exclude; *re != nil; re++){ | |
| 91 | + if(regexec(*re, p, nil, 0) == 1){ | |
| 92 | + DEBUG(DFD, "excluded- %s\n", path); | |
| 93 | + return -1; | |
| 94 | + } | |
| 95 | + } | |
| 96 | + return 0; | |
| 97 | +} | |
| 98 | + | |
| 99 | +int | |
| 100 | +preaddir(Fid *f, uchar *data, int n, vlong offset) | |
| 101 | +{ | |
| 102 | + int r = 0, m; | |
| 103 | + Dir *d; | |
| 104 | + | |
| 105 | + DEBUG(DFD, "\tpreaddir n=%d wo=%lld fo=%lld\n", n, offset, f->offset); | |
| 106 | + if(offset == 0 && f->offset != 0){ | |
| 107 | + if(seek(f->fid, 0, 0) != 0) | |
| 108 | + return -1; | |
| 109 | + f->offset = f->cdir = f->ndir = 0; | |
| 110 | + free(f->dir); | |
| 111 | + f->dir = nil; | |
| 112 | + }else if(offset != f->offset){ | |
| 113 | + werrstr("can't seek dir %lld to %lld", f->offset, offset); | |
| 114 | + return -1; | |
| 115 | + } | |
| 116 | + | |
| 117 | + while(n > 0){ | |
| 118 | + if(f->dir == nil){ | |
| 119 | + f->ndir = dirread(f->fid, &f->dir); | |
| 120 | + if(f->ndir < 0) | |
| 121 | + return f->ndir; | |
| 122 | + if(f->ndir == 0) | |
| 123 | + return r; | |
| 124 | + } | |
| 125 | + d = &f->dir[f->cdir++]; | |
| 126 | + if(exclude){ | |
| 127 | + char *p = makepath(f->f, d->name); | |
| 128 | + if(excludefile(p)){ | |
| 129 | + free(p); | |
| 130 | + goto skipentry; | |
| 131 | + } | |
| 132 | + free(p); | |
| 133 | + } | |
| 134 | + m = convD2M(d, data, n); | |
| 135 | + DEBUG(DFD, "\t\tconvD2M %d\n", m); | |
| 136 | + if(m <= BIT16SZ){ | |
| 137 | + DEBUG(DFD, "\t\t\tneeded %d\n", GBIT16(data)); | |
| 138 | + /* not enough room for full entry; leave for next time */ | |
| 139 | + f->cdir--; | |
| 140 | + return r; | |
| 141 | + }else{ | |
| 142 | + data += m; | |
| 143 | + n -= m; | |
| 144 | + r += m; | |
| 145 | + f->offset += m; | |
| 146 | + } | |
| 147 | +skipentry: if(f->cdir >= f->ndir){ | |
| 148 | + f->cdir = f->ndir = 0; | |
| 149 | + free(f->dir); | |
| 150 | + f->dir = nil; | |
| 151 | + } | |
| 152 | + } | |
| 153 | + return r; | |
| 154 | +} | |
| @@ -30,7 +30,11 @@ echo '************************ PWD = '$PWD · 29 unmodified lines | ||
| 30 | 30 | |
| 31 | 31 | # setup |
| 32 | 32 | # |
| 33 | −NUM=32 | |
| 33 | +NUM=16 | |
| 34 | + | |
| 35 | +# exportfs 14181: warning: process exceeds 100 file descriptors | |
| 36 | +# exportfs: No more work buffers | |
| 37 | +#NUM=32 | |
| 34 | 38 | #NUM=256 |
| 35 | 39 | |
| 36 | 40 | I_MAX=4 |
| @@ -26,7 +26,9 @@ CMD='../8.poke -L '$TESTDIR · 25 unmodified lines | ||
| 26 | 26 | |
| 27 | 27 | # setup |
| 28 | 28 | # |
| 29 | −NUM=32 | |
| 29 | +#NUM=64 # succeds | |
| 30 | +NUM=75 # succeds | |
| 31 | +NUM=80 # fails | |
| 30 | 32 | |
| 31 | 33 | # NUM=32 # (with 1,4,4) gives |
| 32 | 34 | # exportfs 929: warning: process exceeds 100 file descriptors |