xref: /plan9/sys/src/cmd/9660srv/main.c (revision ff8c3af2f44d95267f67219afa20ba82ff6cf7e4)
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 enum
9 {
10 	Maxfdata	= 8192,
11 	Maxiosize	= IOHDRSZ+Maxfdata,
12 };
13 
14 void io(int);
15 void rversion(void);
16 void	rattach(void);
17 void	rauth(void);
18 void	rclunk(void);
19 void	rcreate(void);
20 void	rflush(void);
21 void	ropen(void);
22 void	rread(void);
23 void	rremove(void);
24 void	rsession(void);
25 void	rstat(void);
26 void	rwalk(void);
27 void	rwrite(void);
28 void	rwstat(void);
29 
30 static int	openflags(int);
31 static void	rmservice(void);
32 static void	usage(void);
33 
34 #define Reqsize (sizeof(Fcall)+Maxfdata)
35 
36 Fcall *req;
37 Fcall *rep;
38 
39 uchar mdata[Maxiosize];
40 char fdata[Maxfdata];
41 uchar statbuf[STATMAX];
42 int errno;
43 
44 static char	srvfile[64];
45 
46 extern Xfsub	*xsublist[];
47 
48 jmp_buf	err_lab[16];
49 int	nerr_lab;
50 char	err_msg[ERRMAX];
51 
52 int	chatty;
53 int	nojoliet;
54 int	noplan9;
55 int norock;
56 
57 void	(*fcalls[])(void) = {
58 	[Tversion]	rversion,
59 	[Tflush]	rflush,
60 	[Tauth]	rauth,
61 	[Tattach]	rattach,
62 	[Twalk]		rwalk,
63 	[Topen]		ropen,
64 	[Tcreate]	rcreate,
65 	[Tread]		rread,
66 	[Twrite]	rwrite,
67 	[Tclunk]	rclunk,
68 	[Tremove]	rremove,
69 	[Tstat]		rstat,
70 	[Twstat]	rwstat,
71 };
72 
73 void
74 main(int argc, char **argv)
75 {
76 	int srvfd, pipefd[2], stdio;
77 	Xfsub **xs;
78 
79 	stdio = 0;
80 	ARGBEGIN {
81 	case 'v':
82 		chatty = 1;
83 		break;
84 	case 'f':
85 		deffile = ARGF();
86 		break;
87 	case 's':
88 		stdio = 1;
89 		break;
90 	case '9':
91 		noplan9 = 1;
92 		break;
93 	case 'J':
94 		nojoliet = 1;
95 		break;
96 	case 'r':
97 		norock = 1;
98 		break;
99 	default:
100 		usage();
101 	} ARGEND
102 
103 	switch(argc) {
104 	case 0:
105 		break;
106 	case 1:
107 		srvname = argv[0];
108 		break;
109 	default:
110 		usage();
111 	}
112 
113 	iobuf_init();
114 	for(xs=xsublist; *xs; xs++)
115 		(*(*xs)->reset)();
116 
117 	if(stdio) {
118 		pipefd[0] = 0;
119 		pipefd[1] = 1;
120 	} else {
121 		close(0);
122 		close(1);
123 		open("/dev/null", OREAD);
124 		open("/dev/null", OWRITE);
125 		if(pipe(pipefd) < 0)
126 			panic(1, "pipe");
127 		sprint(srvfile, "/srv/%s", srvname);
128 		srvfd = create(srvfile, OWRITE|ORCLOSE, 0600);
129 		if(srvfd < 0)
130 			panic(1, srvfile);
131 		fprint(srvfd, "%d", pipefd[0]);
132 		close(pipefd[0]);
133 		fprint(2, "%s %d: serving %s\n", argv0, getpid(), srvfile);
134 	}
135 	srvfd = pipefd[1];
136 
137 	switch(rfork(RFNOWAIT|RFNOTEG|RFFDG|RFPROC)){
138 	case -1:
139 		panic(1, "fork");
140 	default:
141 		_exits(0);
142 	case 0:
143 		break;
144 	}
145 
146 	io(srvfd);
147 	exits(0);
148 }
149 
150 void
151 io(int srvfd)
152 {
153 	int n, pid;
154 	Fcall xreq, xrep;
155 
156 	req = &xreq;
157 	rep = &xrep;
158 	pid = getpid();
159 	fmtinstall('F', fcallfmt);
160 
161 	for(;;){
162 		/*
163 		 * reading from a pipe or a network device
164 		 * will give an error after a few eof reads.
165 		 * however, we cannot tell the difference
166 		 * between a zero-length read and an interrupt
167 		 * on the processes writing to us,
168 		 * so we wait for the error.
169 		 */
170 		n = read9pmsg(srvfd, mdata, sizeof mdata);
171 		if(n < 0)
172 			break;
173 		if(n == 0)
174 			continue;
175 		if(convM2S(mdata, n, req) == 0)
176 			continue;
177 
178 		if(chatty)
179 			fprint(2, "9660srv %d:<-%F\n", pid, req);
180 
181 		errno = 0;
182 		if(!waserror()){
183 			err_msg[0] = 0;
184 			if(req->type < 0 || req->type > nelem(fcalls) || !fcalls[req->type])
185 				error("bad fcall type");
186 			(*fcalls[req->type])();
187 			poperror();
188 		}
189 
190 		if(err_msg[0]){
191 			rep->type = Rerror;
192 			rep->ename = err_msg;
193 		}else{
194 			rep->type = req->type + 1;
195 			rep->fid = req->fid;
196 		}
197 		rep->tag = req->tag;
198 
199 		if(chatty)
200 			fprint(2, "9660srv %d:->%F\n", pid, rep);
201 		n = convS2M(rep, mdata, sizeof mdata);
202 		if(n == 0)
203 			panic(1, "convS2M error on write");
204 		if(write(srvfd, mdata, n) != n)
205 			panic(1, "mount write");
206 		if(nerr_lab != 0)
207 			panic(0, "err stack %d: %lux %lux %lux %lux %lux %lux", nerr_lab,
208 			err_lab[0][JMPBUFPC], err_lab[1][JMPBUFPC],
209 			err_lab[2][JMPBUFPC], err_lab[3][JMPBUFPC],
210 			err_lab[4][JMPBUFPC], err_lab[5][JMPBUFPC]);
211 	}
212 	chat("server shut down");
213 }
214 
215 static void
216 usage(void)
217 {
218 	fprint(2, "usage: %s [-v] [-9Jr] [-s] [-f devicefile] [srvname]\n", argv0);
219 	exits("usage");
220 }
221 
222 void
223 error(char *p)
224 {
225 	strecpy(err_msg, err_msg+sizeof err_msg, p);
226 	nexterror();
227 }
228 
229 void
230 nexterror(void)
231 {
232 	longjmp(err_lab[--nerr_lab], 1);
233 }
234 
235 void*
236 ealloc(long n)
237 {
238 	void *p;
239 
240 	p = malloc(n);
241 	if(p == 0)
242 		error("no memory");
243 	return p;
244 }
245 
246 void
247 setnames(Dir *d, char *n)
248 {
249 	d->name = n;
250 	d->uid = n+Maxname;
251 	d->gid = n+Maxname*2;
252 	d->muid = n+Maxname*3;
253 
254 	d->name[0] = '\0';
255 	d->uid[0] = '\0';
256 	d->gid[0] = '\0';
257 	d->muid[0] = '\0';
258 }
259 
260 void
261 rversion(void)
262 {
263 	if(req->msize > Maxiosize)
264 		rep->msize = Maxiosize;
265 	else
266 		rep->msize = req->msize;
267 	rep->version = "9P2000";
268 }
269 
270 void
271 rauth(void)
272 {
273 	error("9660srv: authentication not required");
274 }
275 
276 void
277 rflush(void)
278 {
279 }
280 
281 void
282 rattach(void)
283 {
284 	Xfs *xf;
285 	Xfile *root;
286 	Xfsub **xs;
287 
288 	chat("attach(fid=%d,uname=\"%s\",aname=\"%s\")...",
289 		req->fid, req->uname, req->aname);
290 
291 	if(waserror()){
292 		xfile(req->fid, Clunk);
293 		nexterror();
294 	}
295 	root = xfile(req->fid, Clean);
296 	root->qid = (Qid){0, 0, QTDIR};
297 	root->xf = xf = ealloc(sizeof(Xfs));
298 	memset(xf, 0, sizeof(Xfs));
299 	xf->ref = 1;
300 	xf->d = getxdata(req->aname);
301 
302 	for(xs=xsublist; *xs; xs++)
303 		if((*(*xs)->attach)(root) >= 0){
304 			poperror();
305 			xf->s = *xs;
306 			xf->rootqid = root->qid;
307 			rep->qid = root->qid;
308 			return;
309 		}
310 	error("unknown format");
311 }
312 
313 Xfile*
314 doclone(Xfile *of, int newfid)
315 {
316 	Xfile *nf, *next;
317 
318 	nf = xfile(newfid, Clean);
319 	if(waserror()){
320 		xfile(newfid, Clunk);
321 		nexterror();
322 	}
323 	next = nf->next;
324 	*nf = *of;
325 	nf->next = next;
326 	nf->fid = newfid;
327 	refxfs(nf->xf, 1);
328 	if(nf->len){
329 		nf->ptr = ealloc(nf->len);
330 		memmove(nf->ptr, of->ptr, nf->len);
331 	}else
332 		nf->ptr = of->ptr;
333 	(*of->xf->s->clone)(of, nf);
334 	poperror();
335 	return nf;
336 }
337 
338 void
339 rwalk(void)
340 {
341 	Xfile *f, *nf;
342 	Isofile *oldptr;
343 	int oldlen;
344 	Qid oldqid;
345 
346 	rep->nwqid = 0;
347 	nf = nil;
348 	f = xfile(req->fid, Asis);
349 	if(req->fid != req->newfid)
350 		f = nf = doclone(f, req->newfid);
351 
352 	/* save old state in case of error */
353 	oldqid = f->qid;
354 	oldlen = f->len;
355 	oldptr = f->ptr;
356 	if(oldlen){
357 		oldptr = ealloc(oldlen);
358 		memmove(oldptr, f->ptr, oldlen);
359 	}
360 
361 	if(waserror()){
362 		if(nf != nil)
363 			xfile(req->newfid, Clunk);
364 		if(rep->nwqid == req->nwname){
365 			if(oldlen)
366 				free(oldptr);
367 		}else{
368 			/* restore previous state */
369 			f->qid = oldqid;
370 			if(f->len)
371 				free(f->ptr);
372 			f->ptr = oldptr;
373 			f->len = oldlen;
374 		}
375 		if(rep->nwqid==req->nwname || rep->nwqid > 0){
376 			err_msg[0] = '\0';
377 			return;
378 		}
379 		nexterror();
380 	}
381 
382 	for(rep->nwqid=0; rep->nwqid < req->nwname && rep->nwqid < MAXWELEM; rep->nwqid++){
383 		chat("\twalking %s\n", req->wname[rep->nwqid]);
384 		if(!(f->qid.type & QTDIR)){
385 			chat("\tnot dir: type=%#x\n", f->qid.type);
386 			error("walk in non-directory");
387 		}
388 
389 		if(strcmp(req->wname[rep->nwqid], "..")==0){
390 			if(f->qid.path != f->xf->rootqid.path)
391 				(*f->xf->s->walkup)(f);
392 		}else
393 			(*f->xf->s->walk)(f, req->wname[rep->nwqid]);
394 		rep->wqid[rep->nwqid] = f->qid;
395 	}
396 	poperror();
397 	if(oldlen)
398 		free(oldptr);
399 }
400 
401 void
402 ropen(void)
403 {
404 	Xfile *f;
405 
406 	f = xfile(req->fid, Asis);
407 	if(f->flags&Omodes)
408 		error("open on open file");
409 	if(req->mode&ORCLOSE)
410 		error("no removes");
411 	(*f->xf->s->open)(f, req->mode);
412 	f->flags = openflags(req->mode);
413 	rep->qid = f->qid;
414 	rep->iounit = 0;
415 }
416 
417 void
418 rcreate(void)
419 {
420 	error("no creates");
421 /*
422 	Xfile *f;
423 
424 	if(strcmp(req->name, ".") == 0 || strcmp(req->name, "..") == 0)
425 		error("create . or ..");
426 	f = xfile(req->fid, Asis);
427 	if(f->flags&Omodes)
428 		error("create on open file");
429 	if(!(f->qid.path&CHDIR))
430 		error("create in non-directory");
431 	(*f->xf->s->create)(f, req->name, req->perm, req->mode);
432 	chat("f->qid=0x%8.8lux...", f->qid.path);
433 	f->flags = openflags(req->mode);
434 	rep->qid = f->qid;
435 */
436 }
437 
438 void
439 rread(void)
440 {
441 	Xfile *f;
442 
443 	f=xfile(req->fid, Asis);
444 	if (!(f->flags&Oread))
445 		error("file not opened for reading");
446 	if(f->qid.type & QTDIR)
447 		rep->count = (*f->xf->s->readdir)(f, (uchar*)fdata, req->offset, req->count);
448 	else
449 		rep->count = (*f->xf->s->read)(f, fdata, req->offset, req->count);
450 	rep->data = fdata;
451 }
452 
453 void
454 rwrite(void)
455 {
456 	Xfile *f;
457 
458 	f=xfile(req->fid, Asis);
459 	if(!(f->flags&Owrite))
460 		error("file not opened for writing");
461 	rep->count = (*f->xf->s->write)(f, req->data, req->offset, req->count);
462 }
463 
464 void
465 rclunk(void)
466 {
467 	Xfile *f;
468 
469 	if(!waserror()){
470 		f = xfile(req->fid, Asis);
471 		(*f->xf->s->clunk)(f);
472 		poperror();
473 	}
474 	xfile(req->fid, Clunk);
475 }
476 
477 void
478 rremove(void)
479 {
480 	error("no removes");
481 }
482 
483 void
484 rstat(void)
485 {
486 	Xfile *f;
487 	Dir dir;
488 
489 	chat("stat(fid=%d)...", req->fid);
490 	f=xfile(req->fid, Asis);
491 	setnames(&dir, fdata);
492 	(*f->xf->s->stat)(f, &dir);
493 	if(chatty)
494 		showdir(2, &dir);
495 	rep->nstat = convD2M(&dir, statbuf, sizeof statbuf);
496 	rep->stat = statbuf;
497 }
498 
499 void
500 rwstat(void)
501 {
502 	error("no wstat");
503 }
504 
505 static int
506 openflags(int mode)
507 {
508 	int flags = 0;
509 
510 	switch(mode & ~(OTRUNC|OCEXEC|ORCLOSE)){
511 	case OREAD:
512 	case OEXEC:
513 		flags = Oread; break;
514 	case OWRITE:
515 		flags = Owrite; break;
516 	case ORDWR:
517 		flags = Oread|Owrite; break;
518 	}
519 	if(mode & ORCLOSE)
520 		flags |= Orclose;
521 	return flags;
522 }
523 
524 void
525 showdir(int fd, Dir *s)
526 {
527 	char a_time[32], m_time[32];
528 	char *p;
529 
530 	strcpy(a_time, ctime(s->atime));
531 	if(p=strchr(a_time, '\n'))	/* assign = */
532 		*p = 0;
533 	strcpy(m_time, ctime(s->mtime));
534 	if(p=strchr(m_time, '\n'))	/* assign = */
535 		*p = 0;
536 	fprint(fd, "name=\"%s\" qid=(0x%llux,%lud) type=%d dev=%d \
537 mode=0x%8.8lux=0%luo atime=%s mtime=%s length=%lld uid=\"%s\" gid=\"%s\"...",
538 		s->name, s->qid.path, s->qid.vers, s->type, s->dev,
539 		s->mode, s->mode,
540 		a_time, m_time, s->length, s->uid, s->gid);
541 }
542 
543 #define	SIZE	1024
544 
545 void
546 chat(char *fmt, ...)
547 {
548 	va_list arg;
549 
550 	if(chatty){
551 		va_start(arg, fmt);
552 		vfprint(2, fmt, arg);
553 		va_end(arg);
554 	}
555 }
556 
557 void
558 panic(int rflag, char *fmt, ...)
559 {
560 	va_list arg;
561 	char buf[SIZE]; int n;
562 
563 	n = sprint(buf, "%s %d: ", argv0, getpid());
564 	va_start(arg, fmt);
565 	vseprint(buf+n, buf+SIZE, fmt, arg);
566 	va_end(arg);
567 	fprint(2, (rflag ? "%s: %r\n" : "%s\n"), buf);
568 	if(chatty){
569 		fprint(2, "abort\n");
570 		abort();
571 	}
572 	exits("panic");
573 }
574