1 #include <u.h> 2 #include <libc.h> 3 #include <auth.h> 4 #include <fcall.h> 5 #include "dat.h" 6 #include "fns.h" 7 8 enum 9 { 10 Maxfdata = 8192, 11 Maxiosize = IOHDRSZ+Maxfdata, 12 }; 13 14 void io(int); 15 void rversion(void); 16 void rattach(void); 17 void rauth(void); 18 void rclunk(void); 19 void rcreate(void); 20 void rflush(void); 21 void ropen(void); 22 void rread(void); 23 void rremove(void); 24 void rsession(void); 25 void rstat(void); 26 void rwalk(void); 27 void rwrite(void); 28 void rwstat(void); 29 30 static int openflags(int); 31 static void rmservice(void); 32 static void usage(void); 33 34 #define Reqsize (sizeof(Fcall)+Maxfdata) 35 36 Fcall *req; 37 Fcall *rep; 38 39 uchar mdata[Maxiosize]; 40 char fdata[Maxfdata]; 41 uchar statbuf[STATMAX]; 42 int errno; 43 44 static char srvfile[64]; 45 46 extern Xfsub *xsublist[]; 47 extern int nclust; 48 49 jmp_buf err_lab[16]; 50 int nerr_lab; 51 char err_msg[ERRMAX]; 52 53 int chatty; 54 int nojoliet; 55 int noplan9; 56 int norock; 57 58 void (*fcalls[])(void) = { 59 [Tversion] rversion, 60 [Tflush] rflush, 61 [Tauth] rauth, 62 [Tattach] rattach, 63 [Twalk] rwalk, 64 [Topen] ropen, 65 [Tcreate] rcreate, 66 [Tread] rread, 67 [Twrite] rwrite, 68 [Tclunk] rclunk, 69 [Tremove] rremove, 70 [Tstat] rstat, 71 [Twstat] rwstat, 72 }; 73 74 void 75 main(int argc, char **argv) 76 { 77 int srvfd, pipefd[2], stdio; 78 Xfsub **xs; 79 80 stdio = 0; 81 ARGBEGIN { 82 case '9': 83 noplan9 = 1; 84 break; 85 case 'c': 86 nclust = atoi(EARGF(usage())); 87 if (nclust <= 0) 88 sysfatal("nclust %d non-positive", nclust); 89 break; 90 case 'f': 91 deffile = EARGF(usage()); 92 break; 93 case 'r': 94 norock = 1; 95 break; 96 case 's': 97 stdio = 1; 98 break; 99 case 'v': 100 chatty = 1; 101 break; 102 case 'J': 103 nojoliet = 1; 104 break; 105 default: 106 usage(); 107 } ARGEND 108 109 switch(argc) { 110 case 0: 111 break; 112 case 1: 113 srvname = argv[0]; 114 break; 115 default: 116 usage(); 117 } 118 119 iobuf_init(); 120 for(xs=xsublist; *xs; xs++) 121 (*(*xs)->reset)(); 122 123 if(stdio) { 124 pipefd[0] = 0; 125 pipefd[1] = 1; 126 } else { 127 close(0); 128 close(1); 129 open("/dev/null", OREAD); 130 open("/dev/null", OWRITE); 131 if(pipe(pipefd) < 0) 132 panic(1, "pipe"); 133 sprint(srvfile, "/srv/%s", srvname); 134 srvfd = create(srvfile, OWRITE|ORCLOSE, 0600); 135 if(srvfd < 0) 136 panic(1, srvfile); 137 fprint(srvfd, "%d", pipefd[0]); 138 close(pipefd[0]); 139 fprint(2, "%s %d: serving %s\n", argv0, getpid(), srvfile); 140 } 141 srvfd = pipefd[1]; 142 143 switch(rfork(RFNOWAIT|RFNOTEG|RFFDG|RFPROC)){ 144 case -1: 145 panic(1, "fork"); 146 default: 147 _exits(0); 148 case 0: 149 break; 150 } 151 152 io(srvfd); 153 exits(0); 154 } 155 156 void 157 io(int srvfd) 158 { 159 int n, pid; 160 Fcall xreq, xrep; 161 162 req = &xreq; 163 rep = &xrep; 164 pid = getpid(); 165 fmtinstall('F', fcallfmt); 166 167 for(;;){ 168 /* 169 * reading from a pipe or a network device 170 * will give an error after a few eof reads. 171 * however, we cannot tell the difference 172 * between a zero-length read and an interrupt 173 * on the processes writing to us, 174 * so we wait for the error. 175 */ 176 n = read9pmsg(srvfd, mdata, sizeof mdata); 177 if(n < 0) 178 break; 179 if(n == 0) 180 continue; 181 if(convM2S(mdata, n, req) == 0) 182 continue; 183 184 if(chatty) 185 fprint(2, "9660srv %d:<-%F\n", pid, req); 186 187 errno = 0; 188 if(!waserror()){ 189 err_msg[0] = 0; 190 if(req->type >= nelem(fcalls) || !fcalls[req->type]) 191 error("bad fcall type"); 192 (*fcalls[req->type])(); 193 poperror(); 194 } 195 196 if(err_msg[0]){ 197 rep->type = Rerror; 198 rep->ename = err_msg; 199 }else{ 200 rep->type = req->type + 1; 201 rep->fid = req->fid; 202 } 203 rep->tag = req->tag; 204 205 if(chatty) 206 fprint(2, "9660srv %d:->%F\n", pid, rep); 207 n = convS2M(rep, mdata, sizeof mdata); 208 if(n == 0) 209 panic(1, "convS2M error on write"); 210 if(write(srvfd, mdata, n) != n) 211 panic(1, "mount write"); 212 if(nerr_lab != 0) 213 panic(0, "err stack %d: %lux %lux %lux %lux %lux %lux", nerr_lab, 214 err_lab[0][JMPBUFPC], err_lab[1][JMPBUFPC], 215 err_lab[2][JMPBUFPC], err_lab[3][JMPBUFPC], 216 err_lab[4][JMPBUFPC], err_lab[5][JMPBUFPC]); 217 } 218 chat("server shut down"); 219 } 220 221 static void 222 usage(void) 223 { 224 fprint(2, "usage: %s [-v] [-9Jr] [-s] [-f devicefile] [srvname]\n", argv0); 225 exits("usage"); 226 } 227 228 void 229 error(char *p) 230 { 231 strecpy(err_msg, err_msg+sizeof err_msg, p); 232 nexterror(); 233 } 234 235 void 236 nexterror(void) 237 { 238 longjmp(err_lab[--nerr_lab], 1); 239 } 240 241 void* 242 ealloc(long n) 243 { 244 void *p; 245 246 p = malloc(n); 247 if(p == 0) 248 error("no memory"); 249 return p; 250 } 251 252 void 253 setnames(Dir *d, char *n) 254 { 255 d->name = n; 256 d->uid = n+Maxname; 257 d->gid = n+Maxname*2; 258 d->muid = n+Maxname*3; 259 260 d->name[0] = '\0'; 261 d->uid[0] = '\0'; 262 d->gid[0] = '\0'; 263 d->muid[0] = '\0'; 264 } 265 266 void 267 rversion(void) 268 { 269 if(req->msize > Maxiosize) 270 rep->msize = Maxiosize; 271 else 272 rep->msize = req->msize; 273 rep->version = "9P2000"; 274 } 275 276 void 277 rauth(void) 278 { 279 error("9660srv: authentication not required"); 280 } 281 282 void 283 rflush(void) 284 { 285 } 286 287 void 288 rattach(void) 289 { 290 Xfs *xf; 291 Xfile *root; 292 Xfsub **xs; 293 294 chat("attach(fid=%d,uname=\"%s\",aname=\"%s\")...", 295 req->fid, req->uname, req->aname); 296 297 if(waserror()){ 298 xfile(req->fid, Clunk); 299 nexterror(); 300 } 301 root = xfile(req->fid, Clean); 302 root->qid = (Qid){0, 0, QTDIR}; 303 root->xf = xf = ealloc(sizeof(Xfs)); 304 memset(xf, 0, sizeof(Xfs)); 305 xf->ref = 1; 306 xf->d = getxdata(req->aname); 307 308 for(xs=xsublist; *xs; xs++) 309 if((*(*xs)->attach)(root) >= 0){ 310 poperror(); 311 xf->s = *xs; 312 xf->rootqid = root->qid; 313 rep->qid = root->qid; 314 return; 315 } 316 error("unknown format"); 317 } 318 319 Xfile* 320 doclone(Xfile *of, int newfid) 321 { 322 Xfile *nf, *next; 323 324 nf = xfile(newfid, Clean); 325 if(waserror()){ 326 xfile(newfid, Clunk); 327 nexterror(); 328 } 329 next = nf->next; 330 *nf = *of; 331 nf->next = next; 332 nf->fid = newfid; 333 refxfs(nf->xf, 1); 334 if(nf->len){ 335 nf->ptr = ealloc(nf->len); 336 memmove(nf->ptr, of->ptr, nf->len); 337 }else 338 nf->ptr = of->ptr; 339 (*of->xf->s->clone)(of, nf); 340 poperror(); 341 return nf; 342 } 343 344 void 345 rwalk(void) 346 { 347 Xfile *f, *nf; 348 Isofile *oldptr; 349 int oldlen; 350 Qid oldqid; 351 352 rep->nwqid = 0; 353 nf = nil; 354 f = xfile(req->fid, Asis); 355 if(req->fid != req->newfid) 356 f = nf = doclone(f, req->newfid); 357 358 /* save old state in case of error */ 359 oldqid = f->qid; 360 oldlen = f->len; 361 oldptr = f->ptr; 362 if(oldlen){ 363 oldptr = ealloc(oldlen); 364 memmove(oldptr, f->ptr, oldlen); 365 } 366 367 if(waserror()){ 368 /* 369 * if nf != nil, nf == f, which is derived from req->newfid, 370 * so we can't clunk req->newfid with xfile, which would put 371 * f back on the free list, until we're done with f below. 372 */ 373 if(rep->nwqid == req->nwname){ 374 if(oldlen) 375 free(oldptr); 376 }else{ 377 /* restore previous state */ 378 f->qid = oldqid; 379 if(f->len) 380 free(f->ptr); 381 f->ptr = oldptr; 382 f->len = oldlen; 383 } 384 if(nf != nil) 385 xfile(req->newfid, Clunk); 386 if(rep->nwqid==req->nwname || rep->nwqid > 0){ 387 err_msg[0] = '\0'; 388 return; 389 } 390 nexterror(); 391 } 392 393 for(rep->nwqid=0; rep->nwqid < req->nwname && rep->nwqid < MAXWELEM; rep->nwqid++){ 394 chat("\twalking %s\n", req->wname[rep->nwqid]); 395 if(!(f->qid.type & QTDIR)){ 396 chat("\tnot dir: type=%#x\n", f->qid.type); 397 error("walk in non-directory"); 398 } 399 400 if(strcmp(req->wname[rep->nwqid], "..")==0){ 401 if(f->qid.path != f->xf->rootqid.path) 402 (*f->xf->s->walkup)(f); 403 }else 404 (*f->xf->s->walk)(f, req->wname[rep->nwqid]); 405 rep->wqid[rep->nwqid] = f->qid; 406 } 407 poperror(); 408 if(oldlen) 409 free(oldptr); 410 } 411 412 void 413 ropen(void) 414 { 415 Xfile *f; 416 417 f = xfile(req->fid, Asis); 418 if(f->flags&Omodes) 419 error("open on open file"); 420 if(req->mode&ORCLOSE) 421 error("no removes"); 422 (*f->xf->s->open)(f, req->mode); 423 f->flags = openflags(req->mode); 424 rep->qid = f->qid; 425 rep->iounit = 0; 426 } 427 428 void 429 rcreate(void) 430 { 431 error("no creates"); 432 /* 433 Xfile *f; 434 435 if(strcmp(req->name, ".") == 0 || strcmp(req->name, "..") == 0) 436 error("create . or .."); 437 f = xfile(req->fid, Asis); 438 if(f->flags&Omodes) 439 error("create on open file"); 440 if(!(f->qid.path&CHDIR)) 441 error("create in non-directory"); 442 (*f->xf->s->create)(f, req->name, req->perm, req->mode); 443 chat("f->qid=0x%8.8lux...", f->qid.path); 444 f->flags = openflags(req->mode); 445 rep->qid = f->qid; 446 */ 447 } 448 449 void 450 rread(void) 451 { 452 Xfile *f; 453 454 f=xfile(req->fid, Asis); 455 if (!(f->flags&Oread)) 456 error("file not opened for reading"); 457 if(f->qid.type & QTDIR) 458 rep->count = (*f->xf->s->readdir)(f, (uchar*)fdata, req->offset, req->count); 459 else 460 rep->count = (*f->xf->s->read)(f, fdata, req->offset, req->count); 461 rep->data = fdata; 462 } 463 464 void 465 rwrite(void) 466 { 467 Xfile *f; 468 469 f=xfile(req->fid, Asis); 470 if(!(f->flags&Owrite)) 471 error("file not opened for writing"); 472 rep->count = (*f->xf->s->write)(f, req->data, req->offset, req->count); 473 } 474 475 void 476 rclunk(void) 477 { 478 Xfile *f; 479 480 if(!waserror()){ 481 f = xfile(req->fid, Asis); 482 (*f->xf->s->clunk)(f); 483 poperror(); 484 } 485 xfile(req->fid, Clunk); 486 } 487 488 void 489 rremove(void) 490 { 491 error("no removes"); 492 } 493 494 void 495 rstat(void) 496 { 497 Xfile *f; 498 Dir dir; 499 500 chat("stat(fid=%d)...", req->fid); 501 f=xfile(req->fid, Asis); 502 setnames(&dir, fdata); 503 (*f->xf->s->stat)(f, &dir); 504 if(chatty) 505 showdir(2, &dir); 506 rep->nstat = convD2M(&dir, statbuf, sizeof statbuf); 507 rep->stat = statbuf; 508 } 509 510 void 511 rwstat(void) 512 { 513 error("no wstat"); 514 } 515 516 static int 517 openflags(int mode) 518 { 519 int flags = 0; 520 521 switch(mode & ~(OTRUNC|OCEXEC|ORCLOSE)){ 522 case OREAD: 523 case OEXEC: 524 flags = Oread; break; 525 case OWRITE: 526 flags = Owrite; break; 527 case ORDWR: 528 flags = Oread|Owrite; break; 529 } 530 if(mode & ORCLOSE) 531 flags |= Orclose; 532 return flags; 533 } 534 535 void 536 showdir(int fd, Dir *s) 537 { 538 char a_time[32], m_time[32]; 539 char *p; 540 541 strcpy(a_time, ctime(s->atime)); 542 if(p=strchr(a_time, '\n')) /* assign = */ 543 *p = 0; 544 strcpy(m_time, ctime(s->mtime)); 545 if(p=strchr(m_time, '\n')) /* assign = */ 546 *p = 0; 547 fprint(fd, "name=\"%s\" qid=(0x%llux,%lud) type=%d dev=%d \ 548 mode=0x%8.8lux=0%luo atime=%s mtime=%s length=%lld uid=\"%s\" gid=\"%s\"...", 549 s->name, s->qid.path, s->qid.vers, s->type, s->dev, 550 s->mode, s->mode, 551 a_time, m_time, s->length, s->uid, s->gid); 552 } 553 554 #define SIZE 1024 555 556 void 557 chat(char *fmt, ...) 558 { 559 va_list arg; 560 561 if(chatty){ 562 va_start(arg, fmt); 563 vfprint(2, fmt, arg); 564 va_end(arg); 565 } 566 } 567 568 void 569 panic(int rflag, char *fmt, ...) 570 { 571 va_list arg; 572 char buf[SIZE]; int n; 573 574 n = sprint(buf, "%s %d: ", argv0, getpid()); 575 va_start(arg, fmt); 576 vseprint(buf+n, buf+SIZE, fmt, arg); 577 va_end(arg); 578 fprint(2, (rflag ? "%s: %r\n" : "%s\n"), buf); 579 if(chatty){ 580 fprint(2, "abort\n"); 581 abort(); 582 } 583 exits("panic"); 584 } 585