FreeBSD/Linux Kernel Cross Reference
sys/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 * 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)
293 {
294 isdir(c);
295 return devdirread(c, va, n, 0, 0, srvgen);
296 }
297
298 static long
299 srvwrite(Chan *c, void *va, long n, vlong)
300 {
301 Srv *sp;
302 Chan *c1;
303 int fd;
304 char buf[32];
305
306 if(n >= sizeof buf)
307 error(Egreg);
308 memmove(buf, va, n); /* so we can NUL-terminate */
309 buf[n] = 0;
310 fd = strtoul(buf, 0, 0);
311
312 c1 = fdtochan(fd, -1, 0, 1); /* error check and inc ref */
313
314 qlock(&srvlk);
315 if(waserror()) {
316 qunlock(&srvlk);
317 cclose(c1);
318 nexterror();
319 }
320 if(c1->flag & (CCEXEC|CRCLOSE))
321 error("posted fd has remove-on-close or close-on-exec");
322 if(c1->qid.type & QTAUTH)
323 error("cannot post auth file in srv");
324 sp = srvlookup(nil, c->qid.path);
325 if(sp == 0)
326 error(Enonexist);
327
328 if(sp->chan)
329 error(Ebadusefd);
330
331 sp->chan = c1;
332 qunlock(&srvlk);
333 poperror();
334 return n;
335 }
336
337 Dev srvdevtab = {
338 's',
339 "srv",
340
341 devreset,
342 srvinit,
343 devshutdown,
344 srvattach,
345 srvwalk,
346 srvstat,
347 srvopen,
348 srvcreate,
349 srvclose,
350 srvread,
351 devbread,
352 srvwrite,
353 devbwrite,
354 srvremove,
355 srvwstat,
356 };
Cache object: 4df50088131baa0b2a52d3207633607b
|