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