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