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