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
main(int argc,char ** argv)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
io(int srvfd)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
usage(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
error(char * p)229 error(char *p)
230 {
231 strecpy(err_msg, err_msg+sizeof err_msg, p);
232 nexterror();
233 }
234
235 void
nexterror(void)236 nexterror(void)
237 {
238 longjmp(err_lab[--nerr_lab], 1);
239 }
240
241 void*
ealloc(long n)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
setnames(Dir * d,char * n)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
rversion(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
rauth(void)277 rauth(void)
278 {
279 error("9660srv: authentication not required");
280 }
281
282 void
rflush(void)283 rflush(void)
284 {
285 }
286
287 void
rattach(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*
doclone(Xfile * of,int newfid)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
rwalk(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
ropen(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
rcreate(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
rread(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
rwrite(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
rclunk(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
rremove(void)489 rremove(void)
490 {
491 error("no removes");
492 }
493
494 void
rstat(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
rwstat(void)511 rwstat(void)
512 {
513 error("no wstat");
514 }
515
516 static int
openflags(int mode)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
showdir(int fd,Dir * s)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
chat(char * fmt,...)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
panic(int rflag,char * fmt,...)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