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