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