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