]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/9660srv/main.c
make error handling in 9p service loops consistent
[plan9front.git] / sys / src / cmd / 9660srv / main.c
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|RFNAMEG)){
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         while((n = read9pmsg(srvfd, mdata, sizeof mdata)) != 0){
168                 if(n < 0)
169                         panic(1, "mount read");
170                 if(convM2S(mdata, n, req) != n)
171                         panic(1, "convM2S format error");
172
173                 if(chatty)
174                         fprint(2, "9660srv %d:<-%F\n", pid, req);
175
176                 errno = 0;
177                 if(!waserror()){
178                         err_msg[0] = 0;
179                         if(req->type >= nelem(fcalls) || !fcalls[req->type])
180                                 error("bad fcall type");
181                         (*fcalls[req->type])();
182                         poperror();
183                 }
184
185                 if(err_msg[0]){
186                         rep->type = Rerror;
187                         rep->ename = err_msg;
188                 }else{
189                         rep->type = req->type + 1;
190                         rep->fid = req->fid;
191                 }
192                 rep->tag = req->tag;
193
194                 if(chatty)
195                         fprint(2, "9660srv %d:->%F\n", pid, rep);
196                 n = convS2M(rep, mdata, sizeof mdata);
197                 if(n == 0)
198                         panic(1, "convS2M error on write");
199                 if(write(srvfd, mdata, n) != n)
200                         panic(1, "mount write");
201                 if(nerr_lab != 0)
202                         panic(0, "err stack %d: %lux %lux %lux %lux %lux %lux", nerr_lab,
203                         err_lab[0][JMPBUFPC], err_lab[1][JMPBUFPC],
204                         err_lab[2][JMPBUFPC], err_lab[3][JMPBUFPC],
205                         err_lab[4][JMPBUFPC], err_lab[5][JMPBUFPC]);
206         }
207         chat("server shut down");
208 }
209
210 static void
211 usage(void)
212 {
213         fprint(2, "usage: %s [-v] [-9Jr] [-s] [-f devicefile] [srvname]\n", argv0);
214         exits("usage");
215 }
216
217 void
218 error(char *p)
219 {
220         strecpy(err_msg, err_msg+sizeof err_msg, p);
221         nexterror();
222 }
223
224 void
225 nexterror(void)
226 {
227         longjmp(err_lab[--nerr_lab], 1);
228 }
229
230 void*
231 ealloc(long n)
232 {
233         void *p;
234
235         p = malloc(n);
236         if(p == 0)
237                 error("no memory");
238         setmalloctag(p, getcallerpc(&n));
239         return p;
240 }
241
242 void
243 setnames(Dir *d, char *n)
244 {
245         d->name = n;
246         d->uid = n+Maxname;
247         d->gid = n+Maxname*2;
248         d->muid = n+Maxname*3;
249
250         d->name[0] = '\0';
251         d->uid[0] = '\0';
252         d->gid[0] = '\0';
253         d->muid[0] = '\0';
254 }
255
256 void
257 rversion(void)
258 {
259         if(req->msize > Maxiosize)
260                 rep->msize = Maxiosize;
261         else
262                 rep->msize = req->msize;
263         rep->version = "9P2000";
264 }
265
266 void
267 rauth(void)
268 {
269         error("9660srv: authentication not required");
270 }
271
272 void
273 rflush(void)
274 {
275 }
276
277 void
278 rattach(void)
279 {
280         Xfs *xf;
281         Xfile *root;
282         Xfsub **xs;
283
284         chat("attach(fid=%d,uname=\"%s\",aname=\"%s\")...",
285                 req->fid, req->uname, req->aname);
286
287         if(waserror()){
288                 xfile(req->fid, Clunk);
289                 nexterror();
290         }
291         root = xfile(req->fid, Clean);
292         root->qid = (Qid){0, 0, QTDIR};
293         root->xf = xf = ealloc(sizeof(Xfs));
294         memset(xf, 0, sizeof(Xfs));
295         xf->ref = 1;
296         xf->d = getxdata(req->aname);
297
298         for(xs=xsublist; *xs; xs++)
299                 if((*(*xs)->attach)(root) >= 0){
300                         poperror();
301                         xf->s = *xs;
302                         xf->rootqid = root->qid;
303                         rep->qid = root->qid;
304                         return;
305                 }
306         error("unknown format");
307 }
308
309 Xfile*
310 doclone(Xfile *of, int newfid)
311 {
312         Xfile *nf, *next;
313
314         nf = xfile(newfid, Clean);
315         if(waserror()){
316                 xfile(newfid, Clunk);
317                 nexterror();
318         }
319         next = nf->next;
320         *nf = *of;
321         nf->next = next;
322         nf->fid = newfid;
323         refxfs(nf->xf, 1);
324         if(nf->len){
325                 nf->ptr = ealloc(nf->len);
326                 memmove(nf->ptr, of->ptr, nf->len);
327         }else
328                 nf->ptr = of->ptr;
329         (*of->xf->s->clone)(of, nf);
330         poperror();
331         return nf;
332 }
333
334 void
335 rwalk(void)
336 {
337         Xfile *f, *nf;
338         Isofile *oldptr;
339         int oldlen;
340         Qid oldqid;
341
342         rep->nwqid = 0;
343         nf = nil;
344         f = xfile(req->fid, Asis);
345         if(req->fid != req->newfid)
346                 f = nf = doclone(f, req->newfid);
347
348         /* save old state in case of error */
349         oldqid = f->qid;
350         oldlen = f->len;
351         oldptr = f->ptr;
352         if(oldlen){
353                 oldptr = ealloc(oldlen);
354                 memmove(oldptr, f->ptr, oldlen);
355         }
356
357         if(waserror()){
358                 if(rep->nwqid == req->nwname){
359                         if(oldlen)
360                                 free(oldptr);
361                 }else{
362                         /* restore previous state */
363                         f->qid = oldqid;
364                         if(f->len)
365                                 free(f->ptr);
366                         f->ptr = oldptr;
367                         f->len = oldlen;
368                 }
369                 if(nf != nil)
370                         xfile(req->newfid, Clunk);
371                 if(rep->nwqid==req->nwname || rep->nwqid > 0){
372                         err_msg[0] = '\0';
373                         return;
374                 }
375                 nexterror();
376         }
377
378         for(rep->nwqid=0; rep->nwqid < req->nwname && rep->nwqid < MAXWELEM; rep->nwqid++){
379                 chat("\twalking %s\n", req->wname[rep->nwqid]);
380                 if(!(f->qid.type & QTDIR)){
381                         chat("\tnot dir: type=%#x\n", f->qid.type);
382                         error("walk in non-directory");
383                 }
384
385                 if(strcmp(req->wname[rep->nwqid], "..")==0){
386                         if(f->qid.path != f->xf->rootqid.path)
387                                 (*f->xf->s->walkup)(f);
388                 }else
389                         (*f->xf->s->walk)(f, req->wname[rep->nwqid]);
390                 rep->wqid[rep->nwqid] = f->qid;
391         }
392         poperror();
393         if(oldlen)
394                 free(oldptr);
395 }
396
397 void
398 ropen(void)
399 {
400         Xfile *f;
401
402         f = xfile(req->fid, Asis);
403         if(f->flags&Omodes)
404                 error("open on open file");
405         if(req->mode&ORCLOSE)
406                 error("no removes");
407         (*f->xf->s->open)(f, req->mode);
408         f->flags = openflags(req->mode);
409         rep->qid = f->qid;
410         rep->iounit = 0;
411 }
412
413 void
414 rcreate(void)
415 {
416         error("no creates");
417 /*
418         Xfile *f;
419
420         if(strcmp(req->name, ".") == 0 || strcmp(req->name, "..") == 0)
421                 error("create . or ..");
422         f = xfile(req->fid, Asis);
423         if(f->flags&Omodes)
424                 error("create on open file");
425         if(!(f->qid.path&CHDIR))
426                 error("create in non-directory");
427         (*f->xf->s->create)(f, req->name, req->perm, req->mode);
428         chat("f->qid=0x%8.8lux...", f->qid.path);
429         f->flags = openflags(req->mode);
430         rep->qid = f->qid;
431 */
432 }
433
434 void
435 rread(void)
436 {
437         Xfile *f;
438
439         f=xfile(req->fid, Asis);
440         if (!(f->flags&Oread))
441                 error("file not opened for reading");
442         if(f->qid.type & QTDIR)
443                 rep->count = (*f->xf->s->readdir)(f, (uchar*)fdata, req->offset, req->count);
444         else
445                 rep->count = (*f->xf->s->read)(f, fdata, req->offset, req->count);
446         rep->data = fdata;
447 }
448
449 void
450 rwrite(void)
451 {
452         Xfile *f;
453
454         f=xfile(req->fid, Asis);
455         if(!(f->flags&Owrite))
456                 error("file not opened for writing");
457         rep->count = (*f->xf->s->write)(f, req->data, req->offset, req->count);
458 }
459
460 void
461 rclunk(void)
462 {
463         Xfile *f;
464
465         if(!waserror()){
466                 f = xfile(req->fid, Asis);
467                 (*f->xf->s->clunk)(f);
468                 poperror();
469         }
470         xfile(req->fid, Clunk);
471 }
472
473 void
474 rremove(void)
475 {
476         error("no removes");
477 }
478
479 void
480 rstat(void)
481 {
482         Xfile *f;
483         Dir dir;
484
485         chat("stat(fid=%d)...", req->fid);
486         f=xfile(req->fid, Asis);
487         setnames(&dir, fdata);
488         (*f->xf->s->stat)(f, &dir);
489         if(chatty)
490                 showdir(2, &dir);
491         rep->nstat = convD2M(&dir, statbuf, sizeof statbuf);
492         rep->stat = statbuf;
493 }
494
495 void
496 rwstat(void)
497 {
498         error("no wstat");
499 }
500
501 static int
502 openflags(int mode)
503 {
504         int flags = 0;
505
506         switch(mode & ~(OTRUNC|OCEXEC|ORCLOSE)){
507         case OREAD:
508         case OEXEC:
509                 flags = Oread; break;
510         case OWRITE:
511                 flags = Owrite; break;
512         case ORDWR:
513                 flags = Oread|Owrite; break;
514         }
515         if(mode & ORCLOSE)
516                 flags |= Orclose;
517         return flags;
518 }
519
520 void
521 showdir(int fd, Dir *s)
522 {
523         char a_time[32], m_time[32];
524         char *p;
525
526         strcpy(a_time, ctime(s->atime));
527         if(p=strchr(a_time, '\n'))      /* assign = */
528                 *p = 0;
529         strcpy(m_time, ctime(s->mtime));
530         if(p=strchr(m_time, '\n'))      /* assign = */
531                 *p = 0;
532         fprint(fd, "name=\"%s\" qid=(0x%llux,%lud) type=%d dev=%d \
533 mode=0x%8.8lux=0%luo atime=%s mtime=%s length=%lld uid=\"%s\" gid=\"%s\"...",
534                 s->name, s->qid.path, s->qid.vers, s->type, s->dev,
535                 s->mode, s->mode,
536                 a_time, m_time, s->length, s->uid, s->gid);
537 }
538
539 #define SIZE    1024
540
541 void
542 chat(char *fmt, ...)
543 {
544         va_list arg;
545
546         if(chatty){
547                 va_start(arg, fmt);
548                 vfprint(2, fmt, arg);
549                 va_end(arg);
550         }
551 }
552
553 void
554 panic(int rflag, char *fmt, ...)
555 {
556         va_list arg;
557         char buf[SIZE]; int n;
558
559         n = sprint(buf, "%s %d: ", argv0, getpid());
560         va_start(arg, fmt);
561         vseprint(buf+n, buf+SIZE, fmt, arg);
562         va_end(arg);
563         fprint(2, (rflag ? "%s: %r\n" : "%s\n"), buf);
564         if(chatty){
565                 fprint(2, "abort\n");
566                 abort();
567         }
568         exits("panic");
569 }