Blob


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"
9 enum
10 {
11 Maxfdata = 8192,
12 Maxiosize = IOHDRSZ+Maxfdata,
13 };
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);
31 static int openflags(int);
32 static void usage(void);
34 #define Reqsize (sizeof(Fcall)+Maxfdata)
36 Fcall *req;
37 Fcall *rep;
39 uchar mdata[Maxiosize];
40 char fdata[Maxfdata];
41 uchar statbuf[STATMAX];
44 extern Xfsub *xsublist[];
45 extern int nclust;
47 jmp_buf err_lab[16];
48 int nerr_lab;
49 char err_msg[ERRMAX];
51 int chatty;
52 int nojoliet;
53 int noplan9;
54 int norock;
56 void (*fcalls[Tmax])(void);
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 }
76 void
77 main(int argc, char **argv)
78 {
79 int srvfd, pipefd[2], stdio;
80 Xfsub **xs;
81 char *mtpt;
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
117 switch(argc) {
118 case 0:
119 break;
120 case 1:
121 srvname = argv[0];
122 break;
123 default:
124 usage();
127 iobuf_init();
128 for(xs=xsublist; *xs; xs++)
129 (*(*xs)->reset)();
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");
142 if(post9pservice(pipefd[0], srvname, mtpt) < 0)
143 sysfatal("post9pservice: %r");
144 close(pipefd[0]);
146 srvfd = pipefd[1];
148 switch(rfork(RFNOWAIT|RFNOTEG|RFFDG|RFPROC)){
149 case -1:
150 panic(1, "fork");
151 default:
152 _exits(0);
153 case 0:
154 break;
157 io(srvfd);
158 exits(0);
161 void
162 io(int srvfd)
164 int n, pid;
165 Fcall xreq, xrep;
167 req = &xreq;
168 rep = &xrep;
169 pid = getpid();
170 fmtinstall('F', fcallfmt);
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;
189 if(chatty)
190 fprint(2, "9660srv %d:<-%F\n", pid, req);
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();
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;
208 rep->tag = req->tag;
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");
220 chat("server shut down");
223 static void
224 usage(void)
226 fprint(2, "usage: %s [-v] [-9Jr] [-s] [-f devicefile] [srvname]\n", argv0);
227 exits("usage");
230 void
231 error(char *p)
233 strecpy(err_msg, err_msg+sizeof err_msg, p);
234 nexterror();
237 void
238 nexterror(void)
240 longjmp(err_lab[--nerr_lab], 1);
243 void*
244 ealloc(long n)
246 void *p;
248 p = malloc(n);
249 if(p == 0)
250 error("no memory");
251 return p;
254 void
255 setnames(Dir *d, char *n)
257 d->name = n;
258 d->uid = n+Maxname;
259 d->gid = n+Maxname*2;
260 d->muid = n+Maxname*3;
262 d->name[0] = '\0';
263 d->uid[0] = '\0';
264 d->gid[0] = '\0';
265 d->muid[0] = '\0';
268 void
269 rversion(void)
271 if(req->msize > Maxiosize)
272 rep->msize = Maxiosize;
273 else
274 rep->msize = req->msize;
275 rep->version = "9P2000";
278 void
279 rauth(void)
281 error("9660srv: authentication not required");
284 void
285 rflush(void)
289 void
290 rattach(void)
292 Xfs *xf;
293 Xfile *root;
294 Xfsub **xs;
296 chat("attach(fid=%d,uname=\"%s\",aname=\"%s\")...",
297 req->fid, req->uname, req->aname);
299 if(waserror()){
300 xfile(req->fid, Clunk);
301 nexterror();
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);
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;
318 error("unknown format");
321 Xfile*
322 doclone(Xfile *of, int newfid)
324 Xfile *nf, *next;
326 nf = xfile(newfid, Clean);
327 if(waserror()){
328 xfile(newfid, Clunk);
329 nexterror();
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;
346 void
347 rwalk(void)
349 Xfile *f, *nf;
350 Isofile *oldptr;
351 int oldlen;
352 Qid oldqid;
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);
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);
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;
383 if(rep->nwqid==req->nwname || rep->nwqid > 0){
384 err_msg[0] = '\0';
385 return;
387 nexterror();
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");
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;
404 poperror();
405 if(oldlen)
406 free(oldptr);
409 void
410 ropen(void)
412 Xfile *f;
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;
425 void
426 rcreate(void)
428 error("no creates");
429 /*
430 Xfile *f;
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 */
446 void
447 rread(void)
449 Xfile *f;
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;
461 void
462 rwrite(void)
464 Xfile *f;
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);
472 void
473 rclunk(void)
475 Xfile *f;
477 if(!waserror()){
478 f = xfile(req->fid, Asis);
479 (*f->xf->s->clunk)(f);
480 poperror();
482 xfile(req->fid, Clunk);
485 void
486 rremove(void)
488 error("no removes");
491 void
492 rstat(void)
494 Xfile *f;
495 Dir dir;
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;
507 void
508 rwstat(void)
510 error("no wstat");
513 static int
514 openflags(int mode)
516 int flags = 0;
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;
527 if(mode & ORCLOSE)
528 flags |= Orclose;
529 return flags;
532 void
533 showdir(int fd, Dir *s)
535 char a_time[32], m_time[32];
536 char *p;
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);
551 #define SIZE 1024
553 void
554 chat(char *fmt, ...)
556 va_list arg;
558 if(chatty){
559 va_start(arg, fmt);
560 vfprint(2, fmt, arg);
561 va_end(arg);
565 void
566 panic(int rflag, char *fmt, ...)
568 va_list arg;
569 char buf[SIZE]; int n;
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();
580 exits("panic");