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