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