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