Create akaros wrappers for sysstat and sysfstat
[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, struct dir *dir9ns, 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, (void *)dir9ns, n);
957
958         poperror();
959         cclose(c);
960
961         poperror();
962         return n;
963 }
964
965 int sysfstatakaros(int fd, uint8_t *buf, int n)
966 {
967         struct dir dir9ns;
968         if ((n = sysfstat(fd, &dir9ns, sizeof(dir9ns))) < 0)
969                 return n;
970         convM2kstat((void *)&dir9ns, sizeof(struct dir), (struct kstat *)buf);
971         return n;
972 }
973
974 int sysstat(char *path, struct dir *dir9ns, int n)
975 {
976         ERRSTACK(2);
977         struct chan *c;
978
979         if (waserror()) {
980                 poperror();
981                 return -1;
982         }
983
984         c = namec(path, Aaccess, 0, 0);
985         if (waserror()) {
986                 cclose(c);
987                 nexterror();
988         }
989         devtab[c->type].stat(c, (void *)dir9ns, sizeof(struct dir));
990         poperror();
991         cclose(c);
992
993         poperror();
994
995         return n;
996 }
997
998 int sysstatakaros(char *path, uint8_t * buf, int n)
999 {
1000         struct dir dir9ns;
1001         n = sysstat(path, &dir9ns, sizeof(dir9ns));
1002         if (n < 0)
1003                 return n;
1004         convM2kstat((void *)&dir9ns, sizeof(struct dir), (struct kstat *)buf);
1005         return 0;
1006 }
1007
1008 static long rwrite(int fd, void *va, long n, int64_t * offp)
1009 {
1010         ERRSTACK(3);
1011         struct chan *c;
1012         struct dir *dir;
1013         int64_t off;
1014         long m;
1015
1016         if (waserror()) {
1017                 poperror();
1018                 return -1;
1019         }
1020         c = fdtochan(current->fgrp, fd, OWRITE, 1, 1);
1021         if (waserror()) {
1022                 cclose(c);
1023                 nexterror();
1024         }
1025         if (c->qid.type & QTDIR)
1026                 error(Eisdir);
1027
1028         if (n < 0)
1029                 error(Etoosmall);
1030
1031         if (offp == NULL) {
1032                 /* append changes the offset to the end, and even if we fail later, this
1033                  * change will persist */
1034                 if (c->flag & CAPPEND) {
1035                         dir = chandirstat(c);
1036                         if (!dir)
1037                                 error("internal error: stat error in append write");
1038                         spin_lock(&c->lock);    /* legacy lock for int64 assignment */
1039                         c->offset = dir->length;
1040                         spin_unlock(&c->lock);
1041                         kfree(dir);
1042                 }
1043                 spin_lock(&c->lock);
1044                 off = c->offset;
1045                 c->offset += n;
1046                 spin_unlock(&c->lock);
1047         } else
1048                 off = *offp;
1049
1050         if (waserror()) {
1051                 if (offp == NULL) {
1052                         spin_lock(&c->lock);
1053                         c->offset -= n;
1054                         spin_unlock(&c->lock);
1055                 }
1056                 nexterror();
1057         }
1058         if (off < 0)
1059                 error(Enegoff);
1060         m = devtab[c->type].write(c, va, n, off);
1061         poperror();
1062
1063         if (offp == NULL && m < n) {
1064                 spin_lock(&c->lock);
1065                 c->offset -= n - m;
1066                 spin_unlock(&c->lock);
1067         }
1068
1069         poperror();
1070         cclose(c);
1071
1072         poperror();
1073         return n;
1074 }
1075
1076 long syswrite(int fd, void *va, long n)
1077 {
1078         return rwrite(fd, va, n, NULL);
1079 }
1080
1081 long syspwrite(int fd, void *va, long n, int64_t off)
1082 {
1083         return rwrite(fd, va, n, &off);
1084 }
1085
1086 int syswstat(char *path, uint8_t * buf, int n)
1087 {
1088         ERRSTACK(2);
1089         struct chan *c;
1090
1091         if (waserror()) {
1092                 poperror();
1093                 return -1;
1094         }
1095
1096         validstat(buf, n);
1097         c = namec(path, Aaccess, 0, 0);
1098         if (waserror()) {
1099                 cclose(c);
1100                 nexterror();
1101         }
1102         n = devtab[c->type].wstat(c, buf, n);
1103         poperror();
1104         cclose(c);
1105
1106         poperror();
1107         return n;
1108 }
1109
1110 enum {
1111         DIRSIZE = STATFIXLEN + 32 * 4,
1112         DIRREADLIM = 2048,      /* should handle the largest reasonable directory entry */
1113 };
1114
1115 struct dir *chandirstat(struct chan *c)
1116 {
1117         ERRSTACK(1);
1118         struct dir *d;
1119         uint8_t *buf;
1120         int n, nd, i;
1121
1122         nd = DIRSIZE;
1123         for (i = 0; i < 2; i++) {       /* should work by the second try */
1124                 d = kzmalloc(sizeof(struct dir) + nd, 0);
1125                 buf = (uint8_t *) & d[1];
1126                 if (waserror()) {
1127                         kfree(d);
1128                         poperror();
1129                         return NULL;
1130                 }
1131                 n = devtab[c->type].stat(c, buf, nd);
1132                 poperror();
1133                 if (n < BIT16SZ) {
1134                         kfree(d);
1135                         return NULL;
1136                 }
1137                 nd = GBIT16((uint8_t *) buf) + BIT16SZ; /* size needed to store whole stat buffer including count */
1138                 if (nd <= n) {
1139                         convM2D(buf, n, d, (char *)&d[1]);
1140                         return d;
1141                 }
1142                 /* else sizeof(Dir)+nd is plenty */
1143                 kfree(d);
1144         }
1145         return NULL;
1146
1147 }
1148
1149 struct dir *sysdirstat(char *name)
1150 {
1151         ERRSTACK(2);
1152         struct chan *c;
1153         struct dir *d;
1154
1155         if (waserror()) {
1156                 poperror();
1157                 return NULL;
1158         }
1159
1160         c = namec(name, Aaccess, 0, 0);
1161         if (waserror()) {
1162                 cclose(c);
1163                 nexterror();
1164         }
1165         d = chandirstat(c);
1166         poperror();
1167         cclose(c);
1168
1169         poperror();
1170         return d;
1171 }
1172
1173 struct dir *sysdirfstat(int fd)
1174 {
1175         ERRSTACK(2);
1176         struct chan *c;
1177         struct dir *d;
1178
1179         if (waserror()) {
1180                 poperror();
1181                 return NULL;
1182         }
1183
1184         c = fdtochan(current->fgrp, fd, -1, 0, 1);
1185         if (waserror()) {
1186                 cclose(c);
1187                 nexterror();
1188         }
1189         d = chandirstat(c);
1190         poperror();
1191         cclose(c);
1192
1193         poperror();
1194         return d;
1195 }
1196
1197 int sysdirwstat(char *name, struct dir *dir)
1198 {
1199         uint8_t *buf;
1200         int r;
1201
1202         r = sizeD2M(dir);
1203         buf = kzmalloc(r, 0);
1204         convD2M(dir, buf, r);
1205         r = syswstat(name, buf, r);
1206         kfree(buf);
1207         return r < 0 ? r : 0;
1208 }
1209
1210 int sysdirfwstat(int fd, struct dir *dir)
1211 {
1212         uint8_t *buf;
1213         int r;
1214
1215         r = sizeD2M(dir);
1216         buf = kzmalloc(r, 0);
1217         convD2M(dir, buf, r);
1218         r = sysfwstat(fd, buf, r);
1219         kfree(buf);
1220         return r < 0 ? r : 0;
1221 }
1222
1223 static long dirpackage(uint8_t * buf, long ts, struct kdirent **d)
1224 {
1225         char *s;
1226         long ss, i, n, nn, m = 0;
1227
1228         *d = NULL;
1229         if (ts <= 0)
1230                 return ts;
1231
1232         /*
1233          * first find number of all stats, check they look like stats, & size all associated strings
1234          */
1235         ss = 0;
1236         n = 0;
1237         for (i = 0; i < ts; i += m) {
1238                 m = BIT16SZ + GBIT16(&buf[i]);
1239                 if (statcheck(&buf[i], m) < 0)
1240                         break;
1241                 ss += m;
1242                 n++;
1243         }
1244
1245         if (i != ts)
1246                 error("bad directory format");
1247
1248         *d = kzmalloc(n * sizeof(**d) + ss, 0);
1249         if (*d == NULL)
1250                 error(Enomem);
1251
1252         /*
1253          * then convert all buffers
1254          */
1255         s = (char *)*d + n * sizeof(**d);
1256         nn = 0;
1257         for (i = 0; i < ts; i += m) {
1258                 m = BIT16SZ + GBIT16((uint8_t *) & buf[i]);
1259                 if (nn >= n || /*convM2D */ convM2kdirent(&buf[i], m, *d + nn, s) != m) {
1260                         kfree(*d);
1261                         *d = NULL;
1262                         error("bad directory entry");
1263                 }
1264                 nn++;
1265                 s += m;
1266         }
1267
1268         return nn;
1269 }
1270
1271 long sysdirread(int fd, struct kdirent **d)
1272 {
1273         ERRSTACK(2);
1274         uint8_t *buf;
1275         long ts;
1276
1277         *d = NULL;
1278         if (waserror()) {
1279                 poperror();
1280                 return -1;
1281         }
1282         buf = kzmalloc(DIRREADLIM, 0);
1283         if (buf == NULL)
1284                 error(Enomem);
1285         if (waserror()) {
1286                 kfree(buf);
1287                 nexterror();
1288         }
1289         ts = sysread(fd, buf, DIRREADLIM);
1290         if (ts >= 0)
1291                 ts = dirpackage(buf, ts, d);
1292         poperror();
1293         kfree(buf);
1294         poperror();
1295         return ts;
1296 }
1297
1298 int sysiounit(int fd)
1299 {
1300         ERRSTACK(1);
1301         struct chan *c;
1302         int n;
1303
1304         c = fdtochan(current->fgrp, fd, -1, 0, 1);
1305         if (waserror()) {
1306                 cclose(c);
1307                 poperror();
1308                 return 0;       /* n.b. */
1309         }
1310         n = c->iounit;
1311         poperror();
1312         cclose(c);
1313         return n;
1314 }
1315
1316 /* Notes on concurrency:
1317  * - Can't hold spinlocks while we call cclose, since it might sleep eventually.
1318  * - We're called from proc_destroy, so we could have concurrent openers trying
1319  *   to add to the group (other syscalls), hence the "closed" flag.
1320  * - dot and slash chans are dealt with in proc_free.  its difficult to close
1321  *   and zero those with concurrent syscalls, since those are a source of krefs.
1322  * - the memory is freed in proc_free().  need to wait to do it, since we can
1323  *   have concurrent accesses to fgrp before free.
1324  * - Once we lock and set closed, no further additions can happen.  To simplify
1325  *   our closes, we also allow multiple calls to this func (though that should
1326  *   never happen with the current code). */
1327 void close_9ns_files(struct proc *p, bool only_cloexec)
1328 {
1329         struct fgrp *f = p->fgrp;
1330
1331         spin_lock(&f->lock);
1332         if (f->closed) {
1333                 spin_unlock(&f->lock);
1334                 warn("Unexpected double-close");
1335                 return;
1336         }
1337         if (!only_cloexec)
1338                 f->closed = TRUE;
1339         spin_unlock(&f->lock);
1340
1341         /* maxfd is a legit val, not a +1 */
1342         for (int i = 0; i <= f->maxfd; i++) {
1343                 if (!f->fd[i])
1344                         continue;
1345                 if (only_cloexec && !(f->fd[i]->flag & CCEXEC))
1346                         continue;
1347                 cclose(f->fd[i]);
1348                 f->fd[i] = 0;
1349         }
1350 }
1351
1352 void print_chaninfo(struct chan *c)
1353 {
1354         char buf[64] = { 0 };
1355         bool has_dev = c->type != -1;
1356         printk("Chan pathname: %s, Dev: %s, Devinfo: %s\n",
1357                    c->name ? c->name->s : "no cname",
1358                    has_dev ? devtab[c->type].name : "no dev",
1359                    has_dev ? devtab[c->type].chaninfo(c, buf, sizeof(buf)) : "no info");
1360         if (!has_dev)
1361                 printk("No dev: intermediate chan? qid.path: %p\n", c->qid.path);
1362         printk("\n");
1363 }
1364
1365 void print_9ns_files(struct proc *p)
1366 {
1367         struct fgrp *f = p->fgrp;
1368         spin_lock(&f->lock);
1369         printk("9ns files for proc %d:\n", p->pid);
1370         /* maxfd is a legit val, not a +1 */
1371         for (int i = 0; i <= f->maxfd; i++) {
1372                 if (!f->fd[i])
1373                         continue;
1374                 printk("\t9fs %d, ", i);
1375                 print_chaninfo(f->fd[i]);
1376         }
1377         spin_unlock(&f->lock);
1378 }
1379
1380 /* TODO: 9ns ns inheritance flags: Shared, copied, or empty.  Looks like we're
1381  * copying the fgrp, and sharing the pgrp. */
1382 int plan9setup(struct proc *new_proc, struct proc *parent)
1383 {
1384         struct proc *old_current;
1385         struct kref *new_dot_ref;
1386         ERRSTACK(1);
1387         if (waserror()) {
1388                 printk("plan9setup failed, %s\n", current_errstr());
1389                 poperror();
1390                 return -1;
1391         }
1392         if (!parent) {
1393                 /* We are probably spawned by the kernel directly, and have no parent to
1394                  * inherit from.  Be sure to set up fgrp/pgrp before calling namec().
1395                  *
1396                  * TODO: One problem is namec wants a current set for things like
1397                  * genbuf.  So we'll use new_proc for this bootstrapping.  Note
1398                  * switch_to() also loads the cr3. */
1399                 new_proc->fgrp = newfgrp();
1400                 new_proc->pgrp = newpgrp();
1401                 old_current = switch_to(new_proc);
1402                 new_proc->slash = namec("#r", Atodir, 0, 0);
1403                 if (!new_proc->slash)
1404                         panic("no root device");
1405                 switch_back(new_proc, old_current);
1406                 /* Want the name to be "/" instead of "#r" */
1407                 cnameclose(new_proc->slash->name);
1408                 new_proc->slash->name = newcname("/");
1409                 new_proc->dot = cclone(new_proc->slash);
1410                 poperror();
1411                 return 0;
1412         }
1413         /* Copy semantics: do not change this without revisiting proc_destroy,
1414          * close_9ns_files, and closefgrp. */
1415         new_proc->fgrp = dupfgrp(parent->fgrp);
1416         /* Shared semantics */
1417         kref_get(&parent->pgrp->ref, 1);
1418         new_proc->pgrp = parent->pgrp;
1419         /* copy semantics on / and . (doesn't make a lot of sense in akaros o/w) */
1420         /* / should never disappear while we hold a ref to parent */
1421         kref_get(&parent->slash->ref, 1);
1422         new_proc->slash = parent->slash;
1423         /* dot could change concurrently, and we could fail to gain a ref if whoever
1424          * decref'd dot triggered the release.  if that did happen, new_proc->dot
1425          * should update and we can try again. */
1426         while (!(new_dot_ref = kref_get_not_zero(&parent->dot->ref, 1)))
1427                 cpu_relax();
1428         /* And now, we can't trust parent->dot, and need to determine our dot from
1429          * the ref we obtained. */
1430         new_proc->dot = container_of(new_dot_ref, struct chan, ref);
1431         poperror();
1432         return 0;
1433 }
1434
1435 /* Open flags, create modes, access types, file flags, and all that...
1436  *
1437  * there are a bunch of things here:
1438  *              1) file creation flags (e.g. O_TRUNC)
1439  *              2) file status flags (e.g. O_APPEND)
1440  *              3) file open modes (e.g. O_RDWR)
1441  *              4) file descriptor flags (e.g. CLOEXEC)
1442  *              5) file creation mode (e.g. S_IRWXU)
1443  * the 1-4 are passed in via open's vfs_flags, and the 5 via mode only when
1444  * O_CREATE is set.
1445  *
1446  * file creation flags (1) only matter when creating, but aren't permanent.
1447  * O_EXCL, O_DIRECTORY, O_TRUNC, etc.
1448  *
1449  * file status flags (2) are per struct file/chan.  stuff like O_APPEND,
1450  * O_ASYNC, etc.  we convert those to an internal flag bit and store in c->flags
1451  *
1452  * the open mode (3) matters for a given FD/chan (chan->mode), and should be
1453  * stored in the chan. (c->mode) stuff like O_RDONLY.
1454  *
1455  * the file descriptor flags (4) clearly are in the FD.  note that the same
1456  * file/chan can be opened by two different FDs, with different flags.  the only
1457  * one anyone uses is CLOEXEC.  while exec may not last long in akaros, i can
1458  * imagine similar "never pass to children" flags/meanings.
1459  *
1460  * the file creation mode (5) matters for the device's permissions; given this,
1461  * it should be stored in the device/inode.  ACLs fall under this category.
1462  *
1463  * finally, only certain categories can be edited afterwards: file status flags
1464  * (2), FD flags (4), and file permissions (5). */
1465 int fd_getfl(int fd)
1466 {
1467         ERRSTACK(1);
1468         struct chan *c;
1469         int ret;
1470
1471         if (waserror()) {
1472                 poperror();
1473                 return -1;
1474         }
1475         c = fdtochan(current->fgrp, fd, -1, 0, 1);
1476
1477         ret = c->mode;
1478         if (c->flag & CAPPEND)
1479                 ret |= O_APPEND;
1480
1481         cclose(c);
1482         poperror();
1483         return ret;
1484 }
1485
1486 int fd_setfl(int fd, int flags)
1487 {
1488         ERRSTACK(1);
1489         struct chan *c;
1490
1491         if (waserror()) {
1492                 poperror();
1493                 return -1;
1494         }
1495         c = fdtochan(current->fgrp, fd, -1, 0, 1);
1496
1497         if (flags & O_APPEND)
1498                 c->flag |= CAPPEND;
1499
1500         cclose(c);
1501         poperror();
1502         return 0;
1503 }