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