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