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