]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/devshr.c
kernel: kproc error and exit
[plan9front.git] / sys / src / 9 / port / devshr.c
1 #include        "u.h"
2 #include        "../port/lib.h"
3 #include        "mem.h"
4 #include        "dat.h"
5 #include        "fns.h"
6 #include        "../port/error.h"
7
8 enum {
9         Qroot,
10         Qcroot,
11         Qshr,
12         Qcshr,
13         Qcmpt,
14 };
15
16 typedef struct Ent Ent;
17 typedef struct Shr Shr;
18 typedef struct Mpt Mpt;
19 typedef struct Sch Sch;
20
21 struct Ent
22 {
23         Ref;
24         int     id;
25         char    *name;
26         char    *owner;
27         ulong   perm;
28 };
29
30 struct Shr
31 {
32         Ent;
33         Mhead   umh;
34         Shr     *next;
35 };
36
37 struct Mpt
38 {
39         Ent;
40         Mount   m;
41 };
42
43 struct Sch
44 {
45         int     level;
46
47         Shr     *shr;
48         Mpt     *mpt;
49
50         Chan    *chan;
51 };
52
53 static QLock    shrslk;
54 static Shr      *shrs;
55
56 static int      shrid;
57 static int      mptid;
58
59 static Mpt*
60 tompt(Mount *m)
61 {
62         return (Mpt*)((char*)m - (char*)&((Mpt*)0)->m);
63 }
64
65 static Sch*
66 tosch(Chan *c)
67 {
68         Sch *sch;
69
70         if(c == nil)
71                 error("nil chan");
72         sch = c->aux;
73         if(sch == nil)
74                 error("nil chan aux");
75         if(sch->chan != c)
76                 error("bad chan");
77         return sch;
78 }
79
80 static void
81 shrinit(void)
82 {
83         shrid = 1;
84         mptid = 1;
85 }
86
87 static void
88 putmpt(Mpt *mpt)
89 {
90         if(decref(mpt))
91                 return;
92         if(mpt->m.to != nil)
93                 cclose(mpt->m.to);
94         free(mpt->name);
95         free(mpt->owner);
96         free(mpt);
97 }
98
99 static void
100 putshr(Shr *shr)
101 {
102         if(decref(shr))
103                 return;
104         free(shr->name);
105         free(shr->owner);
106         free(shr);
107 }
108
109 static Qid
110 shrqid(int level, int id)
111 {
112         Qid q;
113
114         q.type = (level == Qcmpt) ? QTFILE : QTDIR;
115         q.path = (uvlong)id<<4 | level;
116         q.vers = 0;
117         return q;
118 }
119
120 static Chan*
121 shrattach(char *spec)
122 {
123         Sch *sch;
124         Chan *c;
125         
126         if(!(spec[0] == 'c' && spec[1] == 0 || spec[0] == 0))
127                 error(Enoattach);
128         c = devattach(L'σ', spec);
129
130         sch = smalloc(sizeof(*sch));
131         sch->level = spec[0] == 'c' ? Qcroot : Qroot;
132         sch->mpt = nil;
133         sch->shr = nil;
134         sch->chan = c;
135         c->aux = sch;
136         c->qid = shrqid(sch->level, 0);
137
138         return c;
139 }
140
141 static Chan*
142 shrclone(Chan *c)
143 {
144         Chan *nc;
145         Sch *sch, *och;
146
147         och = tosch(c);
148         nc = devclone(c);
149         sch = smalloc(sizeof(*sch));
150         memmove(sch, och, sizeof(*sch));
151         if(sch->shr != nil)
152                 incref(sch->shr);
153         if(sch->mpt != nil)
154                 incref(sch->mpt);
155         sch->chan = nc;
156         nc->aux = sch;
157         return nc;
158 }
159
160 static void
161 shrclunk(Chan *c)
162 {
163         Sch *sch;
164
165         sch = tosch(c);
166         c->aux = nil;
167         sch->chan = nil;
168         if(sch->mpt != nil)
169                 putmpt(sch->mpt);
170         if(sch->shr != nil)
171                 putshr(sch->shr);
172         free(sch);      
173 }
174
175 static Walkqid*
176 shrwalk(Chan *c, Chan *nc, char **name, int nname)
177 {
178         Walkqid *wq, *wq2;
179         int alloc, j;
180         char *nam;
181         Sch *sch;
182         Shr *shr;
183         Mpt *mpt;
184         Mount *m;
185         Mhead *h;
186         
187         alloc = 0;
188         if(nc == nil){
189                 nc = shrclone(c);
190                 alloc = 1;
191         }
192         wq = smalloc(sizeof(Walkqid) + (nname - 1) * sizeof(Qid));
193         wq->nqid = 0;
194         wq->clone = nc;
195         if(waserror()){
196                 if(alloc)
197                         cclose(wq->clone);
198                 if(wq->nqid > 0)
199                         wq->clone = nil;
200                 else {
201                         free(wq);
202                         wq = nil;
203                 }
204                 return wq;
205         }
206         sch = tosch(nc);
207         for(j = 0; j < nname; j++){
208                 if(nc->qid.type != QTDIR)
209                         error(Enotdir);
210
211                 nam = name[j];
212                 if(nam[0] == '.' && nam[1] == 0) {
213                         /* nop */
214                 } else if(nam[0] == '.' && nam[1] == '.' && nam[2] == 0) {
215                         switch(sch->level){
216                         default:
217                                 error(Egreg);
218                         case Qshr:
219                                 nc->qid = shrqid(sch->level = Qroot, 0);
220                                 break;
221                         case Qcshr:
222                                 nc->qid = shrqid(sch->level = Qcroot, 0);
223                                 break;
224                         }
225                         putshr(sch->shr);
226                         sch->shr = nil;
227                 } else if(sch->level == Qcroot || sch->level == Qroot) {
228                         qlock(&shrslk);
229                         for(shr = shrs; shr != nil; shr = shr->next)
230                                 if(strcmp(nam, shr->name) == 0){
231                                         incref(shr);
232                                         break;
233                                 }
234                         qunlock(&shrslk);
235                         if(shr == nil)
236                                 error(Enonexist);
237                         sch->level = sch->level == Qcroot ? Qcshr : Qshr;
238                         sch->shr = shr;
239                         nc->qid = shrqid(sch->level, shr->id);
240                 } else if(sch->level == Qcshr) {
241                         mpt = nil;
242                         shr = sch->shr;
243                         h = &shr->umh;
244                         rlock(&h->lock);
245                         for(m = h->mount; m != nil; m = m->next){
246                                 mpt = tompt(m);
247                                 if(strcmp(nam, mpt->name) == 0){
248                                         incref(mpt);
249                                         break;
250                                 }
251                         }
252                         runlock(&h->lock);
253                         if(m == nil)
254                                 error(Enonexist);
255                         sch->mpt = mpt;
256                         nc->qid = shrqid(sch->level = Qcmpt, mpt->id);
257                 } else if(sch->level == Qshr) {
258                         shr = sch->shr;
259                         h = &shr->umh;
260                         wq2 = nil;
261                         rlock(&h->lock);
262                         for(m = h->mount; m != nil && wq2 == nil; m = m->next){
263                                 if(m->to == nil)
264                                         continue;
265                                 if(waserror())
266                                         continue;
267                                 wq2 = devtab[m->to->type]->walk(m->to, nil, name + j, nname - j);
268                                 poperror();
269                         }
270                         runlock(&h->lock);
271                         if(wq2 == nil)
272                                 error(Enonexist);
273                         memmove(wq->qid + wq->nqid, wq2->qid, wq2->nqid);
274                         wq->nqid += wq2->nqid;
275                         if(alloc)
276                                 cclose(wq->clone);
277                         wq->clone = wq2->clone;
278                         free(wq2);
279                         poperror();
280                         return wq;
281                 } else
282                         error(Egreg);
283                 wq->qid[wq->nqid++] = nc->qid;
284         }
285         poperror();
286         return wq;
287 }
288
289 static int
290 shrgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
291 {
292         Mpt *mpt;
293         Sch *sch;
294         Shr *shr;
295         Mhead *h;
296         Mount *m;
297
298         sch = tosch(c);
299         switch(sch->level){
300         default:
301                 return -1;
302         case Qroot:
303         case Qcroot:
304                 qlock(&shrslk);
305                 for(shr = shrs; shr != nil && s > 0; shr = shr->next)
306                         s--;
307                 if(shr == nil){
308                         qunlock(&shrslk);
309                         return -1;
310                 }
311                 kstrcpy(up->genbuf, shr->name, sizeof up->genbuf);
312                 if(sch->level == Qroot)
313                         devdir(c, shrqid(Qshr, shr->id), up->genbuf, 0, shr->owner,
314                                 shr->perm & ~0222, dp);
315                 else
316                         devdir(c, shrqid(Qcshr, shr->id), up->genbuf, 0, shr->owner,
317                                 shr->perm, dp);
318                 qunlock(&shrslk);
319                 return 1;
320         case Qcshr:
321                 shr = sch->shr;
322                 h = &shr->umh;
323                 rlock(&h->lock);
324                 for(m = h->mount; m != nil && s > 0; m = m->next)
325                         s--;
326                 if(m == nil){
327                         runlock(&h->lock);
328                         return -1;
329                 }
330                 mpt = tompt(m);
331                 kstrcpy(up->genbuf, mpt->name, sizeof up->genbuf);
332                 devdir(c, shrqid(Qcmpt, mpt->id), up->genbuf, 0, mpt->owner, mpt->perm, dp);
333                 runlock(&h->lock);
334                 return 1;
335         }
336 }
337
338 static int
339 shrstat(Chan *c, uchar *db, int n)
340 {
341         Sch *sch;
342         Dir dir;
343         int rc;
344
345         sch = tosch(c);
346         switch(sch->level){
347         default:
348                 error(Egreg);
349         case Qroot:
350                 devdir(c, c->qid, "#σ", 0, eve, 0555, &dir);
351                 break;
352         case Qcroot:
353                 devdir(c, c->qid, "#σc", 0, eve, 0777, &dir);
354                 break;
355         case Qshr:
356                 devdir(c, c->qid, sch->shr->name, 0, sch->shr->owner, sch->shr->perm & ~0222, &dir);
357                 break;
358         case Qcshr:
359                 devdir(c, c->qid, sch->shr->name, 0, sch->shr->owner, sch->shr->perm, &dir);
360                 break;
361         case Qcmpt:
362                 devdir(c, c->qid, sch->mpt->name, 0, sch->mpt->owner, sch->mpt->perm, &dir);
363                 break;
364         }
365         rc = convD2M(&dir, db, n);
366         if(rc == 0)
367                 error(Ebadarg);
368         return rc;
369 }
370
371 static Chan*
372 shropen(Chan *c, int omode)
373 {
374         Chan *nc;
375         Sch *sch;
376         Shr *shr;
377         Mpt *mpt;
378         int mode;
379
380         if(c->qid.type == QTDIR && omode != OREAD)
381                 error(Eisdir);
382
383         mode = openmode(omode);
384         sch = tosch(c);
385         switch(sch->level){
386         default:
387                 error(Egreg);
388         case Qroot:
389         case Qcroot:
390                 break;
391         case Qshr:
392         case Qcshr:
393                 shr = sch->shr;
394                 devpermcheck(shr->owner, shr->perm, mode);
395                 break;
396         case Qcmpt:
397                 if(omode&OTRUNC)
398                         error(Eexist);
399                 shr = sch->shr;
400                 mpt = sch->mpt;
401                 devpermcheck(mpt->owner, mpt->perm, mode);
402                 rlock(&shr->umh.lock);
403                 if(mpt->m.to == nil || mpt->m.to->mchan == nil){
404                         runlock(&shr->umh.lock);
405                         error(Eshutdown);
406                 }
407                 nc = mpt->m.to->mchan;
408                 incref(nc);
409                 runlock(&shr->umh.lock);
410                 if(mode != nc->mode){
411                         cclose(nc);
412                         error(Eperm);
413                 }
414                 cclose(c);
415                 return nc;
416         }
417         c->mode = mode;
418         c->flag |= COPEN;
419         c->offset = 0;
420         return c;
421 }
422
423 /* chan.c */
424 Chan* createdir(Chan *c, Mhead *m);
425
426 static Chan*
427 shrcreate(Chan *c, char *name, int omode, ulong perm)
428 {
429         Sch *sch;
430         Shr *shr;
431         Mpt *mpt;
432         Mhead *h;
433         Mount *m;
434         Chan *nc;
435         int mode;
436
437         mode = openmode(omode);
438         sch = tosch(c);
439         switch(sch->level){
440         case Qcroot:
441         case Qcshr:
442                 if(strcmp(up->user, "none") == 0)
443                         error(Eperm);
444         }
445         switch(sch->level){
446         default:
447                 error(Eperm);
448         case Qshr:
449                 incref(c);
450                 if(waserror()){
451                         cclose(c);
452                         nexterror();
453                 }
454                 nc = createdir(c, &sch->shr->umh);
455                 poperror();
456                 if(waserror()){
457                         cclose(nc);
458                         nexterror();
459                 }
460                 nc = devtab[nc->type]->create(nc, name, omode, perm);
461                 poperror();
462                 cclose(c);
463                 return nc;      
464         case Qcroot:
465                 if(up->pgrp->noattach)
466                         error(Enoattach);
467                 if((perm & DMDIR) == 0 || mode != OREAD)
468                         error(Eperm);
469                 if(strlen(name) >= sizeof(up->genbuf))
470                         error(Etoolong);
471                 qlock(&shrslk);
472                 if(waserror()){
473                         qunlock(&shrslk);
474                         nexterror();
475                 }
476                 for(shr = shrs; shr != nil; shr = shr->next)
477                         if(strcmp(name, shr->name) == 0)
478                                 error(Eexist);
479
480                 shr = smalloc(sizeof(*shr));
481                 incref(shr);
482                 shr->id = shrid++;
483
484                 kstrdup(&shr->name, name);
485                 kstrdup(&shr->owner, up->user);
486                 shr->perm = perm;
487
488                 incref(shr);
489                 shr->next = shrs;
490                 shrs = shr;
491
492                 poperror();
493                 qunlock(&shrslk);
494
495                 c->qid = shrqid(sch->level = Qcshr, shr->id);
496                 sch->shr = shr;
497                 break;
498         case Qcshr:
499                 if(up->pgrp->noattach)
500                         error(Enoattach);
501                 if((perm & DMDIR) != 0 || mode != OWRITE)
502                         error(Eperm);
503
504                 shr = sch->shr;
505                 if(strcmp(shr->owner, eve) == 0 && !iseve())
506                         error(Eperm);
507                 devpermcheck(shr->owner, shr->perm, ORDWR);
508
509                 if(strlen(name) >= sizeof(up->genbuf))
510                         error(Etoolong);
511
512                 h = &shr->umh;
513                 wlock(&h->lock);
514                 if(waserror()){
515                         wunlock(&h->lock);
516                         nexterror();
517                 }
518                 for(m = h->mount; m != nil; m = m->next){
519                         mpt = tompt(m);
520                         if(strcmp(name, mpt->name) == 0)
521                                 error(Eexist);
522                 }
523
524                 mpt = smalloc(sizeof(*mpt));
525                 incref(mpt);
526                 mpt->id = mptid++;
527
528                 kstrdup(&mpt->name, name);
529                 kstrdup(&mpt->owner, up->user);
530                 mpt->perm = perm;
531
532                 incref(mpt);
533                 mpt->m.mflag = (h->mount == nil) ? MCREATE : 0;
534                 mpt->m.head = h;
535                 mpt->m.next = h->mount;
536                 h->mount = &mpt->m;
537
538                 poperror();
539                 wunlock(&h->lock);
540
541                 c->qid = shrqid(sch->level = Qcmpt, mpt->id);
542                 sch->mpt = mpt;
543                 break;
544         }
545         c->flag |= COPEN;
546         c->mode = mode;
547         return c;
548 }
549
550 static void
551 shrremove(Chan *c)
552 {
553         Mount *m, **ml;
554         Shr *shr, **sl;
555         Sch *sch;
556         Mpt *mpt;
557         Mhead *h;
558
559         sch = tosch(c);
560         if(waserror()){
561                 shrclunk(c);
562                 nexterror();
563         }
564         switch(sch->level){
565         default:
566                 error(Eperm);
567         case Qcshr:
568         case Qcmpt:
569                 shr = sch->shr;
570                 if(!iseve()){
571                         if(strcmp(shr->owner, eve) == 0)
572                                 error(Eperm);
573                         devpermcheck(shr->owner, shr->perm, ORDWR);
574                 }
575         }
576         switch(sch->level){
577         case Qcshr:
578                 h = &shr->umh;
579                 qlock(&shrslk);
580                 rlock(&h->lock);
581                 if(h->mount != nil){
582                         runlock(&h->lock);
583                         qunlock(&shrslk);
584                         error("directory not empty");
585                 }
586                 runlock(&h->lock);
587                 for(sl = &shrs; *sl != nil; sl = &((*sl)->next))
588                         if(*sl == shr){
589                                 *sl = shr->next;
590                                 shr->next = nil;
591                                 putshr(shr);
592                                 break;
593                         }
594                 qunlock(&shrslk);
595                 break;
596         case Qcmpt:
597                 mpt = sch->mpt;
598                 m = &mpt->m;
599                 h = &shr->umh;
600                 wlock(&h->lock);
601                 for(ml = &h->mount; *ml != nil; ml = &((*ml)->next))
602                         if(*ml == m){
603                                 *ml = m->next;
604                                 m->next = nil;
605                                 m->head = nil;
606                                 putmpt(mpt);
607                                 break;
608                         }
609                 wunlock(&h->lock);
610                 break;
611         }
612         poperror();
613         shrclunk(c);
614 }
615
616 static int
617 shrwstat(Chan *c, uchar *dp, int n)
618 {
619         char *strs;
620         Mhead *h;
621         Sch *sch;
622         Ent *ent;
623         Dir d;
624
625         strs = smalloc(n);
626         if(waserror()){
627                 free(strs);
628                 nexterror();
629         }
630         n = convM2D(dp, n, &d, strs);
631         if(n == 0)
632                 error(Eshortstat);
633
634         h = nil;
635         sch = tosch(c);
636         switch(sch->level){
637         default:
638                 error(Eperm);
639         case Qcshr:
640                 ent = sch->shr;
641                 qlock(&shrslk);
642                 if(waserror()){
643                         qunlock(&shrslk);
644                         nexterror();
645                 }
646                 break;
647         case Qcmpt:
648                 ent = sch->mpt;
649                 h = &sch->shr->umh;
650                 wlock(&h->lock);
651                 if(waserror()){
652                         wunlock(&h->lock);
653                         nexterror();
654                 }
655                 break;
656         }
657
658         if(strcmp(ent->owner, up->user) && !iseve())
659                 error(Eperm);
660
661         if(d.name != nil && *d.name && strcmp(ent->name, d.name) != 0) {
662                 if(strchr(d.name, '/') != nil)
663                         error(Ebadchar);
664                 if(strlen(d.name) >= sizeof(up->genbuf))
665                         error(Etoolong);
666                 kstrdup(&ent->name, d.name);
667         }
668         if(d.uid != nil && *d.uid)
669                 kstrdup(&ent->owner, d.uid);
670         if(d.mode != ~0UL)
671                 ent->perm = d.mode & 0777;
672
673         switch(sch->level){
674         case Qcshr:
675                 poperror();
676                 qunlock(&shrslk);
677                 break;
678         case Qcmpt:
679                 poperror();
680                 wunlock(&h->lock);
681                 break;
682         }
683
684         poperror();
685         free(strs);
686
687         return n;
688 }
689
690 static long
691 shrread(Chan *c, void *va, long n, vlong)
692 {
693         Mhead *omh;
694         Sch *sch;
695
696         sch = tosch(c);
697         switch(sch->level){
698         default:
699                 error(Egreg);
700         case Qroot:
701         case Qcroot:
702         case Qcshr:
703                 return devdirread(c, va, n, 0, 0, shrgen);
704         case Qshr:
705                 omh = c->umh;
706                 c->umh = &sch->shr->umh;
707                 if(waserror()){
708                         c->umh = omh;
709                         nexterror();
710                 }
711                 n = unionread(c, va, n);
712                 poperror();
713                 c->umh = omh;
714                 return n;
715         }
716 }
717
718 static long
719 shrwrite(Chan *c, void *va, long n, vlong)
720 {
721         Sch *sch;
722         char *buf, *p, *aname;
723         int fd;
724         Chan *bc, *c0;
725         Mhead *h;
726         Mount *m;
727         struct{
728                 Chan    *chan;
729                 Chan    *authchan;
730                 char    *spec;
731                 int     flags;
732         }bogus;
733
734         if(up->pgrp->noattach)
735                 error(Enoattach);
736         sch = tosch(c);
737         if(sch->level != Qcmpt)
738                 error(Egreg);
739
740         buf = smalloc(n+1);
741         if(waserror()){
742                 free(buf);
743                 nexterror();
744         }
745         memmove(buf, va, n);
746         buf[n] = 0;
747         
748         fd = strtol(buf, &p, 10);
749         if(p == buf || (*p != 0 && *p != '\n'))
750                 error(Ebadarg);
751         if(*p == '\n' && *(p+1) != 0)
752                 aname = p + 1;
753         else
754                 aname = nil;
755         
756         bc = fdtochan(fd, ORDWR, 0, 1);
757         if(waserror()) {
758                 cclose(bc);
759                 nexterror();
760         }
761         bogus.flags = 0;
762         bogus.chan = bc;
763         bogus.authchan = nil;
764         bogus.spec = aname;
765         c0 = devtab[devno('M', 0)]->attach((char*)&bogus);
766         poperror();
767         cclose(bc);
768         poperror();
769         free(buf);
770
771         if(c0 == nil)
772                 error(Egreg);
773
774         m = &sch->mpt->m;
775         h = &sch->shr->umh;
776         wlock(&h->lock);
777         bc = m->to;
778         m->to = c0;
779         wunlock(&h->lock);
780
781         if(bc != nil)
782                 cclose(bc);
783
784         return n;
785 }
786
787 static void
788 shrclose(Chan *c)
789 {
790         if(c->flag & CRCLOSE)
791                 shrremove(c);
792         else
793                 shrclunk(c);
794 }
795
796 Dev shrdevtab = {
797         L'σ',
798         "shr",
799
800         devreset,
801         shrinit,        
802         devshutdown,
803         shrattach,
804         shrwalk,
805         shrstat,
806         shropen,
807         shrcreate,
808         shrclose,
809         shrread,
810         devbread,
811         shrwrite,
812         devbwrite,
813         shrremove,
814         shrwstat,
815 };
816
817 static void
818 chowner(Ent *ent, char *old, char *new)
819 {
820         if(ent->owner != nil && strcmp(old, ent->owner) == 0)
821                 kstrdup(&ent->owner, new);
822 }
823
824 void
825 shrrenameuser(char *old, char *new)
826 {
827         Shr *shr;
828         Mount *m;
829
830         qlock(&shrslk);
831         for(shr = shrs; shr != nil; shr = shr->next){
832                 wlock(&shr->umh.lock);
833                 for(m = shr->umh.mount; m != nil; m = m->next)
834                         chowner(tompt(m), old, new);
835                 wunlock(&shr->umh.lock);
836                 chowner(shr, old, new);
837         }
838         qunlock(&shrslk);
839 }