]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/devsrv.c
merge
[plan9front.git] / sys / src / 9 / port / devsrv.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
9 typedef struct Srv Srv;
10 struct Srv
11 {
12         char    *name;
13         char    *owner;
14         ulong   perm;
15         Chan    *chan;
16         Srv     *link;
17         ulong   path;
18 };
19
20 static QLock    srvlk;
21 static Srv      *srv;
22 static int      qidpath;
23
24 static Srv*
25 srvlookup(char *name, ulong qidpath)
26 {
27         Srv *sp;
28
29         for(sp = srv; sp != nil; sp = sp->link) {
30                 if(sp->path == qidpath || (name != nil && strcmp(sp->name, name) == 0))
31                         return sp;
32         }
33         return nil;
34 }
35
36 static int
37 srvgen(Chan *c, char *name, Dirtab*, int, int s, Dir *dp)
38 {
39         Srv *sp;
40         Qid q;
41
42         if(s == DEVDOTDOT){
43                 devdir(c, c->qid, "#s", 0, eve, 0555, dp);
44                 return 1;
45         }
46
47         qlock(&srvlk);
48         if(name != nil)
49                 sp = srvlookup(name, -1);
50         else {
51                 for(sp = srv; sp != nil && s > 0; sp = sp->link)
52                         s--;
53         }
54         if(sp == nil || (name != nil && (strlen(sp->name) >= sizeof(up->genbuf)))) {
55                 qunlock(&srvlk);
56                 return -1;
57         }
58         mkqid(&q, sp->path, 0, QTFILE);
59         /* make sure name string continues to exist after we release lock */
60         kstrcpy(up->genbuf, sp->name, sizeof up->genbuf);
61         devdir(c, q, up->genbuf, 0, sp->owner, sp->perm, dp);
62         qunlock(&srvlk);
63         return 1;
64 }
65
66 static void
67 srvinit(void)
68 {
69         qidpath = 1;
70 }
71
72 static Chan*
73 srvattach(char *spec)
74 {
75         return devattach('s', spec);
76 }
77
78 static Walkqid*
79 srvwalk(Chan *c, Chan *nc, char **name, int nname)
80 {
81         return devwalk(c, nc, name, nname, 0, 0, srvgen);
82 }
83
84 static int
85 srvstat(Chan *c, uchar *db, int n)
86 {
87         return devstat(c, db, n, 0, 0, srvgen);
88 }
89
90 char*
91 srvname(Chan *c)
92 {
93         Srv *sp;
94         char *s;
95
96         s = nil;
97         qlock(&srvlk);
98         for(sp = srv; sp != nil; sp = sp->link) {
99                 if(sp->chan == c){
100                         s = malloc(3+strlen(sp->name)+1);
101                         if(s != nil)
102                                 sprint(s, "#s/%s", sp->name);
103                         break;
104                 }
105         }
106         qunlock(&srvlk);
107         return s;
108 }
109
110 static Chan*
111 srvopen(Chan *c, int omode)
112 {
113         Srv *sp;
114         Chan *nc;
115
116         if(c->qid.type == QTDIR){
117                 if(omode & ORCLOSE)
118                         error(Eperm);
119                 if(omode != OREAD)
120                         error(Eisdir);
121                 c->mode = omode;
122                 c->flag |= COPEN;
123                 c->offset = 0;
124                 return c;
125         }
126         qlock(&srvlk);
127         if(waserror()){
128                 qunlock(&srvlk);
129                 nexterror();
130         }
131
132         sp = srvlookup(nil, c->qid.path);
133         if(sp == nil || sp->chan == nil)
134                 error(Eshutdown);
135
136         if(omode&OTRUNC)
137                 error(Eexist);
138         if(openmode(omode)!=sp->chan->mode && sp->chan->mode!=ORDWR)
139                 error(Eperm);
140         devpermcheck(sp->owner, sp->perm, omode);
141
142         nc = sp->chan;
143         incref(nc);
144
145         qunlock(&srvlk);
146         poperror();
147
148         cclose(c);
149         return nc;
150 }
151
152 static Chan*
153 srvcreate(Chan *c, char *name, int omode, ulong perm)
154 {
155         Srv *sp;
156
157         if(openmode(omode) != OWRITE)
158                 error(Eperm);
159
160         if(strlen(name) >= sizeof(up->genbuf))
161                 error(Etoolong);
162
163         sp = smalloc(sizeof *sp);
164         kstrdup(&sp->name, name);
165         kstrdup(&sp->owner, up->user);
166
167         qlock(&srvlk);
168         if(waserror()){
169                 qunlock(&srvlk);
170                 free(sp->owner);
171                 free(sp->name);
172                 free(sp);
173                 nexterror();
174         }
175         if(srvlookup(name, -1) != nil)
176                 error(Eexist);
177
178         sp->perm = perm&0777;
179         sp->path = qidpath++;
180
181         c->qid.path = sp->path;
182         c->qid.type = QTFILE;
183
184         sp->link = srv;
185         srv = sp;
186
187         qunlock(&srvlk);
188         poperror();
189
190         c->flag |= COPEN;
191         c->mode = OWRITE;
192
193         return c;
194 }
195
196 static void
197 srvremove(Chan *c)
198 {
199         Srv *sp, **l;
200
201         if(c->qid.type == QTDIR)
202                 error(Eperm);
203
204         qlock(&srvlk);
205         if(waserror()){
206                 qunlock(&srvlk);
207                 nexterror();
208         }
209         l = &srv;
210         for(sp = *l; sp != nil; sp = *l) {
211                 if(sp->path == c->qid.path)
212                         break;
213                 l = &sp->link;
214         }
215         if(sp == nil)
216                 error(Enonexist);
217
218         /*
219          * Only eve can remove system services.
220          */
221         if(strcmp(sp->owner, eve) == 0 && !iseve())
222                 error(Eperm);
223
224         /*
225          * No removing personal services.
226          */
227         if((sp->perm&7) != 7 && strcmp(sp->owner, up->user) && !iseve())
228                 error(Eperm);
229
230         *l = sp->link;
231         sp->link = nil;
232
233         qunlock(&srvlk);
234         poperror();
235
236         if(sp->chan != nil)
237                 cclose(sp->chan);
238         free(sp->owner);
239         free(sp->name);
240         free(sp);
241 }
242
243 static int
244 srvwstat(Chan *c, uchar *dp, int n)
245 {
246         char *strs;
247         Srv *sp;
248         Dir d;
249
250         if(c->qid.type & QTDIR)
251                 error(Eperm);
252
253         strs = smalloc(n);
254         if(waserror()){
255                 free(strs);
256                 nexterror();
257         }
258         n = convM2D(dp, n, &d, strs);
259         if(n == 0)
260                 error(Eshortstat);
261
262         qlock(&srvlk);
263         if(waserror()){
264                 qunlock(&srvlk);
265                 nexterror();
266         }
267
268         sp = srvlookup(nil, c->qid.path);
269         if(sp == nil)
270                 error(Enonexist);
271
272         if(strcmp(sp->owner, up->user) != 0 && !iseve())
273                 error(Eperm);
274
275         if(d.name != nil && *d.name && strcmp(sp->name, d.name) != 0) {
276                 if(strchr(d.name, '/') != nil)
277                         error(Ebadchar);
278                 if(strlen(d.name) >= sizeof(up->genbuf))
279                         error(Etoolong);
280                 kstrdup(&sp->name, d.name);
281         }
282         if(d.uid != nil && *d.uid)
283                 kstrdup(&sp->owner, d.uid);
284         if(d.mode != ~0UL)
285                 sp->perm = d.mode & 0777;
286
287         qunlock(&srvlk);
288         poperror();
289
290         free(strs);
291         poperror();
292
293         return n;
294 }
295
296 static void
297 srvclose(Chan *c)
298 {
299         /*
300          * in theory we need to override any changes in removability
301          * since open, but since all that's checked is the owner,
302          * which is immutable, all is well.
303          */
304         if(c->flag & CRCLOSE){
305                 if(waserror())
306                         return;
307                 srvremove(c);
308                 poperror();
309         }
310 }
311
312 static long
313 srvread(Chan *c, void *va, long n, vlong)
314 {
315         isdir(c);
316         return devdirread(c, va, n, 0, 0, srvgen);
317 }
318
319 static long
320 srvwrite(Chan *c, void *va, long n, vlong)
321 {
322         Srv *sp;
323         Chan *c1;
324         int fd;
325         char buf[32];
326
327         if(n >= sizeof buf)
328                 error(Etoobig);
329         memmove(buf, va, n);    /* so we can NUL-terminate */
330         buf[n] = 0;
331         fd = strtoul(buf, 0, 0);
332
333         c1 = fdtochan(fd, -1, 0, 1);    /* error check and inc ref */
334
335         qlock(&srvlk);
336         if(waserror()) {
337                 qunlock(&srvlk);
338                 cclose(c1);
339                 nexterror();
340         }
341         if(c1->flag & (CCEXEC|CRCLOSE))
342                 error("posted fd has remove-on-close or close-on-exec");
343         if(c1->qid.type & QTAUTH)
344                 error("cannot post auth file in srv");
345         sp = srvlookup(nil, c->qid.path);
346         if(sp == nil)
347                 error(Enonexist);
348
349         if(sp->chan != nil)
350                 error(Ebadusefd);
351
352         sp->chan = c1;
353
354         qunlock(&srvlk);
355         poperror();
356         return n;
357 }
358
359 Dev srvdevtab = {
360         's',
361         "srv",
362
363         devreset,
364         srvinit,        
365         devshutdown,
366         srvattach,
367         srvwalk,
368         srvstat,
369         srvopen,
370         srvcreate,
371         srvclose,
372         srvread,
373         devbread,
374         srvwrite,
375         devbwrite,
376         srvremove,
377         srvwstat,
378 };
379
380 void
381 srvrenameuser(char *old, char *new)
382 {
383         Srv *sp;
384
385         qlock(&srvlk);
386         for(sp = srv; sp != nil; sp = sp->link) {
387                 if(sp->owner != nil && strcmp(old, sp->owner) == 0)
388                         kstrdup(&sp->owner, new);
389         }
390         qunlock(&srvlk);
391 }