]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/devshr.c
devshr: fixed crash
[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 typedef struct Shr Shr;
9
10 struct Shr
11 {
12         Ref;
13         char    *name;
14         char    *owner;
15         ulong   perm;
16         Shr     *link;
17         ulong   path;
18         Mhead   umh; /* only lock and mount are used */
19         char    *desc; /* contents of file; nil if invalid, rebuild if necessary */
20         QLock   desclock;
21 };
22
23 static QLock    shrlk;
24 static Shr      *shr;
25 static int      qidpath;
26 static int      mntid;
27
28 static void
29 shrdecref(Shr *sp)
30 {
31         Mount *m, *mm;
32         int n;
33
34         qlock(&shrlk);
35         n = decref(sp);
36         qunlock(&shrlk);
37         if(n != 0)
38                 return;
39         
40         for(m = sp->umh.mount; m != nil; m = mm) {
41                 cclose(m->to);
42                 mm = m->next;
43                 free(m);
44         }
45         if(sp->desc != nil)
46                 free(sp->desc);
47         free(sp->owner);
48         free(sp->name);
49         free(sp);
50 }
51
52 static int
53 shrgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
54 {
55         Shr *sp;
56         Qid q;
57
58         if(s == DEVDOTDOT){
59                 devdir(c, c->qid, "#σ", 0, eve, 0555, dp);
60                 return 1;
61         }
62
63         qlock(&shrlk);
64         for(sp = shr; sp && s; sp = sp->link)
65                 s--;
66
67         if(sp == 0) {
68                 qunlock(&shrlk);
69                 return -1;
70         }
71
72         mkqid(&q, sp->path, 0, c->dev ? QTFILE : QTDIR);
73         /* make sure name string continues to exist after we release lock */
74         kstrcpy(up->genbuf, sp->name, sizeof up->genbuf);
75         devdir(c, q, up->genbuf, 0, sp->owner, sp->perm & (c->dev ? ~0111 : ~0), dp);
76         qunlock(&shrlk);
77         return 1;
78 }
79
80 static void
81 shrinit(void)
82 {
83         qidpath = 1;
84 }
85
86 static Chan*
87 shrattach(char *spec)
88 {
89         Chan *c;
90         
91         if(!(spec[0] == 'c' && spec[1] == 0 || spec[0] == 0))
92                 error(Enoattach);
93
94         c = devattach(L'σ', spec);
95         if(spec[0] == 'c')
96                 c->dev = 1;
97         else
98                 c->dev = 0;
99         return c;
100 }
101
102 static Shr*
103 shrlookup(char *name, ulong qidpath)
104 {
105         Shr *sp;
106         for(sp = shr; sp; sp = sp->link)
107                 if(sp->path == qidpath || (name && strcmp(sp->name, name) == 0))
108                         return sp;
109         return nil;
110 }
111
112 static int
113 shrremovemnt(Shr *sp, int id)
114 {
115         Mount *m, **l;
116
117         wlock(&sp->umh.lock);
118         l = &sp->umh.mount;
119         for(m = *l; m; m = m->next){
120                 if(m->mountid == id){
121                         cclose(m->to);
122                         *l = m->next;
123                         free(m);
124                         break;
125                 }
126                 l = &m->next;
127         }
128
129         if(m == nil){
130                 wunlock(&sp->umh.lock);
131                 return -1;
132         }
133         qlock(&sp->desclock);
134         free(sp->desc);
135         sp->desc = nil;
136         qunlock(&sp->desclock);
137         wunlock(&sp->umh.lock);
138         return 0;
139 }
140
141 static Walkqid*
142 shrwalk(Chan *c, Chan *nc, char **name, int nname)
143 {
144         Walkqid *wq, *wq2;
145         Shr *sp;
146         int alloc, j;
147         char *n;
148         Mount *f;
149         
150         if(nname > 0)
151                 isdir(c);
152
153         alloc = 0;
154         wq = smalloc(sizeof(Walkqid) + (nname - 1) * sizeof(Qid));
155         if(waserror()){
156                 if(alloc && wq->clone != nil)
157                         cclose(wq->clone);
158                 free(wq);
159                 return nil;
160         }
161         if(nc == nil){
162                 nc = devclone(c);
163                 nc->type = 0;
164                 alloc = 1;
165         }
166         nc->aux = nil;
167         wq->clone = nc;
168         for(j = 0; j < nname; j++){
169                 if(!(nc->qid.type & QTDIR)){
170                         if(j == 0)
171                                 error(Enotdir);
172                         kstrcpy(up->errstr, Enotdir, ERRMAX);
173                         goto Done;
174                 }
175                 n = name[j];
176                 if(n[0] == '.' && n[1] == 0)
177                         USED(n);
178                 else if(n[0] == '.' && n[1] == '.' && n[2] == 0){
179                         if(nc->qid.path != 0)
180                                 nc->qid.path = 0;
181                         nc->qid.type = QTDIR;
182                 } else if(nc->qid.path == 0) {
183                         qlock(&shrlk);
184                         sp = shrlookup(n, -1);
185                         if(sp != nil){
186                                 if(waserror()){
187                                         qunlock(&shrlk);
188                                         if(j == 0)
189                                                 nexterror();
190                                         goto Done;
191                                 }
192                                 devpermcheck(sp->owner, sp->perm, OEXEC);
193                                 poperror();
194                                 mkqid(&nc->qid, sp->path, 0, c->dev ? QTFILE : QTDIR);
195                         }
196                         qunlock(&shrlk);
197                         if(sp == nil)
198                                 goto Error;
199                 } else {
200                         qlock(&shrlk);
201                         sp = shrlookup(nil, nc->qid.path);
202                         if(sp != nil)
203                                 incref(sp);
204                         qunlock(&shrlk);
205                         if(sp == nil)
206                                 goto Error;
207                         wq2 = nil;
208                         rlock(&sp->umh.lock);
209                         for(f = sp->umh.mount; f != nil && wq2 == nil; f = f->next) {
210                                 if(waserror())
211                                         continue;
212                                 wq2 = devtab[f->to->type]->walk(f->to, nil, name + j, nname - j);
213                                 poperror();
214                         }
215                         runlock(&sp->umh.lock);
216                         shrdecref(sp);
217                         if(wq2 == nil)
218                                 goto Error;
219                         memmove(wq->qid + wq->nqid, wq2->qid, wq2->nqid);
220                         wq->nqid += wq2->nqid;
221                         if(alloc)
222                                 cclose(wq->clone);
223                         wq->clone = wq2->clone;
224                         free(wq2);
225                         poperror();
226                         return wq;
227                 }
228                 wq->qid[wq->nqid++] = nc->qid;
229         }
230
231         goto Done;
232 Error:
233         if(j == 0)
234                 error(Enonexist);
235         kstrcpy(up->errstr, Enonexist, ERRMAX);
236 Done:
237         poperror();
238         if(wq->nqid < nname) {
239                 if(alloc)
240                         cclose(wq->clone);
241                 wq->clone = nil;
242         } else if(wq->clone)
243                 wq->clone->type = c->type;
244         return wq;
245 }
246
247 static int
248 shrstat(Chan *c, uchar *db, int n)
249 {
250         return devstat(c, db, n, 0, 0, shrgen);
251 }
252
253 static Chan*
254 shropen(Chan *c, int omode)
255 {
256         Shr *sp;
257
258         if(c->qid.type == QTDIR && omode != OREAD)
259                 error(Eisdir);
260         if(c->qid.path != 0){
261                 qlock(&shrlk);
262                 if(waserror()){
263                         qunlock(&shrlk);
264                         nexterror();
265                 }
266                 sp = shrlookup(nil, c->qid.path);
267                 if(sp == nil)
268                         error(Enonexist);
269                 if(c->qid.type == QTDIR)
270                         c->umh = &sp->umh;
271                 devpermcheck(sp->owner, sp->perm, openmode(omode));
272                 qunlock(&shrlk);
273                 poperror();
274         }
275         if(omode & ORCLOSE)
276                 error(Eperm);
277         c->mode = openmode(omode);
278         c->flag |= COPEN;
279         c->offset = 0;
280         return c;
281 }
282
283 static void
284 shrunioncreate(Chan *c, char *name, int omode, ulong perm)
285 {
286         Shr *sp;
287         Mount *m;
288         Walkqid *wq;
289         
290         error(Enocreate); /* code below is broken */
291         
292         qlock(&shrlk);
293         sp = shrlookup(nil, c->qid.path);
294         if(sp != nil)
295                 incref(sp);
296         qunlock(&shrlk);
297         if(sp == nil)
298                 error(Enonexist);
299         if(waserror()){
300                 shrdecref(sp);
301                 nexterror();
302         }
303         for(m = sp->umh.mount; m != nil; m = m->next)
304                 if(m->mflag & MCREATE)
305                         break;
306         if(m == nil)
307                 error(Enocreate);
308
309         wq = devtab[m->to->type]->walk(m->to, c, nil, 0);
310         if(wq == nil)
311                 error(Egreg);
312         if(wq->clone != c){
313                 cclose(wq->clone);
314                 free(wq);
315                 error(Egreg);
316         }
317         free(wq);
318         devtab[c->type]->create(c, name, omode, perm);
319         shrdecref(sp);
320         poperror();
321 }
322
323 static void
324 shrcreate(Chan *c, char *name, int omode, ulong perm)
325 {
326         char *sname;
327         Shr *sp;
328         
329         if(c->qid.path != 0) {
330                 shrunioncreate(c, name, omode, perm);
331                 return;
332         }
333         
334         if(c->dev != 1)
335                 error(Eperm);
336
337         if(omode & OCEXEC)      /* can't happen */
338                 panic("someone broke namec");
339
340         sp = smalloc(sizeof *sp);
341         sname = smalloc(strlen(name)+1);
342
343         qlock(&shrlk);
344         if(waserror()){
345                 free(sp);
346                 free(sname);
347                 qunlock(&shrlk);
348                 nexterror();
349         }
350         if(sp == nil || sname == nil)
351                 error(Enomem);
352         if(shrlookup(name, -1))
353                 error(Eexist);
354
355         sp->path = qidpath++;
356         sp->link = shr;
357         strcpy(sname, name);
358         sp->name = sname;
359         incref(sp);
360         c->qid.type = QTFILE;
361         c->qid.path = sp->path;
362         shr = sp;
363         qunlock(&shrlk);
364         poperror();
365
366         kstrdup(&sp->owner, up->user);
367         sp->perm = (perm&0777) | ((perm&0444)>>2);
368
369         c->flag |= COPEN;
370         c->mode = OWRITE;
371 }
372
373 static void
374 shrremove(Chan *c)
375 {
376         Shr *sp, **l;
377
378         if(c->qid.path == 0)
379                 error(Eperm);
380
381         qlock(&shrlk);
382         if(waserror()){
383                 qunlock(&shrlk);
384                 nexterror();
385         }
386         l = &shr;
387         for(sp = *l; sp; sp = sp->link) {
388                 if(sp->path == c->qid.path)
389                         break;
390
391                 l = &sp->link;
392         }
393         if(sp == 0)
394                 error(Enonexist);
395
396         if(strcmp(sp->owner, eve) == 0 && !iseve())
397                 error(Eperm);
398         if((sp->perm&7) != 7 && strcmp(sp->owner, up->user) != 0 && !iseve())
399                 error(Eperm);
400
401         *l = sp->link;
402         qunlock(&shrlk);
403         poperror();
404
405         shrdecref(sp);
406 }
407
408 static int
409 shrwstat(Chan *c, uchar *dp, int n)
410 {
411         char *strs;
412         Dir d;
413         Shr *sp;
414
415         if(c->qid.path == 0)
416                 error(Eperm);
417
418         strs = nil;
419         qlock(&shrlk);
420         if(waserror()){
421                 qunlock(&shrlk);
422                 free(strs);
423                 nexterror();
424         }
425
426         sp = shrlookup(nil, c->qid.path);
427         if(sp == 0)
428                 error(Enonexist);
429
430         if(strcmp(sp->owner, up->user) != 0 && !iseve())
431                 error(Eperm);
432
433         strs = smalloc(n);
434         n = convM2D(dp, n, &d, strs);
435         if(n == 0)
436                 error(Eshortstat);
437         if(d.mode != ~0UL)
438                 sp->perm = d.mode & 0777;
439         if(d.uid && *d.uid)
440                 kstrdup(&sp->owner, d.uid);
441         if(d.name && *d.name && strcmp(sp->name, d.name) != 0) {
442                 if(strchr(d.name, '/') != nil)
443                         error(Ebadchar);
444                 kstrdup(&sp->name, d.name);
445         }
446         qunlock(&shrlk);
447         free(strs);
448         poperror();
449         return n;
450 }
451
452 static void
453 shrclose(Chan *c)
454 {
455         c->umh = nil;
456         if(c->flag & CRCLOSE){
457                 if(waserror())
458                         return;
459                 shrremove(c);
460                 poperror();
461         }
462 }
463
464 static long
465 shrread(Chan *c, void *va, long n, vlong off)
466 {
467         Shr *sp;
468         long ret;
469         int nn;
470         Mount *f;
471         char *s, *e;
472
473         if(c->qid.path == 0)
474                 return devdirread(c, va, n, 0, 0, shrgen);
475         
476         if(c->qid.type & QTDIR)
477                 return unionread(c, va, n);
478         
479         qlock(&shrlk);
480         sp = shrlookup(nil, c->qid.path);
481         if(sp != nil)
482                 incref(sp);
483         qunlock(&shrlk);
484         if(sp == nil)
485                 error(Enonexist);
486         qlock(&sp->desclock);
487         if(sp->desc == nil){
488                 nn = 0;
489                 rlock(&sp->umh.lock);
490                 for(f = sp->umh.mount; f != nil; f = f->next)
491                         nn += 32 + strlen((char*)(f + 1));
492                 s = sp->desc = smalloc(nn + 1);
493                 e = s + nn;
494                 for(f = sp->umh.mount; f != nil; f = f->next)
495                         s = seprint(s, e, "%lud %s %C %lud %lld\n", f->mountid, (char*)(f + 1), devtab[f->to->mchan->type]->dc, f->to->mchan->dev, f->to->qid.path);
496                 runlock(&sp->umh.lock);
497         }
498         ret = readstr(off, va, n, sp->desc);
499         qunlock(&sp->desclock);
500         shrdecref(sp);
501         return ret;
502 }
503
504 static long
505 shrwrite(Chan *c, void *va, long n, vlong)
506 {
507         Shr *sp;
508         char *buf, *p, *desc, *aname;
509         int mode, fd, id;
510         Chan *bc, *c0;
511         Mount *m, *mm;
512         struct{
513                 Chan    *chan;
514                 Chan    *authchan;
515                 char    *spec;
516                 int     flags;
517         }bogus;
518         
519         qlock(&shrlk);
520         sp = shrlookup(nil, c->qid.path);
521         if(sp != nil)
522                 incref(sp);
523         qunlock(&shrlk);
524         if(sp == nil)
525                 error(Enonexist);
526         buf = smalloc(n+1);
527         if(waserror()){
528                 shrdecref(sp);
529                 free(buf);
530                 nexterror();
531         }
532         memmove(buf, va, n);
533         buf[n] = 0;
534         
535         if(*buf == 'u'){
536                 p = buf + 1;
537                 while(*p <= ' ' && *p != '\n')
538                         p++;
539                 if(*p == 0 || *p == '\n')
540                         error(Ebadarg);
541                 id = strtol(p, 0, 10);
542                 if(shrremovemnt(sp, id) < 0)
543                         error(Ebadarg);
544                 shrdecref(sp);
545                 free(buf);
546                 poperror();
547                 return n;
548         }
549         
550         p = buf;
551         mode = 0;
552         for(; *p > ' '; p++)
553                 switch(*p) {
554                 case 'a': mode |= MAFTER; break;
555                 case 'b': mode |= MBEFORE; break;
556                 case 'c': mode |= MCREATE; break;
557                 case 'C': mode |= MCACHE; break;
558                 default: error(Ebadarg);
559                 }
560
561         if((mode & (MAFTER|MBEFORE)) == 0 || (mode & (MAFTER|MBEFORE)) == (MAFTER|MBEFORE))
562                 error(Ebadarg);
563         while(*p <= ' ' && *p != '\n')
564                 p++;
565         if(*p == 0 || *p == '\n')
566                 error(Ebadarg);
567         fd = strtol(p, &p, 10);
568         while(*p <= ' ' && *p != '\n')
569                 p++;
570         if(*p != 0 && *p != '\n') {
571                 desc = p;
572                 p = strchr(desc, '\n');
573                 if(p != nil)
574                         *p = 0;
575         } else
576                 desc = "";
577         aname = strchr(buf, '\n');
578         if(aname != nil && *++aname == 0)
579                 aname = nil;
580         if(strlen(desc) > 128)
581                 error(Ebadarg);
582
583         bc = fdtochan(fd, ORDWR, 0, 1);
584         if(waserror()) {
585                 cclose(bc);
586                 nexterror();
587         }
588         bogus.flags = mode & MCACHE;
589         bogus.chan = bc;
590         bogus.authchan = nil;
591         bogus.spec = aname;
592         c0 = devtab[devno('M', 0)]->attach((char*)&bogus);
593         cclose(bc);
594         poperror();
595
596         m = smalloc(sizeof(Mount) + strlen(desc) + 1);
597         strcpy((char*)(m + 1), desc);
598         m->to = c0;
599         m->mflag = mode;
600         qlock(&shrlk);
601         m->mountid = ++mntid;
602         qunlock(&shrlk);
603         wlock(&sp->umh.lock);
604         if((mode & MAFTER) != 0 && sp->umh.mount != nil) {
605                 for(mm = sp->umh.mount; mm->next != nil; mm = mm->next)
606                         ;
607                 mm->next = m;
608         } else {
609                 m->next = sp->umh.mount;
610                 sp->umh.mount = m;
611         }
612         wunlock(&sp->umh.lock);
613         qlock(&sp->desclock);
614         free(sp->desc);
615         sp->desc = nil;
616         qunlock(&sp->desclock);
617         shrdecref(sp);
618         free(buf);
619         poperror();
620         return n;
621 }
622
623 Dev shrdevtab = {
624         L'σ',
625         "shr",
626
627         devreset,
628         shrinit,        
629         devshutdown,
630         shrattach,
631         shrwalk,
632         shrstat,
633         shropen,
634         shrcreate,
635         shrclose,
636         shrread,
637         devbread,
638         shrwrite,
639         devbwrite,
640         shrremove,
641         shrwstat,
642 };