xref: /plan9/sys/src/9/port/devsrv.c (revision 39734e7ed1eb944f5e7b41936007d0d38b560d7f)
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 	if(d.uid && *d.uid)
247 		kstrdup(&sp->owner, d.uid);
248 
249 	qunlock(&srvlk);
250 	poperror();
251 	return n;
252 }
253 
254 static void
255 srvclose(Chan *c)
256 {
257 	/*
258 	 * in theory we need to override any changes in removability
259 	 * since open, but since all that's checked is the owner,
260 	 * which is immutable, all is well.
261 	 */
262 	if(c->flag & CRCLOSE){
263 		if(waserror())
264 			return;
265 		srvremove(c);
266 		poperror();
267 	}
268 }
269 
270 static long
271 srvread(Chan *c, void *va, long n, vlong)
272 {
273 	isdir(c);
274 	return devdirread(c, va, n, 0, 0, srvgen);
275 }
276 
277 static long
278 srvwrite(Chan *c, void *va, long n, vlong)
279 {
280 	Srv *sp;
281 	Chan *c1;
282 	int fd;
283 	char buf[32];
284 
285 	if(n >= sizeof buf)
286 		error(Egreg);
287 	memmove(buf, va, n);	/* so we can NUL-terminate */
288 	buf[n] = 0;
289 	fd = strtoul(buf, 0, 0);
290 
291 	c1 = fdtochan(fd, -1, 0, 1);	/* error check and inc ref */
292 
293 	qlock(&srvlk);
294 	if(waserror()) {
295 		qunlock(&srvlk);
296 		cclose(c1);
297 		nexterror();
298 	}
299 	if(c1->flag & (CCEXEC|CRCLOSE))
300 		error("posted fd has remove-on-close or close-on-exec");
301 	if(c1->qid.type & QTAUTH)
302 		error("can't post auth file in srv");
303 	sp = srvlookup(nil, c->qid.path);
304 	if(sp == 0)
305 		error(Enonexist);
306 
307 	if(sp->chan)
308 		error(Ebadusefd);
309 
310 	sp->chan = c1;
311 	qunlock(&srvlk);
312 	poperror();
313 	return n;
314 }
315 
316 Dev srvdevtab = {
317 	's',
318 	"srv",
319 
320 	devreset,
321 	srvinit,
322 	devshutdown,
323 	srvattach,
324 	srvwalk,
325 	srvstat,
326 	srvopen,
327 	srvcreate,
328 	srvclose,
329 	srvread,
330 	devbread,
331 	srvwrite,
332 	devbwrite,
333 	srvremove,
334 	srvwstat,
335 };
336