Akaros side of the VFS/9ns connection
[akaros.git] / kern / src / ns / sysfile.c
1 // INFERNO
2 #include <vfs.h>
3 #include <kfs.h>
4 #include <slab.h>
5 #include <kmalloc.h>
6 #include <kref.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <assert.h>
10 #include <error.h>
11 #include <cpio.h>
12 #include <pmap.h>
13 #include <smp.h>
14 #include <ip.h>
15
16 static int
17 growfd(struct fgrp *f, int fd)
18 {
19         int n;
20         struct chan **nfd, **ofd;
21
22         if(fd < f->nfd)
23                 return 0;
24         n = f->nfd+DELTAFD;
25         if(n > MAXNFD)
26                 n = MAXNFD;
27         if(fd >= n)
28                 return -1;
29         nfd = kzmalloc(n * sizeof(struct chan *), 0);
30         if(nfd == NULL)
31                 return -1;
32         ofd = f->fd;
33         memmove(nfd, ofd, f->nfd*sizeof(struct chan *));
34         f->fd = nfd;
35         f->nfd = n;
36         kfree(ofd);
37         return 0;
38 }
39
40 int
41 newfd(struct chan *c)
42 {
43         int i;
44         struct fgrp *f = current->fgrp;
45
46         spin_lock(&f->lock);
47         for(i=f->minfd; i<f->nfd; i++)
48                 if(f->fd[i] == 0)
49                         break;
50         if(i >= f->nfd && growfd(f, i) < 0){
51                 spin_unlock(&f->lock);
52                 exhausted("file descriptors");
53                 return -1;
54         }
55         f->minfd = i + 1;
56         if(i > f->maxfd)
57                 f->maxfd = i;
58         f->fd[i] = c;
59         spin_unlock(&f->lock);
60         return i;
61 }
62
63 struct chan*
64 fdtochan(struct fgrp *f, int fd, int mode, int chkmnt, int iref)
65 {
66         struct chan *c;
67
68         c = 0;
69
70         spin_lock(&f->lock);
71         if(fd<0 || f->maxfd<fd || (c = f->fd[fd])==0) {
72                 spin_unlock(&f->lock);
73                 error(Ebadfd);
74         }
75         if(iref)
76                 kref_get(&c->ref, 1);
77         spin_unlock(&f->lock);
78
79         if(chkmnt && (c->flag&CMSG)) {
80                 if(iref)
81                         cclose(c);
82                 error(Ebadusefd);
83         }
84
85         if(mode<0 || c->mode==ORDWR)
86                 return c;
87
88         if((mode&OTRUNC) && c->mode==OREAD) {
89                 if(iref)
90                         cclose(c);
91                 error(Ebadusefd);
92         }
93
94         if((mode&~OTRUNC) != c->mode) {
95                 if(iref)
96                         cclose(c);
97                 error(Ebadusefd);
98         }
99
100         return c;
101 }
102
103 long
104 kchanio(void *vc, void *buf, int n, int mode)
105 {
106         ERRSTACK(2);
107         int r;
108         struct chan *c;
109
110         c = vc;
111         if(waserror())
112                 return -1;
113
114         if(mode == OREAD)
115                 r = devtab[c->type]->read(c, buf, n, c->offset);
116         else
117                 r = devtab[c->type]->write(c, buf, n, c->offset);
118
119         spin_lock(&c->lock);
120         c->offset += r;
121         spin_unlock(&c->lock);
122         poperror();
123         return r;
124 }
125
126 int
127 openmode(uint32_t o)
128 {
129         if(o >= (OTRUNC|OCEXEC|ORCLOSE|OEXEC))
130                 error(Ebadarg);
131         o &= ~(OTRUNC|OCEXEC|ORCLOSE);
132         if(o > OEXEC)
133                 error(Ebadarg);
134         if(o == OEXEC)
135                 return OREAD;
136         return o;
137 }
138
139 void
140 fdclose(struct fgrp *f, int fd)
141 {
142         int i;
143         struct chan *c;
144
145         spin_lock(&f->lock);
146         c = f->fd[fd];
147         if(c == 0){
148                 /* can happen for users with shared fd tables */
149                 spin_unlock(&f->lock);
150                 return;
151         }
152         f->fd[fd] = 0;
153         if(fd == f->maxfd)
154                 for(i=fd; --i>=0 && f->fd[i]==0; )
155                         f->maxfd = i;
156         if(fd < f->minfd)
157                 f->minfd = fd;
158         spin_unlock(&f->lock);
159         cclose(c);
160 }
161
162 int
163 syschdir(char *path)
164 {
165         ERRSTACK(2);
166         struct chan *c;
167         struct pgrp *pg;
168
169         if(waserror())
170                 return -1;
171
172         c = namec(path, Atodir, 0, 0);
173         pg = current->pgrp;
174         cclose(pg->dot);
175         pg->dot = c;
176         poperror();
177         return 0;
178 }
179
180 int
181 fgrpclose(struct fgrp *f, int fd)
182 {
183         ERRSTACK(2);
184         if(waserror())
185                 return -1;
186
187         /*
188          * Take no reference on the chan because we don't really need the
189          * data structure, and are calling fdtochan only for error checks.
190          * fdclose takes care of processes racing through here.
191          */
192         fdtochan(f, fd, -1, 0, 0);
193         fdclose(f, fd);
194         poperror();
195         return 0;
196 }
197
198 int
199 sysclose(int fd)
200 {
201         return fgrpclose(current->fgrp, fd);
202 }
203
204 int
205 syscreate(char *path, int mode, uint32_t perm)
206 {
207         ERRSTACK(2);
208         int fd;
209         struct chan *c;
210
211         if(waserror())
212                 return -1;
213
214         openmode(mode&~OEXCL);  /* error check only; OEXCL okay here */
215         c = namec(path, Acreate, mode, perm);
216         if(waserror()) {
217                 cclose(c);
218                 nexterror();
219         }
220         fd = newfd(c);
221         if(fd < 0)
222                 error(Enofd);
223         poperror();
224
225         poperror();
226         return fd;
227 }
228
229 int
230 sysdup(int old, int new)
231 {
232         ERRSTACK(2);
233         int fd;
234         struct chan *c, *oc;
235         struct fgrp *f = current->fgrp;
236
237         if(waserror())
238                 return -1;
239
240         c = fdtochan(current->fgrp, old, -1, 0, 1);
241         if(c->qid.type & QTAUTH)
242                 error(Eperm);
243         fd = new;
244         if(fd != -1){
245                 spin_lock(&f->lock);
246                 if(fd<0 || growfd(f, fd) < 0) {
247                         spin_unlock(&f->lock);
248                         cclose(c);
249                         error(Ebadfd);
250                 }
251                 if(fd > f->maxfd)
252                         f->maxfd = fd;
253                 oc = f->fd[fd];
254                 f->fd[fd] = c;
255                 spin_unlock(&f->lock);
256                 if(oc)
257                         cclose(oc);
258         }else{
259                 if(waserror()) {
260                         cclose(c);
261                         nexterror();
262                 }
263                 fd = newfd(c);
264                 if(fd < 0)
265                         error(Enofd);
266                 poperror();
267         }
268         poperror();
269         return fd;
270 }
271
272 int
273 sysfstat(int fd, uint8_t *buf, int n)
274 {
275         ERRSTACK(2);
276         struct chan *c;
277
278         if(waserror())
279                 return -1;
280
281         c = fdtochan(current->fgrp, fd, -1, 0, 1);
282         if(waserror()) {
283                 cclose(c);
284                 nexterror();
285         }
286         devtab[c->type]->stat(c, buf, n);
287
288         poperror();
289         cclose(c);
290
291         poperror();
292         return n;
293 }
294
295 char*
296 sysfd2path(int fd)
297 {
298         ERRSTACK(2);
299         struct chan *c;
300         char *s;
301
302         if(waserror())
303                 return NULL;
304         c = fdtochan(current->fgrp, fd, -1, 0, 1);
305         s = NULL;
306         if(c->name != NULL){
307                 s = kzmalloc(c->name->len + 1, 0);
308                 if(s == NULL){
309                         cclose(c);
310                         error(Enomem);
311                 }
312                 memmove(s, c->name->s, c->name->len+1);
313                 cclose(c);
314         }
315         poperror();
316         return s;
317 }
318
319 int
320 sysfauth(int fd, char *aname)
321 {
322         ERRSTACK(2);
323         struct chan *c, *ac;
324
325         if(waserror())
326                 return -1;
327
328         validname(aname, 0);
329         c = fdtochan(current->fgrp, fd, ORDWR, 0, 1);
330         if(waserror()){
331                 cclose(c);
332                 nexterror();
333         }
334
335         ac = mntauth(c, aname);
336
337         /* at this point ac is responsible for keeping c alive */
338         poperror();     /* c */
339         cclose(c);
340
341         if(waserror()){
342                 cclose(ac);
343                 nexterror();
344         }
345
346         fd = newfd(ac);
347         if(fd < 0)
348                 error(Enofd);
349         poperror();     /* ac */
350
351         poperror();
352
353         return fd;
354 }
355
356 int
357 sysfversion(int fd, unsigned int msize, char *vers, unsigned int arglen)
358 {
359         ERRSTACK(2);
360         int m;
361         struct chan *c;
362
363         if(waserror())
364                 return -1;
365
366         /* check there's a NUL in the version string */
367         if(arglen==0 || memchr(vers, 0, arglen)==0)
368                 error(Ebadarg);
369
370         c = fdtochan(current->fgrp, fd, ORDWR, 0, 1);
371         if(waserror()){
372                 cclose(c);
373                 nexterror();
374         }
375
376         m = mntversion(c, vers, msize, arglen);
377
378         poperror();
379         cclose(c);
380
381         poperror();
382         return m;
383 }
384
385 int
386 syspipe(int fd[2])
387 {
388         ERRSTACK(2);
389         struct dev *d;
390         struct fgrp *f;
391         struct chan *c[2];
392         static char *names[] = {"data", "data1"};
393
394         f = current->fgrp;
395
396         d = devtab[devno('|', 0)];
397         c[0] = namec("#|", Atodir, 0, 0);
398         c[1] = 0;
399         fd[0] = -1;
400         fd[1] = -1;
401         if(waserror()) {
402                 if(c[0] != 0)
403                         cclose(c[0]);
404                 if(c[1] != 0)
405                         cclose(c[1]);
406                 if(fd[0] >= 0)
407                         f->fd[fd[0]]=0;
408                 if(fd[1] >= 0)
409                         f->fd[fd[1]]=0;
410                 return -1;
411         }
412         c[1] = cclone(c[0]);
413         if(walk(&c[0], &names[0], 1, 1, NULL) < 0)
414                 error(Egreg);
415         if(walk(&c[1], &names[1], 1, 1, NULL) < 0)
416                 error(Egreg);
417         c[0] = d->open(c[0], ORDWR);
418         c[1] = d->open(c[1], ORDWR);
419         fd[0] = newfd(c[0]);
420         if(fd[0] < 0)
421                 error(Enofd);
422         fd[1] = newfd(c[1]);
423         if(fd[1] < 0)
424                 error(Enofd);
425         poperror();
426         return 0;
427 }
428
429 int
430 sysfwstat(int fd, uint8_t *buf, int n)
431 {
432         ERRSTACK(2);
433         struct chan *c;
434
435         if(waserror())
436                 return -1;
437
438         validstat(buf, n);
439         c = fdtochan(current->fgrp, fd, -1, 1, 1);
440         if(waserror()) {
441                 cclose(c);
442                 nexterror();
443         }
444         n = devtab[c->type]->wstat(c, buf, n);
445         poperror();
446         cclose(c);
447
448         poperror();
449         return n;
450 }
451
452 long
453 bindmount(struct chan *c, char *old, int flag, char *spec)
454 {
455         ERRSTACK(2);
456         int ret;
457         struct chan *c1;
458
459         if(flag>MMASK || (flag&MORDER) == (MBEFORE|MAFTER))
460                 error(Ebadarg);
461
462         c1 = namec(old, Amount, 0, 0);
463         if(waserror()){
464                 cclose(c1);
465                 nexterror();
466         }
467         ret = cmount(c, c1, flag, spec);
468
469         poperror();
470         cclose(c1);
471         return ret;
472 }
473
474 int
475 sysbind(char *new, char *old, int flags)
476 {
477         ERRSTACK(2);
478         long r;
479         struct chan *c0;
480
481         if(waserror())
482                 return -1;
483
484         c0 = namec(new, Abind, 0, 0);
485         if(waserror()) {
486                 cclose(c0);
487                 nexterror();
488         }
489         r = bindmount(c0, old, flags, "");
490         poperror();
491         cclose(c0);
492
493         poperror();
494         return r;
495 }
496
497 int
498 sysmount(int fd, int afd, char *old, int flags, char *spec)
499 {
500         ERRSTACK(2);
501         long r;
502         volatile struct { struct chan *c; } c0;
503         volatile struct { struct chan *c; } bc;
504         volatile struct { struct chan *c; } ac;
505         struct mntparam mntparam;
506
507         ac.c = NULL;
508         bc.c = NULL;
509         c0.c = NULL;
510         if(waserror()) {
511                 cclose(ac.c);
512                 cclose(bc.c);
513                 cclose(c0.c);
514                 return -1;
515         }
516         bc.c = fdtochan(current->fgrp, fd, ORDWR, 0, 1);
517         if(afd >= 0)
518                 ac.c = fdtochan(current->fgrp, afd, ORDWR, 0, 1);
519         mntparam.chan = bc.c;
520         mntparam.authchan = ac.c;
521         mntparam.spec = spec;
522         mntparam.flags = flags;
523         c0.c = devtab[devno('M', 0)]->attach(( char *)&mntparam);
524
525         r = bindmount(c0.c, old, flags, spec);
526         poperror();
527         cclose(ac.c);
528         cclose(bc.c);
529         cclose(c0.c);
530
531         return r;
532 }
533
534 int
535 sysunmount(char *old, char *new)
536 {
537         ERRSTACK(2);
538         volatile struct { struct chan *c; } cmount;
539         volatile struct { struct chan *c; } cmounted;
540
541         cmount.c = NULL;
542         cmounted.c = NULL;
543         if(waserror()) {
544                 cclose(cmount.c);
545                 cclose(cmounted.c);
546                 return -1;
547         }
548
549         cmount.c = namec(new, Amount, 0, 0);
550         if(old != NULL && old[0] != '\0') {
551                 /*
552                  * This has to be namec(..., Aopen, ...) because
553                  * if arg[0] is something like /srv/cs or /fd/0,
554                  * opening it is the only way to get at the real
555                  * Chan underneath.
556                  */
557                 cmounted.c = namec(old, Aopen, OREAD, 0);
558         }
559
560         cunmount(cmount.c, cmounted.c);
561         poperror();
562         cclose(cmount.c);
563         cclose(cmounted.c);
564         return 0;
565 }
566
567 int
568 sysopen(char *path, int mode)
569 {
570         ERRSTACK(2);
571         int fd;
572         struct chan *c;
573
574         if(waserror())
575                 return -1;
576
577         openmode(mode);                         /* error check only */
578         c = namec(path, Aopen, mode, 0);
579         if(waserror()){
580                 cclose(c);
581                 nexterror();
582         }
583         fd = newfd(c);
584         if(fd < 0)
585                 error(Enofd);
586         poperror();
587
588         poperror();
589         return fd;
590 }
591
592 long
593 unionread(struct chan *c, void *va, long n)
594 {
595         ERRSTACK(2);
596         int i;
597         long nr;
598         struct mhead *m;
599         struct mount *mount;
600
601         qlock(&c->umqlock);
602         m = c->umh;
603         rlock(&m->lock);
604         mount = m->mount;
605         /* bring mount in sync with c->uri and c->umc */
606         for(i = 0; mount != NULL && i < c->uri; i++)
607                 mount = mount->next;
608
609         nr = 0;
610         while(mount != NULL) {
611                 /* Error causes component of union to be skipped */
612                 if(mount->to && !waserror()) {
613                         if(c->umc == NULL){
614                                 c->umc = cclone(mount->to);
615                                 c->umc = devtab[c->umc->type]->open(c->umc, OREAD);
616                         }
617         
618                         nr = devtab[c->umc->type]->read(c->umc, va, n, c->umc->offset);
619                         if(nr < 0)
620                                 nr = 0; /* dev.c can return -1 */
621                         c->umc->offset += nr;
622                         poperror();
623                 }
624                 if(nr > 0)
625                         break;
626
627                 /* Advance to next element */
628                 c->uri++;
629                 if(c->umc) {
630                         cclose(c->umc);
631                         c->umc = NULL;
632                 }
633                 mount = mount->next;
634         }
635         runlock(&m->lock);
636         qunlock(&c->umqlock);
637         return nr;
638 }
639
640 static void
641 unionrewind(struct chan *c)
642 {
643         qlock(&c->umqlock);
644         c->uri = 0;
645         if(c->umc){
646                 cclose(c->umc);
647                 c->umc = NULL;
648         }
649         qunlock(&c->umqlock);
650 }
651
652 static long
653 rread(int fd, void *va, long n, int64_t *offp)
654 {
655         ERRSTACK(2);
656         int dir;
657         struct chan *c;
658         int64_t off;
659
660         if(waserror())
661                 return -1;
662
663         c = fdtochan(current->fgrp, fd, OREAD, 1, 1);
664         if(waserror()) {
665                 cclose(c);
666                 nexterror();
667         }
668
669         if(n < 0)
670                 error(Etoosmall);
671
672         dir = c->qid.type & QTDIR;
673         if(dir && c->umh)
674                 n = unionread(c, va, n);
675         else{
676                 if(offp == NULL){
677                         spin_lock(&c->lock);    /* lock for int64_t assignment */
678                         off = c->offset;
679                         spin_unlock(&c->lock);
680                 }else
681                         off = *offp;
682                 if(off < 0)
683                         error(Enegoff);
684                 if(off == 0){
685                         if(offp == NULL){
686                                 spin_lock(&c->lock);
687                                 c->offset = 0;
688                                 c->dri = 0;
689                                 spin_unlock(&c->lock);
690                         }
691                         unionrewind(c);
692                 }
693                 n = devtab[c->type]->read(c, va, n, off);
694                 spin_lock(&c->lock);
695                 c->offset += n;
696                 spin_unlock(&c->lock);
697         }
698
699         poperror();
700         cclose(c);
701
702         poperror();
703         return n;
704 }
705
706 long
707 sysread(int fd, void *va, long n)
708 {
709         return rread(fd, va, n, NULL);
710 }
711
712 long
713 syspread(int fd, void *va, long n, int64_t off)
714 {
715         return rread(fd, va, n, &off);
716 }
717
718 int
719 sysremove(char *path)
720 {
721         ERRSTACK(2);
722         struct chan *c;
723
724         if(waserror())
725                 return -1;
726
727         c = namec(path, Aremove, 0, 0);
728         if(waserror()) {
729                 c->type = 0;    /* see below */
730                 cclose(c);
731                 nexterror();
732         }
733         devtab[c->type]->remove(c);
734         /*
735          * Remove clunks the fid, but we need to recover the Chan
736          * so fake it up.  rootclose() is known to be a nop.
737          */
738         c->type = 0;
739         poperror();
740         cclose(c);
741
742         poperror();
743         return 0;
744 }
745
746 int64_t
747 sysseek(int fd, int64_t off, int whence)
748 {
749         ERRSTACK(2);
750         struct dir *dir;
751         struct chan *c;
752
753         if(waserror())
754                 return -1;
755
756         c = fdtochan(current->fgrp, fd, -1, 1, 1);
757         if(waserror()) {
758                 cclose(c);
759                 nexterror();
760         }
761
762         if(devtab[c->type]->dc == '|')
763                 error(Eisstream);
764
765         switch(whence) {
766         case 0:
767                 if(c->qid.type & QTDIR){
768                         if(off != 0)
769                                 error(Eisdir);
770                         unionrewind(c);
771                 }else if(off < 0)
772                         error(Enegoff);
773                 spin_lock(&c->lock);    /* lock for int64_t assignment */
774                 c->offset = off;
775                 spin_unlock(&c->lock);
776                 break;
777
778         case 1:
779                 if(c->qid.type & QTDIR)
780                         error(Eisdir);
781                 spin_lock(&c->lock);    /* lock for read/write update */
782                 off += c->offset;
783                 if(off < 0){
784                         spin_unlock(&c->lock);
785                         error(Enegoff);
786                 }
787                 c->offset = off;
788                 spin_unlock(&c->lock);
789                 break;
790
791         case 2:
792                 if(c->qid.type & QTDIR)
793                         error(Eisdir);
794                 dir = chandirstat(c);
795                 if(dir == NULL)
796                         error("internal error: stat error in seek");
797                 off += dir->length;
798                 kfree(dir);
799                 if(off < 0)
800                         error(Enegoff);
801                 spin_lock(&c->lock);    /* lock for read/write update */
802                 c->offset = off;
803                 spin_unlock(&c->lock);
804                 break;
805
806         default:
807                 error(Ebadarg);
808                 break;
809         }
810         poperror();
811         c->dri = 0;
812         cclose(c);
813         poperror();
814         return off;
815 }
816
817 void
818 validstat(uint8_t *s, int n)
819 {
820         int m;
821         char buf[64];
822
823         if(statcheck(s, n) < 0)
824                 error(Ebadstat);
825         /* verify that name entry is acceptable */
826         s += STATFIXLEN - 4*BIT16SZ;    /* location of first string */
827         /*
828          * s now points at count for first string.
829          * if it's too long, let the server decide; this is
830          * only for his protection anyway. otherwise
831          * we'd have to allocate and waserror.
832          */
833         m = GBIT16(s);
834         s += BIT16SZ;
835         if(m+1 > sizeof buf)
836                 return;
837         memmove(buf, s, m);
838         buf[m] = '\0';
839         /* name could be '/' */
840         if(strcmp(buf, "/") != 0)
841                 validname(buf, 0);
842 }
843
844 int
845 sysstat(char *path, uint8_t *buf, int n)
846 {
847         ERRSTACK(2);
848         struct chan *c;
849
850         if(waserror())
851                 return -1;
852
853         c = namec(path, Aaccess, 0, 0);
854         if(waserror()){
855                 cclose(c);
856                 nexterror();
857         }
858         devtab[c->type]->stat(c, buf, n);
859         poperror();
860         cclose(c);
861
862         poperror();
863         return 0;
864 }
865
866 static long
867 rwrite(int fd, void *va, long n, int64_t *offp)
868 {
869         ERRSTACK(2);
870         struct chan *c;
871         int64_t off;
872         long m;
873
874         if(waserror())
875                 return -1;
876         c = fdtochan(current->fgrp, fd, OWRITE, 1, 1);
877         if(waserror()) {
878                 cclose(c);
879                 nexterror();
880         }
881         if(c->qid.type & QTDIR)
882                 error(Eisdir);
883
884         if(n < 0)
885                 error(Etoosmall);
886
887         if(offp == NULL){
888                 spin_lock(&c->lock);
889                 off = c->offset;
890                 c->offset += n;
891                 spin_unlock(&c->lock);
892         }else
893                 off = *offp;
894
895         if(waserror()){
896                 if(offp == NULL){
897                         spin_lock(&c->lock);
898                         c->offset -= n;
899                         spin_unlock(&c->lock);
900                 }
901                 nexterror();
902         }
903         if(off < 0)
904                 error(Enegoff);
905         m = devtab[c->type]->write(c, va, n, off);
906         poperror();
907
908         if(offp == NULL && m < n){
909                 spin_lock(&c->lock);
910                 c->offset -= n - m;
911                 spin_unlock(&c->lock);
912         }
913
914         poperror();
915         cclose(c);
916
917         poperror();
918         return n;
919 }
920
921 long
922 syswrite(int fd, void *va, long n)
923 {
924         return rwrite(fd, va, n, NULL);
925 }
926
927 long
928 syspwrite(int fd, void *va, long n, int64_t off)
929 {
930         return rwrite(fd, va, n, &off);
931 }
932
933 int
934 syswstat(char *path, uint8_t *buf, int n)
935 {
936         ERRSTACK(2);
937         struct chan *c;
938
939         if(waserror())
940                 return -1;
941
942         validstat(buf, n);
943         c = namec(path, Aaccess, 0, 0);
944         if(waserror()){
945                 cclose(c);
946                 nexterror();
947         }
948         n = devtab[c->type]->wstat(c, buf, n);
949         poperror();
950         cclose(c);
951
952         poperror();
953         return n;
954 }
955
956 enum
957 {
958         DIRSIZE = STATFIXLEN + 32 * 4,
959         DIRREADLIM = 2048,      /* should handle the largest reasonable directory entry */
960 };
961
962 struct dir*
963 chandirstat(struct chan *c)
964 {
965         ERRSTACK(2);
966         struct dir *d;
967         uint8_t *buf;
968         int n, nd, i;
969
970         nd = DIRSIZE;
971         for(i=0; i<2; i++){     /* should work by the second try */
972                 d = kzmalloc(sizeof(struct dir) + nd, 0);
973                 buf = ( uint8_t *)&d[1];
974                 if(waserror()){
975                         kfree(d);
976                         return NULL;
977                 }
978                 n = devtab[c->type]->stat(c, buf, nd);
979                 poperror();
980                 if(n < BIT16SZ){
981                         kfree(d);
982                         return NULL;
983                 }
984                 nd = GBIT16(( uint8_t *)buf) + BIT16SZ; /* size needed to store whole stat buffer including count */
985                 if(nd <= n){
986                         convM2D(buf, n, d, ( char *)&d[1]);
987                         return d;
988                 }
989                 /* else sizeof(Dir)+nd is plenty */
990                 kfree(d);
991         }
992         return NULL;
993
994 }
995
996 struct dir*
997 sysdirstat(char *name)
998 {
999         ERRSTACK(2);
1000         struct chan *c;
1001         struct dir *d;
1002
1003         if(waserror())
1004                 return NULL;
1005
1006         c = namec(name, Aaccess, 0, 0);
1007         if(waserror()){
1008                 cclose(c);
1009                 nexterror();
1010         }
1011         d = chandirstat(c);
1012         poperror();
1013         cclose(c);
1014
1015         poperror();
1016         return d;
1017 }
1018
1019 struct dir*
1020 sysdirfstat(int fd)
1021 {
1022         ERRSTACK(2);
1023         struct chan *c;
1024         struct dir *d;
1025
1026         if(waserror())
1027                 return NULL;
1028
1029         c = fdtochan(current->fgrp, fd, -1, 0, 1);
1030         if(waserror()) {
1031                 cclose(c);
1032                 nexterror();
1033         }
1034         d = chandirstat(c);
1035         poperror();
1036         cclose(c);
1037
1038         poperror();
1039         return d;
1040 }
1041
1042 int
1043 sysdirwstat(char *name, struct dir *dir)
1044 {
1045         uint8_t *buf;
1046         int r;
1047
1048         r = sizeD2M(dir);
1049         buf = kzmalloc(r, 0);
1050         convD2M(dir, buf, r);
1051         r = syswstat(name, buf, r);
1052         kfree(buf);
1053         return r < 0? r: 0;
1054 }
1055
1056 int
1057 sysdirfwstat(int fd, struct dir *dir)
1058 {
1059         uint8_t *buf;
1060         int r;
1061
1062         r = sizeD2M(dir);
1063         buf = kzmalloc(r, 0);
1064         convD2M(dir, buf, r);
1065         r = sysfwstat(fd, buf, r);
1066         kfree(buf);
1067         return r < 0? r: 0;
1068 }
1069
1070 static long
1071 dirpackage(uint8_t *buf, long ts, struct dir **d)
1072 {
1073         char *s;
1074         long ss, i, n, nn, m;
1075
1076         *d = NULL;
1077         if(ts <= 0)
1078                 return ts;
1079
1080         /*
1081          * first find number of all stats, check they look like stats, & size all associated strings
1082          */
1083         ss = 0;
1084         n = 0;
1085         for(i = 0; i < ts; i += m){
1086                 m = BIT16SZ + GBIT16(&buf[i]);
1087                 if(statcheck(&buf[i], m) < 0)
1088                         break;
1089                 ss += m;
1090                 n++;
1091         }
1092
1093         if(i != ts)
1094                 error("bad directory format");
1095
1096         *d = kzmalloc(n * sizeof(struct dir) + ss, 0);
1097         if(*d == NULL)
1098                 error(Enomem);
1099
1100         /*
1101          * then convert all buffers
1102          */
1103         s = ( char *)*d + n * sizeof(struct dir);
1104         nn = 0;
1105         for(i = 0; i < ts; i += m){
1106                 m = BIT16SZ + GBIT16(( uint8_t *)&buf[i]);
1107                 if(nn >= n || convM2D(&buf[i], m, *d + nn, s) != m){
1108                         kfree(*d);
1109                         *d = NULL;
1110                         error("bad directory entry");
1111                 }
1112                 nn++;
1113                 s += m;
1114         }
1115
1116         return nn;
1117 }
1118
1119 long
1120 sysdirread(int fd, struct dir **d)
1121 {
1122         ERRSTACK(2);
1123         uint8_t *buf;
1124         long ts;
1125
1126         *d = NULL;
1127         if(waserror())
1128                 return -1;
1129         buf = kzmalloc(DIRREADLIM, 0);
1130         if(buf == NULL)
1131                 error(Enomem);
1132         if(waserror()){
1133                 kfree(buf);
1134                 nexterror();
1135         }
1136         ts = sysread(fd, buf, DIRREADLIM);
1137         if(ts >= 0)
1138                 ts = dirpackage(buf, ts, d);
1139         poperror();
1140         kfree(buf);
1141         poperror();
1142         return ts;
1143 }
1144
1145 int
1146 sysiounit(int fd)
1147 {
1148         ERRSTACK(2);
1149         struct chan *c;
1150         int n;
1151
1152         c = fdtochan(current->fgrp, fd, -1, 0, 1);
1153         if(waserror()){
1154                 cclose(c);
1155                 return 0;       /* n.b. */
1156         }
1157         n = c->iounit;
1158         poperror();
1159         cclose(c);
1160         return n;
1161 }
1162
1163 /* Notes on concurrency:
1164  * - Can't hold spinlocks while we call cclose, since it might sleep eventually.
1165  * - We're called from proc_destroy, so we could have concurrent openers trying
1166  *   to add to the group (other syscalls), hence the "closed" flag.
1167  * - dot and slash chans are dealt with in proc_free.  its difficult to close
1168  *   and zero those with concurrent syscalls, since those are a source of krefs.
1169  * - the memory is freed in proc_free().  need to wait to do it, since we can
1170  *   have concurrent accesses to fgrp before free.
1171  * - Once we lock and set closed, no further additions can happen.  To simplify
1172  *   our closes, we also allow multiple calls to this func (though that should
1173  *   never happen with the current code). */
1174 void close_9ns_files(struct proc *p, bool only_cloexec)
1175 {
1176         struct fgrp *f = p->fgrp;
1177
1178         spin_lock(&f->lock);
1179         if (f->closed) {
1180                 spin_unlock(&f->lock);
1181                 warn("Unexpected double-close");
1182                 return;
1183         }
1184         if (!only_cloexec)
1185                 f->closed = TRUE;
1186         spin_unlock(&f->lock);
1187
1188         /* maxfd is a legit val, not a +1 */
1189         for (int i = 0; i <= f->maxfd; i++) {
1190                 if (!f->fd[i])
1191                         continue;
1192                 if (only_cloexec && !(f->fd[i]->flag & CCEXEC))
1193                         continue;
1194                 cclose(f->fd[i]);
1195                 f->fd[i] = 0;
1196         }
1197 }
1198
1199 void print_chaninfo(struct chan *ch)
1200 {
1201         char buf[64] = {0};
1202 #if 0
1203 FIXME
1204         printk("Chan pathname: %s, Dev: %s, Devinfo: %s\n",
1205                "ch->path ? ch->path->s : \"no path",
1206                ch->dev ? ch->dev->name: "no dev",
1207                    ch->dev ? ch->dev->chaninfo(ch, buf, sizeof(buf)) : "no info");
1208         if (!ch->dev)
1209                 printk("No dev: intermediate chan? qid.path: %p\n", ch->qid.path);
1210 #endif
1211 }
1212
1213 void print_9ns_files(struct proc *p)
1214 {
1215         struct fgrp *f = p->fgrp;
1216         spin_lock(&f->lock);
1217         printk("9ns files for proc %d:\n", p->pid);
1218         /* maxfd is a legit val, not a +1 */
1219         for (int i = 0; i <= f->maxfd; i++) {
1220                 if (!f->fd[i])
1221                         continue;
1222                 printk("\t9fs %d, ", i);
1223                 print_chaninfo(f->fd[i]);
1224         }
1225         spin_unlock(&f->lock);
1226 }
1227
1228 /* TODO: 9ns ns inheritance flags: Shared, copied, or empty.  Looks like we're
1229  * copying the fgrp, and sharing the pgrp. */
1230 int plan9setup(struct proc *new_proc, struct proc *parent)
1231 {
1232         struct proc *old_current;
1233         struct kref *new_dot_ref;
1234         ERRSTACK(1);
1235         if (waserror()) {
1236                 printd("plan9setup failed\n");
1237                 poperror();
1238                 return -1;
1239         }
1240         if (!parent) {
1241                 /* We are probably spawned by the kernel directly, and have no parent to
1242                  * inherit from.  Be sure to set up fgrp/pgrp before calling namec().
1243                  *
1244                  * TODO: One problem is namec wants a current set for things like
1245                  * genbuf.  So we'll use new_proc for this bootstrapping.  Note
1246                  * switch_to() also loads the cr3. */
1247                 new_proc->fgrp = dupfgrp(NULL);
1248                 new_proc->pgrp = newpgrp();
1249                 old_current = switch_to(new_proc);
1250                 new_proc->slash = namec("#r", Atodir, 0, 0);
1251                 switch_back(new_proc, old_current);
1252                 /* Want the name to be "/" instead of "#r" */
1253                 cnameclose(new_proc->slash->name);
1254                 new_proc->slash->name = newcname("/");
1255                 new_proc->dot = cclone(new_proc->slash);
1256                 poperror();
1257                 return 0;
1258         }
1259         /* Copy semantics: do not change this without revisiting proc_destroy,
1260          * close_9ns_files, and closefgrp. */
1261         new_proc->fgrp = dupfgrp(parent->fgrp);
1262         /* Shared semantics */
1263         kref_get(&parent->pgrp->ref, 1);
1264         new_proc->pgrp = parent->pgrp;
1265         /* copy semantics on / and . (doesn't make a lot of sense in akaros o/w) */
1266         /* / should never disappear while we hold a ref to parent */
1267         kref_get(&parent->slash->ref, 1);
1268         new_proc->slash = parent->slash;
1269         /* dot could change concurrently, and we could fail to gain a ref if whoever
1270          * decref'd dot triggered the release.  if that did happen, new_proc->dot
1271          * should update and we can try again. */
1272         while (!(new_dot_ref = kref_get_not_zero(&parent->dot->ref, 1)))
1273                 cpu_relax();
1274         /* And now, we can't trust parent->dot, and need to determine our dot from
1275          * the ref we obtained. */
1276         new_proc->dot = container_of(new_dot_ref, struct chan, ref);
1277         poperror();
1278         return 0;
1279 }
1280