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