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