Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
	int size;
90
	Srv *sp;
91
	char *s;
92
 
93
	for(sp = srv; sp; sp = sp->link)
94
		if(sp->chan == c){
95
			size = 3+strlen(sp->name)+1;
96
			s = smalloc(size);
97
			snprint(s, size, "#s/%s", sp->name);
98
			return s;
99
		}
100
	return nil;
101
}
102
 
103
static Chan*
104
srvopen(Chan *c, int omode)
105
{
106
	Srv *sp;
107
 
108
	if(c->qid.type == QTDIR){
109
		if(omode & ORCLOSE)
110
			error(Eperm);
111
		if(omode != OREAD)
112
			error(Eisdir);
113
		c->mode = omode;
114
		c->flag |= COPEN;
115
		c->offset = 0;
116
		return c;
117
	}
118
	qlock(&srvlk);
119
	if(waserror()){
120
		qunlock(&srvlk);
121
		nexterror();
122
	}
123
 
124
	sp = srvlookup(nil, c->qid.path);
125
	if(sp == 0 || sp->chan == 0)
126
		error(Eshutdown);
127
 
128
	if(omode&OTRUNC)
129
		error("srv file already exists");
130
	if(openmode(omode)!=sp->chan->mode && sp->chan->mode!=ORDWR)
131
		error(Eperm);
132
	devpermcheck(sp->owner, sp->perm, omode);
133
 
134
	cclose(c);
135
	incref(sp->chan);
136
	qunlock(&srvlk);
137
	poperror();
138
	return sp->chan;
139
}
140
 
141
static void
142
srvcreate(Chan *c, char *name, int omode, ulong perm)
143
{
144
	char *sname;
145
	Srv *sp;
146
 
147
	if(openmode(omode) != OWRITE)
148
		error(Eperm);
149
 
150
	if(omode & OCEXEC)	/* can't happen */
151
		panic("someone broke namec");
152
 
153
	sp = smalloc(sizeof *sp);
154
	sname = smalloc(strlen(name)+1);
155
 
156
	qlock(&srvlk);
157
	if(waserror()){
158
		free(sp);
159
		free(sname);
160
		qunlock(&srvlk);
161
		nexterror();
162
	}
163
	if(sp == nil || sname == nil)
164
		error(Enomem);
165
	if(srvlookup(name, -1))
166
		error(Eexist);
167
 
168
	sp->path = qidpath++;
169
	sp->link = srv;
170
	strcpy(sname, name);
171
	sp->name = sname;
172
	c->qid.type = QTFILE;
173
	c->qid.path = sp->path;
174
	srv = sp;
175
	qunlock(&srvlk);
176
	poperror();
177
 
178
	kstrdup(&sp->owner, up->user);
179
	sp->perm = perm&0777;
180
 
181
	c->flag |= COPEN;
182
	c->mode = OWRITE;
183
}
184
 
185
static void
186
srvremove(Chan *c)
187
{
188
	Srv *sp, **l;
189
 
190
	if(c->qid.type == QTDIR)
191
		error(Eperm);
192
 
193
	qlock(&srvlk);
194
	if(waserror()){
195
		qunlock(&srvlk);
196
		nexterror();
197
	}
198
	l = &srv;
199
	for(sp = *l; sp; sp = sp->link) {
200
		if(sp->path == c->qid.path)
201
			break;
202
 
203
		l = &sp->link;
204
	}
205
	if(sp == 0)
206
		error(Enonexist);
207
 
208
	/*
209
	 * Only eve can remove system services.
210
	 * No one can remove #s/boot.
211
	 */
212
	if(strcmp(sp->owner, eve) == 0 && !iseve())
213
		error(Eperm);
214
	if(strcmp(sp->name, "boot") == 0)
215
		error(Eperm);
216
 
217
	/*
218
	 * No removing personal services.
219
	 */
220
	if((sp->perm&7) != 7 && strcmp(sp->owner, up->user) && !iseve())
221
		error(Eperm);
222
 
223
	*l = sp->link;
224
	qunlock(&srvlk);
225
	poperror();
226
 
227
	if(sp->chan)
228
		cclose(sp->chan);
229
	free(sp->owner);
230
	free(sp->name);
231
	free(sp);
232
}
233
 
