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