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 #define Extern 9 #include "exportfs.h" 10 11 void (*fcalls[])(Fsrpc*) = 12 { 13 [Tnop] Xnop, 14 [Tsession] Xsession, 15 [Tflush] Xflush, 16 [Tattach] Xattach, 17 [Tclone] Xclone, 18 [Twalk] Xwalk, 19 [Topen] slave, 20 [Tcreate] Xcreate, 21 [Tclunk] Xclunk, 22 [Tread] slave, 23 [Twrite] slave, 24 [Tremove] Xremove, 25 [Tstat] Xstat, 26 [Twstat] Xwstat, 27 [Tclwalk] Xclwalk, 28 }; 29 30 int nonone; 31 32 void 33 usage(void) 34 { 35 fprint(2, "usage: %s [-as] [-c ctlfile]\n", argv0); 36 fatal("usage"); 37 } 38 39 void 40 main(int argc, char **argv) 41 { 42 char buf[128]; 43 Fsrpc *r; 44 int n, srv; 45 char *dbfile; 46 char *ctlfile; 47 char user[NAMELEN]; 48 49 dbfile = "/tmp/exportdb"; 50 ctlfile = 0; 51 srv = 0; 52 53 ARGBEGIN{ 54 case 'a': 55 if(srvauth(0, user) < 0) 56 fatal("srvauth"); 57 if(newns(user, 0) < 0) 58 fatal("newns"); 59 putenv("service", "exportfs"); 60 break; 61 62 case 'c': 63 ctlfile = ARGF(); 64 break; 65 66 case 'd': 67 dbg++; 68 break; 69 70 case 'f': 71 dbfile = ARGF(); 72 break; 73 74 case 's': 75 srv++; 76 break; 77 78 default: 79 usage(); 80 }ARGEND 81 USED(argc, argv); 82 83 if(dbg) { 84 n = create(dbfile, OWRITE|OTRUNC, 0666); 85 dup(n, 2); 86 close(n); 87 } 88 89 DEBUG(2, "exportfs: started\n"); 90 91 rfork(RFNOTEG); 92 93 Workq = malloc(sizeof(Fsrpc)*Nr_workbufs); 94 fhash = malloc(sizeof(Fid*)*FHASHSIZE); 95 96 if(Workq == 0 || fhash == 0) 97 fatal("no initial memory"); 98 99 memset(Workq, 0, sizeof(Fsrpc)*Nr_workbufs); 100 101 fmtinstall('F', fcallconv); 102 103 /* 104 * Get tree to serve from network connection, 105 * check we can get there and ack the connection 106 */ 107 if(srv) { 108 chdir("/"); 109 DEBUG(2, "invoked as server for /"); 110 } 111 else { 112 buf[0] = 0; 113 n = read(0, buf, sizeof(buf)); 114 if(n < 0) { 115 errstr(buf); 116 fprint(0, "read(0): %s", buf); 117 DEBUG(2, "read(0): %s", buf); 118 exits(buf); 119 } 120 buf[n] = 0; 121 if(chdir(buf) < 0) { 122 char ebuf[128]; 123 errstr(ebuf); 124 fprint(0, "chdir(%d:\"%s\"): %s", n, buf, ebuf); 125 DEBUG(2, "chdir(%d:\"%s\"): %s", n, buf, ebuf); 126 exits(ebuf); 127 } 128 } 129 130 /* 131 * take ownership of the network connection and 132 * push the fcall line discipline 133 */ 134 if(ctlfile) 135 pushfcall(ctlfile); 136 137 DEBUG(2, "initing root\n"); 138 initroot(); 139 140 DEBUG(2, "exportfs: %s\n", buf); 141 142 if(srv == 0 && write(0, "OK", 2) != 2) 143 fatal("open ack write"); 144 145 /* 146 * Start serving file requests from the network 147 */ 148 for(;;) { 149 r = getsbuf(); 150 if(r == 0) 151 fatal("Out of service buffers"); 152 153 do 154 n = read9p(0, r->buf, sizeof(r->buf)); 155 while(n == 0); 156 157 if(n < 0) 158 fatal("server read"); 159 160 161 if(convM2S(r->buf, &r->work, n) == 0) 162 fatal("format error"); 163 164 DEBUG(2, "%F\n", &r->work, &r->work); 165 (fcalls[r->work.type])(r); 166 } 167 } 168 169 void 170 reply(Fcall *r, Fcall *t, char *err) 171 { 172 char data[MAXFDATA+MAXMSG]; 173 int n; 174 175 t->tag = r->tag; 176 t->fid = r->fid; 177 if(err) { 178 t->type = Rerror; 179 strncpy(t->ename, err, ERRLEN); 180 } 181 else 182 t->type = r->type + 1; 183 184 DEBUG(2, "\t%F\n", t); 185 186 n = convS2M(t, data); 187 if(write9p(0, data, n)!=n) 188 fatal("mount write"); 189 } 190 191 Fid * 192 getfid(int nr) 193 { 194 Fid *f; 195 196 for(f = fidhash(nr); f; f = f->next) 197 if(f->nr == nr) 198 return f; 199 200 return 0; 201 } 202 203 int 204 freefid(int nr) 205 { 206 Fid *f, **l; 207 char buf[128]; 208 209 l = &fidhash(nr); 210 for(f = *l; f; f = f->next) { 211 if(f->nr == nr) { 212 if(f->mpend) 213 f->mpend->busy = 0; 214 if(f->mid) { 215 sprint(buf, "/mnt/exportfs/%d", f->mid); 216 unmount(0, buf); 217 psmap[f->mid] = 0; 218 } 219 *l = f->next; 220 f->next = fidfree; 221 fidfree = f; 222 return 1; 223 } 224 l = &f->next; 225 } 226 227 return 0; 228 } 229 230 Fid * 231 newfid(int nr) 232 { 233 Fid *new, **l; 234 int i; 235 236 l = &fidhash(nr); 237 for(new = *l; new; new = new->next) 238 if(new->nr == nr) 239 return 0; 240 241 if(fidfree == 0) { 242 fidfree = malloc(sizeof(Fid) * Fidchunk); 243 if(fidfree == 0) 244 fatal("out of memory"); 245 246 for(i = 0; i < Fidchunk-1; i++) 247 fidfree[i].next = &fidfree[i+1]; 248 249 fidfree[Fidchunk-1].next = 0; 250 } 251 252 new = fidfree; 253 fidfree = new->next; 254 255 memset(new, 0, sizeof(Fid)); 256 new->next = *l; 257 *l = new; 258 new->nr = nr; 259 new->fid = -1; 260 new->mpend = 0; 261 new->mid = 0; 262 263 return new; 264 } 265 266 Fsrpc * 267 getsbuf(void) 268 { 269 static int ap; 270 int look; 271 Fsrpc *wb; 272 273 for(look = 0; look < Nr_workbufs; look++) { 274 if(++ap == Nr_workbufs) 275 ap = 0; 276 if(Workq[ap].busy == 0) 277 break; 278 } 279 280 if(look == Nr_workbufs) 281 fatal("No more work buffers"); 282 283 wb = &Workq[ap]; 284 wb->pid = 0; 285 wb->canint = 0; 286 wb->flushtag = NOTAG; 287 wb->busy = 1; 288 289 return wb; 290 } 291 292 char * 293 strcatalloc(char *p, char *n) 294 { 295 char *v; 296 297 v = realloc(p, strlen(p)+strlen(n)+1); 298 if(v == 0) 299 fatal("no memory"); 300 strcat(v, n); 301 return v; 302 } 303 304 File * 305 file(File *parent, char *name) 306 { 307 Dir dir; 308 char buf[128]; 309 File *f, *new; 310 311 DEBUG(2, "\tfile: 0x%x %s name %s\n", parent, parent->name, name); 312 313 for(f = parent->child; f; f = f->childlist) 314 if(strcmp(name, f->name) == 0) 315 return f; 316 317 makepath(buf, parent, name); 318 if(dirstat(buf, &dir) < 0) 319 return 0; 320 321 new = malloc(sizeof(File)); 322 if(new == 0) 323 fatal("no memory"); 324 325 memset(new, 0, sizeof(File)); 326 strcpy(new->name, name); 327 new->qid.vers = dir.qid.vers; 328 new->qid.path = (dir.qid.path&CHDIR)|++qid; 329 330 new->parent = parent; 331 new->childlist = parent->child; 332 parent->child = new; 333 334 return new; 335 } 336 337 void 338 initroot(void) 339 { 340 Dir dir; 341 342 root = malloc(sizeof(File)); 343 if(root == 0) 344 fatal("no memory"); 345 346 memset(root, 0, sizeof(File)); 347 strcpy(root->name, "."); 348 if(dirstat(root->name, &dir) < 0) 349 fatal("root stat"); 350 351 root->qid.vers = dir.qid.vers; 352 root->qid.path = (dir.qid.path&CHDIR)|++qid; 353 354 psmpt = malloc(sizeof(File)); 355 if(psmpt == 0) 356 fatal("no memory"); 357 358 memset(psmpt, 0, sizeof(File)); 359 strcpy(psmpt->name, "/"); 360 if(dirstat(psmpt->name, &dir) < 0) 361 return; 362 363 psmpt->qid.vers = dir.qid.vers; 364 psmpt->qid.path = (dir.qid.path&CHDIR)|++qid; 365 366 psmpt = file(psmpt, "mnt"); 367 if(psmpt == 0) 368 return; 369 psmpt = file(psmpt, "exportfs"); 370 } 371 372 void 373 makepath(char *s, File *p, char *name) 374 { 375 int i; 376 char *c, *seg[256]; 377 378 seg[0] = name; 379 for(i = 1; i < 100 && p; i++, p = p->parent) 380 seg[i] = p->name; 381 382 while(i--) { 383 for(c = seg[i]; *c; c++) 384 *s++ = *c; 385 *s++ = '/'; 386 } 387 while(s[-1] == '/') 388 s--; 389 *s = '\0'; 390 } 391 392 void 393 fatal(char *s) 394 { 395 char buf[128]; 396 Proc *m; 397 398 sprint(buf, "exportfs: %r: %s", s); 399 400 /* Clear away the slave children */ 401 for(m = Proclist; m; m = m->next) 402 postnote(PNPROC, m->pid, "kill"); 403 404 DEBUG(2, "%s\n", buf); 405 exits(buf); 406 } 407 408 char pushmsg[] = "push fcall"; 409 410 void 411 pushfcall(char *ctl) 412 { 413 int cfd; 414 Dir dir; 415 416 if(dirfstat(0, &dir) < 0){ 417 fprint(2, "dirfstat(0) failed: %r\n"); 418 return; 419 } 420 memmove(dir.uid, getuser(), NAMELEN); 421 if(dirfwstat(1, &dir) < 0){ 422 fprint(2, "dirfwstat(1) failed: %r\n"); 423 return; 424 } 425 cfd = open(ctl, ORDWR); 426 if(cfd < 0){ 427 fprint(2, "open(%s0) failed: %r\n", ctl); 428 return; 429 } 430 if(write(cfd, pushmsg, strlen(pushmsg)) < 0){ 431 fprint(2, "%s failed: %r\n", pushmsg); 432 return; 433 } 434 close(cfd); 435 } 436