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