234
static int
235
srvwstat(Chan *c, uchar *dp, int n)
236
{
237
	char *strs;
238
	Dir d;
239
	Srv *sp;
240
 
241
	if(c->qid.type & QTDIR)
242
		error(Eperm);
243
 
244
	strs = nil;
245
	qlock(&srvlk);
246
	if(waserror()){
247
		qunlock(&srvlk);
248
		free(strs);
249
		nexterror();
250
	}
251
 
252
	sp = srvlookup(nil, c->qid.path);
253
	if(sp == 0)
254
		error(Enonexist);
255
 
256
	if(strcmp(sp->owner, up->user) != 0 && !iseve())
257
		error(Eperm);
258
 
259
	strs = smalloc(n);
260
	n = convM2D(dp, n, &d, strs);
261
	if(n == 0)
262
		error(Eshortstat);
263
	if(d.mode != ~0UL)
264
		sp->perm = d.mode & 0777;
265
	if(d.uid && *d.uid)
266
		kstrdup(&sp->owner, d.uid);
267
	if(d.name && *d.name && strcmp(sp->name, d.name) != 0) {
268
		if(strchr(d.name, '/') != nil)
269
			error(Ebadchar);
270
		kstrdup(&sp->name, d.name);
271
	}
272
	qunlock(&srvlk);
273
	free(strs);
274
	poperror();
275
	return n;
276
}
277
 
278
static void
279
srvclose(Chan *c)
280
{
281
	/*
282
	 * in theory we need to override any changes in removability
283
	 * since open, but since all that's checked is the owner,
284
	 * which is immutable, all is well.
285
	 */
286
	if(c->flag & CRCLOSE){
287
		if(waserror())
288
			return;
289
		srvremove(c);
290
		poperror();
291
	}
292
}
293
 
294
static long
295
srvread(Chan *c, void *va, long n, vlong)
296
{
297
	isdir(c);
298
	return devdirread(c, va, n, 0, 0, srvgen);
299
}
300
 
301
static long
302
srvwrite(Chan *c, void *va, long n, vlong)
303
{
304
	Srv *sp;
305
	Chan *c1;
306
	int fd;
307
	char buf[32];
308
 
309
	if(n >= sizeof buf)
310
		error(Egreg);
311
	memmove(buf, va, n);	/* so we can NUL-terminate */
312
	buf[n] = 0;
313
	fd = strtoul(buf, 0, 0);
314
 
315
	c1 = fdtochan(fd, -1, 0, 1);	/* error check and inc ref */
316
 
317
	qlock(&srvlk);
318
	if(waserror()) {
319
		qunlock(&srvlk);
320
		cclose(c1);
321
		nexterror();
322
	}
323
	if(c1->flag & (CCEXEC|CRCLOSE))
324
		error("posted fd has remove-on-close or close-on-exec");
325
	if(c1->qid.type & QTAUTH)
326
		error("cannot post auth file in srv");
327
	sp = srvlookup(nil, c->qid.path);
328
	if(sp == 0)
329
		error(Enonexist);
330
 
331
	if(sp->chan)
332
		error(Ebadusefd);
333
 
334
	sp->chan = c1;
335
	qunlock(&srvlk);
336
	poperror();
337
	return n;
338
}
339
 
340
Dev srvdevtab = {
341
	's',
342
	"srv",
343
 
344
	devreset,
345
	srvinit,	
346
	devshutdown,
347
	srvattach,
348
	srvwalk,
349
	srvstat,
350
	srvopen,
351
	srvcreate,
352
	srvclose,
353
	srvread,
354
	devbread,
355
	srvwrite,
356
	devbwrite,
357
	srvremove,
358
	srvwstat,
359
};