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