xref: /plan9-contrib/sys/src/cmd/aux/vmware/vmwarefs.c (revision 06d2afa6aa61b39f2ff8184391f0458258bcc86a)
1 #include "all.h"
2 #include <fcall.h>
3 #include <thread.h>
4 #include <9p.h>
5 
6 char *mtpt = "/mnt/vmware";
7 char *srvname;
8 uint time0;
9 
10 enum
11 {
12 	Qroot = 0,
13 	Qmousepoint,
14 	Qsnarf,
15 	Qgui,
16 	Qdev,
17 	Qtime,
18 	Qbintime,
19 	Qmsg,
20 };
21 
22 typedef struct Tab Tab;
23 struct Tab
24 {
25 	int qid;
26 	char *name;
27 	uint perm;
28 	uint vers;
29 	void (*open)(Req*);
30 	void (*read)(Req*);
31 	void (*write)(Req*);
32 	void (*close)(Fid*);
33 };
34 
35 static void
mousepointread(Req * r)36 mousepointread(Req *r)
37 {
38 	char buf[32];
39 	Point p;
40 
41 	p = getmousepoint();
42 	snprint(buf, sizeof buf, "%11d %11d ", p.x, p.y);
43 	readstr(r, buf);
44 	respond(r, nil);
45 }
46 
47 static void
mousepointwrite(Req * r)48 mousepointwrite(Req *r)
49 {
50 	char buf[32], *f[3];
51 	int nf, n;
52 	Point p;
53 
54 	n = r->ifcall.count;
55 	if(n >= sizeof buf){
56 		respond(r, "write too large");
57 		return;
58 	}
59 	memmove(buf, r->ifcall.data, n);
60 	buf[n] = '\0';
61 	nf = tokenize(buf, f, nelem(f));
62 	if(nf != 2){
63 		respond(r, "bad point format");
64 		return;
65 	}
66 	p.x = atoi(f[0]);
67 	p.y = atoi(f[1]);
68 	setmousepoint(p);
69 	respond(r, nil);
70 }
71 
72 static void
timeread(Req * r)73 timeread(Req *r)
74 {
75 	char buf[32];
76 	uint sec, microsec, lag;
77 
78 	gettime(&sec, &microsec, &lag);
79 	snprint(buf, sizeof buf, "%11d ", sec);
80 	readstr(r, buf);
81 	respond(r, nil);
82 }
83 
84 static uvlong uvorder = 0x0001020304050607ULL;
85 static uchar*
vlong2le(uchar * t,vlong from)86 vlong2le(uchar *t, vlong from)
87 {
88 	uchar *f, *o;
89 	int i;
90 
91 	f = (uchar*)&from;
92 	o = (uchar*)&uvorder;
93 	for(i = 0; i < sizeof(vlong); i++)
94 		t[i] = f[o[i]];
95 	return t+sizeof(vlong);
96 }
97 
98 static void
bintimeread(Req * r)99 bintimeread(Req *r)
100 {
101 	uchar *b;
102 	int i, n;
103 	uint sec, microsec, lag;
104 	vlong nsec;
105 
106 	b = (uchar*)r->ofcall.data;
107 	n = r->ifcall.count;
108 
109 	i = 0;
110 	if(n >= 8){
111 		gettime(&sec, &microsec, &lag);
112 		nsec = sec*1000000000LL+microsec*1000LL;
113 		vlong2le(b, nsec);
114 		i = 8;
115 	}
116 	if(n >= 16){
117 		vlong2le(b+8, nsec);
118 		i = 16;
119 	}
120 	if(n >= 24){
121 		vlong2le(b+16, 1000000000LL);
122 		i = 24;
123 	}
124 	r->ofcall.count = i;
125 	respond(r, nil);
126 }
127 
128 char *snarf;
129 int nsnarf;
130 char *tsnarf;
131 int ntsnarf;
132 
133 static void
snarfread(Req * r)134 snarfread(Req *r)
135 {
136 	int i;
137 
138 	if(r->ifcall.offset == 0){
139 		if(snarf)
140 			free(snarf);
141 		nsnarf = getsnarflength();
142 		snarf = emalloc9p(nsnarf+4+1);
143 		for(i=0; i<nsnarf; i+=4)
144 			*(uint*)(snarf+i) = getsnarfpiece();
145 		snarf[nsnarf] = '\0';
146 		nsnarf = strlen(snarf);	/* there's extra crap because we have to transfer 4 bytes at a time */
147 	}
148 
149 	readbuf(r, snarf, nsnarf);
150 	respond(r, nil);
151 }
152 
153 static void
snarfwrite(Req * r)154 snarfwrite(Req *r)
155 {
156 	if(r->ifcall.offset == 0){
157 		free(tsnarf);
158 		tsnarf = nil;
159 		ntsnarf = 0;
160 	}
161 	if(r->ifcall.offset > 100*1024){
162 		respond(r, "snarf buffer too long");
163 		return;
164 	}
165 	tsnarf = erealloc9p(tsnarf, ntsnarf+r->ifcall.count);
166 	memmove(tsnarf+ntsnarf, r->ifcall.data, r->ifcall.count);
167 	ntsnarf += r->ifcall.count;
168 	r->ofcall.count = r->ifcall.count;
169 	respond(r, nil);
170 }
171 
172 static void
snarfclose(Fid * fid)173 snarfclose(Fid *fid)
174 {
175 	int i, n;
176 
177 	if((fid->omode&3) == OREAD)
178 		return;
179 
180 	// read old snarf - dunno why but it helps
181 	n = getsnarflength();
182 	for(i=0; i<n; i+=4)
183 		getsnarfpiece();
184 
185 	setsnarflength(ntsnarf);
186 	for(i=0; i<ntsnarf; i+=4)
187 		setsnarfpiece(*(uint*)(tsnarf+i));
188 	free(tsnarf);
189 	tsnarf = nil;
190 	ntsnarf = 0;
191 }
192 
193 typedef struct Bit Bit;
194 struct Bit
195 {
196 	char *name;
197 	uint bit;
198 };
199 
200 Bit guibit[] = {
201 	"autograb",	1,
202 	"autorelease",	2,
203 	"autoscroll",	4,
204 	"autoraise",	8,
205 	"copypaste",	0x10,
206 	"hidecursor",	0x20,
207 	"fullscreen",	0x40,
208 	"tofullscreen",	0x80,
209 	"towindow",	0x100,
210 	"autoraise-disabled",	0x200,
211 	"synctime",	0x400,
212 };
213 
214 static void
guiread(Req * r)215 guiread(Req *r)
216 {
217 	int i;
218 	char *s;
219 	Fmt fmt;
220 	uint val;
221 
222 	val = getguistate();
223 	fmtstrinit(&fmt);
224 	for(i=0; i<nelem(guibit); i++)
225 		fmtprint(&fmt, "%s %s\n", guibit[i].name, (val & guibit[i].bit) ? "on" : "off");
226 	s = fmtstrflush(&fmt);
227 	readstr(r, s);
228 	free(s);
229 	respond(r, nil);
230 }
231 
232 static void
guiwrite(Req * r)233 guiwrite(Req *r)
234 {
235 	int i, on;
236 	uint v;
237 	Cmdbuf *cb;
238 
239 	cb = parsecmd(r->ifcall.data, r->ifcall.count);
240 	if(cb->nf != 2){
241 		respondcmderror(r, cb, "bad gui ctl");
242 		free(cb);
243 		return;
244 	}
245 
246 	if(strcmp(cb->f[1], "off")==0)
247 		on = 0;
248 	else if(strcmp(cb->f[1], "on") == 0)
249 		on = 1;
250 	else{
251 		respondcmderror(r, cb, "bad gui ctl");
252 		free(cb);
253 		return;
254 	}
255 
256 	for(i=0; i<nelem(guibit); i++)
257 		if(strcmp(guibit[i].name, cb->f[0]) == 0)
258 			goto Have;
259 	respondcmderror(r, cb, "bad gui ctl");
260 	free(cb);
261 	return;
262 
263 Have:
264 	v = getguistate();
265 	if(on)
266 		v |= guibit[i].bit;
267 	else
268 		v &= ~guibit[i].bit;
269 	setguistate(v);
270 	r->ofcall.count = r->ifcall.count;
271 	free(cb);
272 	respond(r, nil);
273 }
274 
275 typedef struct Info Info;
276 struct Info
277 {
278 	char name[32];
279 	uint uid;
280 	uint enabled;
281 };
282 static int
getinfo(uint id,Info * p)283 getinfo(uint id, Info *p)
284 {
285 	uint i;
286 
287 	for(i=0; i<sizeof(Info); i+=4)
288 		if(getdeviceinfo(id, i, (uint*)((uchar*)p+i)) == 0)
289 			return -1;
290 	return 0;
291 }
292 
293 static void
devread(Req * r)294 devread(Req *r)
295 {
296 	int i;
297 	char *s;
298 	Fmt fmt;
299 	Info info;
300 
301 	fmtstrinit(&fmt);
302 	memset(&info, 0, sizeof info);
303 	for(i=0; i<100; i++){
304 		if(getinfo(i, &info) < 0)
305 			break;
306 		fmtprint(&fmt, "%11d %q %s\n", info.uid, info.name, info.enabled ? "on" : "off");
307 	}
308 	s = fmtstrflush(&fmt);
309 	readstr(r, s);
310 	respond(r, nil);
311 	free(s);
312 }
313 
314 static void
fsmsgread(Req * r)315 fsmsgread(Req *r)
316 {
317 	char *s;
318 	Msgchan *c;
319 
320 	c = r->fid->aux;
321 	if(c == nil){
322 		respond(r, "message channel not open");
323 		return;
324 	}
325 
326 	if(r->ifcall.offset == 0){
327 		if(recvmsg(c, &s) < 0){
328 			respond(r, "no messages waiting");
329 			return;
330 		}
331 	}
332 	if(c->a == nil){
333 		respond(r, "no messages waiting");
334 		return;
335 	}
336 	readbuf(r, c->a, c->na);
337 	respond(r, nil);
338 }
339 
340 static void
fsmsgwrite(Req * r)341 fsmsgwrite(Req *r)
342 {
343 	char buf[32], *p;
344 	int n;
345 	Msgchan *c;
346 
347 	if(r->ifcall.offset != 0){
348 		respond(r, "must write at offset zero");
349 		return;
350 	}
351 
352 	r->ofcall.count = r->ifcall.count;
353 	c = r->fid->aux;
354 	if(c == nil){
355 		if(r->ifcall.count >= sizeof buf){
356 			respond(r, "bad message channel number");
357 			return;
358 		}
359 		memmove(buf, r->ifcall.data, r->ifcall.count);
360 		buf[r->ifcall.count] = 0;
361 		p = buf;
362 		n = strtol(buf, &p, 0);
363 		if(p == buf){
364 			respond(r, "bad message channel number");
365 			return;
366 		}
367 		c = openmsg(n);
368 		if(c == nil){
369 			respond(r, "could not open message channel");
370 			return;
371 		}
372 		r->fid->aux = c;
373 		respond(r, nil);
374 		return;
375 	}
376 
377 	if(sendmsg(c, r->ifcall.data, r->ifcall.count) < 0){
378 		respond(r, "could not send message");
379 		return;
380 	}
381 	respond(r, nil);
382 }
383 
384 static void
fsmsgclose(Fid * fid)385 fsmsgclose(Fid *fid)
386 {
387 	Msgchan *c;
388 
389 	c = fid->aux;
390 	if(c)
391 		closemsg(c);
392 }
393 
394 Tab tab[] = {
395 	Qmousepoint, "mouse", 0666, 0, nil, mousepointread, mousepointwrite, nil,
396 	Qsnarf, "snarf", 0666, 0, nil, snarfread, snarfwrite, snarfclose,
397 	Qgui, "gui", 0666, 0, nil, guiread, guiwrite, nil,
398 	Qdev, "dev", 0444, 0, nil, devread, nil, nil,
399 	Qtime, "time", 0444, 0, nil, timeread, nil, nil,
400 	Qbintime, "bintime", 0444, 0, nil, bintimeread, nil, nil,
401 	Qmsg, "msg", 0666, 0, nil, fsmsgread, fsmsgwrite, fsmsgclose,
402 };
403 
404 void
fsattach(Req * r)405 fsattach(Req *r)
406 {
407 	char *spec;
408 
409 	spec = r->ifcall.aname;
410 	if(spec && spec[0]){
411 		respond(r, "invalid attach specifier");
412 		return;
413 	}
414 	r->ofcall.qid = (Qid){Qroot, 0, QTDIR};
415 	r->fid->qid = r->ofcall.qid;
416 	respond(r, nil);
417 }
418 
419 char*
fswalk1(Fid * fid,char * name,Qid * qid)420 fswalk1(Fid *fid, char *name, Qid *qid)
421 {
422 	int i;
423 
424 	switch((int)fid->qid.path){
425 	case Qroot:
426 		for(i=0; i<nelem(tab); i++){
427 			if(strcmp(name, tab[i].name) == 0){
428 				fid->qid.path = tab[i].qid;
429 				fid->qid.type = tab[i].perm>>24;;
430 				fid->qid.vers = tab[i].vers;
431 				*qid = fid->qid;
432 				return nil;
433 			}
434 		}
435 		break;
436 	}
437 
438 	return "file not found";
439 }
440 
441 void
fsstat(Req * r)442 fsstat(Req *r)
443 {
444 	int i, q;
445 	Dir *d;
446 
447 	d = &r->d;
448 	memset(d, 0, sizeof *d);
449 	q = r->fid->qid.path;
450 	d->qid = r->fid->qid;
451 	switch(q){
452 	case Qroot:
453 		d->name = estrdup9p("/");
454 		d->mode = DMDIR|0777;
455 		break;
456 
457 	default:
458 		for(i=0; i<nelem(tab); i++){
459 			if(tab[i].qid == q){
460 				d->qid.vers = tab[i].vers;
461 				d->qid.type = tab[i].perm>>24;
462 				d->mode = tab[i].perm;
463 				goto Out;
464 			}
465 		}
466 		respond(r, "file not found");
467 	}
468 
469 Out:
470 	d->atime = d->mtime = time0;
471 	d->uid = estrdup9p("vmware");
472 	d->gid = estrdup9p("vmware");
473 	d->muid = estrdup9p("");
474 	respond(r, nil);
475 }
476 
477 int
dirgen(int off,Dir * d,void *)478 dirgen(int off, Dir *d, void*)
479 {
480 	if(off >= nelem(tab))
481 		return -1;
482 
483 	memset(d, 0, sizeof *d);
484 	d->atime = d->mtime = time0;
485 	d->name = estrdup9p(tab[off].name);
486 	d->mode = tab[off].perm;
487 	d->qid.path = tab[off].qid;
488 	d->qid.vers = tab[off].vers;
489 	d->qid.type = d->mode>>24;
490 	d->uid = estrdup9p("vmware");
491 	d->gid = estrdup9p("vmware");
492 	d->muid = estrdup9p("");
493 	return 0;
494 }
495 
496 void
fsread(Req * r)497 fsread(Req *r)
498 {
499 	int i, q;
500 
501 	q = r->fid->qid.path;
502 	switch(q){
503 	case Qroot:
504 		dirread9p(r, dirgen, nil);
505 		respond(r, nil);
506 		return;
507 
508 	default:
509 		for(i=0; i<nelem(tab); i++)
510 			if(tab[i].qid == q)
511 				goto Have;
512 
513 		respond(r, "cannot happen in fsread");
514 		return;
515 
516 	Have:
517 		if(tab[i].read == nil){
518 			respond(r, "no read function");
519 			return;
520 		}
521 		tab[i].read(r);
522 		return;
523 	}
524 }
525 
526 void
fswrite(Req * r)527 fswrite(Req *r)
528 {
529 	int i, q;
530 
531 	q = r->fid->qid.path;
532 	for(i=0; i<nelem(tab); i++)
533 		if(tab[i].qid == q){
534 			if(tab[i].write == nil){
535 				respond(r, "no write function");
536 				return;
537 			}
538 			tab[i].write(r);
539 			return;
540 		}
541 
542 	respond(r, "cannot happen in fswrite");
543 }
544 
545 void
fsopen(Req * r)546 fsopen(Req *r)
547 {
548 	int i, q;
549 
550 	q = r->fid->qid.path;
551 	for(i=0; i<nelem(tab); i++)
552 		if(tab[i].qid == q){
553 			switch(r->ifcall.mode&3){
554 			case OREAD:
555 				if(!(tab[i].perm&0400))
556 					goto Eperm;
557 				break;
558 			case OWRITE:
559 				if(!(tab[i].perm&0200))
560 					goto Eperm;
561 				break;
562 			case ORDWR:
563 				if((tab[i].perm&0600) != 0600)
564 					goto Eperm;
565 				break;
566 			case OEXEC:
567 			Eperm:
568 				respond(r, "permission denied");
569 				return;
570 			}
571 			if(tab[i].open)
572 				tab[i].open(r);
573 			else
574 				respond(r, nil);
575 			return;
576 		}
577 
578 	/* directory */
579 	if(r->ifcall.mode != OREAD)
580 		respond(r, "permission denied");
581 	else
582 		respond(r, nil);
583 }
584 
585 void
fsdestroyfid(Fid * fid)586 fsdestroyfid(Fid *fid)
587 {
588 	int i, q;
589 
590 	q = fid->qid.path;
591 	for(i=0; i<nelem(tab); i++)
592 		if(tab[i].qid == q){
593 			if(tab[i].close)
594 				tab[i].close(fid);
595 			break;
596 		}
597 }
598 
599 Srv fs = {
600 	.attach=	fsattach,
601 	.open=	fsopen,
602 	.read=	fsread,
603 	.write=	fswrite,
604 	.stat=	fsstat,
605 	.walk1=	fswalk1,
606 	.destroyfid=	fsdestroyfid,
607 };
608 
609 void
usage(void)610 usage(void)
611 {
612 	fprint(2, "usage: aux/vmware [-s srvname] [-m mtpt]\n");
613 	exits("usage");
614 }
615 
616 void
nohwaccel(void)617 nohwaccel(void)
618 {
619 	int fd;
620 
621 	if((fd = open("#v/vgactl", OWRITE)) < 0)
622 		return;
623 	fprint(fd, "hwaccel off");
624 }
625 
626 void
main(int argc,char ** argv)627 main(int argc, char **argv)
628 {
629 	quotefmtinstall();
630 
631 	time0 = time(0);
632 
633 	ARGBEGIN{
634 	case 'D':
635 		chatty9p++;
636 		break;
637 	case 's':
638 		srvname = EARGF(usage());
639 		break;
640 	case 'm':
641 		mtpt = EARGF(usage());
642 		break;
643 	default:
644 		usage();
645 	}ARGEND
646 
647 	if(argc != 0)
648 		usage();
649 
650 	if(setjmp(backdoorjmp))
651 		sysfatal("VMware backdoor call failed");
652 
653 	if(getversion() < 0)
654 		sysfatal("no vmware");
655 	nohwaccel();
656 	postmountsrv(&fs, srvname, mtpt, MREPL);
657 }
658