]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/exportfs/exportsrv.c
upas/fs: remove useless loop in rf822()
[plan9front.git] / sys / src / cmd / exportfs / exportsrv.c
1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <fcall.h>
5 #define Extern  extern
6 #include "exportfs.h"
7
8 extern char *netdir, *local, *remote;
9
10 char Ebadfid[] = "Bad fid";
11 char Enotdir[] = "Not a directory";
12 char Edupfid[] = "Fid already in use";
13 char Eopen[] = "Fid already opened";
14 char Exmnt[] = "Cannot .. past mount point";
15 char Emip[] = "Mount in progress";
16 char Enopsmt[] = "Out of pseudo mount points";
17 char Enomem[] = "No memory";
18 char Eversion[] = "Bad 9P2000 version";
19 char Ereadonly[] = "File system read only";
20 char Enoprocs[] = "Out of processes";
21
22 ulong messagesize;
23 int readonly;
24
25 void
26 Xversion(Fsrpc *t)
27 {
28         Fcall rhdr;
29
30         if(t->work.msize < 256){
31                 reply(&t->work, &rhdr, "version: message size too small");
32                 putsbuf(t);
33                 return;
34         }
35         if(t->work.msize > messagesize)
36                 t->work.msize = messagesize;
37         messagesize = t->work.msize;
38         if(strncmp(t->work.version, "9P2000", 6) != 0){
39                 reply(&t->work, &rhdr, Eversion);
40                 putsbuf(t);
41                 return;
42         }
43         rhdr.version = "9P2000";
44         rhdr.msize = t->work.msize;
45         reply(&t->work, &rhdr, 0);
46         putsbuf(t);
47 }
48
49 void
50 Xauth(Fsrpc *t)
51 {
52         Fcall rhdr;
53
54         reply(&t->work, &rhdr, "exportfs: authentication not required");
55         putsbuf(t);
56 }
57
58 void
59 Xflush(Fsrpc *t)
60 {
61         Fcall rhdr;
62         Fsrpc *w;
63         Proc *m;
64
65         for(m = Proclist; m != nil; m = m->next){
66                 w = m->busy;
67                 if(w == nil || w->work.tag != t->work.oldtag)
68                         continue;
69
70                 lock(m);
71                 w = m->busy;
72                 if(w != nil && w->work.tag == t->work.oldtag) {
73                         w->flushtag = t->work.tag;
74                         DEBUG(DFD, "\tset flushtag %d\n", t->work.tag);
75                         postnote(PNPROC, m->pid, "flush");
76                         unlock(m);
77                         putsbuf(t);
78                         return;
79                 }
80                 unlock(m);
81         }
82
83         reply(&t->work, &rhdr, 0);
84         DEBUG(DFD, "\tflush reply\n");
85         putsbuf(t);
86 }
87
88 void
89 Xattach(Fsrpc *t)
90 {
91         int i, nfd;
92         Fcall rhdr;
93         Fid *f;
94         char buf[128];
95
96         f = newfid(t->work.fid);
97         if(f == nil) {
98                 reply(&t->work, &rhdr, Ebadfid);
99                 putsbuf(t);
100                 return;
101         }
102
103         if(srvfd >= 0){
104                 if(psmpt == nil){
105                 Nomount:
106                         reply(&t->work, &rhdr, Enopsmt);
107                         freefid(t->work.fid);
108                         putsbuf(t);
109                         return;
110                 }
111                 for(i=0; i<Npsmpt; i++)
112                         if(psmap[i] == 0)
113                                 break;
114                 if(i >= Npsmpt)
115                         goto Nomount;
116                 sprint(buf, "%d", i);
117                 f->f = file(psmpt, buf);
118                 if(f->f == nil)
119                         goto Nomount;
120                 sprint(buf, "/mnt/exportfs/%d", i);
121                 nfd = dup(srvfd, -1);
122                 if(amount(nfd, buf, MREPL|MCREATE, t->work.aname) < 0){
123                         errstr(buf, sizeof buf);
124                         reply(&t->work, &rhdr, buf);
125                         freefid(t->work.fid);
126                         putsbuf(t);
127                         close(nfd);
128                         return;
129                 }
130                 psmap[i] = 1;
131                 f->mid = i;
132         }else{
133                 f->f = root;
134                 f->f->ref++;
135         }
136
137         rhdr.qid = f->f->qid;
138         reply(&t->work, &rhdr, 0);
139         putsbuf(t);
140 }
141
142 Fid*
143 clonefid(Fid *f, int new)
144 {
145         Fid *n;
146
147         n = newfid(new);
148         if(n == nil) {
149                 n = getfid(new);
150                 if(n == nil)
151                         fatal("inconsistent fids");
152                 if(n->fid >= 0)
153                         close(n->fid);
154                 freefid(new);
155                 n = newfid(new);
156                 if(n == nil)
157                         fatal("inconsistent fids2");
158         }
159         n->f = f->f;
160         n->f->ref++;
161         return n;
162 }
163
164 void
165 Xwalk(Fsrpc *t)
166 {
167         char err[ERRMAX], *e;
168         Fcall rhdr;
169         Fid *f, *nf;
170         File *wf;
171         int i;
172
173         f = getfid(t->work.fid);
174         if(f == nil) {
175                 reply(&t->work, &rhdr, Ebadfid);
176                 putsbuf(t);
177                 return;
178         }
179
180         nf = nil;
181         if(t->work.newfid != t->work.fid){
182                 nf = clonefid(f, t->work.newfid);
183                 f = nf;
184         }
185
186         rhdr.nwqid = 0;
187         e = nil;
188         for(i=0; i<t->work.nwname; i++){
189                 if(i == MAXWELEM){
190                         e = "Too many path elements";
191                         break;
192                 }
193
194                 if(strcmp(t->work.wname[i], "..") == 0) {
195                         if(f->f->parent == nil) {
196                                 e = Exmnt;
197                                 break;
198                         }
199                         wf = f->f->parent;
200                         wf->ref++;
201                         goto Accept;
202                 }
203         
204                 wf = file(f->f, t->work.wname[i]);
205                 if(wf == nil){
206                         errstr(err, sizeof err);
207                         e = err;
208                         break;
209                 }
210     Accept:
211                 freefile(f->f);
212                 rhdr.wqid[rhdr.nwqid++] = wf->qid;
213                 f->f = wf;
214                 continue;
215         }
216
217         if(nf!=nil && (e!=nil || rhdr.nwqid!=t->work.nwname))
218                 freefid(t->work.newfid);
219         if(rhdr.nwqid > 0)
220                 e = nil;
221         reply(&t->work, &rhdr, e);
222         putsbuf(t);
223 }
224
225 void
226 Xclunk(Fsrpc *t)
227 {
228         Fcall rhdr;
229         Fid *f;
230
231         f = getfid(t->work.fid);
232         if(f == nil) {
233                 reply(&t->work, &rhdr, Ebadfid);
234                 putsbuf(t);
235                 return;
236         }
237
238         if(f->fid >= 0)
239                 close(f->fid);
240
241         freefid(t->work.fid);
242         reply(&t->work, &rhdr, 0);
243         putsbuf(t);
244 }
245
246 void
247 Xstat(Fsrpc *t)
248 {
249         char err[ERRMAX], *path;
250         Fcall rhdr;
251         Fid *f;
252         Dir *d;
253         int s;
254         uchar *statbuf;
255
256         f = getfid(t->work.fid);
257         if(f == nil) {
258                 reply(&t->work, &rhdr, Ebadfid);
259                 putsbuf(t);
260                 return;
261         }
262         if(f->fid >= 0)
263                 d = dirfstat(f->fid);
264         else {
265                 path = makepath(f->f, "");
266                 d = dirstat(path);
267                 free(path);
268         }
269
270         if(d == nil) {
271                 errstr(err, sizeof err);
272                 reply(&t->work, &rhdr, err);
273                 putsbuf(t);
274                 return;
275         }
276
277         d->qid.path = f->f->qidt->uniqpath;
278         s = sizeD2M(d);
279         statbuf = emallocz(s);
280         s = convD2M(d, statbuf, s);
281         free(d);
282         rhdr.nstat = s;
283         rhdr.stat = statbuf;
284         reply(&t->work, &rhdr, 0);
285         free(statbuf);
286         putsbuf(t);
287 }
288
289 static int
290 getiounit(int fd)
291 {
292         int n;
293
294         n = iounit(fd);
295         if(n > messagesize-IOHDRSZ)
296                 n = messagesize-IOHDRSZ;
297         return n;
298 }
299
300 void
301 Xcreate(Fsrpc *t)
302 {
303         char err[ERRMAX], *path;
304         Fcall rhdr;
305         Fid *f;
306         File *nf;
307
308         if(readonly) {
309                 reply(&t->work, &rhdr, Ereadonly);
310                 putsbuf(t);
311                 return;
312         }
313         f = getfid(t->work.fid);
314         if(f == nil) {
315                 reply(&t->work, &rhdr, Ebadfid);
316                 putsbuf(t);
317                 return;
318         }
319         
320
321         path = makepath(f->f, t->work.name);
322         f->fid = create(path, t->work.mode, t->work.perm);
323         free(path);
324         if(f->fid < 0) {
325                 errstr(err, sizeof err);
326                 reply(&t->work, &rhdr, err);
327                 putsbuf(t);
328                 return;
329         }
330
331         nf = file(f->f, t->work.name);
332         if(nf == nil) {
333                 errstr(err, sizeof err);
334                 reply(&t->work, &rhdr, err);
335                 putsbuf(t);
336                 return;
337         }
338
339         f->mode = t->work.mode;
340         freefile(f->f);
341         f->f = nf;
342         rhdr.qid = f->f->qid;
343         rhdr.iounit = getiounit(f->fid);
344         reply(&t->work, &rhdr, 0);
345         putsbuf(t);
346 }
347
348 void
349 Xremove(Fsrpc *t)
350 {
351         char err[ERRMAX], *path;
352         Fcall rhdr;
353         Fid *f;
354
355         if(readonly) {
356                 reply(&t->work, &rhdr, Ereadonly);
357                 putsbuf(t);
358                 return;
359         }
360         f = getfid(t->work.fid);
361         if(f == nil) {
362                 reply(&t->work, &rhdr, Ebadfid);
363                 putsbuf(t);
364                 return;
365         }
366
367         path = makepath(f->f, "");
368         DEBUG(DFD, "\tremove: %s\n", path);
369         if(remove(path) < 0) {
370                 free(path);
371                 errstr(err, sizeof err);
372                 reply(&t->work, &rhdr, err);
373                 putsbuf(t);
374                 return;
375         }
376         free(path);
377
378         f->f->inval = 1;
379         if(f->fid >= 0)
380                 close(f->fid);
381         freefid(t->work.fid);
382
383         reply(&t->work, &rhdr, 0);
384         putsbuf(t);
385 }
386
387 void
388 Xwstat(Fsrpc *t)
389 {
390         char err[ERRMAX], *path;
391         Fcall rhdr;
392         Fid *f;
393         int s;
394         char *strings;
395         Dir d;
396
397         if(readonly) {
398                 reply(&t->work, &rhdr, Ereadonly);
399                 putsbuf(t);
400                 return;
401         }
402         f = getfid(t->work.fid);
403         if(f == nil) {
404                 reply(&t->work, &rhdr, Ebadfid);
405                 putsbuf(t);
406                 return;
407         }
408         strings = emallocz(t->work.nstat);      /* ample */
409         if(convM2D(t->work.stat, t->work.nstat, &d, strings) <= BIT16SZ){
410                 rerrstr(err, sizeof err);
411                 reply(&t->work, &rhdr, err);
412                 putsbuf(t);
413                 free(strings);
414                 return;
415         }
416
417         if(f->fid >= 0)
418                 s = dirfwstat(f->fid, &d);
419         else {
420                 path = makepath(f->f, "");
421                 s = dirwstat(path, &d);
422                 free(path);
423         }
424         if(s < 0) {
425                 rerrstr(err, sizeof err);
426                 reply(&t->work, &rhdr, err);
427         }
428         else {
429                 /* wstat may really be rename */
430                 if(strcmp(d.name, f->f->name)!=0 && strcmp(d.name, "")!=0){
431                         free(f->f->name);
432                         f->f->name = estrdup(d.name);
433                 }
434                 reply(&t->work, &rhdr, 0);
435         }
436         free(strings);
437         putsbuf(t);
438 }
439
440 void
441 slave(Fsrpc *f)
442 {
443         static int nproc;
444         Proc *m, **l;
445         Fcall rhdr;
446         int pid;
447
448         if(readonly){
449                 switch(f->work.type){
450                 case Twrite:
451                         reply(&f->work, &rhdr, Ereadonly);
452                         putsbuf(f);
453                         return;
454                 case Topen:
455                         if((f->work.mode&3) == OWRITE || (f->work.mode&(OTRUNC|ORCLOSE))){
456                                 reply(&f->work, &rhdr, Ereadonly);
457                                 putsbuf(f);
458                                 return;
459                         }
460                 }
461         }
462         for(;;) {
463                 for(l = &Proclist; (m = *l) != nil; l = &m->next) {
464                         if(m->busy != nil)
465                                 continue;
466
467                         m->busy = f;
468                         while(rendezvous(m, f) == (void*)~0)
469                                 ;
470
471                         /* swept a slave proc */
472                         if(f == nil){
473                                 *l = m->next;
474                                 free(m);
475                                 nproc--;
476                                 break;
477                         }
478                         f = nil;
479
480                         /*
481                          * as long as the number of slave procs
482                          * is small, dont bother sweeping.
483                          */
484                         if(nproc < 16)
485                                 break;
486                 }
487                 if(f == nil)
488                         return;
489
490                 m = emallocz(sizeof(Proc));
491                 pid = rfork(RFPROC|RFMEM|RFNOWAIT);
492                 switch(pid) {
493                 case -1:
494                         reply(&f->work, &rhdr, Enoprocs);
495                         putsbuf(f);
496                         free(m);
497                         return;
498
499                 case 0:
500                         if (local[0] != '\0')
501                                 if (netdir[0] != '\0')
502                                         procsetname("%s: %s -> %s", netdir, 
503                                                 local, remote);
504                                 else
505                                         procsetname("%s -> %s", local, remote);
506                         blockingslave(m);
507                         _exits(0);
508
509                 default:
510                         m->pid = pid;
511                         m->next = Proclist;
512                         Proclist = m;
513                         nproc++;
514                 }
515         }
516 }
517
518 void
519 blockingslave(Proc *m)
520 {
521         Fsrpc *p;
522         Fcall rhdr;
523
524         notify(flushaction);
525
526         for(;;) {
527                 p = rendezvous(m, nil);
528                 if(p == (void*)~0)      /* Interrupted */
529                         continue;
530                 if(p == nil)            /* Swept */
531                         break;
532
533                 DEBUG(DFD, "\tslave: %d %F\n", m->pid, &p->work);
534                 if(p->flushtag != NOTAG)
535                         goto flushme;
536
537                 switch(p->work.type) {
538                 case Tread:
539                         slaveread(p);
540                         break;
541
542                 case Twrite:
543                         slavewrite(p);
544                         break;
545
546                 case Topen:
547                         slaveopen(p);
548                         break;
549
550                 default:
551                         reply(&p->work, &rhdr, "exportfs: slave type error");
552                 }
553 flushme:
554                 lock(m);
555                 m->busy = nil;
556                 unlock(m);
557
558                 /* no more flushes can come in now */
559                 if(p->flushtag != NOTAG) {
560                         p->work.type = Tflush;
561                         p->work.tag = p->flushtag;
562                         reply(&p->work, &rhdr, 0);
563                 }
564                 putsbuf(p);
565         }
566 }
567
568 int
569 openmount(int sfd)
570 {
571         int p[2], fd, i, n;
572         char *arg[10], fdbuf[20], mbuf[20];
573         Dir *dir;
574
575         if(pipe(p) < 0)
576                 return -1;
577
578         switch(rfork(RFPROC|RFMEM|RFNOWAIT|RFNAMEG|RFFDG|RFREND)){
579         case -1:
580                 close(p[0]);
581                 close(p[1]);
582                 return -1;
583
584         default:
585                 close(sfd);
586                 close(p[0]);
587                 return p[1];
588
589         case 0:
590                 break;
591         }
592
593         dup(p[0], 0);
594         dup(p[0], 1);
595
596         /* close all remaining file descriptors except sfd */
597         if((fd = open("/fd", OREAD)) < 0)
598                 _exits("open /fd failed");
599         n = dirreadall(fd, &dir);
600         for(i=0; i<n; i++){
601                 if(strstr(dir[i].name, "ctl"))
602                         continue;
603                 fd = atoi(dir[i].name);
604                 if(fd > 2 && fd != sfd)
605                         close(fd);
606         }
607         free(dir);
608
609         arg[0] = argv0; /* "/bin/exportfs" */
610         snprint(fdbuf, sizeof fdbuf, "-S/fd/%d", sfd);
611         arg[1] = fdbuf;
612         snprint(mbuf, sizeof mbuf, "-m%lud", messagesize-IOHDRSZ);
613         arg[2] = mbuf;
614         arg[3] = nil;
615
616         exec(arg[0], arg);
617         arg[0] = "/bin/exportfs";
618         exec(arg[0], arg);
619         _exits("whoops: exec failed");  
620         return -1;
621 }
622
623 void
624 slaveopen(Fsrpc *p)
625 {
626         char err[ERRMAX], *path;
627         Fcall *work, rhdr;
628         Fid *f;
629         Dir *d;
630
631         work = &p->work;
632
633         f = getfid(work->fid);
634         if(f == nil) {
635                 reply(work, &rhdr, Ebadfid);
636                 return;
637         }
638         if(f->fid >= 0) {
639                 close(f->fid);
640                 f->fid = -1;
641         }
642         
643         path = makepath(f->f, "");
644         DEBUG(DFD, "\topen: %s %d\n", path, work->mode);
645         f->fid = open(path, work->mode);
646         free(path);
647         if(f->fid < 0 || (d = dirfstat(f->fid)) == nil) {
648         Error:
649                 errstr(err, sizeof err);
650                 reply(work, &rhdr, err);
651                 return;
652         }
653         f->f->qid = d->qid;
654         free(d);
655         if(f->f->qid.type & QTMOUNT){   /* fork new exportfs for this */
656                 f->fid = openmount(f->fid);
657                 if(f->fid < 0)
658                         goto Error;
659         }
660
661         DEBUG(DFD, "\topen: fd %d\n", f->fid);
662         f->mode = work->mode;
663         f->offset = 0;
664         rhdr.iounit = getiounit(f->fid);
665         rhdr.qid = f->f->qid;
666         reply(work, &rhdr, 0);
667 }
668
669 void
670 slaveread(Fsrpc *p)
671 {
672         Fid *f;
673         int n, r;
674         Fcall *work, rhdr;
675         char *data, err[ERRMAX];
676
677         work = &p->work;
678
679         f = getfid(work->fid);
680         if(f == nil) {
681                 reply(work, &rhdr, Ebadfid);
682                 return;
683         }
684
685         n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count;
686         data = malloc(n);
687         if(data == nil) {
688                 reply(work, &rhdr, Enomem);
689                 return;
690         }
691
692         /* can't just call pread, since directories must update the offset */
693         if(patternfile != nil && (f->f->qid.type&QTDIR))
694                 r = preaddir(f, (uchar*)data, n, work->offset);
695         else
696                 r = pread(f->fid, data, n, work->offset);
697         if(r < 0) {
698                 free(data);
699                 errstr(err, sizeof err);
700                 reply(work, &rhdr, err);
701                 return;
702         }
703         DEBUG(DFD, "\tread: fd=%d %d bytes\n", f->fid, r);
704
705         rhdr.data = data;
706         rhdr.count = r;
707         reply(work, &rhdr, 0);
708         free(data);
709 }
710
711 void
712 slavewrite(Fsrpc *p)
713 {
714         char err[ERRMAX];
715         Fcall *work, rhdr;
716         Fid *f;
717         int n;
718
719         work = &p->work;
720
721         f = getfid(work->fid);
722         if(f == nil) {
723                 reply(work, &rhdr, Ebadfid);
724                 return;
725         }
726
727         n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count;
728         n = pwrite(f->fid, work->data, n, work->offset);
729         if(n < 0) {
730                 errstr(err, sizeof err);
731                 reply(work, &rhdr, err);
732                 return;
733         }
734
735         DEBUG(DFD, "\twrite: %d bytes fd=%d\n", n, f->fid);
736
737         rhdr.count = n;
738         reply(work, &rhdr, 0);
739 }
740
741 void
742 reopen(Fid *f)
743 {
744         USED(f);
745         fatal("reopen");
746 }
747
748 void
749 flushaction(void *a, char *cause)
750 {
751         USED(a);
752         if(strncmp(cause, "sys:", 4) == 0 && !strstr(cause, "pipe")) {
753                 fprint(2, "exportsrv: note: %s\n", cause);
754                 exits("noted");
755         }
756         if(strncmp(cause, "kill", 4) == 0)
757                 noted(NDFLT);
758
759         noted(NCONT);
760 }