]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/devshr.c
03739a31de39bd846757561c69ab7b122411ff26
[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
379         if(c->qid.type == QTDIR && omode != OREAD)
380                 error(Eisdir);
381
382         sch = tosch(c);
383         switch(sch->level){
384         default:
385                 error(Egreg);
386         case Qroot:
387         case Qcroot:
388                 break;
389         case Qshr:
390         case Qcshr:
391                 shr = sch->shr;
392                 devpermcheck(shr->owner, shr->perm, openmode(omode));
393                 break;
394         case Qcmpt:
395                 if(omode&OTRUNC)
396                         error(Eexist);
397                 shr = sch->shr;
398                 mpt = sch->mpt;
399                 devpermcheck(mpt->owner, mpt->perm, openmode(omode));
400                 rlock(&shr->umh.lock);
401                 if(mpt->m.to == nil || mpt->m.to->mchan == nil){
402                         runlock(&shr->umh.lock);
403                         error(Eshutdown);
404                 }
405                 nc = mpt->m.to->mchan;
406                 incref(nc);
407                 runlock(&shr->umh.lock);
408                 if(openmode(omode) != nc->mode){
409                         cclose(nc);
410                         error(Eperm);
411                 }
412                 cclose(c);
413                 return nc;
414         }
415         c->mode = openmode(omode);
416         c->flag |= COPEN;
417         c->offset = 0;
418         return c;
419 }
420
421 /* chan.c */
422 Chan* createdir(Chan *c, Mhead *m);
423
424 static Chan*
425 shrcreate(Chan *c, char *name, int omode, ulong perm)
426 {
427         Sch *sch;
428         Shr *shr;
429         Mpt *mpt;
430         Mhead *h;
431         Mount *m;
432         Chan *nc;
433
434         sch = tosch(c);
435         switch(sch->level){
436         case Qcroot:
437         case Qcshr:
438                 if(strcmp(up->user, "none") == 0)
439                         error(Eperm);
440         }
441         switch(sch->level){
442         default:
443                 error(Eperm);
444         case Qshr:
445                 incref(c);
446                 if(waserror()){
447                         cclose(c);
448                         nexterror();
449                 }
450                 nc = createdir(c, &sch->shr->umh);
451                 poperror();
452                 if(waserror()){
453                         cclose(nc);
454                         nexterror();
455                 }
456                 nc = devtab[nc->type]->create(nc, name, omode, perm);
457                 poperror();
458                 cclose(c);
459                 return nc;      
460         case Qcroot:
461                 if(up->pgrp->noattach)
462                         error(Enoattach);
463                 if((perm & DMDIR) == 0 || openmode(omode) != OREAD)
464                         error(Eperm);
465                 if(strlen(name) >= sizeof(up->genbuf))
466                         error(Etoolong);
467                 qlock(&shrslk);
468                 if(waserror()){
469                         qunlock(&shrslk);
470                         nexterror();
471                 }
472                 for(shr = shrs; shr != nil; shr = shr->next)
473                         if(strcmp(name, shr->name) == 0)
474                                 error(Eexist);
475
476                 shr = smalloc(sizeof(*shr));
477                 incref(shr);
478                 shr->id = shrid++;
479
480                 kstrdup(&shr->name, name);
481                 kstrdup(&shr->owner, up->user);
482                 shr->perm = perm;
483
484                 incref(shr);
485                 shr->next = shrs;
486                 shrs = shr;
487
488                 poperror();
489                 qunlock(&shrslk);
490
491                 c->qid = shrqid(sch->level = Qcshr, shr->id);
492                 sch->shr = shr;
493                 break;
494         case Qcshr:
495                 if(up->pgrp->noattach)
496                         error(Enoattach);
497                 if((perm & DMDIR) != 0 || openmode(omode) != OWRITE)
498                         error(Eperm);
499
500                 shr = sch->shr;
501                 if(strcmp(shr->owner, eve) == 0 && !iseve())
502                         error(Eperm);
503                 devpermcheck(shr->owner, shr->perm, ORDWR);
504
505                 if(strlen(name) >= sizeof(up->genbuf))
506                         error(Etoolong);
507
508                 h = &shr->umh;
509                 wlock(&h->lock);
510                 if(waserror()){
511                         wunlock(&h->lock);
512                         nexterror();
513                 }
514                 for(m = h->mount; m != nil; m = m->next){
515                         mpt = tompt(m);
516                         if(strcmp(name, mpt->name) == 0)
517                                 error(Eexist);
518                 }
519
520                 mpt = smalloc(sizeof(*mpt));
521                 incref(mpt);
522                 mpt->id = mptid++;
523
524                 kstrdup(&mpt->name, name);
525                 kstrdup(&mpt->owner, up->user);
526                 mpt->perm = perm;
527
528                 incref(mpt);
529                 mpt->m.mflag = (h->mount == nil) ? MCREATE : 0;
530                 mpt->m.head = h;
531                 mpt->m.next = h->mount;
532                 h->mount = &mpt->m;
533
534                 poperror();
535                 wunlock(&h->lock);
536
537                 c->qid = shrqid(sch->level = Qcmpt, mpt->id);
538                 sch->mpt = mpt;
539                 break;
540         }
541         c->flag |= COPEN;
542         c->mode = openmode(omode);
543         return c;
544 }
545
546 static void
547 shrremove(Chan *c)
548 {
549         Mount *m, **ml;
550         Shr *shr, **sl;
551         Sch *sch;
552         Mpt *mpt;
553         Mhead *h;
554
555         sch = tosch(c);
556         if(waserror()){
557                 shrclunk(c);
558                 nexterror();
559         }
560         switch(sch->level){
561         default:
562                 error(Eperm);
563         case Qcshr:
564         case Qcmpt:
565                 shr = sch->shr;
566                 if(!iseve()){
567                         if(strcmp(shr->owner, eve) == 0)
568                                 error(Eperm);
569                         devpermcheck(shr->owner, shr->perm, ORDWR);
570                 }
571         }
572         switch(sch->level){
573         case Qcshr:
574                 h = &shr->umh;
575                 qlock(&shrslk);
576                 rlock(&h->lock);
577                 if(h->mount != nil){
578                         runlock(&h->lock);
579                         qunlock(&shrslk);
580                         error("directory not empty");
581                 }
582                 runlock(&h->lock);
583                 for(sl = &shrs; *sl != nil; sl = &((*sl)->next))
584                         if(*sl == shr){
585                                 *sl = shr->next;
586                                 shr->next = nil;
587                                 putshr(shr);
588                                 break;
589                         }
590                 qunlock(&shrslk);
591                 break;
592         case Qcmpt:
593                 mpt = sch->mpt;
594                 m = &mpt->m;
595                 h = &shr->umh;
596                 wlock(&h->lock);
597                 for(ml = &h->mount; *ml != nil; ml = &((*ml)->next))
598                         if(*ml == m){
599                                 *ml = m->next;
600                                 m->next = nil;
601                                 m->head = nil;
602                                 putmpt(mpt);
603                                 break;
604                         }
605                 wunlock(&h->lock);
606                 break;
607         }
608         poperror();
609         shrclunk(c);
610 }
611
612 static int
613 shrwstat(Chan *c, uchar *dp, int n)
614 {
615         char *strs;
616         Mhead *h;
617         Sch *sch;
618         Ent *ent;
619         Dir d;
620
621         strs = smalloc(n);
622         if(waserror()){
623                 free(strs);
624                 nexterror();
625         }
626         n = convM2D(dp, n, &d, strs);
627         if(n == 0)
628                 error(Eshortstat);
629
630         h = nil;
631         sch = tosch(c);
632         switch(sch->level){
633         default:
634                 error(Eperm);
635         case Qcshr:
636                 ent = sch->shr;
637                 qlock(&shrslk);
638                 if(waserror()){
639                         qunlock(&shrslk);
640                         nexterror();
641                 }
642                 break;
643         case Qcmpt:
644                 ent = sch->mpt;
645                 h = &sch->shr->umh;
646                 wlock(&h->lock);
647                 if(waserror()){
648                         wunlock(&h->lock);
649                         nexterror();
650                 }
651                 break;
652         }
653
654         if(strcmp(ent->owner, up->user) && !iseve())
655                 error(Eperm);
656
657         if(d.mode != ~0UL)
658                 ent->perm = d.mode & 0777;
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
669         switch(sch->level){
670         case Qcshr:
671                 poperror();
672                 qunlock(&shrslk);
673                 break;
674         case Qcmpt:
675                 poperror();
676                 wunlock(&h->lock);
677                 break;
678         }
679
680         poperror();
681         free(strs);
682
683         return n;
684 }
685
686 static long
687 shrread(Chan *c, void *va, long n, vlong)
688 {
689         Mhead *omh;
690         Sch *sch;
691
692         sch = tosch(c);
693         switch(sch->level){
694         default:
695                 error(Egreg);
696         case Qroot:
697         case Qcroot:
698         case Qcshr:
699                 return devdirread(c, va, n, 0, 0, shrgen);
700         case Qshr:
701                 omh = c->umh;
702                 c->umh = &sch->shr->umh;
703                 if(waserror()){
704                         c->umh = omh;
705                         nexterror();
706                 }
707                 n = unionread(c, va, n);
708                 poperror();
709                 c->umh = omh;
710                 return n;
711         }
712 }
713
714 static long
715 shrwrite(Chan *c, void *va, long n, vlong)
716 {
717         Sch *sch;
718         char *buf, *p, *aname;
719         int fd;
720         Chan *bc, *c0;
721         Mhead *h;
722         Mount *m;
723         struct{
724                 Chan    *chan;
725                 Chan    *authchan;
726                 char    *spec;
727                 int     flags;
728         }bogus;
729
730         if(up->pgrp->noattach)
731                 error(Enoattach);
732         sch = tosch(c);
733         if(sch->level != Qcmpt)
734                 error(Egreg);
735
736         buf = smalloc(n+1);
737         if(waserror()){
738                 free(buf);
739                 nexterror();
740         }
741         memmove(buf, va, n);
742         buf[n] = 0;
743         
744         fd = strtol(buf, &p, 10);
745         if(p == buf || (*p != 0 && *p != '\n'))
746                 error(Ebadarg);
747         if(*p == '\n' && *(p+1) != 0)
748                 aname = p + 1;
749         else
750                 aname = nil;
751         
752         bc = fdtochan(fd, ORDWR, 0, 1);
753         if(waserror()) {
754                 cclose(bc);
755                 nexterror();
756         }
757         bogus.flags = 0;
758         bogus.chan = bc;
759         bogus.authchan = nil;
760         bogus.spec = aname;
761         c0 = devtab[devno('M', 0)]->attach((char*)&bogus);
762         poperror();
763         cclose(bc);
764         poperror();
765         free(buf);
766
767         if(c0 == nil)
768                 error(Egreg);
769
770         m = &sch->mpt->m;
771         h = &sch->shr->umh;
772         wlock(&h->lock);
773         bc = m->to;
774         m->to = c0;
775         wunlock(&h->lock);
776
777         if(bc != nil)
778                 cclose(bc);
779
780         return n;
781 }
782
783 static void
784 shrclose(Chan *c)
785 {
786         if(c->flag & CRCLOSE)
787                 shrremove(c);
788         else
789                 shrclunk(c);
790 }
791
792 Dev shrdevtab = {
793         L'σ',
794         "shr",
795
796         devreset,
797         shrinit,        
798         devshutdown,
799         shrattach,
800         shrwalk,
801         shrstat,
802         shropen,
803         shrcreate,
804         shrclose,
805         shrread,
806         devbread,
807         shrwrite,
808         devbwrite,
809         shrremove,
810         shrwstat,
811 };
812
813 static void
814 chowner(Ent *ent, char *old, char *new)
815 {
816         if(ent->owner != nil && strcmp(old, ent->owner) == 0)
817                 kstrdup(&ent->owner, new);
818 }
819
820 void
821 shrrenameuser(char *old, char *new)
822 {
823         Shr *shr;
824         Mount *m;
825
826         qlock(&shrslk);
827         for(shr = shrs; shr != nil; shr = shr->next){
828                 wlock(&shr->umh.lock);
829                 for(m = shr->umh.mount; m != nil; m = m->next)
830                         chowner(tompt(m), old, new);
831                 wunlock(&shr->umh.lock);
832                 chowner(shr, old, new);
833         }
834         qunlock(&shrslk);
835 }