]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/devshr.c
kernel: avoid selecting the boot process in killbig()
[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.next = h->mount;
535                 h->mount = &mpt->m;
536
537                 poperror();
538                 wunlock(&h->lock);
539
540                 c->qid = shrqid(sch->level = Qcmpt, mpt->id);
541                 sch->mpt = mpt;
542                 break;
543         }
544         c->flag |= COPEN;
545         c->mode = mode;
546         return c;
547 }
548
549 static void
550 shrremove(Chan *c)
551 {
552         Mount *m, **ml;
553         Shr *shr, **sl;
554         Sch *sch;
555         Mpt *mpt;
556         Mhead *h;
557
558         sch = tosch(c);
559         if(waserror()){
560                 shrclunk(c);
561                 nexterror();
562         }
563         switch(sch->level){
564         default:
565                 error(Eperm);
566         case Qcshr:
567         case Qcmpt:
568                 shr = sch->shr;
569                 if(!iseve()){
570                         if(strcmp(shr->owner, eve) == 0)
571                                 error(Eperm);
572                         devpermcheck(shr->owner, shr->perm, ORDWR);
573                 }
574         }
575         switch(sch->level){
576         case Qcshr:
577                 h = &shr->umh;
578                 qlock(&shrslk);
579                 rlock(&h->lock);
580                 if(h->mount != nil){
581                         runlock(&h->lock);
582                         qunlock(&shrslk);
583                         error("directory not empty");
584                 }
585                 runlock(&h->lock);
586                 for(sl = &shrs; *sl != nil; sl = &((*sl)->next))
587                         if(*sl == shr){
588                                 *sl = shr->next;
589                                 shr->next = nil;
590                                 putshr(shr);
591                                 break;
592                         }
593                 qunlock(&shrslk);
594                 break;
595         case Qcmpt:
596                 mpt = sch->mpt;
597                 m = &mpt->m;
598                 h = &shr->umh;
599                 wlock(&h->lock);
600                 for(ml = &h->mount; *ml != nil; ml = &((*ml)->next))
601                         if(*ml == m){
602                                 *ml = m->next;
603                                 m->next = nil;
604                                 putmpt(mpt);
605                                 break;
606                         }
607                 wunlock(&h->lock);
608                 break;
609         }
610         poperror();
611         shrclunk(c);
612 }
613
614 static int
615 shrwstat(Chan *c, uchar *dp, int n)
616 {
617         char *strs;
618         Mhead *h;
619         Sch *sch;
620         Ent *ent;
621         Dir d;
622
623         strs = smalloc(n);
624         if(waserror()){
625                 free(strs);
626                 nexterror();
627         }
628         n = convM2D(dp, n, &d, strs);
629         if(n == 0)
630                 error(Eshortstat);
631
632         h = nil;
633         sch = tosch(c);
634         switch(sch->level){
635         default:
636                 error(Eperm);
637         case Qcshr:
638                 ent = sch->shr;
639                 qlock(&shrslk);
640                 if(waserror()){
641                         qunlock(&shrslk);
642                         nexterror();
643                 }
644                 break;
645         case Qcmpt:
646                 ent = sch->mpt;
647                 h = &sch->shr->umh;
648                 wlock(&h->lock);
649                 if(waserror()){
650                         wunlock(&h->lock);
651                         nexterror();
652                 }
653                 break;
654         }
655
656         if(strcmp(ent->owner, up->user) && !iseve())
657                 error(Eperm);
658
659         if(d.name != nil && *d.name && strcmp(ent->name, d.name) != 0) {
660                 if(strchr(d.name, '/') != nil)
661                         error(Ebadchar);
662                 if(strlen(d.name) >= sizeof(up->genbuf))
663                         error(Etoolong);
664                 kstrdup(&ent->name, d.name);
665         }
666         if(d.uid != nil && *d.uid)
667                 kstrdup(&ent->owner, d.uid);
668         if(d.mode != ~0UL)
669                 ent->perm = d.mode & 0777;
670
671         switch(sch->level){
672         case Qcshr:
673                 poperror();
674                 qunlock(&shrslk);
675                 break;
676         case Qcmpt:
677                 poperror();
678                 wunlock(&h->lock);
679                 break;
680         }
681
682         poperror();
683         free(strs);
684
685         return n;
686 }
687
688 static long
689 shrread(Chan *c, void *va, long n, vlong)
690 {
691         Mhead *omh;
692         Sch *sch;
693
694         sch = tosch(c);
695         switch(sch->level){
696         default:
697                 error(Egreg);
698         case Qroot:
699         case Qcroot:
700         case Qcshr:
701                 return devdirread(c, va, n, 0, 0, shrgen);
702         case Qshr:
703                 omh = c->umh;
704                 c->umh = &sch->shr->umh;
705                 if(waserror()){
706                         c->umh = omh;
707                         nexterror();
708                 }
709                 n = unionread(c, va, n);
710                 poperror();
711                 c->umh = omh;
712                 return n;
713         }
714 }
715
716 static long
717 shrwrite(Chan *c, void *va, long n, vlong)
718 {
719         Sch *sch;
720         char *buf, *p, *aname;
721         int fd;
722         Chan *bc, *c0;
723         Mhead *h;
724         Mount *m;
725
726         if(up->pgrp->noattach)
727                 error(Enoattach);
728         sch = tosch(c);
729         if(sch->level != Qcmpt)
730                 error(Egreg);
731
732         buf = smalloc(n+1);
733         if(waserror()){
734                 free(buf);
735                 nexterror();
736         }
737         memmove(buf, va, n);
738         buf[n] = 0;
739         
740         fd = strtol(buf, &p, 10);
741         if(p == buf || (*p != 0 && *p != '\n'))
742                 error(Ebadarg);
743         if(*p == '\n' && *(p+1) != 0)
744                 aname = p + 1;
745         else
746                 aname = nil;
747         
748         bc = fdtochan(fd, ORDWR, 0, 1);
749         if(waserror()) {
750                 cclose(bc);
751                 nexterror();
752         }
753         c0 = mntattach(bc, nil, aname, 0);
754         poperror();
755         cclose(bc);
756         poperror();
757         free(buf);
758
759         if(c0 == nil)
760                 error(Egreg);
761
762         m = &sch->mpt->m;
763         h = &sch->shr->umh;
764         wlock(&h->lock);
765         bc = m->to;
766         m->to = c0;
767         wunlock(&h->lock);
768
769         if(bc != nil)
770                 cclose(bc);
771
772         return n;
773 }
774
775 static void
776 shrclose(Chan *c)
777 {
778         if(c->flag & CRCLOSE)
779                 shrremove(c);
780         else
781                 shrclunk(c);
782 }
783
784 Dev shrdevtab = {
785         L'σ',
786         "shr",
787
788         devreset,
789         shrinit,        
790         devshutdown,
791         shrattach,
792         shrwalk,
793         shrstat,
794         shropen,
795         shrcreate,
796         shrclose,
797         shrread,
798         devbread,
799         shrwrite,
800         devbwrite,
801         shrremove,
802         shrwstat,
803 };
804
805 static void
806 chowner(Ent *ent, char *old, char *new)
807 {
808         if(ent->owner != nil && strcmp(old, ent->owner) == 0)
809                 kstrdup(&ent->owner, new);
810 }
811
812 void
813 shrrenameuser(char *old, char *new)
814 {
815         Shr *shr;
816         Mount *m;
817
818         qlock(&shrslk);
819         for(shr = shrs; shr != nil; shr = shr->next){
820                 wlock(&shr->umh.lock);
821                 for(m = shr->umh.mount; m != nil; m = m->next)
822                         chowner(tompt(m), old, new);
823                 wunlock(&shr->umh.lock);
824                 chowner(shr, old, new);
825         }
826         qunlock(&shrslk);
827 }