SYS_dup_fds_to (XCC)
[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 /* Could pass in the fgrp instead of the proc, but we need the to_proc for now
350  * so we can claim a VFS FD */
351 int sys_dup_to(struct proc *from_proc, unsigned int from_fd,
352                struct proc *to_proc, unsigned int to_fd)
353 {
354         ERRSTACK(1);
355         struct chan *c, *old_chan;
356         struct fgrp *to_fgrp = to_proc->fgrp;
357
358         if (waserror()) {
359                 poperror();
360                 return -1;
361         }
362
363         c = fdtochan(from_proc->fgrp, from_fd, -1, 0, 1);
364         if (c->qid.type & QTAUTH) {
365                 cclose(c);
366                 error(Eperm);
367         }
368
369         spin_lock(&to_fgrp->lock);
370         if (to_fgrp->closed) {
371                 spin_unlock(&to_fgrp->lock);
372                 cclose(c);
373                 error("Can't dup, FGRP closed");
374         }
375         if (claim_fd(&to_proc->open_files, to_fd)) {
376                 spin_unlock(&to_fgrp->lock);
377                 cclose(c);
378                 error("Can't claim FD %d", to_fd);
379         }
380         if (growfd(to_fgrp, to_fd) < 0) {
381                 spin_unlock(&to_fgrp->lock);
382                 cclose(c);
383                 error("Couldn't grow, to_fd %d", to_fd);
384         }
385         if (to_fd > to_fgrp->maxfd)
386                 to_fgrp->maxfd = to_fd;
387         old_chan = to_fgrp->fd[to_fd];
388         to_fgrp->fd[to_fd] = c;
389         spin_unlock(&to_fgrp->lock);
390         if (old_chan)
391                 cclose(old_chan);
392
393         poperror();
394         return 0;
395 }
396
397 char *sysfd2path(int fd)
398 {
399         ERRSTACK(1);
400         struct chan *c;
401         char *s;
402
403         if (waserror()) {
404                 poperror();
405                 return NULL;
406         }
407         c = fdtochan(current->fgrp, fd, -1, 0, 1);
408         s = NULL;
409         if (c->name != NULL) {
410                 s = kzmalloc(c->name->len + 1, 0);
411                 if (s == NULL) {
412                         cclose(c);
413                         error(Enomem);
414                 }
415                 memmove(s, c->name->s, c->name->len + 1);
416         }
417         cclose(c);
418         poperror();
419         return s;
420 }
421
422 int sysfauth(int fd, char *aname)
423 {
424         ERRSTACK(2);
425         struct chan *c, *ac;
426
427         if (waserror()) {
428                 poperror();
429                 return -1;
430         }
431
432         validname(aname, 0);
433         c = fdtochan(current->fgrp, fd, ORDWR, 0, 1);
434         if (waserror()) {
435                 cclose(c);
436                 nexterror();
437         }
438
439         ac = mntauth(c, aname);
440
441         /* at this point ac is responsible for keeping c alive */
442         poperror();     /* c */
443         cclose(c);
444
445         if (waserror()) {
446                 cclose(ac);
447                 nexterror();
448         }
449
450         fd = newfd(ac);
451         if (fd < 0)
452                 error(Enofd);
453         poperror();     /* ac */
454
455         poperror();
456
457         return fd;
458 }
459
460 int sysfversion(int fd, unsigned int msize, char *vers, unsigned int arglen)
461 {
462         ERRSTACK(2);
463         int m;
464         struct chan *c;
465
466         if (waserror()) {
467                 poperror();
468                 return -1;
469         }
470
471         /* check there's a NUL in the version string */
472         if (arglen == 0 || memchr(vers, 0, arglen) == 0)
473                 error(Ebadarg);
474
475         c = fdtochan(current->fgrp, fd, ORDWR, 0, 1);
476         if (waserror()) {
477                 cclose(c);
478                 nexterror();
479         }
480
481         m = mntversion(c, vers, msize, arglen);
482
483         poperror();
484         cclose(c);
485
486         poperror();
487         return m;
488 }
489
490 int syspipe(int fd[2])
491 {
492         ERRSTACK(1);
493         struct dev *d;
494         struct fgrp *f;
495         struct chan *c[2];
496         static char *names[] = { "data", "data1" };
497
498         f = current->fgrp;
499
500         d = &devtab[devno('|', 0)];
501         c[0] = namec("#|", Atodir, 0, 0);
502         c[1] = 0;
503         fd[0] = -1;
504         fd[1] = -1;
505         if (waserror()) {
506                 if (c[0] != 0)
507                         cclose(c[0]);
508                 if (c[1] != 0)
509                         cclose(c[1]);
510                 if (fd[0] >= 0) {
511                         /* VFS hack */
512                         f->fd[fd[0]] = 0;
513                         put_fd(&current->open_files, fd[0]);
514                 }
515                 if (fd[1] >= 0) {
516                         /* VFS hack */
517                         f->fd[fd[1]] = 0;
518                         put_fd(&current->open_files, fd[1]);
519                 }
520                 poperror();
521                 return -1;
522         }
523         c[1] = cclone(c[0]);
524         if (walk(&c[0], &names[0], 1, 1, NULL) < 0)
525                 error(Egreg);
526         if (walk(&c[1], &names[1], 1, 1, NULL) < 0)
527                 error(Egreg);
528         c[0] = d->open(c[0], ORDWR);
529         c[1] = d->open(c[1], ORDWR);
530         fd[0] = newfd(c[0]);
531         if (fd[0] < 0)
532                 error(Enofd);
533         fd[1] = newfd(c[1]);
534         if (fd[1] < 0)
535                 error(Enofd);
536         poperror();
537         return 0;
538 }
539
540 int sysfwstat(int fd, uint8_t * buf, int n)
541 {
542         ERRSTACK(2);
543         struct chan *c;
544
545         if (waserror()) {
546                 poperror();
547                 return -1;
548         }
549
550         validstat(buf, n, 0);
551         c = fdtochan(current->fgrp, fd, -1, 1, 1);
552         if (waserror()) {
553                 cclose(c);
554                 nexterror();
555         }
556         n = devtab[c->type].wstat(c, buf, n);
557         poperror();
558         cclose(c);
559
560         poperror();
561         return n;
562 }
563
564 long bindmount(struct chan *c, char *old, int flag, char *spec)
565 {
566         ERRSTACK(1);
567         int ret;
568         struct chan *c1;
569
570         if (flag > MMASK || (flag & MORDER) == (MBEFORE | MAFTER))
571                 error(Ebadarg);
572
573         c1 = namec(old, Amount, 0, 0);
574         if (waserror()) {
575                 cclose(c1);
576                 nexterror();
577         }
578         ret = cmount(c, c1, flag, spec);
579
580         poperror();
581         cclose(c1);
582         return ret;
583 }
584
585 int sysbind(char *new, char *old, int flags)
586 {
587         ERRSTACK(2);
588         long r;
589         struct chan *c0;
590
591         if (waserror()) {
592                 poperror();
593                 return -1;
594         }
595
596         c0 = namec(new, Abind, 0, 0);
597         if (waserror()) {
598                 cclose(c0);
599                 nexterror();
600         }
601         r = bindmount(c0, old, flags, "");
602         poperror();
603         cclose(c0);
604
605         poperror();
606         return r;
607 }
608
609 int sysmount(int fd, int afd, char *old, int flags, char *spec)
610 {
611         ERRSTACK(1);
612         long r;
613         volatile struct {
614                 struct chan *c;
615         } c0;
616         volatile struct {
617                 struct chan *c;
618         } bc;
619         volatile struct {
620                 struct chan *c;
621         } ac;
622         struct mntparam mntparam;
623
624         ac.c = NULL;
625         bc.c = NULL;
626         c0.c = NULL;
627         if (waserror()) {
628                 cclose(ac.c);
629                 cclose(bc.c);
630                 cclose(c0.c);
631                 poperror();
632                 return -1;
633         }
634         bc.c = fdtochan(current->fgrp, fd, ORDWR, 0, 1);
635         if (afd >= 0)
636                 ac.c = fdtochan(current->fgrp, afd, ORDWR, 0, 1);
637         mntparam.chan = bc.c;
638         mntparam.authchan = ac.c;
639         mntparam.spec = spec;
640         mntparam.flags = flags;
641         c0.c = devtab[devno('M', 0)].attach((char *)&mntparam);
642
643         r = bindmount(c0.c, old, flags, spec);
644         poperror();
645         cclose(ac.c);
646         cclose(bc.c);
647         cclose(c0.c);
648
649         return r;
650 }
651
652 int sysunmount(char *old, char *new)
653 {
654         ERRSTACK(1);
655         volatile struct {
656                 struct chan *c;
657         } cmount;
658         volatile struct {
659                 struct chan *c;
660         } cmounted;
661
662         cmount.c = NULL;
663         cmounted.c = NULL;
664         if (waserror()) {
665                 cclose(cmount.c);
666                 cclose(cmounted.c);
667                 poperror();
668                 return -1;
669         }
670
671         cmount.c = namec(new, Amount, 0, 0);
672         if (old != NULL && old[0] != '\0') {
673                 /*
674                  * This has to be namec(..., Aopen, ...) because
675                  * if arg[0] is something like /srv/cs or /fd/0,
676                  * opening it is the only way to get at the real
677                  * Chan underneath.
678                  */
679                 cmounted.c = namec(old, Aopen, OREAD, 0);
680         }
681
682         cunmount(cmount.c, cmounted.c);
683         poperror();
684         cclose(cmount.c);
685         cclose(cmounted.c);
686         return 0;
687 }
688
689 int sysopen(char *path, int vfs_flags)
690 {
691         ERRSTACK(2);
692         int fd;
693         struct chan *c;
694
695         if (waserror()) {
696                 poperror();
697                 return -1;
698         }
699
700         openmode(vfs_flags);    /* error check only */
701         c = namec(path, Aopen, vfs_flags, 0);
702         if (waserror()) {
703                 cclose(c);
704                 nexterror();
705         }
706         fd = newfd(c);
707         if (fd < 0)
708                 error(Enofd);
709         poperror();
710
711         poperror();
712         return fd;
713 }
714
715 long unionread(struct chan *c, void *va, long n)
716 {
717         ERRSTACK(1);
718         int i;
719         long nr;
720         struct mhead *m;
721         struct mount *mount;
722
723         qlock(&c->umqlock);
724         m = c->umh;
725         rlock(&m->lock);
726         mount = m->mount;
727         /* bring mount in sync with c->uri and c->umc */
728         for (i = 0; mount != NULL && i < c->uri; i++)
729                 mount = mount->next;
730
731         nr = 0;
732         while (mount != NULL) {
733                 /* Error causes component of union to be skipped */
734                 if (mount->to) {
735                         /* normally we want to discard the error, but for our ghetto kdirent
736                          * hack, we need to repeat unionread if we saw a Eshort */
737                         if (waserror()) {
738                                 if (!strcmp(current_errstr(), Eshort)) {
739                                         runlock(&m->lock);
740                                         qunlock(&c->umqlock);
741                                         nexterror();
742                                 }
743                                 /* poperror done below for either branch */
744                         } else {
745                                 if (c->umc == NULL) {
746                                         c->umc = cclone(mount->to);
747                                         c->umc = devtab[c->umc->type].open(c->umc, OREAD);
748                                 }
749
750                                 nr = devtab[c->umc->type].read(c->umc, va, n, c->umc->offset);
751                                 if (nr < 0)
752                                         nr = 0; /* dev.c can return -1 */
753                                 c->umc->offset += nr;
754                         }
755                         poperror();     /* pop regardless */
756                 }
757                 if (nr > 0)
758                         break;
759
760                 /* Advance to next element */
761                 c->uri++;
762                 if (c->umc) {
763                         cclose(c->umc);
764                         c->umc = NULL;
765                 }
766                 mount = mount->next;
767         }
768         runlock(&m->lock);
769         qunlock(&c->umqlock);
770         return nr;
771 }
772
773 static void unionrewind(struct chan *c)
774 {
775         qlock(&c->umqlock);
776         c->uri = 0;
777         if (c->umc) {
778                 cclose(c->umc);
779                 c->umc = NULL;
780         }
781         qunlock(&c->umqlock);
782 }
783
784 static long rread(int fd, void *va, long n, int64_t * offp)
785 {
786         ERRSTACK(3);
787         int dir;
788         struct chan *c;
789         int64_t off;
790
791         /* dirty dirent hack */
792         void *real_va = va;
793
794         if (waserror()) {
795                 poperror();
796                 return -1;
797         }
798
799         c = fdtochan(current->fgrp, fd, OREAD, 1, 1);
800         if (waserror()) {
801                 cclose(c);
802                 nexterror();
803         }
804
805         if (n < 0)
806                 error(Etoosmall);
807
808         dir = c->qid.type & QTDIR;
809
810         /* kdirent hack: userspace is expecting kdirents, but all of 9ns
811          * produces Ms.  Just save up what we don't use and append the
812          * new stuff later. Allocate DIRREADSIZE bytes for that purpose.
813          */
814         if (dir) {
815                 int amt;
816                 /* expecting only one dirent at a time, o/w we're busted */
817                 assert(n >= sizeof(struct kdirent));
818                 if (!c->buf) {
819                         c->buf=kmalloc(DIRREADSIZE, KMALLOC_WAIT);
820                         c->bufused = 0;
821                 }
822                 /* Attempt to extract an M, in case there was some already */
823                 amt = convM2kdirent(c->buf, c->bufused, real_va, 0);
824                 if (amt) {
825                         c->bufused -= amt;
826                         memmove(c->buf, c->buf + amt, c->bufused);
827                         n = sizeof(struct kdirent);
828                         goto out;
829                 }
830                 /* debugging */
831                 if (waserror()) {
832                         printk("Well, sysread of a dir sucks.%s \n", current_errstr());
833                         nexterror();
834                 }
835                 va = c->buf + c->bufused;
836                 n = DIRREADSIZE - c->bufused;
837         }
838
839         /* this is the normal plan9 read */
840         if (dir && c->umh)
841                 n = unionread(c, va, n);
842         else {
843                 if (offp == NULL) {
844                         spin_lock(&c->lock);    /* lock for int64_t assignment */
845                         off = c->offset;
846                         spin_unlock(&c->lock);
847                 } else
848                         off = *offp;
849                 if (off < 0)
850                         error(Enegoff);
851                 if (off == 0) {
852                         if (offp == NULL) {
853                                 spin_lock(&c->lock);
854                                 c->offset = 0;
855                                 c->dri = 0;
856                                 spin_unlock(&c->lock);
857                         }
858                         unionrewind(c);
859                 }
860                 if (! c->ateof) {
861                         n = devtab[c->type].read(c, va, n, off);
862                         if (n == 0 && dir)
863                                 c->ateof = 1;
864                 } else {
865                         n = 0;
866                 }
867                 spin_lock(&c->lock);
868                 c->offset += n;
869                 spin_unlock(&c->lock);
870         }
871
872         /* dirty kdirent hack */
873         if (dir) {
874                 int amt;
875                 c->bufused = c->bufused + n;
876                 /* extract an M from the front, then shift the remainder back */
877                 amt = convM2kdirent(c->buf, c->bufused, real_va, 0);
878                 c->bufused -= amt;
879                 memmove(c->buf, c->buf + amt, c->bufused);
880                 n = amt ? sizeof(struct kdirent) : 0;
881                 poperror();     /* matching our debugging waserror */
882         }
883
884 out:
885         poperror();
886         cclose(c);
887
888         poperror();
889         return n;
890 }
891
892 long sysread(int fd, void *va, long n)
893 {
894         return rread(fd, va, n, NULL);
895 }
896
897 long syspread(int fd, void *va, long n, int64_t off)
898 {
899         return rread(fd, va, n, &off);
900 }
901
902 int sysremove(char *path)
903 {
904         ERRSTACK(2);
905         struct chan *c;
906
907         if (waserror()) {
908                 poperror();
909                 return -1;
910         }
911
912         c = namec(path, Aremove, 0, 0);
913         if (waserror()) {
914                 c->type = -1;   /* see below */
915                 cclose(c);
916                 nexterror();
917         }
918         devtab[c->type].remove(c);
919         /*
920          * Remove clunks the fid, but we need to recover the Chan
921          * so fake it up.  -1 aborts the dev's close.
922          */
923         c->type = -1;
924         poperror();
925         cclose(c);
926
927         poperror();
928         return 0;
929 }
930
931 int64_t sysseek(int fd, int64_t off, int whence)
932 {
933         ERRSTACK(2);
934         struct dir *dir;
935         struct chan *c;
936
937         if (waserror()) {
938                 poperror();
939                 return -1;
940         }
941
942         c = fdtochan(current->fgrp, fd, -1, 1, 1);
943         if (waserror()) {
944                 cclose(c);
945                 nexterror();
946         }
947
948         if (devtab[c->type].dc == '|')
949                 error(Eisstream);
950
951         switch (whence) {
952                 case 0:
953                         if (c->qid.type & QTDIR) {
954                                 if (off != 0)
955                                         error(Eisdir);
956                                 unionrewind(c);
957                         } else if (off < 0)
958                                 error(Enegoff);
959                         spin_lock(&c->lock);    /* lock for int64_t assignment */
960                         c->offset = off;
961                         spin_unlock(&c->lock);
962                         break;
963
964                 case 1:
965                         if (c->qid.type & QTDIR)
966                                 error(Eisdir);
967                         spin_lock(&c->lock);    /* lock for read/write update */
968                         off += c->offset;
969                         if (off < 0) {
970                                 spin_unlock(&c->lock);
971                                 error(Enegoff);
972                         }
973                         c->offset = off;
974                         spin_unlock(&c->lock);
975                         break;
976
977                 case 2:
978                         if (c->qid.type & QTDIR)
979                                 error(Eisdir);
980                         dir = chandirstat(c);
981                         if (dir == NULL)
982                                 error("internal error: stat error in seek");
983                         off += dir->length;
984                         kfree(dir);
985                         if (off < 0)
986                                 error(Enegoff);
987                         spin_lock(&c->lock);    /* lock for read/write update */
988                         c->offset = off;
989                         spin_unlock(&c->lock);
990                         break;
991
992                 default:
993                         error(Ebadarg);
994                         break;
995         }
996         poperror();
997         c->dri = 0;
998         cclose(c);
999         poperror();
1000         return off;
1001 }
1002
1003 void validstat(uint8_t * s, int n, int slashok)
1004 {
1005         
1006         int m;
1007         char buf[64];
1008
1009         if (statcheck(s, n) < 0)
1010                 error(Ebadstat);
1011         /* verify that name entry is acceptable */
1012         s += STATFIXLEN - 4 * BIT16SZ;  /* location of first string */
1013         /*
1014          * s now points at count for first string.
1015          * if it's too long, let the server decide; this is
1016          * only for his protection anyway. otherwise
1017          * we'd have to allocate and waserror.
1018          */
1019         m = GBIT16(s);
1020         s += BIT16SZ;
1021         if (m + 1 > sizeof buf) {
1022                 return;
1023         }
1024         memmove(buf, s, m);
1025         buf[m] = '\0';
1026         /* name could be '/' */
1027         if (strcmp(buf, "/") != 0)
1028                 validname(buf, slashok);
1029 }
1030
1031 int sysfstat(int fd, uint8_t *buf, int n)
1032 {
1033         ERRSTACK(2);
1034         struct chan *c;
1035
1036         if (waserror()) {
1037                 poperror();
1038                 return -1;
1039         }
1040
1041         c = fdtochan(current->fgrp, fd, -1, 0, 1);
1042         if (waserror()) {
1043                 cclose(c);
1044                 nexterror();
1045         }
1046         devtab[c->type].stat(c, buf, n);
1047
1048         poperror();
1049         cclose(c);
1050
1051         poperror();
1052         return n;
1053 }
1054
1055 int sysfstatakaros(int fd, struct kstat *ks)
1056 {
1057         
1058         int n = 4096;
1059         uint8_t *buf;
1060         buf = kmalloc(n, KMALLOC_WAIT);
1061         n = sysfstat(fd, buf, n);
1062         if (n > 0) {
1063                 convM2kstat(buf, n, ks);
1064                 n = 0;
1065         }
1066         kfree(buf);
1067         return n;
1068 }
1069
1070 int sysstat(char *path, uint8_t *buf, int n)
1071 {
1072         ERRSTACK(2);
1073         struct chan *c;
1074
1075         if (waserror()) {
1076                 poperror();
1077                 return -1;
1078         }
1079
1080         c = namec(path, Aaccess, 0, 0);
1081         if (waserror()) {
1082                 cclose(c);
1083                 nexterror();
1084         }
1085         devtab[c->type].stat(c, buf, n);
1086         poperror();
1087         cclose(c);
1088
1089         poperror();
1090
1091         return n;
1092 }
1093
1094 int sysstatakaros(char *path, struct kstat *ks)
1095 {
1096         
1097         int n = 4096;
1098         uint8_t *buf;
1099         buf = kmalloc(n, KMALLOC_WAIT);
1100         n = sysstat(path, buf, n);
1101         if (n > 0) {
1102                 convM2kstat(buf, n, ks);
1103                 n = 0;
1104         }
1105         kfree(buf);
1106         return n;
1107 }
1108
1109 static long rwrite(int fd, void *va, long n, int64_t * offp)
1110 {
1111         ERRSTACK(3);
1112         struct chan *c;
1113         struct dir *dir;
1114         int64_t off;
1115         long m;
1116
1117         if (waserror()) {
1118                 poperror();
1119                 return -1;
1120         }
1121         c = fdtochan(current->fgrp, fd, OWRITE, 1, 1);
1122         if (waserror()) {
1123                 cclose(c);
1124                 nexterror();
1125         }
1126         if (c->qid.type & QTDIR)
1127                 error(Eisdir);
1128
1129         if (n < 0)
1130                 error(Etoosmall);
1131
1132         if (offp == NULL) {
1133                 /* append changes the offset to the end, and even if we fail later, this
1134                  * change will persist */
1135                 if (c->flag & CAPPEND) {
1136                         dir = chandirstat(c);
1137                         if (!dir)
1138                                 error("internal error: stat error in append write");
1139                         spin_lock(&c->lock);    /* legacy lock for int64 assignment */
1140                         c->offset = dir->length;
1141                         spin_unlock(&c->lock);
1142                         kfree(dir);
1143                 }
1144                 spin_lock(&c->lock);
1145                 off = c->offset;
1146                 c->offset += n;
1147                 spin_unlock(&c->lock);
1148         } else
1149                 off = *offp;
1150
1151         if (waserror()) {
1152                 if (offp == NULL) {
1153                         spin_lock(&c->lock);
1154                         c->offset -= n;
1155                         spin_unlock(&c->lock);
1156                 }
1157                 nexterror();
1158         }
1159         if (off < 0)
1160                 error(Enegoff);
1161         m = devtab[c->type].write(c, va, n, off);
1162         poperror();
1163
1164         if (offp == NULL && m < n) {
1165                 spin_lock(&c->lock);
1166                 c->offset -= n - m;
1167                 spin_unlock(&c->lock);
1168         }
1169
1170         poperror();
1171         cclose(c);
1172
1173         poperror();
1174         return n;
1175 }
1176
1177 long syswrite(int fd, void *va, long n)
1178 {
1179         return rwrite(fd, va, n, NULL);
1180 }
1181
1182 long syspwrite(int fd, void *va, long n, int64_t off)
1183 {
1184         return rwrite(fd, va, n, &off);
1185 }
1186
1187 int syswstat(char *path, uint8_t * buf, int n)
1188 {
1189         ERRSTACK(2);
1190         struct chan *c;
1191
1192         if (waserror()) {
1193                 poperror();
1194                 return -1;
1195         }
1196
1197         validstat(buf, n, 0);
1198         c = namec(path, Aaccess, 0, 0);
1199         if (waserror()) {
1200                 cclose(c);
1201                 nexterror();
1202         }
1203         n = devtab[c->type].wstat(c, buf, n);
1204         poperror();
1205         cclose(c);
1206
1207         poperror();
1208         return n;
1209 }
1210
1211 struct dir *chandirstat(struct chan *c)
1212 {
1213         ERRSTACK(1);
1214         struct dir *d;
1215         uint8_t *buf;
1216         int n, nd, i;
1217
1218         nd = DIRSIZE;
1219         for (i = 0; i < 2; i++) {       /* should work by the second try */
1220                 d = kzmalloc(sizeof(struct dir) + nd, 0);
1221                 buf = (uint8_t *) & d[1];
1222                 if (waserror()) {
1223                         kfree(d);
1224                         poperror();
1225                         return NULL;
1226                 }
1227                 n = devtab[c->type].stat(c, buf, nd);
1228                 poperror();
1229                 if (n < BIT16SZ) {
1230                         kfree(d);
1231                         return NULL;
1232                 }
1233                 nd = GBIT16((uint8_t *) buf) + BIT16SZ; /* size needed to store whole stat buffer including count */
1234                 if (nd <= n) {
1235                         convM2D(buf, n, d, (char *)&d[1]);
1236                         return d;
1237                 }
1238                 /* else sizeof(Dir)+nd is plenty */
1239                 kfree(d);
1240         }
1241         return NULL;
1242
1243 }
1244
1245 struct dir *sysdirstat(char *name)
1246 {
1247         ERRSTACK(2);
1248         struct chan *c;
1249         struct dir *d;
1250
1251         if (waserror()) {
1252                 poperror();
1253                 return NULL;
1254         }
1255
1256         c = namec(name, Aaccess, 0, 0);
1257         if (waserror()) {
1258                 cclose(c);
1259                 nexterror();
1260         }
1261         d = chandirstat(c);
1262         poperror();
1263         cclose(c);
1264
1265         poperror();
1266         return d;
1267 }
1268
1269 struct dir *sysdirfstat(int fd)
1270 {
1271         ERRSTACK(2);
1272         struct chan *c;
1273         struct dir *d;
1274
1275         if (waserror()) {
1276                 poperror();
1277                 return NULL;
1278         }
1279
1280         c = fdtochan(current->fgrp, fd, -1, 0, 1);
1281         if (waserror()) {
1282                 cclose(c);
1283                 nexterror();
1284         }
1285         d = chandirstat(c);
1286         poperror();
1287         cclose(c);
1288
1289         poperror();
1290         return d;
1291 }
1292
1293 int sysdirwstat(char *name, struct dir *dir)
1294 {
1295         
1296         uint8_t *buf;
1297         int r;
1298
1299         r = sizeD2M(dir);
1300         buf = kzmalloc(r, 0);
1301         convD2M(dir, buf, r);
1302         r = syswstat(name, buf, r);
1303         kfree(buf);
1304         return r < 0 ? r : 0;
1305 }
1306
1307 int sysdirfwstat(int fd, struct dir *dir)
1308 {
1309         
1310         uint8_t *buf;
1311         int r;
1312
1313         r = sizeD2M(dir);
1314         buf = kzmalloc(r, 0);
1315         convD2M(dir, buf, r);
1316         r = sysfwstat(fd, buf, r);
1317         kfree(buf);
1318         return r < 0 ? r : 0;
1319 }
1320
1321 static long dirpackage(uint8_t * buf, long ts, struct kdirent **d)
1322 {
1323         
1324         char *s;
1325         long ss, i, n, nn, m = 0;
1326
1327         *d = NULL;
1328         if (ts <= 0) {
1329                 return ts;
1330         }
1331
1332         /*
1333          * first find number of all stats, check they look like stats, & size all associated strings
1334          */
1335         ss = 0;
1336         n = 0;
1337         for (i = 0; i < ts; i += m) {
1338                 m = BIT16SZ + GBIT16(&buf[i]);
1339                 if (statcheck(&buf[i], m) < 0)
1340                         break;
1341                 ss += m;
1342                 n++;
1343         }
1344
1345         if (i != ts)
1346                 error("bad directory format");
1347
1348         *d = kzmalloc(n * sizeof(**d) + ss, 0);
1349         if (*d == NULL)
1350                 error(Enomem);
1351
1352         /*
1353          * then convert all buffers
1354          */
1355         s = (char *)*d + n * sizeof(**d);
1356         nn = 0;
1357         for (i = 0; i < ts; i += m) {
1358                 m = BIT16SZ + GBIT16((uint8_t *) & buf[i]);
1359                 if (nn >= n || /*convM2D */ convM2kdirent(&buf[i], m, *d + nn, s) != m) {
1360                         kfree(*d);
1361                         *d = NULL;
1362                         error("bad directory entry");
1363                 }
1364                 nn++;
1365                 s += m;
1366         }
1367
1368         return nn;
1369 }
1370
1371 long sysdirread(int fd, struct kdirent **d)
1372 {
1373         ERRSTACK(2);
1374         uint8_t *buf;
1375         long ts;
1376
1377         *d = NULL;
1378         if (waserror()) {
1379                 poperror();
1380                 return -1;
1381         }
1382         buf = kzmalloc(DIRREADLIM, 0);
1383         if (buf == NULL)
1384                 error(Enomem);
1385         if (waserror()) {
1386                 kfree(buf);
1387                 nexterror();
1388         }
1389         ts = sysread(fd, buf, DIRREADLIM);
1390         if (ts >= 0)
1391                 ts = dirpackage(buf, ts, d);
1392         poperror();
1393         kfree(buf);
1394         poperror();
1395         return ts;
1396 }
1397
1398 int sysiounit(int fd)
1399 {
1400         ERRSTACK(1);
1401         struct chan *c;
1402         int n;
1403
1404         c = fdtochan(current->fgrp, fd, -1, 0, 1);
1405         if (waserror()) {
1406                 cclose(c);
1407                 poperror();
1408                 return 0;       /* n.b. */
1409         }
1410         n = c->iounit;
1411         poperror();
1412         cclose(c);
1413         return n;
1414 }
1415
1416 /* Notes on concurrency:
1417  * - Can't hold spinlocks while we call cclose, since it might sleep eventually.
1418  * - We're called from proc_destroy, so we could have concurrent openers trying
1419  *   to add to the group (other syscalls), hence the "closed" flag.
1420  * - dot and slash chans are dealt with in proc_free.  its difficult to close
1421  *   and zero those with concurrent syscalls, since those are a source of krefs.
1422  * - the memory is freed in proc_free().  need to wait to do it, since we can
1423  *   have concurrent accesses to fgrp before free.
1424  * - Once we lock and set closed, no further additions can happen.  To simplify
1425  *   our closes, we also allow multiple calls to this func (though that should
1426  *   never happen with the current code). */
1427 void close_9ns_files(struct proc *p, bool only_cloexec)
1428 {
1429         
1430         struct fgrp *f = p->fgrp;
1431
1432         spin_lock(&f->lock);
1433         if (f->closed) {
1434                 spin_unlock(&f->lock);
1435                 warn("Unexpected double-close");
1436                 return;
1437         }
1438         if (!only_cloexec)
1439                 f->closed = TRUE;
1440         spin_unlock(&f->lock);
1441
1442         /* maxfd is a legit val, not a +1 */
1443         for (int i = 0; i <= f->maxfd; i++) {
1444                 if (!f->fd[i])
1445                         continue;
1446                 if (only_cloexec && !(f->fd[i]->flag & CCEXEC))
1447                         continue;
1448                 cclose(f->fd[i]);
1449                 f->fd[i] = 0;
1450         }
1451 }
1452
1453 void print_chaninfo(struct chan *c)
1454 {
1455         
1456         char buf[64] = { 0 };
1457         bool has_dev = c->type != -1;
1458         if (has_dev && !devtab[c->type].chaninfo) {
1459                 printk("Chan type %d has no chaninfo!\n", c->type);
1460                 has_dev = FALSE;
1461         }
1462         printk("Chan pathname: %s ref %d, Dev: %s, Devinfo: %s",
1463                    c->name ? c->name->s : "no cname",
1464                    kref_refcnt(&c->ref),
1465                    has_dev ? devtab[c->type].name : "no dev",
1466                    has_dev ? devtab[c->type].chaninfo(c, buf, sizeof(buf)) : "");
1467         if (!has_dev)
1468                 printk("qid.path: %p\n", c->qid.path);
1469         printk("\n");
1470 }
1471
1472 void print_9ns_files(struct proc *p)
1473 {
1474         
1475         struct fgrp *f = p->fgrp;
1476         spin_lock(&f->lock);
1477         printk("9ns files for proc %d:\n", p->pid);
1478         /* maxfd is a legit val, not a +1 */
1479         for (int i = 0; i <= f->maxfd; i++) {
1480                 if (!f->fd[i])
1481                         continue;
1482                 printk("\t9fs %4d, ", i);
1483                 print_chaninfo(f->fd[i]);
1484         }
1485         spin_unlock(&f->lock);
1486 }
1487
1488 /* TODO: 9ns ns inheritance flags: Shared, copied, or empty.  Looks like we're
1489  * copying the fgrp, and sharing the pgrp. */
1490 int plan9setup(struct proc *new_proc, struct proc *parent, int flags)
1491 {
1492         
1493         struct proc *old_current;
1494         struct kref *new_dot_ref;
1495         ERRSTACK(1);
1496         if (waserror()) {
1497                 printk("plan9setup failed, %s\n", current_errstr());
1498                 poperror();
1499                 return -1;
1500         }
1501         if (!parent) {
1502                 /* We are probably spawned by the kernel directly, and have no parent to
1503                  * inherit from.  Be sure to set up fgrp/pgrp before calling namec().
1504                  *
1505                  * TODO: One problem is namec wants a current set for things like
1506                  * genbuf.  So we'll use new_proc for this bootstrapping.  Note
1507                  * switch_to() also loads the cr3. */
1508                 new_proc->fgrp = newfgrp();
1509                 new_proc->pgrp = newpgrp();
1510                 old_current = switch_to(new_proc);
1511                 new_proc->slash = namec("#r", Atodir, 0, 0);
1512                 if (!new_proc->slash)
1513                         panic("no root device");
1514                 switch_back(new_proc, old_current);
1515                 /* Want the name to be "/" instead of "#r" */
1516                 cnameclose(new_proc->slash->name);
1517                 new_proc->slash->name = newcname("/");
1518                 new_proc->dot = cclone(new_proc->slash);
1519                 poperror();
1520                 return 0;
1521         }
1522         /* When we use the old fgrp, we have copy semantics: do not change this
1523          * without revisiting proc_destroy, close_9ns_files, and closefgrp. */
1524         if (flags & PROC_DUP_FGRP)
1525                 new_proc->fgrp = dupfgrp(new_proc, parent->fgrp);
1526         else
1527                 new_proc->fgrp = newfgrp();
1528         /* Shared semantics */
1529         kref_get(&parent->pgrp->ref, 1);
1530         new_proc->pgrp = parent->pgrp;
1531         /* copy semantics on / and . (doesn't make a lot of sense in akaros o/w) */
1532         /* / should never disappear while we hold a ref to parent */
1533         chan_incref(parent->slash);
1534         new_proc->slash = parent->slash;
1535         /* dot could change concurrently, and we could fail to gain a ref if whoever
1536          * decref'd dot triggered the release.  if that did happen, new_proc->dot
1537          * should update and we can try again. */
1538         while (!(new_dot_ref = kref_get_not_zero(&parent->dot->ref, 1)))
1539                 cpu_relax();
1540         /* And now, we can't trust parent->dot, and need to determine our dot from
1541          * the ref we obtained. */
1542         new_proc->dot = container_of(new_dot_ref, struct chan, ref);
1543         poperror();
1544         return 0;
1545 }
1546
1547 /* Open flags, create modes, access types, file flags, and all that...
1548  *
1549  * there are a bunch of things here:
1550  *              1) file creation flags (e.g. O_TRUNC)
1551  *              2) file status flags (e.g. O_APPEND)
1552  *              3) file open modes (e.g. O_RDWR)
1553  *              4) file descriptor flags (e.g. CLOEXEC)
1554  *              5) file creation mode (e.g. S_IRWXU)
1555  * the 1-4 are passed in via open's vfs_flags, and the 5 via mode only when
1556  * O_CREATE is set.
1557  *
1558  * file creation flags (1) only matter when creating, but aren't permanent.
1559  * O_EXCL, O_DIRECTORY, O_TRUNC, etc.
1560  *
1561  * file status flags (2) are per struct file/chan.  stuff like O_APPEND,
1562  * O_ASYNC, etc.  we convert those to an internal flag bit and store in c->flags
1563  *
1564  * the open mode (3) matters for a given FD/chan (chan->mode), and should be
1565  * stored in the chan. (c->mode) stuff like O_RDONLY.
1566  *
1567  * the file descriptor flags (4) clearly are in the FD.  note that the same
1568  * file/chan can be opened by two different FDs, with different flags.  the only
1569  * one anyone uses is CLOEXEC.  while exec may not last long in akaros, i can
1570  * imagine similar "never pass to children" flags/meanings.
1571  *
1572  * the file creation mode (5) matters for the device's permissions; given this,
1573  * it should be stored in the device/inode.  ACLs fall under this category.
1574  *
1575  * finally, only certain categories can be edited afterwards: file status flags
1576  * (2), FD flags (4), and file permissions (5). */
1577 int fd_getfl(int fd)
1578 {
1579         ERRSTACK(1);
1580         struct chan *c;
1581         int ret;
1582
1583         if (waserror()) {
1584                 poperror();
1585                 return -1;
1586         }
1587         c = fdtochan(current->fgrp, fd, -1, 0, 1);
1588
1589         ret = c->mode;
1590         if (c->flag & CAPPEND)
1591                 ret |= O_APPEND;
1592
1593         cclose(c);
1594         poperror();
1595         return ret;
1596 }
1597
1598 int fd_setfl(int fd, int flags)
1599 {
1600         ERRSTACK(1);
1601         struct chan *c;
1602
1603         if (waserror()) {
1604                 poperror();
1605                 return -1;
1606         }
1607         c = fdtochan(current->fgrp, fd, -1, 0, 1);
1608
1609         if (flags & O_APPEND)
1610                 c->flag |= CAPPEND;
1611
1612         cclose(c);
1613         poperror();
1614         return 0;
1615 }