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, µsec, &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, µsec, &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