direct-io.hg

view tools/xenfb/vncfb.c @ 15456:eb2b7ce05f97

hvm vlapic: Fix one_shot argument passed to create_periodic_time().
Signed-off-by: Yosuke Iwamatsu <y-iwamatsu@ab.jp.nec.com>
author kfraser@localhost.localdomain
date Tue Jul 03 11:47:08 2007 +0100 (2007-07-03)
parents b83a81b99f20
children
line source
1 #define _GNU_SOURCE
2 #include <errno.h>
3 #include <getopt.h>
4 #include <stdlib.h>
5 #include <signal.h>
6 #include <unistd.h>
7 #include <malloc.h>
8 #include <rfb/rfb.h>
9 #include <rfb/keysym.h>
10 #include <linux/input.h>
11 #include <xs.h>
12 #include "xenfb.h"
14 /* Grab key translation support routines from qemu directory. */
15 #define qemu_mallocz(size) calloc(1, (size))
16 static const char *bios_dir = "/usr/share/xen/qemu";
17 #include "vnc_keysym.h"
18 #include "keymaps.c"
20 static unsigned char atkbd_set2_keycode[512] = {
22 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117,
23 0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0,
24 0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183,
25 0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185,
26 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
27 0, 89, 40, 0, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 85,
28 0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0,
29 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
31 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
32 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125,
33 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127,
34 159, 0,115, 0,164, 0, 0,116,158, 0,150,166, 0, 0, 0,142,
35 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0,
36 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0,
37 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112,
38 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0,
40 };
42 static unsigned char atkbd_unxlate_table[128] = {
44 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
45 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
46 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
47 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3,
48 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105,
49 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63,
50 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
51 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
53 };
55 unsigned char keycode_table[512];
57 static void *kbd_layout;
59 static int btnmap[] = {
60 BTN_LEFT, BTN_MIDDLE, BTN_RIGHT, BTN_SIDE,
61 BTN_EXTRA, BTN_FORWARD, BTN_BACK, BTN_TASK
62 };
64 static void on_kbd_event(rfbBool down, rfbKeySym keycode, rfbClientPtr cl)
65 {
66 /*
67 * We need to map to the key's Linux input layer keycode.
68 * Unfortunately, we don't get the key here, only the
69 * rfbKeySym, which is what the key is mapped to. Mapping
70 * back to the key is impossible in general, even when you
71 * know the keymap. For instance, the standard German keymap
72 * maps both KEY_COMMA and KEY_102ND to XK_less. We simply
73 * assume standard US layout. This sucks.
74 */
75 rfbScreenInfoPtr server = cl->screen;
76 struct xenfb *xenfb = server->screenData;
77 int scancode;
79 if (keycode >= 'A' && keycode <= 'Z')
80 keycode += 'a' - 'A';
82 scancode = keycode_table[keysym2scancode(kbd_layout, keycode)];
83 if (scancode == 0)
84 return;
85 if (xenfb_send_key(xenfb, down, scancode) < 0)
86 fprintf(stderr, "Key %d %s lost (%s)\n",
87 scancode, down ? "down" : "up",
88 strerror(errno));
89 }
91 static void on_ptr_event(int buttonMask, int x, int y, rfbClientPtr cl)
92 {
93 /* initial pointer state: at (0,0), buttons up */
94 static int last_x, last_y, last_button;
95 rfbScreenInfoPtr server = cl->screen;
96 struct xenfb *xenfb = server->screenData;
97 int i, last_down, down, ret;
99 for (i = 0; i < 8; i++) {
100 last_down = last_button & (1 << i);
101 down = buttonMask & (1 << i);
102 if (down == last_down)
103 continue;
104 if (i >= sizeof(btnmap) / sizeof(*btnmap))
105 break;
106 if (btnmap[i] == 0)
107 break;
108 if (xenfb_send_key(xenfb, down != 0, btnmap[i]) < 0)
109 fprintf(stderr, "Button %d %s lost (%s)\n",
110 i, down ? "down" : "up", strerror(errno));
111 }
113 if (x != last_x || y != last_y) {
114 if (xenfb->abs_pointer_wanted)
115 ret = xenfb_send_position(xenfb, x, y);
116 else
117 ret = xenfb_send_motion(xenfb, x - last_x, y - last_y);
118 if (ret < 0)
119 fprintf(stderr, "Pointer to %d,%d lost (%s)\n",
120 x, y, strerror(errno));
121 }
123 last_button = buttonMask;
124 last_x = x;
125 last_y = y;
126 }
128 static void xenstore_write_vncport(struct xs_handle *xsh, int port, int domid)
129 {
130 char *buf, *path;
131 char portstr[10];
133 path = xs_get_domain_path(xsh, domid);
134 if (path == NULL) {
135 fprintf(stderr, "Can't get domain path (%s)\n",
136 strerror(errno));
137 goto out;
138 }
140 if (asprintf(&buf, "%s/console/vnc-port", path) == -1) {
141 fprintf(stderr, "Can't make vncport path\n");
142 goto out;
143 }
145 if (snprintf(portstr, sizeof(portstr), "%d", port) == -1) {
146 fprintf(stderr, "Can't make vncport value\n");
147 goto out;
148 }
150 if (!xs_write(xsh, XBT_NULL, buf, portstr, strlen(portstr)))
151 fprintf(stderr, "Can't set vncport (%s)\n",
152 strerror(errno));
154 out:
155 free(buf);
156 }
159 static int xenstore_read_vncpasswd(struct xs_handle *xsh, int domid, char *pwbuf, int pwbuflen)
160 {
161 char buf[256], *path, *uuid = NULL, *passwd = NULL;
162 unsigned int len, rc = 0;
164 if (xsh == NULL) {
165 return -1;
166 }
168 path = xs_get_domain_path(xsh, domid);
169 if (path == NULL) {
170 fprintf(stderr, "xs_get_domain_path() error\n");
171 return -1;
172 }
174 snprintf(buf, 256, "%s/vm", path);
175 uuid = xs_read(xsh, XBT_NULL, buf, &len);
176 if (uuid == NULL) {
177 fprintf(stderr, "xs_read(): uuid get error\n");
178 free(path);
179 return -1;
180 }
182 snprintf(buf, 256, "%s/vncpasswd", uuid);
183 passwd = xs_read(xsh, XBT_NULL, buf, &len);
184 if (passwd == NULL) {
185 free(uuid);
186 free(path);
187 return rc;
188 }
190 strncpy(pwbuf, passwd, pwbuflen-1);
191 pwbuf[pwbuflen-1] = '\0';
193 fprintf(stderr, "Got a VNC password read from XenStore\n");
195 passwd[0] = '\0';
196 snprintf(buf, 256, "%s/vncpasswd", uuid);
197 if (xs_write(xsh, XBT_NULL, buf, passwd, len) == 0) {
198 fprintf(stderr, "xs_write() vncpasswd failed\n");
199 rc = -1;
200 }
202 free(passwd);
203 free(uuid);
204 free(path);
206 return rc;
207 }
209 static void vnc_update(struct xenfb *xenfb, int x, int y, int w, int h)
210 {
211 rfbScreenInfoPtr server = xenfb->user_data;
212 rfbMarkRectAsModified(server, x, y, x + w, y + h);
213 }
215 static struct option options[] = {
216 { "domid", 1, NULL, 'd' },
217 { "vncport", 1, NULL, 'p' },
218 { "title", 1, NULL, 't' },
219 { "unused", 0, NULL, 'u' },
220 { "listen", 1, NULL, 'l' },
221 { "keymap", 1, NULL, 'k' },
222 { NULL }
223 };
225 int main(int argc, char **argv)
226 {
227 rfbScreenInfoPtr server;
228 char *fake_argv[7] = { "vncfb", "-rfbport", "5901",
229 "-desktop", "xen-vncfb",
230 "-listen", "127.0.0.1" };
231 int fake_argc = sizeof(fake_argv) / sizeof(fake_argv[0]);
232 int domid = -1, port = -1;
233 char *title = NULL;
234 char *listen = NULL;
235 char *keymap = NULL;
236 bool unused = false;
237 int opt;
238 struct xenfb *xenfb;
239 fd_set readfds;
240 int nfds;
241 char portstr[10];
242 char *endp;
243 int r;
244 struct xs_handle *xsh;
245 char vncpasswd[1024];
246 int i;
248 vncpasswd[0] = '\0';
250 while ((opt = getopt_long(argc, argv, "d:p:t:uk:", options,
251 NULL)) != -1) {
252 switch (opt) {
253 case 'd':
254 errno = 0;
255 domid = strtol(optarg, &endp, 10);
256 if (endp == optarg || *endp || errno) {
257 fprintf(stderr, "Invalid domain id specified\n");
258 exit(1);
259 }
260 break;
261 case 'p':
262 errno = 0;
263 port = strtol(optarg, &endp, 10);
264 if (endp == optarg || *endp || errno) {
265 fprintf(stderr, "Invalid port specified\n");
266 exit(1);
267 }
268 break;
269 case 't':
270 title = strdup(optarg);
271 break;
272 case 'u':
273 unused = true;
274 break;
275 case 'l':
276 listen = strdup(optarg);
277 break;
278 case 'k':
279 keymap = strdup(optarg);
280 break;
281 case '?':
282 exit(1);
283 }
284 }
285 if (optind != argc) {
286 fprintf(stderr, "Invalid options!\n");
287 exit(1);
288 }
289 if (domid <= 0) {
290 fprintf(stderr, "Domain ID must be specified!\n");
291 exit(1);
292 }
294 if (port <= 0)
295 port = 5900 + domid;
296 if (snprintf(portstr, sizeof(portstr), "%d", port) == -1) {
297 fprintf(stderr, "Invalid port specified\n");
298 exit(1);
299 }
301 if (keymap == NULL){
302 keymap = "en-us";
303 }
305 kbd_layout = init_keyboard_layout(keymap);
306 if( !kbd_layout ){
307 fprintf(stderr, "Invalid keyboard_layout\n");
308 exit(1);
309 }
311 for (i = 0; i < 128; i++) {
312 keycode_table[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
313 keycode_table[i | 0x80] =
314 atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
315 }
317 fake_argv[2] = portstr;
319 if (title != NULL)
320 fake_argv[4] = title;
322 if (listen != NULL)
323 fake_argv[6] = listen;
325 signal(SIGPIPE, SIG_IGN);
327 xenfb = xenfb_new();
328 if (xenfb == NULL) {
329 fprintf(stderr, "Could not create framebuffer (%s)\n",
330 strerror(errno));
331 exit(1);
332 }
334 if (xenfb_attach_dom(xenfb, domid) < 0) {
335 fprintf(stderr, "Could not connect to domain (%s)\n",
336 strerror(errno));
337 exit(1);
338 }
340 xsh = xs_daemon_open();
341 if (xsh == NULL) {
342 fprintf(stderr, "cannot open connection to xenstore\n");
343 exit(1);
344 }
347 if (xenstore_read_vncpasswd(xsh, domid, vncpasswd,
348 sizeof(vncpasswd)/sizeof(char)) < 0) {
349 fprintf(stderr, "cannot read VNC password from xenstore\n");
350 exit(1);
351 }
354 server = rfbGetScreen(&fake_argc, fake_argv,
355 xenfb->width, xenfb->height,
356 8, 3, xenfb->depth / 8);
357 if (server == NULL) {
358 fprintf(stderr, "Could not create VNC server\n");
359 exit(1);
360 }
362 xenfb->user_data = server;
363 xenfb->update = vnc_update;
365 if (unused)
366 server->autoPort = true;
368 if (vncpasswd[0]) {
369 char **passwds = malloc(sizeof(char**)*2);
370 if (!passwds) {
371 fprintf(stderr, "cannot allocate memory (%s)\n",
372 strerror(errno));
373 exit(1);
374 }
375 fprintf(stderr, "Registered password\n");
376 passwds[0] = vncpasswd;
377 passwds[1] = NULL;
379 server->authPasswdData = passwds;
380 server->passwordCheck = rfbCheckPasswordByList;
381 } else {
382 fprintf(stderr, "Running with no password\n");
383 }
384 server->serverFormat.redShift = 16;
385 server->serverFormat.greenShift = 8;
386 server->serverFormat.blueShift = 0;
387 server->kbdAddEvent = on_kbd_event;
388 server->ptrAddEvent = on_ptr_event;
389 server->frameBuffer = xenfb->pixels;
390 server->screenData = xenfb;
391 server->cursor = NULL;
392 rfbInitServer(server);
394 rfbRunEventLoop(server, -1, true);
396 xenstore_write_vncport(xsh, server->port, domid);
398 for (;;) {
399 FD_ZERO(&readfds);
400 nfds = xenfb_select_fds(xenfb, &readfds);
402 if (select(nfds, &readfds, NULL, NULL, NULL) < 0) {
403 if (errno == EINTR)
404 continue;
405 fprintf(stderr,
406 "Can't select() on event channel (%s)\n",
407 strerror(errno));
408 break;
409 }
411 r = xenfb_poll(xenfb, &readfds);
412 if (r == -2)
413 xenfb_teardown(xenfb);
414 if (r < 0)
415 break;
416 }
418 rfbScreenCleanup(server);
419 xenfb_delete(xenfb);
421 return 0;
422 }