xref: /plan9/sys/src/cmd/srvold9p/srvold9p.c (revision 74f16c8187aab477889167f2422d0597b1b7d0ff)
1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <fcall.h>
5 #include <libsec.h>
6 #include "9p1.h"
7 
8 char	*user;
9 int	newfd;
10 int	roldfd;
11 int	woldfd;
12 int	debug;
13 int	dofcall;
14 QLock	servelock;
15 QLock	fidlock;
16 QLock	taglock;
17 int	mainpid;
18 int	ntag;
19 int	nfork;
20 char FLUSHED[] = "FLUSHED";
21 
22 enum{
23 	Maxfdata = 8192
24 };
25 
26 enum{
27 	Command,
28 	Network,
29 	File,
30 	Stdio,
31 };
32 
33 typedef struct Tag Tag;
34 struct Tag
35 {
36 	int	tag;
37 	int	flushed;
38 	int	received;
39 	int	ref;
40 	Tag	*next;
41 };
42 
43 typedef struct Message Message;
44 struct Message
45 {
46 	char	*data;
47 	int	n;
48 };
49 
50 typedef struct Fid Fid;
51 
52 struct Fid
53 {
54 	short	busy;
55 	short	allocated;
56 	int	fid;
57 	Qid	qid;
58 	ulong	newoffset;
59 	ulong	oldoffset;
60 	Fid	*next;
61 };
62 
63 Fid	*fids;
64 Tag	*tags;
65 
66 char	*rflush(Fcall*, Fcall*, char*),
67 	*rversion(Fcall*, Fcall*, char*),
68 	*rauth(Fcall*, Fcall*, char*),
69 	*rattach(Fcall*, Fcall*, char*),
70 	*rwalk(Fcall*, Fcall*, char*),
71 	*ropen(Fcall*, Fcall*, char*),
72 	*rcreate(Fcall*, Fcall*, char*),
73 	*rread(Fcall*, Fcall*, char*),
74 	*rwrite(Fcall*, Fcall*, char*),
75 	*rclunk(Fcall*, Fcall*, char*),
76 	*rremove(Fcall*, Fcall*, char*),
77 	*rstat(Fcall*, Fcall*, char*),
78 	*rwstat(Fcall*, Fcall*, char*);
79 
80 char 	*(*fcalls[])(Fcall*, Fcall*, char*) = {
81 	[Tversion]	rversion,
82 	[Tflush]	rflush,
83 	[Tauth]	rauth,
84 	[Tattach]	rattach,
85 	[Twalk]		rwalk,
86 	[Topen]		ropen,
87 	[Tcreate]	rcreate,
88 	[Tread]		rread,
89 	[Twrite]	rwrite,
90 	[Tclunk]	rclunk,
91 	[Tremove]	rremove,
92 	[Tstat]		rstat,
93 	[Twstat]	rwstat,
94 };
95 
96 char Etoolong[] = "name too long";
97 
98 void	connect(int, char*);
99 void	post(int, char*);
100 void	serve(void);
101 void	demux(void);
102 void*	emalloc(ulong);
103 char*	transact9p1(Fcall9p1*, Fcall9p1*, char*);
104 Fid*	newfid(int);
105 
106 struct
107 {
108 	char	chal[CHALLEN];		/* my challenge */
109 	char	rchal[CHALLEN];		/* his challenge */
110 	char	authid[NAMEREC];
111 	char	authdom[DOMLEN];
112 	int	id;
113 } ai;
114 
115 void
usage(void)116 usage(void)
117 {
118 	fprint(2, "usage: srvold9p [-abcCd] [-u user] [-s | [-m mountpoint]] [-x 'command' | -n network-addr | -f file] [-F] [-p servicename]\n");
119 	exits("usage");
120 }
121 
122 void
main(int argc,char * argv[])123 main(int argc, char *argv[])
124 {
125 	int method;
126 	char *oldstring;
127 	char *mountpoint, *postname;
128 	int mountflag, mountfd;
129 	int p[2];
130 int i;
131 
132 	fmtinstall('F', fcallfmt);
133 	fmtinstall('G', fcallfmt9p1);
134 	fmtinstall('D', dirfmt);
135 
136 	user = getuser();
137 	mountpoint = nil;
138 	mountflag = 0;
139 	postname = nil;
140 	oldstring = nil;
141 	method = -1;
142 	mountfd = -1;
143 
144 	ARGBEGIN{
145 	case 'a':
146 		mountflag |= MAFTER;
147 		break;
148 	case 'b':
149 		mountflag |= MBEFORE;
150 		break;
151 	case 'c':
152 		mountflag |= MCREATE;
153 		break;
154 	case 'C':
155 		mountflag |= MCACHE;
156 		break;
157 	case 'd':
158 		debug++;
159 		break;
160 	case 'f':
161 		method = File;
162 		oldstring = ARGF();
163 		break;
164 	case 'F':
165 		dofcall++;
166 		break;
167 	case 'm':
168 		mountpoint = EARGF(usage());
169 		break;
170 	case 'n':
171 		method = Network;
172 		oldstring = ARGF();
173 		break;
174 	case 'p':
175 		postname = ARGF();
176 		if(postname == nil)
177 			usage();
178 		break;
179 	case 's':
180 		method = Stdio;
181 		break;
182 	case 'u':
183 		user = EARGF(usage());
184 		break;
185 	case 'x':
186 		method = Command;
187 		oldstring = ARGF();
188 		break;
189 	default:
190 		usage();
191 	}ARGEND;
192 
193 	if(method == Stdio){
194 		if(mountpoint!=nil || argc!=0)
195 			usage();
196 	}else{
197 		if(oldstring == nil || argc != 0 || (mountflag!=0 && mountpoint==nil))
198 			usage();
199 	}
200 
201 	rfork(RFNOTEG|RFREND);
202 
203 	connect(method, oldstring);
204 
205 	if(method == Stdio)
206 		newfd = 0;
207 	else{
208 		if(pipe(p) < 0)
209 			fatal("pipe: %r");
210 		if(postname != nil)
211 			post(p[0], postname);
212 		mountfd = p[0];
213 		newfd = p[1];
214 	}
215 	if(debug)
216 		fprint(2, "connected and posted\n");
217 
218 	switch(rfork(RFPROC|RFMEM|RFNAMEG|RFFDG)){
219 	case 0:
220 		mainpid = getpid();
221 		/* child does all the work */
222 		if(mountfd >= 0)
223 			close(mountfd);
224 		switch(rfork(RFPROC|RFMEM|RFFDG)){
225 		case 0:
226 			for(i = 0; i < 20; i++)
227 				if (i != roldfd) close(i);
228 			demux();
229 			return;
230 		case -1:
231 			fatal("fork error: %r");
232 			break;
233 		}
234 		for(i = 0; i < 20; i++)
235 			if (i != newfd && i != woldfd && (debug == 0 || i != 2)) close(i);
236 		serve();
237 		break;
238 	case -1:
239 		fatal("fork error: %r");
240 		break;
241 	default:
242 		/* parent mounts if required, then exits */
243 		if(mountpoint){
244 			if(mount(mountfd, -1, mountpoint, mountflag, "") < 0)
245 				fatal("can't mount: %r");
246 		}
247 		break;
248 	}
249 	exits(nil);
250 }
251 
252 void
connect(int method,char * oldstring)253 connect(int method, char *oldstring)
254 {
255 	char *s;
256 	char dir[256];
257 
258 	switch(method){
259 	default:
260 		roldfd = -1;
261 		woldfd = -1;
262 		fatal("can't handle method type %d", method);
263 		break;
264 	case Network:
265 		s = netmkaddr(oldstring, 0, "9fs");
266 		roldfd = dial(s, 0, dir, 0);
267 		if(roldfd < 0)
268 			fatal("dial %s: %r", s);
269 		woldfd = roldfd;
270 		if(dofcall)
271 			roldfd = fcall(woldfd);
272 		break;
273 	case File:
274 		roldfd = open(oldstring, ORDWR);
275 		if(roldfd < 0)
276 			fatal("can't open %s: %r", oldstring);
277 		woldfd = roldfd;
278 		if(dofcall)
279 			roldfd = fcall(woldfd);
280 		break;
281 	case Stdio:
282 		roldfd = fcall(1);
283 		woldfd = 1;
284 		break;
285 	}
286 }
287 
288 void
post(int fd,char * srv)289 post(int fd, char *srv)
290 {
291 	int f;
292 	char buf[128];
293 
294 	snprint(buf, sizeof buf, "/srv/%s", srv);
295 	f = create(buf, OWRITE, 0666);
296 	if(f < 0)
297 		fatal("can't create %s: %r", buf);
298 	sprint(buf, "%d", fd);
299 	if(write(f, buf, strlen(buf)) != strlen(buf))
300 		fatal("post write: %r");
301 	close(f);
302 }
303 
304 Fid *
newfid(int fid)305 newfid(int fid)
306 {
307 	Fid *f, *ff;
308 
309 	ff = 0;
310 	qlock(&fidlock);
311 	for(f = fids; f; f = f->next)
312 		if(f->fid == fid){
313 			f->allocated = 1;
314 			qunlock(&fidlock);
315 			return f;
316 		}
317 		else if(!ff && !f->allocated)
318 			ff = f;
319 	if(ff){
320 		ff->fid = fid;
321 		ff->allocated = 1;
322 		qunlock(&fidlock);
323 		return ff;
324 	}
325 	f = emalloc(sizeof *f);
326 	f->fid = fid;
327 	f->next = fids;
328 	f->allocated = 1;
329 	fids = f;
330 	qunlock(&fidlock);
331 	return f;
332 }
333 
334 /*
335  * Reads returning 9P1 messages and demultiplexes them.
336  * BUG: assumes one read per message.
337  */
338 void
demux(void)339 demux(void)
340 {
341 	int m, n;
342 	char *data;
343 	Fcall9p1 r;
344 	Message *msg;
345 	Tag *t;
346 
347 	for(;;){
348 		data = malloc(IOHDRSZ+Maxfdata);	/* no need to clear memory */
349 		if(data == nil)
350 			fatal("demux malloc: %r");
351 		m = read(roldfd, data, IOHDRSZ+Maxfdata);
352 		if(m <= 0)
353 			fatal("read error talking to old system: %r");
354 		n = convM2S9p1(data, &r, m);
355 		if(n == 0)
356 			fatal("bad conversion receiving from old system");
357 		if(debug)
358 			fprint(2, "srvold9p:<=%G\n", &r);
359 		qlock(&taglock);
360 		for(t=tags; t!=nil; t=t->next)
361 			if(t->tag == r.tag){
362 				t->received = 1;
363 				break;
364 			}
365 		qunlock(&taglock);
366 		/*
367 		 * Fcall9p1 tag is used to rendezvous.
368 		 * Recipient converts message a second time, but that's OK.
369 		 */
370 		msg = emalloc(sizeof(Message));
371 		msg->data = data;
372 		msg->n = n;
373 		rendezvous((void*)r.tag, msg);
374 	}
375 }
376 
377 Tag*
newtag(int tag)378 newtag(int tag)
379 {
380 	Tag *t;
381 
382 	t = emalloc(sizeof(Tag));
383 	t->tag = tag;
384 	t->flushed = 0;
385 	t->received = 0;
386 	t->ref = 1;
387 	qlock(&taglock);
388 	t->next = tags;
389 	tags = t;
390 	qunlock(&taglock);
391 	return t;
392 }
393 
394 void
freetag(Tag * tag)395 freetag(Tag *tag)	/* called with taglock set */
396 {
397 	Tag *t, *prev;
398 
399 	if(tag->ref-- == 1){
400 		prev = nil;
401 		for(t=tags; t!=nil; t=t->next){
402 			if(t == tag){
403 				if(prev == nil)
404 					tags = t->next;
405 				else
406 					prev->next = t->next;
407 				break;
408 			}
409 			prev = t;
410 		}
411 		if(t == nil)
412 			sysfatal("freetag");
413 		free(tag);
414 	}
415 }
416 
417 void
serve(void)418 serve(void)
419 {
420 	char *err;
421 	int n;
422 	Fcall thdr;
423 	Fcall	rhdr;
424 	uchar mdata[IOHDRSZ+Maxfdata];
425 	char mdata9p1[IOHDRSZ+Maxfdata];
426 	Tag *tag;
427 
428 	for(;;){
429 		qlock(&servelock);
430 		for(;;){
431 			n = read9pmsg(newfd, mdata, sizeof mdata);
432 
433 			if(n == 0)
434 				continue;
435 			if(n < 0)
436 				break;
437 			if(n > 0 && convM2S(mdata, n, &thdr) > 0)
438 				break;
439 		}
440 		if(n>0 && servelock.head==nil)	/* no other processes waiting to read */
441 			switch(rfork(RFPROC|RFMEM)){
442 			case 0:
443 				/* child starts serving */
444 				continue;
445 				break;
446 			case -1:
447 				fatal("fork error: %r");
448 				break;
449 			default:
450 				break;
451 			}
452 		qunlock(&servelock);
453 
454 		if(n < 0)
455 			fatal(nil);	/* exit quietly; remote end has just hung up */
456 
457 		if(debug)
458 			fprint(2, "srvold9p:<-%F\n", &thdr);
459 
460 		tag = newtag(thdr.tag);
461 
462 		if(!fcalls[thdr.type])
463 			err = "bad fcall type";
464 		else
465 			err = (*fcalls[thdr.type])(&thdr, &rhdr, mdata9p1);
466 
467 		qlock(&taglock);
468 		if(tag->flushed){
469 			freetag(tag);
470 			qunlock(&taglock);
471 			continue;
472 		}
473 		qunlock(&taglock);
474 
475 		if(err){
476 			rhdr.type = Rerror;
477 			rhdr.ename = err;
478 		}else{
479 			rhdr.type = thdr.type + 1;
480 			rhdr.fid = thdr.fid;
481 		}
482 		rhdr.tag = thdr.tag;
483 		if(debug)
484 			fprint(2, "srvold9p:->%F\n", &rhdr);/**/
485 		n = convS2M(&rhdr, mdata, sizeof mdata);
486 		if(n == 0)
487 			fatal("convS2M error on write");
488 		if(write(newfd, mdata, n) != n)
489 			fatal("mount write");
490 
491 		qlock(&taglock);
492 		freetag(tag);
493 		qunlock(&taglock);
494 	}
495 }
496 
497 void
send9p1(Fcall9p1 * t,char * data)498 send9p1(Fcall9p1 *t, char *data)
499 {
500 	int m, n;
501 
502 	if(debug)
503 		fprint(2, "srvold9p:=>%G\n", t);
504 	n = convS2M9p1(t, data);
505 	if(n == 0)
506 		fatal("bad conversion sending to old system");
507 	m = write(woldfd, data, n);
508 	if(m != n)
509 		fatal("wrote %d to old system; should be %d", m, n);
510 }
511 
512 int
recv9p1(Fcall9p1 * r,int tag,char * data)513 recv9p1(Fcall9p1 *r, int tag, char *data)
514 {
515 	int n;
516 	Message *msg;
517 
518 	msg = rendezvous((void*)tag, 0);
519 	if(msg == (void*)~0)
520 		fatal("rendezvous: %r");
521 	if(msg == nil){
522 		if(debug)
523 			fprint(2, "recv flushed\n");
524 		return -1;
525 	}
526 	/* copy data to local buffer */
527 	memmove(data, msg->data, msg->n);
528 	n = convM2S9p1(data, r, msg->n);
529 	if(n == 0)
530 		fatal("bad conversion receiving from old system");
531 	free(msg->data);
532 	free(msg);
533 	return 1;
534 }
535 
536 char*
transact9p1(Fcall9p1 * t,Fcall9p1 * r,char * mdata9p1)537 transact9p1(Fcall9p1 *t, Fcall9p1 *r, char *mdata9p1)
538 {
539 	send9p1(t, mdata9p1);
540 	if(recv9p1(r, t->tag, mdata9p1) < 0)
541 		return FLUSHED;
542 	if(r->type == Rerror9p1)
543 		return r->ename;
544 	if(r->type != t->type+1)
545 		fatal("bad message type; expected %d got %d", t->type+1, r->type);
546 	return nil;
547 }
548 
549 char*
rflush(Fcall * t,Fcall *,char * mdata9p1)550 rflush(Fcall *t, Fcall *, char *mdata9p1)
551 {
552 	Fcall9p1 t9, r9;
553 	Tag *oldt;
554 
555 	t9.type = Tflush9p1;
556 	t9.tag = t->tag;
557 	t9.oldtag = t->oldtag;
558 	qlock(&taglock);
559 	for(oldt=tags; oldt!=nil; oldt=oldt->next)
560 		if(oldt->tag == t->oldtag){
561 			oldt->flushed = 1;
562 			oldt->ref++;
563 			break;
564 		}
565 	qunlock(&taglock);
566 
567 	if(oldt == nil){	/* nothing to flush */
568 		if(debug)
569 			fprint(2, "no such tag to flush\n");
570 		return 0;
571 	}
572 
573 	transact9p1(&t9, &r9, mdata9p1);	/* can't error */
574 
575 	qlock(&taglock);
576 	if(oldt->received == 0){	/* wake up receiver */
577 		if(debug)
578 			fprint(2, "wake up receiver\n");
579 		oldt->received = 1;
580 		rendezvous((void*)t->oldtag, 0);
581 	}
582 	freetag(oldt);
583 	qunlock(&taglock);
584 	return 0;
585 }
586 
587 char*
rversion(Fcall * t,Fcall * r,char *)588 rversion(Fcall *t, Fcall *r, char*)
589 {
590 	Fid *f;
591 
592 	/* just ack; this one doesn't go to old service */
593 	if(t->msize > IOHDRSZ+Maxfdata)
594 		r->msize = IOHDRSZ+Maxfdata;
595 	else
596 		r->msize = t->msize;
597 	if(strncmp(t->version, "9P2000", 6) != 0)
598 		return "unknown 9P version";
599 	r->version = "9P2000";
600 
601 	qlock(&fidlock);
602 	for(f = fids; f; f = f->next){
603 		f->busy = 0;
604 		f->allocated = 0;
605 	}
606 	qunlock(&fidlock);
607 
608 	return 0;
609 }
610 
611 char*
rauth(Fcall *,Fcall *,char *)612 rauth(Fcall *, Fcall *, char *)
613 {
614 	return "srvold9p: authentication not supported";
615 }
616 
617 #ifdef asdf
618 
619 void
memrandom(void * p,int n)620 memrandom(void *p, int n)
621 {
622 	ulong *lp;
623 	uchar *cp;
624 
625 	for(lp = p; n >= sizeof(ulong); n -= sizeof(ulong))
626 		*lp++ = fastrand();
627 	for(cp = (uchar*)lp; n > 0; n--)
628 		*cp++ = fastrand();
629 }
630 
631 char*
rsession(Fcall * t,Fcall * r,char * mdata9p1)632 rsession(Fcall *t, Fcall *r, char *mdata9p1)
633 {
634 	char *err;
635 	Fcall9p1 t9, r9;
636 	Fid *f;
637 
638 	t9.type = Tsession9p1;
639 	t9.tag = t->tag;
640 	if(doauth)
641 		memrandom(t9.chal, sizeof t9.chal);
642 	else
643 		memset(t9.chal, 0, sizeof t9.chal);
644 	err = transact9p1(&t9, &r9, mdata9p1);
645 	if(err)
646 		return err;
647 
648 	qlock(&fidlock);
649 	for(f = fids; f; f = f->next){
650 		f->busy = 0;
651 		f->allocated = 0;
652 	}
653 	qunlock(&fidlock);
654 
655 	if(doauth){
656 		memmove(ai.authid, r9.authid, sizeof ai.authid);
657 		memmove(ai.authdom, r9.authdom, sizeof ai.authid);
658 		memmove(ai.rchal, r9.chal, sizeof ai.rchal);
659 		memmove(ai.chal, t9.chal, sizeof ai.chal);
660 		r->authid = ai.authid;
661 		r->authdom = ai.authdom;
662 		r->chal = (uchar*)ai.rchal;
663 		r->nchal = CHALLEN;
664 	} else {
665 		r->authid = "";
666 		r->authdom = "";
667 		r->nchal = 0;
668 		r->chal = nil;
669 	}
670 	return 0;
671 }
672 #endif
673 
674 char*
rattach(Fcall * t,Fcall * r,char * mdata9p1)675 rattach(Fcall *t, Fcall *r, char *mdata9p1)
676 {
677 	char *err;
678 	Fcall9p1 t9, r9;
679 	Fid *f;
680 
681 	f = newfid(t->fid);
682 	if(f->busy)
683 		return "attach: fid in use";
684 	/* no authentication! */
685 	t9.type = Tattach9p1;
686 	t9.tag = t->tag;
687 	t9.fid = t->fid;
688 	strncpy(t9.uname, t->uname, NAMEREC);
689 	if(strcmp(user, "none") == 0)
690 		strncpy(t9.uname, user, NAMEREC);
691 	strncpy(t9.aname, t->aname, NAMEREC);
692 	memset(t9.ticket, 0, sizeof t9.ticket);
693 	memset(t9.auth, 0, sizeof t9.auth);
694 	err = transact9p1(&t9, &r9, mdata9p1);
695 	if(err)
696 		return err;
697 
698 	r->qid.path = r9.qid.path & ~0x80000000;
699 	r->qid.vers = r9.qid.version;
700 	r->qid.type = QTDIR;
701 	f->busy = 1;
702 	f->qid = r->qid;
703 	return 0;
704 }
705 
706 char*
rwalk(Fcall * t,Fcall * r,char * mdata9p1)707 rwalk(Fcall *t, Fcall *r, char *mdata9p1)
708 {
709 	char *err;
710 	Fcall9p1 t9, r9;
711 	int i, fid;
712 	Qid *q;
713 	Fid *f, *nf;
714 
715 	f = newfid(t->fid);
716 	if(!f->busy)
717 		return "walk: bad fid";
718 
719 	fid = t->fid;
720 	nf = nil;
721 	if(t->fid != t->newfid){
722 		nf = newfid(t->newfid);
723 		if(nf->busy)
724 			return "walk: newfid in use";
725 		t9.type = Tclone9p1;
726 		t9.tag = t->tag;
727 		t9.fid = t->fid;
728 		t9.newfid = t->newfid;
729 		err = transact9p1(&t9, &r9, mdata9p1);
730 		if(err){
731 			nf->busy = 0;
732 			nf->allocated = 0;
733 			return err;
734 		}
735 		fid = t->newfid;
736 		nf->busy = 1;
737 	}
738 
739 	err = nil;
740 	r->nwqid = 0;
741 	for(i=0; i<t->nwname && err==nil; i++){
742 		if(i > MAXWELEM)
743 			break;
744 		t9.type = Twalk9p1;
745 		t9.tag = t->tag;
746 		t9.fid = fid;
747 		strncpy(t9.name, t->wname[i], NAMEREC);
748 		err = transact9p1(&t9, &r9, mdata9p1);
749 		if(err == FLUSHED){
750 			i = -1;	/* guarantee cleanup */
751 			break;
752 		}
753 		if(err == nil){
754 			q = &r->wqid[r->nwqid++];
755 			q->type = QTFILE;
756 			if(r9.qid.path & 0x80000000)
757 				q->type = QTDIR;
758 			q->vers = r9.qid.version;
759 			q->path = r9.qid.path & ~0x80000000;
760 		}
761 	}
762 
763 	if(nf!=nil && (err!=nil || i<t->nwname)){
764 		/* clunk the new fid */
765 		t9.type = Tclunk9p1;
766 		t9.tag = t->tag;
767 		t9.fid = t->newfid;
768 		transact9p1(&t9, &r9, mdata9p1);
769 		/* ignore more errors */
770 		nf->busy = 0;
771 		nf->allocated = 0;
772 	}
773 
774 	if(i>0 && i==t->nwname && err==nil)
775 		f->qid = r->wqid[r->nwqid-1];
776 	if(i > 0)
777 		return 0;
778 	return err;
779 }
780 
781 char*
ropen(Fcall * t,Fcall * r,char * mdata9p1)782 ropen(Fcall *t, Fcall *r, char *mdata9p1)
783 {
784 	char *err;
785 	Fcall9p1 t9, r9;
786 	Fid *f;
787 
788 	f = newfid(t->fid);
789 	if(!f->busy)
790 		return "open: bad fid";
791 
792 	t9.type = Topen9p1;
793 	t9.tag = t->tag;
794 	t9.fid = t->fid;
795 	t9.mode = t->mode;
796 	err = transact9p1(&t9, &r9, mdata9p1);
797 	if(err)
798 		return err;
799 
800 	r->qid.path = r9.qid.path & ~0x80000000;
801 	r->qid.vers = r9.qid.version;
802 	r->qid.type = QTFILE;
803 	if(r9.qid.path & 0x80000000)
804 		r->qid.type = QTDIR;
805 	f->qid = r->qid;
806 	f->newoffset = 0;
807 	f->oldoffset = 0;
808 	r->iounit = 0;
809 	return 0;
810 }
811 
812 char*
rcreate(Fcall * t,Fcall * r,char * mdata9p1)813 rcreate(Fcall *t, Fcall *r, char *mdata9p1)
814 {
815 	char *err;
816 	Fcall9p1 t9, r9;
817 	Fid *f;
818 
819 	f = newfid(t->fid);
820 	if(!f->busy)
821 		return "create: bad fid";
822 
823 	t9.type = Tcreate9p1;
824 	t9.tag = t->tag;
825 	t9.fid = t->fid;
826 	if(strlen(t->name)+1 >= NAMEREC)
827 		return "file name element too long";
828 	strncpy(t9.name, t->name, NAMEREC);
829 	t9.perm = t->perm;
830 	t9.mode = t->mode;
831 	err = transact9p1(&t9, &r9, mdata9p1);
832 	if(err)
833 		return err;
834 
835 	r->qid.path = r9.qid.path & ~0x80000000;
836 	r->qid.vers = r9.qid.version;
837 	r->qid.type = QTFILE;
838 	if(r9.qid.path & 0x80000000)
839 		r->qid.type = QTDIR;
840 	if(r9.qid.path & 0x40000000)
841 		r->qid.type |= QTAPPEND;
842 	if(r9.qid.path & 0x20000000)
843 		r->qid.type |= QTEXCL;
844 	f->qid = r->qid;
845 	r->iounit = 0;
846 	return 0;
847 }
848 
849 char*
dirrread(Fcall * t,Fcall * r,char * mdata9p1)850 dirrread(Fcall *t, Fcall *r, char *mdata9p1)
851 {
852 	char *err;
853 	Fcall9p1 t9, r9;
854 	Fid *f;
855 	int i, ndir, n, count;
856 	Dir d;
857 	uchar buf[Maxfdata];
858 	char *old;
859 
860 	f = newfid(t->fid);
861 	if(!f->busy)
862 		return "dirread: bad fid";
863 
864 	if(f->newoffset != t->offset)
865 		return "seek in directory disallowed";
866 
867 	t9.type = Tread9p1;
868 	t9.tag = t->tag;
869 	t9.fid = t->fid;
870 	t9.offset = f->oldoffset;
871 	t9.count = t->count;	/* new directories tend to be smaller, so this may overshoot */
872 	err = transact9p1(&t9, &r9, mdata9p1);
873 	if(err)
874 		return err;
875 
876 	ndir = r9.count/DIRREC;
877 	old = r9.data;
878 	count = 0;
879 	for(i=0; i<ndir; i++){
880 		if(convM2D9p1(old, &d) != DIRREC)
881 			return "bad dir conversion in read";
882 		n = convD2M(&d, buf+count, sizeof buf-count);
883 		if(n<=BIT16SZ || count+n>t->count)
884 			break;
885 		old += DIRREC;
886 		f->oldoffset += DIRREC;
887 		f->newoffset += n;
888 		count += n;
889 	}
890 	memmove(r9.data, buf, count);	/* put it back in stable storage */
891 	r->data = r9.data;
892 	r->count = count;
893 	return 0;
894 }
895 
896 char*
rread(Fcall * t,Fcall * r,char * mdata9p1)897 rread(Fcall *t, Fcall *r, char *mdata9p1)
898 {
899 	char *err;
900 	Fcall9p1 t9, r9;
901 	Fid *f;
902 
903 	f = newfid(t->fid);
904 	if(!f->busy)
905 		return "read: bad fid";
906 
907 	if(f->qid.type & QTDIR)
908 		return dirrread(t, r, mdata9p1);
909 
910 	t9.type = Tread9p1;
911 	t9.tag = t->tag;
912 	t9.fid = t->fid;
913 	t9.offset = t->offset;
914 	t9.count = t->count;
915 	err = transact9p1(&t9, &r9, mdata9p1);
916 	if(err)
917 		return err;
918 
919 	r->count = r9.count;
920 	r->data = r9.data;	/* points to stable storage */
921 	return 0;
922 }
923 
924 char*
rwrite(Fcall * t,Fcall * r,char * mdata9p1)925 rwrite(Fcall *t, Fcall *r, char *mdata9p1)
926 {
927 	char *err;
928 	Fcall9p1 t9, r9;
929 	Fid *f;
930 
931 	f = newfid(t->fid);
932 	if(!f->busy)
933 		return "write: bad fid";
934 
935 	t9.type = Twrite9p1;
936 	t9.tag = t->tag;
937 	t9.fid = t->fid;
938 	t9.offset = t->offset;
939 	t9.count = t->count;
940 	t9.data = t->data;
941 	err = transact9p1(&t9, &r9, mdata9p1);
942 	if(err)
943 		return err;
944 
945 	r->count = r9.count;
946 	return 0;
947 }
948 
949 char*
rclunk(Fcall * t,Fcall *,char * mdata9p1)950 rclunk(Fcall *t, Fcall *, char *mdata9p1)
951 {
952 	Fcall9p1 t9, r9;
953 	Fid *f;
954 
955 	f = newfid(t->fid);
956 	if(!f->busy)
957 		return "clunk: bad fid";
958 	t9.type = Tclunk9p1;
959 	t9.tag = t->tag;
960 	t9.fid = t->fid;
961 	transact9p1(&t9, &r9, mdata9p1);
962 	f->busy = 0;
963 	f->allocated = 0;
964 	/* disregard error */
965 	return 0;
966 }
967 
968 char*
rremove(Fcall * t,Fcall *,char * mdata9p1)969 rremove(Fcall *t, Fcall*, char *mdata9p1)
970 {
971 	char *err;
972 	Fcall9p1 t9, r9;
973 	Fid *f;
974 
975 	f = newfid(t->fid);
976 	if(!f->busy)
977 		return "remove: bad fid";
978 	t9.type = Tremove9p1;
979 	t9.tag = t->tag;
980 	t9.fid = t->fid;
981 	err = transact9p1(&t9, &r9, mdata9p1);
982 	f->busy = 0;
983 	f->allocated = 0;
984 	return err;
985 }
986 
987 char*
rstat(Fcall * t,Fcall * r,char * mdata9p1)988 rstat(Fcall *t, Fcall *r, char *mdata9p1)
989 {
990 	Fcall9p1 t9, r9;
991 	char *err;
992 	Fid *f;
993 	Dir d;
994 	uchar buf[256];	/* big enough; there's no long names */
995 
996 	f = newfid(t->fid);
997 	if(!f->busy)
998 		return "stat: bad fid";
999 
1000 	t9.type = Tstat9p1;
1001 	t9.tag = t->tag;
1002 	t9.fid = t->fid;
1003 	err = transact9p1(&t9, &r9, mdata9p1);
1004 	if(err)
1005 		return err;
1006 
1007 	if(convM2D9p1(r9.stat, &d) != DIRREC)
1008 		return "bad conversion in stat";
1009 	r->stat = buf;
1010 	r->nstat = convD2M(&d, buf, sizeof buf);
1011 	return 0;
1012 }
1013 
1014 int
anydefault(Dir * d)1015 anydefault(Dir *d)
1016 {
1017 	if(d->name[0] == '\0')
1018 		return 1;
1019 	if(d->uid[0] == '\0')
1020 		return 1;
1021 	if(d->gid[0] == '\0')
1022 		return 1;
1023 	if(d->mode == ~0)
1024 		return 1;
1025 	if(d->mtime == ~0)
1026 		return 1;
1027 	return 0;
1028 }
1029 
1030 char*
rwstat(Fcall * t,Fcall *,char * mdata9p1)1031 rwstat(Fcall *t, Fcall *, char *mdata9p1)
1032 {
1033 	Fcall9p1 t9, r9;
1034 	char strs[DIRREC];
1035 	char *err;
1036 	Fid *f;
1037 	Dir d, cd;
1038 
1039 	f = newfid(t->fid);
1040 	if(!f->busy)
1041 		return "wstat: bad fid";
1042 
1043 	convM2D(t->stat, t->nstat, &d, strs);
1044 	cd = d;
1045 	if(anydefault(&d)){
1046 		/* must first stat file so we can copy current values */
1047 		t9.type = Tstat9p1;
1048 		t9.tag = t->tag;
1049 		t9.fid = t->fid;
1050 		err = transact9p1(&t9, &r9, mdata9p1);
1051 		if(err)
1052 			return err;
1053 		if(convM2D9p1(r9.stat, &cd) != DIRREC)
1054 			return "bad in conversion in wstat";
1055 
1056 		/* fill in default values */
1057 		if(d.name[0] != '\0'){
1058 			if(strlen(d.name) >= NAMEREC)
1059 				return Etoolong;
1060 			cd.name = d.name;
1061 		}
1062 		if(d.uid[0] != '\0'){
1063 			if(strlen(d.uid) >= NAMEREC)
1064 				return Etoolong;
1065 			cd.uid = d.uid;
1066 		}
1067 		if(d.gid[0] != '\0'){
1068 			if(strlen(d.gid) >= NAMEREC)
1069 				return Etoolong;
1070 			cd.gid = d.gid;
1071 		}
1072 		if(d.mode != ~0)
1073 			cd.mode = d.mode;
1074 		if(d.mtime != ~0)
1075 			cd.mtime = d.mtime;
1076 		if(d.length != ~0LL)
1077 			cd.length = d.length;
1078 	}
1079 
1080 	if(convD2M9p1(&cd, t9.stat) != DIRREC)
1081 		return "bad out conversion in wstat";
1082 
1083 	t9.type = Twstat9p1;
1084 	t9.tag = t->tag;
1085 	t9.fid = t->fid;
1086 	err = transact9p1(&t9, &r9, mdata9p1);
1087 	if(err)
1088 		return err;
1089 	return 0;
1090 }
1091 
1092 void *
emalloc(ulong n)1093 emalloc(ulong n)
1094 {
1095 	void *p;
1096 
1097 	p = malloc(n);
1098 	if(!p)
1099 		fatal("out of memory: %r");
1100 	memset(p, 0, n);
1101 	return p;
1102 }
1103 
1104 void
fatal(char * fmt,...)1105 fatal(char *fmt, ...)
1106 {
1107 	char buf[1024];
1108 	va_list arg;
1109 
1110 	if(fmt){
1111 		va_start(arg, fmt);
1112 		vseprint(buf, buf+sizeof(buf), fmt, arg);
1113 		va_end(arg);
1114 		fprint(2, "%s: (pid %d) %s\n", argv0, getpid(), buf);
1115 	}else
1116 		buf[0] = '\0';
1117 	if(mainpid){
1118 		/* two hits are sometimes needed */
1119 		postnote(PNGROUP, mainpid, "die1 - from srvold9p");
1120 		postnote(PNGROUP, mainpid, "die2 - from srvold9p");
1121 	}
1122 	exits(buf);
1123 }
1124