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