devsrv.c - vx32 - Local 9vx git repository for patches.
(HTM) git clone git://r-36.net/vx32
(DIR) Log
(DIR) Files
(DIR) Refs
---
devsrv.c (5982B)
---
1 #include "u.h"
2 #include "lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "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 *name, Dirtab *dt, int i, 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->ref);
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 * No one can remove #s/boot.
209 */
210 if(strcmp(sp->owner, eve) == 0 && !iseve())
211 error(Eperm);
212 if(strcmp(sp->name, "boot") == 0)
213 error(Eperm);
214
215 /*
216 * No removing personal services.
217 */
218 if((sp->perm&7) != 7 && strcmp(sp->owner, up->user) && !iseve())
219 error(Eperm);
220
221 *l = sp->link;
222 qunlock(&srvlk);
223 poperror();
224
225 if(sp->chan)
226 cclose(sp->chan);
227 free(sp->name);
228 free(sp);
229 }
230
231 static int
232 srvwstat(Chan *c, uchar *dp, int n)
233 {
234 char *strs;
235 Dir d;
236 Srv *sp;
237
238 if(c->qid.type & QTDIR)
239 error(Eperm);
240
241 strs = nil;
242 qlock(&srvlk);
243 if(waserror()){
244 qunlock(&srvlk);
245 free(strs);
246 nexterror();
247 }
248
249 sp = srvlookup(nil, c->qid.path);
250 if(sp == 0)
251 error(Enonexist);
252
253 if(strcmp(sp->owner, up->user) != 0 && !iseve())
254 error(Eperm);
255
256 strs = smalloc(n);
257 n = convM2D(dp, n, &d, strs);
258 if(n == 0)
259 error(Eshortstat);
260 if(d.mode != ~0UL)
261 sp->perm = d.mode & 0777;
262 if(d.uid && *d.uid)
263 kstrdup(&sp->owner, d.uid);
264 if(d.name && *d.name && strcmp(sp->name, d.name) != 0) {
265 if(strchr(d.name, '/') != nil)
266 error(Ebadchar);
267 kstrdup(&sp->name, d.name);
268 }
269 qunlock(&srvlk);
270 free(strs);
271 poperror();
272 return n;
273 }
274
275 static void
276 srvclose(Chan *c)
277 {
278 /*
279 * in theory we need to override any changes in removability
280 * since open, but since all that's checked is the owner,
281 * which is immutable, all is well.
282 */
283 if(c->flag & CRCLOSE){
284 if(waserror())
285 return;
286 srvremove(c);
287 poperror();
288 }
289 }
290
291 static long
292 srvread(Chan *c, void *va, long n, vlong off)
293 {
294 isdir(c);
295 return devdirread(c, va, n, 0, 0, srvgen);
296 }
297 static void srvadd(Chan*, Chan*);
298
299
300 static long
301 srvwrite(Chan *c, void *va, long n, vlong off)
302 {
303 Chan *c1;
304 int fd;
305 char buf[32];
306
307 if(n >= sizeof buf)
308 error(Egreg);
309 memmove(buf, va, n); /* so we can NUL-terminate */
310 buf[n] = 0;
311 fd = strtoul(buf, 0, 0);
312
313 c1 = fdtochan(fd, -1, 0, 1); /* error check and inc ref */
314 srvadd(c, c1);
315 return n;
316 }
317
318 // Plan 9 VX split srvadd out from srvwrite.
319 static void
320 srvadd(Chan *c, Chan *c1)
321 {
322 Srv *sp;
323
324 /* c1 already incref'ed */
325
326 qlock(&srvlk);
327 if(waserror()) {
328 qunlock(&srvlk);
329 cclose(c1);
330 nexterror();
331 }
332 if(c1->flag & (CCEXEC|CRCLOSE))
333 error("posted fd has remove-on-close or close-on-exec");
334 if(c1->qid.type & QTAUTH)
335 error("cannot post auth file in srv");
336 sp = srvlookup(nil, c->qid.path);
337 if(sp == 0)
338 error(Enonexist);
339
340 if(sp->chan)
341 error(Ebadusefd);
342
343 sp->chan = c1;
344 qunlock(&srvlk);
345 poperror();
346 }
347
348 Dev srvdevtab = {
349 's',
350 "srv",
351
352 devreset,
353 srvinit,
354 devshutdown,
355 srvattach,
356 srvwalk,
357 srvstat,
358 srvopen,
359 srvcreate,
360 srvclose,
361 srvread,
362 devbread,
363 srvwrite,
364 devbwrite,
365 srvremove,
366 srvwstat,
367 };
368
369 // Plan 9 VX addition
370 void
371 ksrvadd(Chan *c, Chan *c1)
372 {
373 incref(&c1->ref);
374 srvadd(c, c1);
375 }
376