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