Allow a parent to set up a child's fd's via a new system call
[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 enum {
17         DIRSIZE = STATFIXLEN + 32 * 4,
18         DIRREADLIM = 2048,      /* should handle the largest reasonable directory entry */
19         DIRREADSIZE=8192,       /* Just read a lot. Memory is cheap, lots of bandwidth,
20                                  * and RPCs are very expensive. At the same time,
21                                  * let's not yet exceed a common MSIZE. */
22
23 };
24
25 static int growfd(struct fgrp *f, int fd)
26 {
27         
28         int n;
29         struct chan **nfd, **ofd;
30
31         if (fd < f->nfd) {
32                 return 0;
33         }
34         n = f->nfd + DELTAFD;
35         if (n > MAXNFD)
36                 n = MAXNFD;
37         if (fd >= n) {
38                 return -1;
39         }
40         nfd = kzmalloc(n * sizeof(struct chan *), 0);
41         if (nfd == NULL) {
42                 return -1;
43         }
44         ofd = f->fd;
45         memmove(nfd, ofd, f->nfd * sizeof(struct chan *));
46         f->fd = nfd;
47         f->nfd = n;
48         kfree(ofd);
49         return 0;
50 }
51
52 int newfd(struct chan *c)
53 {
54         
55         int i;
56         struct fgrp *f = current->fgrp;
57
58         spin_lock(&f->lock);
59         if (f->closed) {
60                 spin_unlock(&f->lock);
61                 return -1;
62         }
63         /* VFS hack */
64         /* We'd like to ask it to start at f->minfd, but that would require us to
65          * know if we closed anything.  Since we share the FD numbers with the VFS,
66          * there is no way to know that. */
67         i = get_fd(&current->open_files, 0);
68         while (i >= f->nfd) {
69                 if (growfd(f, i) < 0) {
70                         spin_unlock(&f->lock);
71                         exhausted("file descriptors");
72                         return -1;
73                 }
74                 cpu_relax();
75         }
76         assert(f->fd[i] == 0);
77 #if 0   // 9ns style
78         /* TODO: use a unique integer allocator */
79         for (i = f->minfd; i < f->nfd; i++)
80                 if (f->fd[i] == 0)
81                         break;
82         if (i >= f->nfd && growfd(f, i) < 0) {
83                 spin_unlock(&f->lock);
84                 exhausted("file descriptors");
85                 return -1;
86         }
87 #endif
88         f->minfd = i + 1;
89         if (i > f->maxfd)
90                 f->maxfd = i;
91         f->fd[i] = c;
92         spin_unlock(&f->lock);
93         return i;
94 }
95
96 struct chan *fdtochan(struct fgrp *f, int fd, int mode, int chkmnt, int iref)
97 {
98         
99         struct chan *c;
100
101         c = 0;
102
103         spin_lock(&f->lock);
104         if (f->closed) {
105                 spin_unlock(&f->lock);
106                 error("File group closed");
107         }
108         if (fd < 0 || f->maxfd < fd || (c = f->fd[fd]) == 0) {
109                 spin_unlock(&f->lock);
110                 error(Ebadfd);
111         }
112         if (iref)
113                 chan_incref(c);
114         spin_unlock(&f->lock);
115
116         if (chkmnt && (c->flag & CMSG)) {
117                 if (iref)
118                         cclose(c);
119                 error(Ebadusefd);
120         }
121
122         if (mode < 0 || c->mode == ORDWR) {
123                 return c;
124         }
125
126         if ((mode & OTRUNC) && IS_RDONLY(c->mode)) {
127                 if (iref)
128                         cclose(c);
129                 error(Ebadusefd);
130         }
131
132         /* TODO: this is probably wrong.  if you get this from a dev, in the dev's
133          * open, you are probably saving mode directly, without passing it through
134          * openmode. */
135         if ((mode & ~OTRUNC) != c->mode) {
136                 warn("Trunc mode issue: mode %o, mode minus trunc %o, chan mode %o\n",
137                          mode, mode & ~OTRUNC, c->mode);
138                 if (iref)
139                         cclose(c);
140                 error(Ebadusefd);
141         }
142
143         return c;
144 }
145
146 long kchanio(void *vc, void *buf, int n, int mode)
147 {
148         ERRSTACK(1);
149         int r;
150         struct chan *c;
151
152         c = vc;
153         if (waserror()) {
154                 poperror();
155                 return -1;
156         }
157
158         if (IS_RDONLY(mode))
159                 r = devtab[c->type].read(c, buf, n, c->offset);
160         else
161                 r = devtab[c->type].write(c, buf, n, c->offset);
162
163         spin_lock(&c->lock);
164         c->offset += r;
165         spin_unlock(&c->lock);
166         poperror();
167         return r;
168 }
169
170 int openmode(uint32_t omode)
171 {
172 /* GIANT WARNING: if this ever throws, ipopen (and probably many others) will
173  * screw up refcnts of Qctl, err, data, etc */
174 #if 0
175         /* this is the old plan9 style.  i think they want to turn exec into read,
176          * and strip off anything higher, and just return the RD/WR style bits.  not
177          * stuff like ORCLOSE.  the lack of OEXCL might be a bug on their part (it's
178          * the only one of their non-RW-related flags that isn't masked out) */
179         if (o >= (OTRUNC | OCEXEC | ORCLOSE | OEXEC))
180                 error(Ebadarg);
181         o &= ~(OTRUNC | OCEXEC | ORCLOSE);
182         if (o > OEXEC)
183                 error(Ebadarg);
184         if (o == OEXEC)
185                 return OREAD;
186         return o;
187 #endif
188         /* no error checking (we have a shitload of flags anyway), and we return the
189          * basic access modes (RD/WR/ETC) */
190         if (omode == O_EXEC) {
191         return O_RDONLY;
192         }
193         return omode & O_ACCMODE;
194 }
195
196 void fdclose(struct fgrp *f, int fd)
197 {
198         
199         int i;
200         struct chan *c;
201
202         spin_lock(&f->lock);
203         if (f->closed) {
204                 spin_unlock(&f->lock);
205                 return;
206         }
207         c = f->fd[fd];
208         if (c == 0) {
209                 /* can happen for users with shared fd tables */
210                 spin_unlock(&f->lock);
211                 return;
212         }
213         f->fd[fd] = 0;
214         if (fd == f->maxfd)
215                 for (i = fd; --i >= 0 && f->fd[i] == 0;)
216                         f->maxfd = i;
217         if (fd < f->minfd)
218                 f->minfd = fd;
219         /* VFS hack: give the FD back to VFS */
220         put_fd(&current->open_files, fd);
221         spin_unlock(&f->lock);
222         cclose(c);
223 }
224
225 int syschdir(char *path)
226 {
227         ERRSTACK(1);
228         struct chan *c;
229         struct pgrp *pg;
230
231         if (waserror()) {
232                 poperror();
233                 return -1;
234         }
235
236         c = namec(path, Atodir, 0, 0);
237         pg = current->pgrp;
238         cclose(pg->dot);
239         pg->dot = c;
240         poperror();
241         return 0;
242 }
243
244 int fgrpclose(struct fgrp *f, int fd)
245 {
246         ERRSTACK(1);
247         if (waserror()) {
248                 poperror();
249                 return -1;
250         }
251
252         /*
253          * Take no reference on the chan because we don't really need the
254          * data structure, and are calling fdtochan only for error checks.
255          * fdclose takes care of processes racing through here.
256          */
257         fdtochan(f, fd, -1, 0, 0);
258         fdclose(f, fd);
259         poperror();
260         return 0;
261 }
262
263 int sysclose(int fd)
264 {
265         return fgrpclose(current->fgrp, fd);
266 }
267
268 int syscreate(char *path, int mode, uint32_t perm)
269 {
270         ERRSTACK(2);
271         int fd;
272         struct chan *c;
273
274         if (waserror()) {
275                 poperror();
276                 return -1;
277         }
278
279         openmode(mode & ~OEXCL);        /* error check only; OEXCL okay here */
280         c = namec(path, Acreate, mode, perm);
281         if (waserror()) {
282                 cclose(c);
283                 nexterror();
284         }
285         fd = newfd(c);
286         if (fd < 0)
287                 error(Enofd);
288         poperror();
289
290         poperror();
291         return fd;
292 }
293
294 // This is in need of rework but for now just copy and convert.
295 int sysdup(int old, int new)
296 {
297         ERRSTACK(2);
298         int fd;
299         struct chan *c, *oc;
300         struct fgrp *f = current->fgrp;
301
302         if (waserror()) {
303                 poperror();
304                 return -1;
305         }
306
307         c = fdtochan(current->fgrp, old, -1, 0, 1);
308         if (c->qid.type & QTAUTH) {
309                 cclose(c);
310                 error(Eperm);
311         }
312         fd = new;
313         if (fd != -1) {
314                 /* ideally we'll be done with the VFS before we fix this */
315                 /* double check the ccloses when you fix this */
316                 panic("Need to sync with the VFS");
317                 spin_lock(&f->lock);
318                 if (f->closed) {
319                         spin_unlock(&f->lock);
320                         cclose(c);
321                         return -1;
322                 }
323                 if (fd < 0 || growfd(f, fd) < 0) {
324                         spin_unlock(&f->lock);
325                         cclose(c);
326                         error(Ebadfd);
327                 }
328                 if (fd > f->maxfd)
329                         f->maxfd = fd;
330                 oc = f->fd[fd];
331                 f->fd[fd] = c;
332                 spin_unlock(&f->lock);
333                 if (oc)
334                         cclose(oc);
335         } else {
336                 if (waserror()) {
337                         cclose(c);
338                         nexterror();
339                 }
340                 fd = newfd(c);
341                 if (fd < 0)
342                         error(Enofd);
343                 poperror();
344         }
345         poperror();
346         return fd;
347 }
348
349 int sysdup2(struct proc *to, int old, int new)
350 {
351         ERRSTACK(2);
352         int fd;
353         struct chan *c, *oc;
354         struct fgrp *fromf = current->fgrp;
355         struct fgrp *tof = to->fgrp;
356
357         if (waserror()) {
358                 poperror();
359                 return -1;
360         }
361
362         c = fdtochan(current->fgrp, old, -1, 0, 1);
363         if (c->qid.type & QTAUTH) {
364                 cclose(c);
365                 error(Eperm);
366         }
367         fd = new;
368         if (fd != -1) {
369                 /* ideally we'll be done with the VFS before we fix this */
370                 /* double check the ccloses when you fix this */
371                 panic("Need to sync with the VFS");
372                 spin_lock(&tof->lock);
373                 if (tof->closed) {
374                         spin_unlock(&tof->lock);
375                         cclose(c);
376                         return -1;
377                 }
378                 if (fd < 0 || growfd(tof, fd) < 0) {
379                         spin_unlock(&tof->lock);
380                         cclose(c);
381                         error(Ebadfd);
382                 }
383                 if (fd > tof->maxfd)
384                         tof->maxfd = fd;
385                 oc = tof->fd[fd];
386                 tof->fd[fd] = c;
387                 spin_unlock(&tof->lock);
388                 if (oc)
389                         cclose(oc);
390         } else {
391                 panic("unhandled; rewrite newfd");
392                 if (waserror()) {
393                         cclose(c);
394                         nexterror();
395                 }
396                 fd = newfd(c);
397                 if (fd < 0)
398                         error(Enofd);
399                 poperror();
400         }
401         poperror();
402         return fd;
403 }
404
405 char *sysfd2path(int fd)
406 {
407         ERRSTACK(1);
408         struct chan *c;
409         char *s;
410
411         if (waserror()) {
412                 poperror();
413                 return NULL;
414         }
415         c = fdtochan(current->fgrp, fd, -1, 0, 1);
416         s = NULL;
417         if (c->name != NULL) {
418                 s = kzmalloc(c->name->len + 1, 0);
419                 if (s == NULL) {
420                         cclose(c);
421                         error(Enomem);
422                 }
423                 memmove(s, c->name->s, c->name->len + 1);
424         }
425         cclose(c);
426         poperror();
427         return s;
428 }
429
430 int sysfauth(int fd, char *aname)
431 {
432         ERRSTACK(2);
433         struct chan *c, *ac;
434
435         if (waserror()) {
436                 poperror();
437                 return -1;
438         }
439
440         validname(aname, 0);
441         c = fdtochan(current->fgrp, fd, ORDWR, 0, 1);
442         if (waserror()) {
443                 cclose(c);
444                 nexterror();
445         }
446
447         ac = mntauth(c, aname);
448
449         /* at this point ac is responsible for keeping c alive */
450         poperror();     /* c */
451         cclose(c);
452
453         if (waserror()) {
454                 cclose(ac);
455                 nexterror();
456         }
457
458         fd = newfd(ac);
459         if (fd < 0)
460                 error(Enofd);
461         poperror();     /* ac */
462
463         poperror();
464
465         return fd;
466 }
467
468 int sysfversion(int fd, unsigned int msize, char *vers, unsigned int arglen)
469 {
470         ERRSTACK(2);
471         int m;
472         struct chan *c;
473
474         if (waserror()) {
475                 poperror();
476                 return -1;
477         }
478
479         /* check there's a NUL in the version string */
480         if (arglen == 0 || memchr(vers, 0, arglen) == 0)
481                 error(Ebadarg);
482
483         c = fdtochan(current->fgrp, fd, ORDWR, 0, 1);
484         if (waserror()) {
485                 cclose(c);
486                 nexterror();
487         }
488
489         m = mntversion(c, vers, msize, arglen);
490
491         poperror();
492         cclose(c);
493
494         poperror();
495         return m;
496 }
497
498 int syspipe(int fd[2])
499 {
500         ERRSTACK(1);
501         struct dev *d;
502         struct fgrp *f;
503         struct chan *c[2];
504         static char *names[] = { "data", "data1" };
505
506         f = current->fgrp;
507
508         d = &devtab[devno('|', 0)];
509         c[0] = namec("#|", Atodir, 0, 0);
510         c[1] = 0;
511         fd[0] = -1;
512         fd[1] = -1;
513         if (waserror()) {
514                 if (c[0] != 0)
515                         cclose(c[0]);
516                 if (c[1] != 0)
517                         cclose(c[1]);
518                 if (fd[0] >= 0) {
519                         /* VFS hack */
520                         f->fd[fd[0]] = 0;
521                         put_fd(&current->open_files, fd[0]);
522                 }
523                 if (fd[1] >= 0) {
524                         /* VFS hack */
525                         f->fd[fd[1]] = 0;
526                         put_fd(&current->open_files, fd[1]);
527                 }
528                 poperror();
529                 return -1;
530         }
531         c[1] = cclone(c[0]);
532         if (walk(&c[0], &names[0], 1, 1, NULL) < 0)
533                 error(Egreg);
534         if (walk(&c[1], &names[1], 1, 1, NULL) < 0)
535                 error(Egreg);
536         c[0] = d->open(c[0], ORDWR);
537         c[1] = d->open(c[1], ORDWR);
538         fd[0] = newfd(c[0]);
539         if (fd[0] < 0)
540                 error(Enofd);
541         fd[1] = newfd(c[1]);
542         if (fd[1] < 0)
543                 error(Enofd);
544         poperror();
545         return 0;
546 }
547
548 int sysfwstat(int fd, uint8_t * buf, int n)
549 {
550         ERRSTACK(2);
551         struct chan *c;
552
553         if (waserror()) {
554                 poperror();
555                 return -1;
556         }
557
558         validstat(buf, n, 0);
559         c = fdtochan(current->fgrp, fd, -1, 1, 1);
560         if (waserror()) {
561                 cclose(c);
562                 nexterror();
563         }
564         n = devtab[c->type].wstat(c, buf, n);
565         poperror();
566         cclose(c);
567
568         poperror();
569         return n;
570 }
571
572 long bindmount(struct chan *c, char *old, int flag, char *spec)
573 {
574         ERRSTACK(1);
575         int ret;
576         struct chan *c1;
577
578         if (flag > MMASK || (flag & MORDER) == (MBEFORE | MAFTER))
579                 error(Ebadarg);
580
581         c1 = namec(old, Amount, 0, 0);
582         if (waserror()) {
583                 cclose(c1);
584                 nexterror();
585         }
586         ret = cmount(c, c1, flag, spec);
587
588         poperror();
589         cclose(c1);
590         return ret;
591 }
592
593 int sysbind(char *new, char *old, int flags)
594 {
595         ERRSTACK(2);
596         long r;
597         struct chan *c0;
598
599         if (waserror()) {
600                 poperror();
601                 return -1;
602         }
603
604         c0 = namec(new, Abind, 0, 0);
605         if (waserror()) {
606                 cclose(c0);
607                 nexterror();
608         }
609         r = bindmount(c0, old, flags, "");
610         poperror();
611         cclose(c0);
612
613         poperror();
614         return r;
615 }
616
617 int sysmount(int fd, int afd, char *old, int flags, char *spec)
618 {
619         ERRSTACK(1);
620         long r;
621         volatile struct {
622                 struct chan *c;
623         } c0;
624         volatile struct {
625                 struct chan *c;
626         } bc;
627         volatile struct {
628                 struct chan *c;
629         } ac;
630         struct mntparam mntparam;
631
632         ac.c = NULL;
633         bc.c = NULL;
634         c0.c = NULL;
635         if (waserror()) {
636                 cclose(ac.c);
637                 cclose(bc.c);
638                 cclose(c0.c);
639                 poperror();
640                 return -1;
641         }
642         bc.c = fdtochan(current->fgrp, fd, ORDWR, 0, 1);
643         if (afd >= 0)
644                 ac.c = fdtochan(current->fgrp, afd, ORDWR, 0, 1);
645         mntparam.chan = bc.c;
646         mntparam.authchan = ac.c;
647         mntparam.spec = spec;
648         mntparam.flags = flags;
649         c0.c = devtab[devno('M', 0)].attach((char *)&mntparam);
650
651         r = bindmount(c0.c, old, flags, spec);
652         poperror();
653         cclose(ac.c);
654         cclose(bc.c);
655         cclose(c0.c);
656
657         return r;
658 }
659
660 int sysunmount(char *old, char *new)
661 {
662         ERRSTACK(1);
663         volatile struct {
664                 struct chan *c;
665         } cmount;
666         volatile struct {
667                 struct chan *c;
668         } cmounted;
669
670         cmount.c = NULL;
671         cmounted.c = NULL;
672         if (waserror()) {
673                 cclose(cmount.c);
674                 cclose(cmounted.c);
675                 poperror();
676                 return -1;
677         }
678
679         cmount.c = namec(new, Amount, 0, 0);
680         if (old != NULL && old[0] != '\0') {
681                 /*
682                  * This has to be namec(..., Aopen, ...) because
683                  * if arg[0] is something like /srv/cs or /fd/0,
684                  * opening it is the only way to get at the real
685                  * Chan underneath.
686                  */
687                 cmounted.c = namec(old, Aopen, OREAD, 0);
688         }
689
690         cunmount(cmount.c, cmounted.c);
691         poperror();
692         cclose(cmount.c);
693         cclose(cmounted.c);
694         return 0;
695 }
696
697 int sysopen(char *path, int vfs_flags)
698 {
699         ERRSTACK(2);
700         int fd;
701         struct chan *c;
702
703         if (waserror()) {
704                 poperror();
705                 return -1;
706         }
707
708         openmode(vfs_flags);    /* error check only */
709         c = namec(path, Aopen, vfs_flags, 0);
710         if (waserror()) {
711                 cclose(c);
712                 nexterror();
713         }
714         fd = newfd(c);
715         if (fd < 0)
716                 error(Enofd);
717         poperror();
718
719         poperror();
720         return fd;
721 }
722
723 long unionread(struct chan *c, void *va, long n)
724 {
725         ERRSTACK(1);
726         int i;
727         long nr;
728         struct mhead *m;
729         struct mount *mount;
730
731         qlock(&c->umqlock);
732         m = c->umh;
733         rlock(&m->lock);
734         mount = m->mount;
735         /* bring mount in sync with c->uri and c->umc */
736         for (i = 0; mount != NULL && i < c->uri; i++)
737                 mount = mount->next;
738
739         nr = 0;
740         while (mount != NULL) {
741                 /* Error causes component of union to be skipped */
742                 if (mount->to) {
743                         /* normally we want to discard the error, but for our ghetto kdirent
744                          * hack, we need to repeat unionread if we saw a Eshort */
745                         if (waserror()) {
746                                 if (!strcmp(current_errstr(), Eshort)) {
747                                         runlock(&m->lock);
748                                         qunlock(&c->umqlock);
749                                         nexterror();
750                                 }
751                                 /* poperror done below for either branch */
752                         } else {
753                                 if (c->umc == NULL) {
754                                         c->umc = cclone(mount->to);
755                                         c->umc = devtab[c->umc->type].open(c->umc, OREAD);
756                                 }
757
758                                 nr = devtab[c->umc->type].read(c->umc, va, n, c->umc->offset);
759                                 if (nr < 0)
760                                         nr = 0; /* dev.c can return -1 */
761                                 c->umc->offset += nr;
762                         }
763                         poperror();     /* pop regardless */
764                 }
765                 if (nr > 0)
766                         break;
767
768                 /* Advance to next element */
769                 c->uri++;
770                 if (c->umc) {
771                         cclose(c->umc);
772                         c->umc = NULL;
773                 }
774                 mount = mount->next;
775         }
776         runlock(&m->lock);
777         qunlock(&c->umqlock);
778         return nr;
779 }
780
781 static void unionrewind(struct chan *c)
782 {
783         qlock(&c->umqlock);
784         c->uri = 0;
785         if (c->umc) {
786                 cclose(c->umc);
787                 c->umc = NULL;
788         }
789         qunlock(&c->umqlock);
790 }
791
792 static long rread(int fd, void *va, long n, int64_t * offp)
793 {
794         ERRSTACK(3);
795         int dir;
796         struct chan *c;
797         int64_t off;
798
799         /* dirty dirent hack */
800         void *real_va = va;
801
802         if (waserror()) {
803                 poperror();
804                 return -1;
805         }
806
807         c = fdtochan(current->fgrp, fd, OREAD, 1, 1);
808         if (waserror()) {
809                 cclose(c);
810                 nexterror();
811         }
812
813         if (n < 0)
814                 error(Etoosmall);
815
816         dir = c->qid.type & QTDIR;
817
818         /* kdirent hack: userspace is expecting kdirents, but all of 9ns
819          * produces Ms.  Just save up what we don't use and append the
820          * new stuff later. Allocate DIRREADSIZE bytes for that purpose.
821          */
822         if (dir) {
823                 int amt;
824                 /* expecting only one dirent at a time, o/w we're busted */
825                 assert(n >= sizeof(struct kdirent));
826                 if (!c->buf) {
827                         c->buf=kmalloc(DIRREADSIZE, KMALLOC_WAIT);
828                         c->bufused = 0;
829                 }
830                 /* Attempt to extract an M, in case there was some already */
831                 amt = convM2kdirent(c->buf, c->bufused, real_va, 0);
832                 if (amt) {
833                         c->bufused -= amt;
834                         memmove(c->buf, c->buf + amt, c->bufused);
835                         n = sizeof(struct kdirent);
836                         goto out;
837                 }
838                 /* debugging */
839                 if (waserror()) {
840                         printk("Well, sysread of a dir sucks.%s \n", current_errstr());
841                         nexterror();
842                 }
843                 va = c->buf + c->bufused;
844                 n = DIRREADSIZE - c->bufused;
845         }
846
847         /* this is the normal plan9 read */
848         if (dir && c->umh)
849                 n = unionread(c, va, n);
850         else {
851                 if (offp == NULL) {
852                         spin_lock(&c->lock);    /* lock for int64_t assignment */
853                         off = c->offset;
854                         spin_unlock(&c->lock);
855                 } else
856                         off = *offp;
857                 if (off < 0)
858                         error(Enegoff);
859                 if (off == 0) {
860                         if (offp == NULL) {
861                                 spin_lock(&c->lock);
862                                 c->offset = 0;
863                                 c->dri = 0;
864                                 spin_unlock(&c->lock);
865                         }
866                         unionrewind(c);
867                 }
868                 if (! c->ateof) {
869                         n = devtab[c->type].read(c, va, n, off);
870                         if (n == 0 && dir)
871                                 c->ateof = 1;
872                 } else {
873                         n = 0;
874                 }
875                 spin_lock(&c->lock);
876                 c->offset += n;
877                 spin_unlock(&c->lock);
878         }
879
880         /* dirty kdirent hack */
881         if (dir) {
882                 int amt;
883                 c->bufused = c->bufused + n;
884                 /* extract an M from the front, then shift the remainder back */
885                 amt = convM2kdirent(c->buf, c->bufused, real_va, 0);
886                 c->bufused -= amt;
887                 memmove(c->buf, c->buf + amt, c->bufused);
888                 n = amt ? sizeof(struct kdirent) : 0;
889                 poperror();     /* matching our debugging waserror */
890         }
891
892 out:
893         poperror();
894         cclose(c);
895
896         poperror();
897         return n;
898 }
899
900 long sysread(int fd, void *va, long n)
901 {
902         return rread(fd, va, n, NULL);
903 }
904
905 long syspread(int fd, void *va, long n, int64_t off)
906 {
907         return rread(fd, va, n, &off);
908 }
909
910 int sysremove(char *path)
911 {
912         ERRSTACK(2);
913         struct chan *c;
914
915         if (waserror()) {
916                 poperror();
917                 return -1;
918         }
919
920         c = namec(path, Aremove, 0, 0);
921         if (waserror()) {
922                 c->type = -1;   /* see below */
923                 cclose(c);
924                 nexterror();
925         }
926         devtab[c->type].remove(c);
927         /*
928          * Remove clunks the fid, but we need to recover the Chan
929          * so fake it up.  -1 aborts the dev's close.
930          */
931         c->type = -1;
932         poperror();
933         cclose(c);
934
935         poperror();
936         return 0;
937 }
938
939 int64_t sysseek(int fd, int64_t off, int whence)
940 {
941         ERRSTACK(2);
942         struct dir *dir;
943         struct chan *c;
944
945         if (waserror()) {
946                 poperror();
947                 return -1;
948         }
949
950         c = fdtochan(current->fgrp, fd, -1, 1, 1);
951         if (waserror()) {
952                 cclose(c);
953                 nexterror();
954         }
955
956         if (devtab[c->type].dc == '|')
957                 error(Eisstream);
958
959         switch (whence) {
960                 case 0:
961                         if (c->qid.type & QTDIR) {
962                                 if (off != 0)
963                                         error(Eisdir);
964                                 unionrewind(c);
965                         } else if (off < 0)
966                                 error(Enegoff);
967                         spin_lock(&c->lock);    /* lock for int64_t assignment */
968                         c->offset = off;
969                         spin_unlock(&c->lock);
970                         break;
971
972                 case 1:
973                         if (c->qid.type & QTDIR)
974                                 error(Eisdir);
975                         spin_lock(&c->lock);    /* lock for read/write update */
976                         off += c->offset;
977                         if (off < 0) {
978                                 spin_unlock(&c->lock);
979                                 error(Enegoff);
980                         }
981                         c->offset = off;
982                         spin_unlock(&c->lock);
983                         break;
984
985                 case 2:
986                         if (c->qid.type & QTDIR)
987                                 error(Eisdir);
988                         dir = chandirstat(c);
989                         if (dir == NULL)
990                                 error("internal error: stat error in seek");
991                         off += dir->length;
992                         kfree(dir);
993                         if (off < 0)
994                                 error(Enegoff);
995                         spin_lock(&c->lock);    /* lock for read/write update */
996                         c->offset = off;
997                         spin_unlock(&c->lock);
998                         break;
999
1000                 default:
1001                         error(Ebadarg);
1002                         break;
1003         }
1004         poperror();
1005         c->dri = 0;
1006         cclose(c);
1007         poperror();
1008         return off;
1009 }
1010
1011 void validstat(uint8_t * s, int n, int slashok)
1012 {
1013         
1014         int m;
1015         char buf[64];
1016
1017         if (statcheck(s, n) < 0)
1018                 error(Ebadstat);
1019         /* verify that name entry is acceptable */
1020         s += STATFIXLEN - 4 * BIT16SZ;  /* location of first string */
1021         /*
1022          * s now points at count for first string.
1023          * if it's too long, let the server decide; this is
1024          * only for his protection anyway. otherwise
1025          * we'd have to allocate and waserror.
1026          */
1027         m = GBIT16(s);
1028         s += BIT16SZ;
1029         if (m + 1 > sizeof buf) {
1030                 return;
1031         }
1032         memmove(buf, s, m);
1033         buf[m] = '\0';
1034         /* name could be '/' */
1035         if (strcmp(buf, "/") != 0)
1036                 validname(buf, slashok);
1037 }
1038
1039 int sysfstat(int fd, uint8_t *buf, int n)
1040 {
1041         ERRSTACK(2);
1042         struct chan *c;
1043
1044         if (waserror()) {
1045                 poperror();
1046                 return -1;
1047         }
1048
1049         c = fdtochan(current->fgrp, fd, -1, 0, 1);
1050         if (waserror()) {
1051                 cclose(c);
1052                 nexterror();
1053         }
1054         devtab[c->type].stat(c, buf, n);
1055
1056         poperror();
1057         cclose(c);
1058
1059         poperror();
1060         return n;
1061 }
1062
1063 int sysfstatakaros(int fd, struct kstat *ks)
1064 {
1065         
1066         int n = 4096;
1067         uint8_t *buf;
1068         buf = kmalloc(n, KMALLOC_WAIT);
1069         n = sysfstat(fd, buf, n);
1070         if (n > 0) {
1071                 convM2kstat(buf, n, ks);
1072                 n = 0;
1073         }
1074         kfree(buf);
1075         return n;
1076 }
1077
1078 int sysstat(char *path, uint8_t *buf, int n)
1079 {
1080         ERRSTACK(2);
1081         struct chan *c;
1082
1083         if (waserror()) {
1084                 poperror();
1085                 return -1;
1086         }
1087
1088         c = namec(path, Aaccess, 0, 0);
1089         if (waserror()) {
1090                 cclose(c);
1091                 nexterror();
1092         }
1093         devtab[c->type].stat(c, buf, n);
1094         poperror();
1095         cclose(c);
1096
1097         poperror();
1098
1099         return n;
1100 }
1101
1102 int sysstatakaros(char *path, struct kstat *ks)
1103 {
1104         
1105         int n = 4096;
1106         uint8_t *buf;
1107         buf = kmalloc(n, KMALLOC_WAIT);
1108         n = sysstat(path, buf, n);
1109         if (n > 0) {
1110                 convM2kstat(buf, n, ks);
1111                 n = 0;
1112         }
1113         kfree(buf);
1114         return n;
1115 }
1116
1117 static long rwrite(int fd, void *va, long n, int64_t * offp)
1118 {
1119         ERRSTACK(3);
1120         struct chan *c;
1121         struct dir *dir;
1122         int64_t off;
1123         long m;
1124
1125         if (waserror()) {
1126                 poperror();
1127                 return -1;
1128         }
1129         c = fdtochan(current->fgrp, fd, OWRITE, 1, 1);
1130         if (waserror()) {
1131                 cclose(c);
1132                 nexterror();
1133         }
1134         if (c->qid.type & QTDIR)
1135                 error(Eisdir);
1136
1137         if (n < 0)
1138                 error(Etoosmall);
1139
1140         if (offp == NULL) {
1141                 /* append changes the offset to the end, and even if we fail later, this
1142                  * change will persist */
1143                 if (c->flag & CAPPEND) {
1144                         dir = chandirstat(c);
1145                         if (!dir)
1146                                 error("internal error: stat error in append write");
1147                         spin_lock(&c->lock);    /* legacy lock for int64 assignment */
1148                         c->offset = dir->length;
1149                         spin_unlock(&c->lock);
1150                         kfree(dir);
1151                 }
1152                 spin_lock(&c->lock);
1153                 off = c->offset;
1154                 c->offset += n;
1155                 spin_unlock(&c->lock);
1156         } else
1157                 off = *offp;
1158
1159         if (waserror()) {
1160                 if (offp == NULL) {
1161                         spin_lock(&c->lock);
1162                         c->offset -= n;
1163                         spin_unlock(&c->lock);
1164                 }
1165                 nexterror();
1166         }
1167         if (off < 0)
1168                 error(Enegoff);
1169         m = devtab[c->type].write(c, va, n, off);
1170         poperror();
1171
1172         if (offp == NULL && m < n) {
1173                 spin_lock(&c->lock);
1174                 c->offset -= n - m;
1175                 spin_unlock(&c->lock);
1176         }
1177
1178         poperror();
1179         cclose(c);
1180
1181         poperror();
1182         return n;
1183 }
1184
1185 long syswrite(int fd, void *va, long n)
1186 {
1187         return rwrite(fd, va, n, NULL);
1188 }
1189
1190 long syspwrite(int fd, void *va, long n, int64_t off)
1191 {
1192         return rwrite(fd, va, n, &off);
1193 }
1194
1195 int syswstat(char *path, uint8_t * buf, int n)
1196 {
1197         ERRSTACK(2);
1198         struct chan *c;
1199
1200         if (waserror()) {
1201                 poperror();
1202                 return -1;
1203         }
1204
1205         validstat(buf, n, 0);
1206         c = namec(path, Aaccess, 0, 0);
1207         if (waserror()) {
1208                 cclose(c);
1209                 nexterror();
1210         }
1211         n = devtab[c->type].wstat(c, buf, n);
1212         poperror();
1213         cclose(c);
1214
1215         poperror();
1216         return n;
1217 }
1218
1219 struct dir *chandirstat(struct chan *c)
1220 {
1221         ERRSTACK(1);
1222         struct dir *d;
1223         uint8_t *buf;
1224         int n, nd, i;
1225
1226         nd = DIRSIZE;
1227         for (i = 0; i < 2; i++) {       /* should work by the second try */
1228                 d = kzmalloc(sizeof(struct dir) + nd, 0);
1229                 buf = (uint8_t *) & d[1];
1230                 if (waserror()) {
1231                         kfree(d);
1232                         poperror();
1233                         return NULL;
1234                 }
1235                 n = devtab[c->type].stat(c, buf, nd);
1236                 poperror();
1237                 if (n < BIT16SZ) {
1238                         kfree(d);
1239                         return NULL;
1240                 }
1241                 nd = GBIT16((uint8_t *) buf) + BIT16SZ; /* size needed to store whole stat buffer including count */
1242                 if (nd <= n) {
1243                         convM2D(buf, n, d, (char *)&d[1]);
1244                         return d;
1245                 }
1246                 /* else sizeof(Dir)+nd is plenty */
1247                 kfree(d);
1248         }
1249         return NULL;
1250
1251 }
1252
1253 struct dir *sysdirstat(char *name)
1254 {
1255         ERRSTACK(2);
1256         struct chan *c;
1257         struct dir *d;
1258
1259         if (waserror()) {
1260                 poperror();
1261                 return NULL;
1262         }
1263
1264         c = namec(name, Aaccess, 0, 0);
1265         if (waserror()) {
1266                 cclose(c);
1267                 nexterror();
1268         }
1269         d = chandirstat(c);
1270         poperror();
1271         cclose(c);
1272
1273         poperror();
1274         return d;
1275 }
1276
1277 struct dir *sysdirfstat(int fd)
1278 {
1279         ERRSTACK(2);
1280         struct chan *c;
1281         struct dir *d;
1282
1283         if (waserror()) {
1284                 poperror();
1285                 return NULL;
1286         }
1287
1288         c = fdtochan(current->fgrp, fd, -1, 0, 1);
1289         if (waserror()) {
1290                 cclose(c);
1291                 nexterror();
1292         }
1293         d = chandirstat(c);
1294         poperror();
1295         cclose(c);
1296
1297         poperror();
1298         return d;
1299 }
1300
1301 int sysdirwstat(char *name, struct dir *dir)
1302 {
1303         
1304         uint8_t *buf;
1305         int r;
1306
1307         r = sizeD2M(dir);
1308         buf = kzmalloc(r, 0);
1309         convD2M(dir, buf, r);
1310         r = syswstat(name, buf, r);
1311         kfree(buf);
1312         return r < 0 ? r : 0;
1313 }
1314
1315 int sysdirfwstat(int fd, struct dir *dir)
1316 {
1317         
1318         uint8_t *buf;
1319         int r;
1320
1321         r = sizeD2M(dir);
1322         buf = kzmalloc(r, 0);
1323         convD2M(dir, buf, r);
1324         r = sysfwstat(fd, buf, r);
1325         kfree(buf);
1326         return r < 0 ? r : 0;
1327 }
1328
1329 static long dirpackage(uint8_t * buf, long ts, struct kdirent **d)
1330 {
1331         
1332         char *s;
1333         long ss, i, n, nn, m = 0;
1334
1335         *d = NULL;
1336         if (ts <= 0) {
1337                 return ts;
1338         }
1339
1340         /*
1341          * first find number of all stats, check they look like stats, & size all associated strings
1342          */
1343         ss = 0;
1344         n = 0;
1345         for (i = 0; i < ts; i += m) {
1346                 m = BIT16SZ + GBIT16(&buf[i]);
1347                 if (statcheck(&buf[i], m) < 0)
1348                         break;
1349                 ss += m;
1350                 n++;
1351         }
1352
1353         if (i != ts)
1354                 error("bad directory format");
1355
1356         *d = kzmalloc(n * sizeof(**d) + ss, 0);
1357         if (*d == NULL)
1358                 error(Enomem);
1359
1360         /*
1361          * then convert all buffers
1362          */
1363         s = (char *)*d + n * sizeof(**d);
1364         nn = 0;
1365         for (i = 0; i < ts; i += m) {
1366                 m = BIT16SZ + GBIT16((uint8_t *) & buf[i]);
1367                 if (nn >= n || /*convM2D */ convM2kdirent(&buf[i], m, *d + nn, s) != m) {
1368                         kfree(*d);
1369                         *d = NULL;
1370                         error("bad directory entry");
1371                 }
1372                 nn++;
1373                 s += m;
1374         }
1375
1376         return nn;
1377 }
1378
1379 long sysdirread(int fd, struct kdirent **d)
1380 {
1381         ERRSTACK(2);
1382         uint8_t *buf;
1383         long ts;
1384
1385         *d = NULL;
1386         if (waserror()) {
1387                 poperror();
1388                 return -1;
1389         }
1390         buf = kzmalloc(DIRREADLIM, 0);
1391         if (buf == NULL)
1392                 error(Enomem);
1393         if (waserror()) {
1394                 kfree(buf);
1395                 nexterror();
1396         }
1397         ts = sysread(fd, buf, DIRREADLIM);
1398         if (ts >= 0)
1399                 ts = dirpackage(buf, ts, d);
1400         poperror();
1401         kfree(buf);
1402         poperror();
1403         return ts;
1404 }
1405
1406 int sysiounit(int fd)
1407 {
1408         ERRSTACK(1);
1409         struct chan *c;
1410         int n;
1411
1412         c = fdtochan(current->fgrp, fd, -1, 0, 1);
1413         if (waserror()) {
1414                 cclose(c);
1415                 poperror();
1416                 return 0;       /* n.b. */
1417         }
1418         n = c->iounit;
1419         poperror();
1420         cclose(c);
1421         return n;
1422 }
1423
1424 /* Notes on concurrency:
1425  * - Can't hold spinlocks while we call cclose, since it might sleep eventually.
1426  * - We're called from proc_destroy, so we could have concurrent openers trying
1427  *   to add to the group (other syscalls), hence the "closed" flag.
1428  * - dot and slash chans are dealt with in proc_free.  its difficult to close
1429  *   and zero those with concurrent syscalls, since those are a source of krefs.
1430  * - the memory is freed in proc_free().  need to wait to do it, since we can
1431  *   have concurrent accesses to fgrp before free.
1432  * - Once we lock and set closed, no further additions can happen.  To simplify
1433  *   our closes, we also allow multiple calls to this func (though that should
1434  *   never happen with the current code). */
1435 void close_9ns_files(struct proc *p, bool only_cloexec)
1436 {
1437         
1438         struct fgrp *f = p->fgrp;
1439
1440         spin_lock(&f->lock);
1441         if (f->closed) {
1442                 spin_unlock(&f->lock);
1443                 warn("Unexpected double-close");
1444                 return;
1445         }
1446         if (!only_cloexec)
1447                 f->closed = TRUE;
1448         spin_unlock(&f->lock);
1449
1450         /* maxfd is a legit val, not a +1 */
1451         for (int i = 0; i <= f->maxfd; i++) {
1452                 if (!f->fd[i])
1453                         continue;
1454                 if (only_cloexec && !(f->fd[i]->flag & CCEXEC))
1455                         continue;
1456                 cclose(f->fd[i]);
1457                 f->fd[i] = 0;
1458         }
1459 }
1460
1461 void print_chaninfo(struct chan *c)
1462 {
1463         
1464         char buf[64] = { 0 };
1465         bool has_dev = c->type != -1;
1466         if (has_dev && !devtab[c->type].chaninfo) {
1467                 printk("Chan type %d has no chaninfo!\n", c->type);
1468                 has_dev = FALSE;
1469         }
1470         printk("Chan pathname: %s ref %d, Dev: %s, Devinfo: %s",
1471                    c->name ? c->name->s : "no cname",
1472                    kref_refcnt(&c->ref),
1473                    has_dev ? devtab[c->type].name : "no dev",
1474                    has_dev ? devtab[c->type].chaninfo(c, buf, sizeof(buf)) : "");
1475         if (!has_dev)
1476                 printk("qid.path: %p\n", c->qid.path);
1477         printk("\n");
1478 }
1479
1480 void print_9ns_files(struct proc *p)
1481 {
1482         
1483         struct fgrp *f = p->fgrp;
1484         spin_lock(&f->lock);
1485         printk("9ns files for proc %d:\n", p->pid);
1486         /* maxfd is a legit val, not a +1 */
1487         for (int i = 0; i <= f->maxfd; i++) {
1488                 if (!f->fd[i])
1489                         continue;
1490                 printk("\t9fs %4d, ", i);
1491                 print_chaninfo(f->fd[i]);
1492         }
1493         spin_unlock(&f->lock);
1494 }
1495
1496 /* TODO: 9ns ns inheritance flags: Shared, copied, or empty.  Looks like we're
1497  * copying the fgrp, and sharing the pgrp. */
1498 int plan9setup(struct proc *new_proc, struct proc *parent, int flags)
1499 {
1500         
1501         struct proc *old_current;
1502         struct kref *new_dot_ref;
1503         ERRSTACK(1);
1504         if (waserror()) {
1505                 printk("plan9setup failed, %s\n", current_errstr());
1506                 poperror();
1507                 return -1;
1508         }
1509         if (!parent) {
1510                 /* We are probably spawned by the kernel directly, and have no parent to
1511                  * inherit from.  Be sure to set up fgrp/pgrp before calling namec().
1512                  *
1513                  * TODO: One problem is namec wants a current set for things like
1514                  * genbuf.  So we'll use new_proc for this bootstrapping.  Note
1515                  * switch_to() also loads the cr3. */
1516                 new_proc->fgrp = newfgrp();
1517                 new_proc->pgrp = newpgrp();
1518                 old_current = switch_to(new_proc);
1519                 new_proc->slash = namec("#r", Atodir, 0, 0);
1520                 if (!new_proc->slash)
1521                         panic("no root device");
1522                 switch_back(new_proc, old_current);
1523                 /* Want the name to be "/" instead of "#r" */
1524                 cnameclose(new_proc->slash->name);
1525                 new_proc->slash->name = newcname("/");
1526                 new_proc->dot = cclone(new_proc->slash);
1527                 poperror();
1528                 return 0;
1529         }
1530         /* When we use the old fgrp, we have copy semantics: do not change this
1531          * without revisiting proc_destroy, close_9ns_files, and closefgrp. */
1532         if (flags & PROC_DUP_FGRP)
1533                 new_proc->fgrp = dupfgrp(new_proc, parent->fgrp);
1534         else
1535                 new_proc->fgrp = newfgrp();
1536         /* Shared semantics */
1537         kref_get(&parent->pgrp->ref, 1);
1538         new_proc->pgrp = parent->pgrp;
1539         /* copy semantics on / and . (doesn't make a lot of sense in akaros o/w) */
1540         /* / should never disappear while we hold a ref to parent */
1541         chan_incref(parent->slash);
1542         new_proc->slash = parent->slash;
1543         /* dot could change concurrently, and we could fail to gain a ref if whoever
1544          * decref'd dot triggered the release.  if that did happen, new_proc->dot
1545          * should update and we can try again. */
1546         while (!(new_dot_ref = kref_get_not_zero(&parent->dot->ref, 1)))
1547                 cpu_relax();
1548         /* And now, we can't trust parent->dot, and need to determine our dot from
1549          * the ref we obtained. */
1550         new_proc->dot = container_of(new_dot_ref, struct chan, ref);
1551         poperror();
1552         return 0;
1553 }
1554
1555 /* Open flags, create modes, access types, file flags, and all that...
1556  *
1557  * there are a bunch of things here:
1558  *              1) file creation flags (e.g. O_TRUNC)
1559  *              2) file status flags (e.g. O_APPEND)
1560  *              3) file open modes (e.g. O_RDWR)
1561  *              4) file descriptor flags (e.g. CLOEXEC)
1562  *              5) file creation mode (e.g. S_IRWXU)
1563  * the 1-4 are passed in via open's vfs_flags, and the 5 via mode only when
1564  * O_CREATE is set.
1565  *
1566  * file creation flags (1) only matter when creating, but aren't permanent.
1567  * O_EXCL, O_DIRECTORY, O_TRUNC, etc.
1568  *
1569  * file status flags (2) are per struct file/chan.  stuff like O_APPEND,
1570  * O_ASYNC, etc.  we convert those to an internal flag bit and store in c->flags
1571  *
1572  * the open mode (3) matters for a given FD/chan (chan->mode), and should be
1573  * stored in the chan. (c->mode) stuff like O_RDONLY.
1574  *
1575  * the file descriptor flags (4) clearly are in the FD.  note that the same
1576  * file/chan can be opened by two different FDs, with different flags.  the only
1577  * one anyone uses is CLOEXEC.  while exec may not last long in akaros, i can
1578  * imagine similar "never pass to children" flags/meanings.
1579  *
1580  * the file creation mode (5) matters for the device's permissions; given this,
1581  * it should be stored in the device/inode.  ACLs fall under this category.
1582  *
1583  * finally, only certain categories can be edited afterwards: file status flags
1584  * (2), FD flags (4), and file permissions (5). */
1585 int fd_getfl(int fd)
1586 {
1587         ERRSTACK(1);
1588         struct chan *c;
1589         int ret;
1590
1591         if (waserror()) {
1592                 poperror();
1593                 return -1;
1594         }
1595         c = fdtochan(current->fgrp, fd, -1, 0, 1);
1596
1597         ret = c->mode;
1598         if (c->flag & CAPPEND)
1599                 ret |= O_APPEND;
1600
1601         cclose(c);
1602         poperror();
1603         return ret;
1604 }
1605
1606 int fd_setfl(int fd, int flags)
1607 {
1608         ERRSTACK(1);
1609         struct chan *c;
1610
1611         if (waserror()) {
1612                 poperror();
1613                 return -1;
1614         }
1615         c = fdtochan(current->fgrp, fd, -1, 0, 1);
1616
1617         if (flags & O_APPEND)
1618                 c->flag |= CAPPEND;
1619
1620         cclose(c);
1621         poperror();
1622         return 0;
1623 }