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 if(nf != nil) 369 xfile(req->newfid, Clunk); 370 if(rep->nwqid == req->nwname){ 371 if(oldlen) 372 free(oldptr); 373 }else{ 374 /* restore previous state */ 375 f->qid = oldqid; 376 if(f->len) 377 free(f->ptr); 378 f->ptr = oldptr; 379 f->len = oldlen; 380 } 381 if(rep->nwqid==req->nwname || rep->nwqid > 0){ 382 err_msg[0] = '\0'; 383 return; 384 } 385 nexterror(); 386 } 387 388 for(rep->nwqid=0; rep->nwqid < req->nwname && rep->nwqid < MAXWELEM; rep->nwqid++){ 389 chat("\twalking %s\n", req->wname[rep->nwqid]); 390 if(!(f->qid.type & QTDIR)){ 391 chat("\tnot dir: type=%#x\n", f->qid.type); 392 error("walk in non-directory"); 393 } 394 395 if(strcmp(req->wname[rep->nwqid], "..")==0){ 396 if(f->qid.path != f->xf->rootqid.path) 397 (*f->xf->s->walkup)(f); 398 }else 399 (*f->xf->s->walk)(f, req->wname[rep->nwqid]); 400 rep->wqid[rep->nwqid] = f->qid; 401 } 402 poperror(); 403 if(oldlen) 404 free(oldptr); 405 } 406 407 void 408 ropen(void) 409 { 410 Xfile *f; 411 412 f = xfile(req->fid, Asis); 413 if(f->flags&Omodes) 414 error("open on open file"); 415 if(req->mode&ORCLOSE) 416 error("no removes"); 417 (*f->xf->s->open)(f, req->mode); 418 f->flags = openflags(req->mode); 419 rep->qid = f->qid; 420 rep->iounit = 0; 421 } 422 423 void 424 rcreate(void) 425 { 426 error("no creates"); 427 /* 428 Xfile *f; 429 430 if(strcmp(req->name, ".") == 0 || strcmp(req->name, "..") == 0) 431 error("create . or .."); 432 f = xfile(req->fid, Asis); 433 if(f->flags&Omodes) 434 error("create on open file"); 435 if(!(f->qid.path&CHDIR)) 436 error("create in non-directory"); 437 (*f->xf->s->create)(f, req->name, req->perm, req->mode); 438 chat("f->qid=0x%8.8lux...", f->qid.path); 439 f->flags = openflags(req->mode); 440 rep->qid = f->qid; 441 */ 442 } 443 444 void 445 rread(void) 446 { 447 Xfile *f; 448 449 f=xfile(req->fid, Asis); 450 if (!(f->flags&Oread)) 451 error("file not opened for reading"); 452 if(f->qid.type & QTDIR) 453 rep->count = (*f->xf->s->readdir)(f, (uchar*)fdata, req->offset, req->count); 454 else 455 rep->count = (*f->xf->s->read)(f, fdata, req->offset, req->count); 456 rep->data = fdata; 457 } 458 459 void 460 rwrite(void) 461 { 462 Xfile *f; 463 464 f=xfile(req->fid, Asis); 465 if(!(f->flags&Owrite)) 466 error("file not opened for writing"); 467 rep->count = (*f->xf->s->write)(f, req->data, req->offset, req->count); 468 } 469 470 void 471 rclunk(void) 472 { 473 Xfile *f; 474 475 if(!waserror()){ 476 f = xfile(req->fid, Asis); 477 (*f->xf->s->clunk)(f); 478 poperror(); 479 } 480 xfile(req->fid, Clunk); 481 } 482 483 void 484 rremove(void) 485 { 486 error("no removes"); 487 } 488 489 void 490 rstat(void) 491 { 492 Xfile *f; 493 Dir dir; 494 495 chat("stat(fid=%d)...", req->fid); 496 f=xfile(req->fid, Asis); 497 setnames(&dir, fdata); 498 (*f->xf->s->stat)(f, &dir); 499 if(chatty) 500 showdir(2, &dir); 501 rep->nstat = convD2M(&dir, statbuf, sizeof statbuf); 502 rep->stat = statbuf; 503 } 504 505 void 506 rwstat(void) 507 { 508 error("no wstat"); 509 } 510 511 static int 512 openflags(int mode) 513 { 514 int flags = 0; 515 516 switch(mode & ~(OTRUNC|OCEXEC|ORCLOSE)){ 517 case OREAD: 518 case OEXEC: 519 flags = Oread; break; 520 case OWRITE: 521 flags = Owrite; break; 522 case ORDWR: 523 flags = Oread|Owrite; break; 524 } 525 if(mode & ORCLOSE) 526 flags |= Orclose; 527 return flags; 528 } 529 530 void 531 showdir(int fd, Dir *s) 532 { 533 char a_time[32], m_time[32]; 534 char *p; 535 536 strcpy(a_time, ctime(s->atime)); 537 if(p=strchr(a_time, '\n')) /* assign = */ 538 *p = 0; 539 strcpy(m_time, ctime(s->mtime)); 540 if(p=strchr(m_time, '\n')) /* assign = */ 541 *p = 0; 542 fprint(fd, "name=\"%s\" qid=(0x%llux,%lud) type=%d dev=%d \ 543 mode=0x%8.8lux=0%luo atime=%s mtime=%s length=%lld uid=\"%s\" gid=\"%s\"...", 544 s->name, s->qid.path, s->qid.vers, s->type, s->dev, 545 s->mode, s->mode, 546 a_time, m_time, s->length, s->uid, s->gid); 547 } 548 549 #define SIZE 1024 550 551 void 552 chat(char *fmt, ...) 553 { 554 va_list arg; 555 556 if(chatty){ 557 va_start(arg, fmt); 558 vfprint(2, fmt, arg); 559 va_end(arg); 560 } 561 } 562 563 void 564 panic(int rflag, char *fmt, ...) 565 { 566 va_list arg; 567 char buf[SIZE]; int n; 568 569 n = sprint(buf, "%s %d: ", argv0, getpid()); 570 va_start(arg, fmt); 571 vseprint(buf+n, buf+SIZE, fmt, arg); 572 va_end(arg); 573 fprint(2, (rflag ? "%s: %r\n" : "%s\n"), buf); 574 if(chatty){ 575 fprint(2, "abort\n"); 576 abort(); 577 } 578 exits("panic"); 579 } 580