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