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