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