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