]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/devsrv.c
change definition of Chan.create to return a chan like open
[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(Eexist);
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 Chan*
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         sp = smalloc(sizeof *sp);
149         sname = smalloc(strlen(name)+1);
150
151         qlock(&srvlk);
152         if(waserror()){
153                 free(sp);
154                 free(sname);
155                 qunlock(&srvlk);
156                 nexterror();
157         }
158         if(sp == nil || sname == nil)
159                 error(Enomem);
160         if(srvlookup(name, -1))
161                 error(Eexist);
162
163         sp->path = qidpath++;
164         sp->link = srv;
165         strcpy(sname, name);
166         sp->name = sname;
167         c->qid.type = QTFILE;
168         c->qid.path = sp->path;
169         srv = sp;
170         qunlock(&srvlk);
171         poperror();
172
173         kstrdup(&sp->owner, up->user);
174         sp->perm = perm&0777;
175
176         c->flag |= COPEN;
177         c->mode = OWRITE;
178         return c;
179 }
180
181 static void
182 srvremove(Chan *c)
183 {
184         Srv *sp, **l;
185
186         if(c->qid.type == QTDIR)
187                 error(Eperm);
188
189         qlock(&srvlk);
190         if(waserror()){
191                 qunlock(&srvlk);
192                 nexterror();
193         }
194         l = &srv;
195         for(sp = *l; sp; sp = sp->link) {
196                 if(sp->path == c->qid.path)
197                         break;
198
199                 l = &sp->link;
200         }
201         if(sp == 0)
202                 error(Enonexist);
203
204         /*
205          * Only eve can remove system services.
206          */
207         if(strcmp(sp->owner, eve) == 0 && !iseve())
208                 error(Eperm);
209
210         /*
211          * No removing personal services.
212          */
213         if((sp->perm&7) != 7 && strcmp(sp->owner, up->user) && !iseve())
214                 error(Eperm);
215
216         *l = sp->link;
217         qunlock(&srvlk);
218         poperror();
219
220         if(sp->chan)
221                 cclose(sp->chan);
222         free(sp->owner);
223         free(sp->name);
224         free(sp);
225 }
226
227 static int
228 srvwstat(Chan *c, uchar *dp, int n)
229 {
230         char *strs;
231         Dir d;
232         Srv *sp;
233
234         if(c->qid.type & QTDIR)
235                 error(Eperm);
236
237         strs = nil;
238         qlock(&srvlk);
239         if(waserror()){
240                 qunlock(&srvlk);
241                 free(strs);
242                 nexterror();
243         }
244
245         sp = srvlookup(nil, c->qid.path);
246         if(sp == 0)
247                 error(Enonexist);
248
249         if(strcmp(sp->owner, up->user) != 0 && !iseve())
250                 error(Eperm);
251
252         strs = smalloc(n);
253         n = convM2D(dp, n, &d, strs);
254         if(n == 0)
255                 error(Eshortstat);
256         if(d.mode != ~0UL)
257                 sp->perm = d.mode & 0777;
258         if(d.uid && *d.uid)
259                 kstrdup(&sp->owner, d.uid);
260         if(d.name && *d.name && strcmp(sp->name, d.name) != 0) {
261                 if(strchr(d.name, '/') != nil)
262                         error(Ebadchar);
263                 kstrdup(&sp->name, d.name);
264         }
265         qunlock(&srvlk);
266         free(strs);
267         poperror();
268         return n;
269 }
270
271 static void
272 srvclose(Chan *c)
273 {
274         /*
275          * in theory we need to override any changes in removability
276          * since open, but since all that's checked is the owner,
277          * which is immutable, all is well.
278          */
279         if(c->flag & CRCLOSE){
280                 if(waserror())
281                         return;
282                 srvremove(c);
283                 poperror();
284         }
285 }
286
287 static long
288 srvread(Chan *c, void *va, long n, vlong)
289 {
290         isdir(c);
291         return devdirread(c, va, n, 0, 0, srvgen);
292 }
293
294 static long
295 srvwrite(Chan *c, void *va, long n, vlong)
296 {
297         Srv *sp;
298         Chan *c1;
299         int fd;
300         char buf[32];
301
302         if(n >= sizeof buf)
303                 error(Egreg);
304         memmove(buf, va, n);    /* so we can NUL-terminate */
305         buf[n] = 0;
306         fd = strtoul(buf, 0, 0);
307
308         c1 = fdtochan(fd, -1, 0, 1);    /* error check and inc ref */
309
310         qlock(&srvlk);
311         if(waserror()) {
312                 qunlock(&srvlk);
313                 cclose(c1);
314                 nexterror();
315         }
316         if(c1->flag & (CCEXEC|CRCLOSE))
317                 error("posted fd has remove-on-close or close-on-exec");
318         if(c1->qid.type & QTAUTH)
319                 error("cannot post auth file in srv");
320         sp = srvlookup(nil, c->qid.path);
321         if(sp == 0)
322                 error(Enonexist);
323
324         if(sp->chan)
325                 error(Ebadusefd);
326
327         sp->chan = c1;
328         qunlock(&srvlk);
329         poperror();
330         return n;
331 }
332
333 Dev srvdevtab = {
334         's',
335         "srv",
336
337         devreset,
338         srvinit,        
339         devshutdown,
340         srvattach,
341         srvwalk,
342         srvstat,
343         srvopen,
344         srvcreate,
345         srvclose,
346         srvread,
347         devbread,
348         srvwrite,
349         devbwrite,
350         srvremove,
351         srvwstat,
352 };
353
354 void
355 srvrenameuser(char *old, char *new)
356 {
357         Srv *sp;
358
359         qlock(&srvlk);
360         for(sp = srv; sp; sp = sp->link)
361                 if(sp->owner!=nil && strcmp(old, sp->owner)==0)
362                         kstrdup(&sp->owner, new);
363         qunlock(&srvlk);
364 }