xref: /plan9/sys/src/cmd/9660srv/main.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <fcall.h>
5 #include "dat.h"
6 #include "fns.h"
7 
8 static int	openflags(int);
9 static void	rattach(void);
10 static void	rsession(void);
11 static void	rclone(void);
12 static void	rclunk(void);
13 static void	rcreate(void);
14 static void	rflush(void);
15 static void	rmservice(void);
16 static void	rnop(void);
17 static void	ropen(void);
18 static void	rread(void);
19 static void	rremove(void);
20 static void	rsession(void);
21 static void	rstat(void);
22 static void	rwalk(void);
23 static void	rwrite(void);
24 static void	rwstat(void);
25 static void	usage(void);
26 
27 static Fcall	thdr;
28 static Fcall	rhdr;
29 static char	data[MAXMSG+MAXFDATA];
30 static char	fdata[MAXFDATA];
31 static char	srvfile[2*NAMELEN];
32 
33 extern Xfsub	*xsublist[];
34 
35 jmp_buf	err_lab[16];
36 int	nerr_lab;
37 char	err_msg[ERRLEN];
38 
39 int	chatty;
40 
41 void
42 main(int argc, char **argv)
43 {
44 	int srvfd, pipefd[2], n, nw, stdio;
45 	Xfsub **xs;
46 
47 	stdio = 0;
48 	ARGBEGIN {
49 	case 'v':
50 		chatty = 1;
51 		break;
52 	case 'f':
53 		deffile = ARGF();
54 		break;
55 	case 's':
56 		stdio = 1;
57 		break;
58 	default:
59 		usage();
60 	} ARGEND
61 
62 	switch(argc) {
63 	case 0:
64 		break;
65 	case 1:
66 		srvname = argv[0];
67 		break;
68 	default:
69 		usage();
70 	}
71 
72 	iobuf_init();
73 	for(xs=xsublist; *xs; xs++)
74 		(*(*xs)->reset)();
75 
76 	if(stdio) {
77 		pipefd[0] = 0;
78 		pipefd[1] = 1;
79 	} else {
80 		close(0);
81 		close(1);
82 		open("/dev/null", OREAD);
83 		open("/dev/null", OWRITE);
84 		if(pipe(pipefd) < 0)
85 			panic(1, "pipe");
86 		sprint(srvfile, "/srv/%s", srvname);
87 		srvfd = create(srvfile, OWRITE, 0666);
88 		if(srvfd < 0)
89 			panic(1, srvfile);
90 		atexit(rmservice);
91 		fprint(srvfd, "%d", pipefd[0]);
92 		close(pipefd[0]);
93 		close(srvfd);
94 		fprint(2, "%s %d: serving %s\n", argv0, getpid(), srvfile);
95 	}
96 	srvfd = pipefd[1];
97 
98 	switch(rfork(RFNOWAIT|RFNOTEG|RFFDG|RFPROC)){
99 	case -1:
100 		panic(1, "fork");
101 	default:
102 		_exits(0);
103 	case 0:
104 		break;
105 	}
106 
107 	while((n = read(srvfd, data, sizeof data)) > 0){
108 		if(convM2S(data, &thdr, n) <= 0)
109 			panic(0, "convM2S");
110 		if(!waserror()){
111 			switch(thdr.type){
112 			default:	panic(0, "type %d", thdr.type);
113 							break;
114 			case Tnop:	rnop();		break;
115 			case Tsession:	rsession();	break;
116 			case Tflush:	rflush();	break;
117 			case Tattach:	rattach();	break;
118 			case Tclone:	rclone();	break;
119 			case Twalk:	rwalk();	break;
120 			case Topen:	ropen();	break;
121 			case Tcreate:	rcreate();	break;
122 			case Tread:	rread();	break;
123 			case Twrite:	rwrite();	break;
124 			case Tclunk:	rclunk();	break;
125 			case Tremove:	rremove();	break;
126 			case Tstat:	rstat();	break;
127 			case Twstat:	rwstat();	break;
128 			}
129 			poperror();
130 			rhdr.type = thdr.type+1;
131 		}else{
132 			rhdr.type = Rerror;
133 			strncpy(rhdr.ename, err_msg, ERRLEN);
134 		}
135 		rhdr.fid = thdr.fid;
136 		rhdr.tag = thdr.tag;
137 		chat((rhdr.type != Rerror ? "OK\n" : "%s\n"), err_msg);
138 		if((n = convS2M(&rhdr, (char *)data)) <= 0)
139 			panic(0, "convS2M");
140 		nw = write(srvfd, data, n);
141 		if(nw != n)
142 			panic(1, "write");
143 		if(nerr_lab != 0)
144 			panic(0, "err stack %d: %lux %lux %lux %lux %lux %lux", nerr_lab,
145 			err_lab[0][JMPBUFPC], err_lab[1][JMPBUFPC],
146 			err_lab[2][JMPBUFPC], err_lab[3][JMPBUFPC],
147 			err_lab[4][JMPBUFPC], err_lab[5][JMPBUFPC]);
148 	}
149 	if(n < 0)
150 		panic(1, "read");
151 	chat("%s %d: exiting\n", argv0, getpid());
152 	exits(0);
153 }
154 
155 static void
156 usage(void)
157 {
158 	fprint(2, "usage: %s [-v] [-s] [-f devicefile] [srvname]\n", argv0);
159 	exits("usage");
160 }
161 
162 void
163 error(char *p)
164 {
165 	strncpy(err_msg, p, ERRLEN);
166 	nexterror();
167 }
168 
169 void
170 nexterror(void)
171 {
172 	longjmp(err_lab[--nerr_lab], 1);
173 }
174 
175 void*
176 ealloc(long n)
177 {
178 	void *p;
179 
180 	p = malloc(n);
181 	if(p == 0)
182 		error("no memory");
183 	return p;
184 }
185 
186 static void
187 rmservice(void)
188 {
189 	remove(srvfile);
190 }
191 
192 static void
193 rnop(void)
194 {
195 	chat("nop...");
196 }
197 
198 static void
199 rauth(void)
200 {
201 	chat("auth...");
202 	error(Eauth);
203 }
204 
205 static void
206 rsession(void)
207 {
208 	chat("session...");
209 	memset(rhdr.authid, 0, sizeof(rhdr.authid));
210 	memset(rhdr.authdom, 0, sizeof(rhdr.authdom));
211 	memset(rhdr.chal, 0, sizeof(rhdr.chal));
212 }
213 
214 static void
215 rflush(void)
216 {
217 	chat("flush...");
218 }
219 
220 static void
221 rattach(void)
222 {
223 	Xfile *root;
224 	Xfs *xf;
225 	Xfsub **xs;
226 
227 	chat("attach(fid=%d,uname=\"%s\",aname=\"%s\",auth=\"%s\")...",
228 		thdr.fid, thdr.uname, thdr.aname, thdr.auth);
229 
230 	if(waserror()){
231 		xfile(thdr.fid, Clunk);
232 		nexterror();
233 	}
234 	root = xfile(thdr.fid, Clean);
235 	root->qid = (Qid){CHDIR, 0};
236 	root->xf = xf = ealloc(sizeof(Xfs));
237 	memset(xf, 0, sizeof(Xfs));
238 	xf->ref = 1;
239 	xf->d = getxdata(thdr.aname);
240 
241 	for(xs=xsublist; *xs; xs++)
242 		if((*(*xs)->attach)(root) >= 0){
243 			poperror();
244 			xf->s = *xs;
245 			xf->rootqid = root->qid;
246 			rhdr.qid = root->qid;
247 			return;
248 		}
249 	error("unknown format");
250 }
251 
252 static void
253 rclone(void)
254 {
255 	Xfile *of, *nf, *next;
256 
257 	chat("clone(fid=%d,newfid=%d)...", thdr.fid, thdr.newfid);
258 	of = xfile(thdr.fid, Asis);
259 	nf = xfile(thdr.newfid, Clean);
260 	if(waserror()){
261 		xfile(thdr.newfid, Clunk);
262 		nexterror();
263 	}
264 	next = nf->next;
265 	*nf = *of;
266 	nf->next = next;
267 	nf->fid = thdr.newfid;
268 	refxfs(nf->xf, 1);
269 	if(nf->len){
270 		nf->ptr = ealloc(nf->len);
271 		memmove(nf->ptr, of->ptr, nf->len);
272 	}else
273 		nf->ptr = of->ptr;
274 	(*of->xf->s->clone)(of, nf);
275 	poperror();
276 }
277 
278 static void
279 rwalk(void)
280 {
281 	Xfile *f;
282 
283 	chat("walk(fid=%d,name=\"%s\")...", thdr.fid, thdr.name);
284 	f=xfile(thdr.fid, Asis);
285 	if(!(f->qid.path & CHDIR)){
286 		chat("qid.path=0x%x...", f->qid.path);
287 		error("walk in non-directory");
288 	}
289 	if(strcmp(thdr.name, ".")==0)
290 		/* nop */;
291 	else if(strcmp(thdr.name, "..")==0){
292 		if(f->qid.path==f->xf->rootqid.path)
293 			error("walkup from root");
294 		(*f->xf->s->walkup)(f);
295 	}else
296 		(*f->xf->s->walk)(f, thdr.name);
297 	rhdr.qid = f->qid;
298 }
299 
300 static void
301 ropen(void)
302 {
303 	Xfile *f;
304 
305 	chat("open(fid=%d,mode=%d)...", thdr.fid, thdr.mode);
306 	f = xfile(thdr.fid, Asis);
307 	if(f->flags&Omodes)
308 		error("open on open file");
309 	(*f->xf->s->open)(f, thdr.mode);
310 	chat("f->qid=0x%8.8lux...", f->qid.path);
311 	f->flags = openflags(thdr.mode);
312 	rhdr.qid = f->qid;
313 }
314 
315 static void
316 rcreate(void)
317 {
318 	Xfile *f;
319 
320 	chat("create(fid=%d,name=\"%s\",perm=%uo,mode=%d)...",
321 		thdr.fid, thdr.name, thdr.perm, thdr.mode);
322 	if(strcmp(thdr.name, ".") == 0 || strcmp(thdr.name, "..") == 0)
323 		error("create . or ..");
324 	f = xfile(thdr.fid, Asis);
325 	if(f->flags&Omodes)
326 		error("create on open file");
327 	if(!(f->qid.path&CHDIR))
328 		error("create in non-directory");
329 	(*f->xf->s->create)(f, thdr.name, thdr.perm, thdr.mode);
330 	chat("f->qid=0x%8.8lux...", f->qid.path);
331 	f->flags = openflags(thdr.mode);
332 	rhdr.qid = f->qid;
333 }
334 
335 static void
336 rread(void)
337 {
338 	Xfile *f;
339 
340 	chat("read(fid=%d,offset=%d,count=%d)...",
341 		thdr.fid, thdr.offset, thdr.count);
342 	f=xfile(thdr.fid, Asis);
343 	if (!(f->flags&Oread))
344 		error("file not opened for reading");
345 	if(f->qid.path & CHDIR){
346 		if(thdr.count%DIRLEN || thdr.offset%DIRLEN){
347 			chat("count%%%d=%d,offset%%%d=%d...",
348 				DIRLEN, thdr.count%DIRLEN,
349 				DIRLEN, thdr.offset%DIRLEN);
350 			error("bad offset or count");
351 		}
352 		rhdr.count = (*f->xf->s->readdir)(f, fdata, thdr.offset, thdr.count);
353 	}else
354 		rhdr.count = (*f->xf->s->read)(f, fdata, thdr.offset, thdr.count);
355 	rhdr.data = fdata;
356 	chat("rcnt=%d...", rhdr.count);
357 }
358 
359 static void
360 rwrite(void)
361 {
362 	Xfile *f;
363 
364 	chat("write(fid=%d,offset=%d,count=%d)...",
365 		thdr.fid, thdr.offset, thdr.count);
366 	f=xfile(thdr.fid, Asis);
367 	if(!(f->flags&Owrite))
368 		error("file not opened for writing");
369 	rhdr.count = (*f->xf->s->write)(f, thdr.data, thdr.offset, thdr.count);
370 	chat("rcnt=%d...", rhdr.count);
371 }
372 
373 static void
374 rclunk(void)
375 {
376 	Xfile *f;
377 
378 	chat("clunk(fid=%d)...", thdr.fid);
379 	if(!waserror()){
380 		f = xfile(thdr.fid, Asis);
381 		if(f->flags&Orclose)
382 			(*f->xf->s->remove)(f);
383 		else
384 			(*f->xf->s->clunk)(f);
385 		poperror();
386 	}
387 	xfile(thdr.fid, Clunk);
388 }
389 
390 static void
391 rremove(void)
392 {
393 	Xfile *f;
394 
395 	chat("remove(fid=%d)...", thdr.fid);
396 	if(waserror()){
397 		xfile(thdr.fid, Clunk);
398 		nexterror();
399 	}
400 	f=xfile(thdr.fid, Asis);
401 	(*f->xf->s->remove)(f);
402 	poperror();
403 	xfile(thdr.fid, Clunk);
404 }
405 
406 static void
407 rstat(void)
408 {
409 	Xfile *f;
410 	Dir dir;
411 
412 	chat("stat(fid=%d)...", thdr.fid);
413 	f=xfile(thdr.fid, Asis);
414 	(*f->xf->s->stat)(f, &dir);
415 	if(chatty)
416 		showdir(2, &dir);
417 	convD2M(&dir, rhdr.stat);
418 }
419 
420 static void
421 rwstat(void)
422 {
423 	Xfile *f;
424 	Dir dir;
425 
426 	chat("wstat(fid=%d)...", thdr.fid);
427 	f=xfile(thdr.fid, Asis);
428 	convM2D(rhdr.stat, &dir);
429 	(*f->xf->s->wstat)(f, &dir);
430 }
431 
432 static int
433 openflags(int mode)
434 {
435 	int flags = 0;
436 
437 	switch(mode & ~(OTRUNC|OCEXEC|ORCLOSE)){
438 	case OREAD:
439 	case OEXEC:
440 		flags = Oread; break;
441 	case OWRITE:
442 		flags = Owrite; break;
443 	case ORDWR:
444 		flags = Oread|Owrite; break;
445 	}
446 	if(mode & ORCLOSE)
447 		flags |= Orclose;
448 	return flags;
449 }
450 
451 void
452 showdir(int fd, Dir *s)
453 {
454 	char a_time[32], m_time[32];
455 	char *p;
456 
457 	strcpy(a_time, ctime(s->atime));
458 	if(p=strchr(a_time, '\n'))	/* assign = */
459 		*p = 0;
460 	strcpy(m_time, ctime(s->mtime));
461 	if(p=strchr(m_time, '\n'))	/* assign = */
462 		*p = 0;
463 	fprint(fd, "name=\"%s\" qid=(0x%8.8ux,%d) type=%d dev=%d \
464 mode=0x%8.8ux=0%uo atime=%s mtime=%s length=%d uid=\"%s\" gid=\"%s\"...",
465 		s->name, s->qid.path, s->qid.vers, s->type, s->dev,
466 		s->mode, s->mode,
467 		a_time, m_time, s->length, s->uid, s->gid);
468 }
469 
470 #define	SIZE	1024
471 #define	DOTDOT	(&fmt+1)
472 
473 void
474 chat(char *fmt, ...)
475 {
476 	char buf[SIZE], *out;
477 
478 	if(chatty){
479 		out = doprint(buf, buf+SIZE, fmt, DOTDOT);
480 		write(2, buf, out-buf);
481 	}
482 }
483 
484 void
485 panic(int rflag, char *fmt, ...)
486 {
487 	char buf[SIZE]; int n;
488 
489 	n = sprint(buf, "%s %d: ", argv0, getpid());
490 	doprint(buf+n, buf+SIZE, fmt, DOTDOT);
491 	fprint(2, (rflag ? "%s: %r\n" : "%s\n"), buf);
492 	if(chatty){
493 		fprint(2, "abort\n");
494 		abort();
495 	}
496 	exits("panic");
497 }
498