ia64/xen-unstable

view tools/ioemu/xenstore.c @ 14443:9e07e0133f52

[QEMU] fix typo in 14405
Signe-off-by: Tim Deegan <Tim.Deegan@xensource.com>
author Tim Deegan <Tim.Deegan@xensource.com>
date Fri Mar 16 16:40:18 2007 +0000 (2007-03-16)
parents 8e76e1b95b12
children 4b9150e9ecfd
line source
1 /*
2 * This file is subject to the terms and conditions of the GNU General
3 * Public License. See the file "COPYING" in the main directory of
4 * this archive for more details.
5 *
6 * Copyright (C) 2006 Christian Limpach
7 * Copyright (C) 2006 XenSource Ltd.
8 *
9 */
11 #include "vl.h"
12 #include "block_int.h"
13 #include <unistd.h>
14 #include <sys/ipc.h>
15 #include <sys/shm.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
20 static struct xs_handle *xsh = NULL;
21 static char *hd_filename[MAX_DISKS];
22 static QEMUTimer *insert_timer = NULL;
24 #define UWAIT_MAX (30*1000000) /* thirty seconds */
25 #define UWAIT (100000) /* 1/10th second */
27 static int pasprintf(char **buf, const char *fmt, ...)
28 {
29 va_list ap;
30 int ret = 0;
32 if (*buf)
33 free(*buf);
34 va_start(ap, fmt);
35 if (vasprintf(buf, fmt, ap) == -1) {
36 buf = NULL;
37 ret = -1;
38 }
39 va_end(ap);
40 return ret;
41 }
43 static void insert_media(void *opaque)
44 {
45 int i;
47 for (i = 0; i < MAX_DISKS; i++) {
48 if (hd_filename[i]) {
49 do_change(bs_table[i]->device_name, hd_filename[i]);
50 free(hd_filename[i]);
51 hd_filename[i] = NULL;
52 }
53 }
54 }
56 void xenstore_check_new_media_present(int timeout)
57 {
59 if (insert_timer == NULL)
60 insert_timer = qemu_new_timer(rt_clock, insert_media, NULL);
61 qemu_mod_timer(insert_timer, qemu_get_clock(rt_clock) + timeout);
62 }
64 static void waitForDevice(char *fn)
65 {
66 struct stat sbuf;
67 int status;
68 int uwait = UWAIT_MAX;
70 do {
71 status = stat(fn, &sbuf);
72 if (!status) break;
73 usleep(UWAIT);
74 uwait -= UWAIT;
75 } while (uwait > 0);
77 return;
78 }
80 void xenstore_parse_domain_config(int domid)
81 {
82 char **e = NULL;
83 char *buf = NULL, *path;
84 char *fpath = NULL, *bpath = NULL,
85 *dev = NULL, *params = NULL, *type = NULL;
86 int i;
87 unsigned int len, num, hd_index;
89 for(i = 0; i < MAX_DISKS; i++)
90 hd_filename[i] = NULL;
92 xsh = xs_daemon_open();
93 if (xsh == NULL) {
94 fprintf(logfile, "Could not contact xenstore for domain config\n");
95 return;
96 }
98 path = xs_get_domain_path(xsh, domid);
99 if (path == NULL) {
100 fprintf(logfile, "xs_get_domain_path() error\n");
101 goto out;
102 }
104 if (pasprintf(&buf, "%s/device/vbd", path) == -1)
105 goto out;
107 e = xs_directory(xsh, XBT_NULL, buf, &num);
108 if (e == NULL)
109 goto out;
111 for (i = 0; i < num; i++) {
112 /* read the backend path */
113 if (pasprintf(&buf, "%s/device/vbd/%s/backend", path, e[i]) == -1)
114 continue;
115 free(bpath);
116 bpath = xs_read(xsh, XBT_NULL, buf, &len);
117 if (bpath == NULL)
118 continue;
119 /* read the name of the device */
120 if (pasprintf(&buf, "%s/dev", bpath) == -1)
121 continue;
122 free(dev);
123 dev = xs_read(xsh, XBT_NULL, buf, &len);
124 if (dev == NULL)
125 continue;
126 if (strncmp(dev, "hd", 2) || strlen(dev) != 3)
127 continue;
128 hd_index = dev[2] - 'a';
129 if (hd_index >= MAX_DISKS)
130 continue;
131 /* read the type of the device */
132 if (pasprintf(&buf, "%s/device/vbd/%s/device-type", path, e[i]) == -1)
133 continue;
134 free(type);
135 type = xs_read(xsh, XBT_NULL, buf, &len);
136 /* read params to get the patch of the image -- read it last
137 * so that we have its path in buf when setting up the
138 * watch */
139 if (pasprintf(&buf, "%s/params", bpath) == -1)
140 continue;
141 free(params);
142 params = xs_read(xsh, XBT_NULL, buf, &len);
143 if (params == NULL)
144 continue;
145 if (params[0]) {
146 hd_filename[hd_index] = params; /* strdup() */
147 params = NULL; /* don't free params on re-use */
148 }
149 /*
150 * check if device has a phantom vbd; the phantom is hooked
151 * to the frontend device (for ease of cleanup), so lookup
152 * the frontend device, and see if there is a phantom_vbd
153 * if there is, we will use resolution as the filename
154 */
155 if (pasprintf(&buf, "%s/device/vbd/%s/phantom_vbd", path, e[i]) == -1)
156 continue;
157 free(fpath);
158 fpath = xs_read(xsh, XBT_NULL, buf, &len);
159 if (fpath != NULL) {
160 if (pasprintf(&buf, "%s/dev", fpath) == -1)
161 continue;
162 params = xs_read(xsh, XBT_NULL, buf , &len);
163 if (params != NULL) {
164 free(hd_filename[hd_index]);
165 hd_filename[hd_index] = params;
166 params = NULL; /* don't free params on re-use */
167 /*
168 * wait for device, on timeout silently fail because we will
169 * fail to open below
170 */
171 waitForDevice(hd_filename[hd_index]);
172 }
173 }
174 bs_table[hd_index] = bdrv_new(dev);
175 /* re-establish buf */
176 if (pasprintf(&buf, "%s/params", bpath) == -1)
177 continue;
178 /* check if it is a cdrom */
179 if (type && !strcmp(type, "cdrom")) {
180 bdrv_set_type_hint(bs_table[hd_index], BDRV_TYPE_CDROM);
181 xs_watch(xsh, buf, dev);
182 }
183 if (hd_filename[hd_index]) {
184 if (bdrv_open(bs_table[hd_index], hd_filename[hd_index],
185 0 /* snapshot */) < 0)
186 fprintf(stderr, "qemu: could not open hard disk image '%s'\n",
187 hd_filename[hd_index]);
188 }
189 }
191 /* Set a watch for log-dirty requests from the migration tools */
192 if (pasprintf(&buf, "%s/logdirty/next-active", path) != -1) {
193 xs_watch(xsh, buf, "logdirty");
194 fprintf(logfile, "Watching %s\n", buf);
195 }
198 out:
199 free(type);
200 free(params);
201 free(dev);
202 free(bpath);
203 free(buf);
204 free(path);
205 free(e);
206 return;
207 }
209 int xenstore_fd(void)
210 {
211 if (xsh)
212 return xs_fileno(xsh);
213 return -1;
214 }
216 unsigned long *logdirty_bitmap = NULL;
217 unsigned long logdirty_bitmap_size;
218 extern int vga_ram_size, bios_size;
220 void xenstore_process_logdirty_event(void)
221 {
222 char *act;
223 static char *active_path = NULL;
224 static char *next_active_path = NULL;
225 static char *seg = NULL;
226 unsigned int len;
227 int i;
229 fprintf(logfile, "Triggered log-dirty buffer switch\n");
231 if (!seg) {
232 char *path, *p, *key_ascii, key_terminated[17] = {0,};
233 key_t key;
234 int shmid;
236 /* Find and map the shared memory segment for log-dirty bitmaps */
237 if (!(path = xs_get_domain_path(xsh, domid))) {
238 fprintf(logfile, "Log-dirty: can't get domain path in store\n");
239 exit(1);
240 }
241 if (!(path = realloc(path, strlen(path)
242 + strlen("/logdirty/next-active") + 1))) {
243 fprintf(logfile, "Log-dirty: out of memory\n");
244 exit(1);
245 }
246 strcat(path, "/logdirty/");
247 p = path + strlen(path);
248 strcpy(p, "key");
250 key_ascii = xs_read(xsh, XBT_NULL, path, &len);
251 if (!key_ascii) {
252 /* No key yet: wait for the next watch */
253 free(path);
254 return;
255 }
256 strncpy(key_terminated, key_ascii, 16);
257 free(key_ascii);
258 key = (key_t) strtoull(key_terminated, NULL, 16);
260 /* Figure out how bit the log-dirty bitmaps are */
261 logdirty_bitmap_size = ((phys_ram_size + 0x20
262 - (vga_ram_size + bios_size))
263 >> (TARGET_PAGE_BITS)); /* nr of bits in map*/
264 if (logdirty_bitmap_size > HVM_BELOW_4G_MMIO_START >> TARGET_PAGE_BITS)
265 logdirty_bitmap_size +=
266 HVM_BELOW_4G_MMIO_LENGTH >> TARGET_PAGE_BITS; /* still bits */
267 logdirty_bitmap_size = ((logdirty_bitmap_size + HOST_LONG_BITS - 1)
268 / HOST_LONG_BITS); /* longs */
269 logdirty_bitmap_size *= sizeof (unsigned long); /* bytes */
271 /* Map the shared-memory segment */
272 if ((shmid = shmget(key,
273 2 * logdirty_bitmap_size,
274 S_IRUSR|S_IWUSR)) == -1
275 || (seg = shmat(shmid, NULL, 0)) == (void *)-1) {
276 fprintf(logfile, "Log-dirty: can't map segment %16.16llx (%s)\n",
277 (unsigned long long) key, strerror(errno));
278 exit(1);
279 }
281 fprintf(logfile, "Log-dirty: mapped segment at %p\n", seg);
283 /* Double-check that the bitmaps are the size we expect */
284 if (logdirty_bitmap_size != *(uint32_t *)seg) {
285 fprintf(logfile, "Log-dirty: got %lu, calc %lu\n",
286 *(uint32_t *)seg, logdirty_bitmap_size);
287 return;
288 }
290 /* Remember the paths for the next-active and active entries */
291 strcpy(p, "active");
292 if (!(active_path = strdup(path))) {
293 fprintf(logfile, "Log-dirty: out of memory\n");
294 exit(1);
295 }
296 strcpy(p, "next-active");
297 if (!(next_active_path = strdup(path))) {
298 fprintf(logfile, "Log-dirty: out of memory\n");
299 exit(1);
300 }
301 free(path);
302 }
304 /* Read the required active buffer from the store */
305 act = xs_read(xsh, XBT_NULL, next_active_path, &len);
306 if (!act) {
307 fprintf(logfile, "Log-dirty: can't read next-active\n");
308 exit(1);
309 }
311 /* Switch buffers */
312 i = act[0] - '0';
313 if (i != 0 && i != 1) {
314 fprintf(logfile, "Log-dirty: bad next-active entry: %s\n", act);
315 exit(1);
316 }
317 logdirty_bitmap = seg + i * logdirty_bitmap_size;
319 /* Ack that we've switched */
320 xs_write(xsh, XBT_NULL, active_path, act, len);
321 free(act);
322 }
326 void xenstore_process_event(void *opaque)
327 {
328 char **vec, *image = NULL;
329 unsigned int len, num, hd_index;
331 vec = xs_read_watch(xsh, &num);
332 if (!vec)
333 return;
335 if (!strcmp(vec[XS_WATCH_TOKEN], "logdirty")) {
336 xenstore_process_logdirty_event();
337 goto out;
338 }
340 if (strncmp(vec[XS_WATCH_TOKEN], "hd", 2) ||
341 strlen(vec[XS_WATCH_TOKEN]) != 3)
342 goto out;
343 hd_index = vec[XS_WATCH_TOKEN][2] - 'a';
344 image = xs_read(xsh, XBT_NULL, vec[XS_WATCH_PATH], &len);
345 if (image == NULL || !strcmp(image, bs_table[hd_index]->filename))
346 goto out; /* gone or identical */
348 do_eject(0, vec[XS_WATCH_TOKEN]);
349 bs_table[hd_index]->filename[0] = 0;
350 if (hd_filename[hd_index]) {
351 free(hd_filename[hd_index]);
352 hd_filename[hd_index] = NULL;
353 }
355 if (image[0]) {
356 hd_filename[hd_index] = strdup(image);
357 xenstore_check_new_media_present(5000);
358 }
360 out:
361 free(image);
362 free(vec);
363 }
365 void xenstore_write_vncport(int display)
366 {
367 char *buf = NULL, *path;
368 char *portstr = NULL;
370 if (xsh == NULL)
371 return;
373 path = xs_get_domain_path(xsh, domid);
374 if (path == NULL) {
375 fprintf(logfile, "xs_get_domain_path() error\n");
376 goto out;
377 }
379 if (pasprintf(&buf, "%s/console/vnc-port", path) == -1)
380 goto out;
382 if (pasprintf(&portstr, "%d", 5900 + display) == -1)
383 goto out;
385 if (xs_write(xsh, XBT_NULL, buf, portstr, strlen(portstr)) == 0)
386 fprintf(logfile, "xs_write() vncport failed\n");
388 out:
389 free(portstr);
390 free(buf);
391 }
393 int xenstore_read_vncpasswd(int domid)
394 {
395 extern char vncpasswd[64];
396 char *buf = NULL, *path, *uuid = NULL, *passwd = NULL;
397 unsigned int i, len, rc = 0;
399 if (xsh == NULL) {
400 return -1;
401 }
403 path = xs_get_domain_path(xsh, domid);
404 if (path == NULL) {
405 fprintf(logfile, "xs_get_domain_path() error. domid %d.\n", domid);
406 return -1;
407 }
409 pasprintf(&buf, "%s/vm", path);
410 uuid = xs_read(xsh, XBT_NULL, buf, &len);
411 if (uuid == NULL) {
412 fprintf(logfile, "xs_read(): uuid get error. %s.\n", buf);
413 free(path);
414 return -1;
415 }
417 pasprintf(&buf, "%s/vncpasswd", uuid);
418 passwd = xs_read(xsh, XBT_NULL, buf, &len);
419 if (passwd == NULL) {
420 fprintf(logfile, "xs_read(): vncpasswd get error. %s.\n", buf);
421 free(uuid);
422 free(path);
423 return rc;
424 }
426 for (i=0; i<len && i<63; i++) {
427 vncpasswd[i] = passwd[i];
428 passwd[i] = '\0';
429 }
430 vncpasswd[len] = '\0';
431 pasprintf(&buf, "%s/vncpasswd", uuid);
432 if (xs_write(xsh, XBT_NULL, buf, passwd, len) == 0) {
433 fprintf(logfile, "xs_write() vncpasswd failed.\n");
434 rc = -1;
435 }
437 free(passwd);
438 free(uuid);
439 free(path);
441 return rc;
442 }
445 /*
446 * get all device instances of a certain type
447 */
448 char **xenstore_domain_get_devices(struct xs_handle *handle,
449 const char *devtype, unsigned int *num)
450 {
451 char *path;
452 char *buf = NULL;
453 char **e = NULL;
455 path = xs_get_domain_path(handle, domid);
456 if (path == NULL)
457 goto out;
459 if (pasprintf(&buf, "%s/device/%s", path,devtype) == -1)
460 goto out;
462 e = xs_directory(handle, XBT_NULL, buf, num);
464 out:
465 free(path);
466 free(buf);
467 return e;
468 }
470 /*
471 * Check whether a domain has devices of the given type
472 */
473 int xenstore_domain_has_devtype(struct xs_handle *handle, const char *devtype)
474 {
475 int rc = 0;
476 unsigned int num;
477 char **e = xenstore_domain_get_devices(handle, devtype, &num);
478 if (e)
479 rc = 1;
480 free(e);
481 return rc;
482 }
484 /*
485 * Function that creates a path to a variable of an instance of a
486 * certain device
487 */
488 static char *get_device_variable_path(const char *devtype, const char *inst,
489 const char *var)
490 {
491 char *buf = NULL;
492 if (pasprintf(&buf, "/local/domain/0/backend/%s/%d/%s/%s",
493 devtype,
494 domid,
495 inst,
496 var) == -1) {
497 free(buf);
498 buf = NULL;
499 }
500 return buf;
501 }
503 char *xenstore_backend_read_variable(struct xs_handle *handle,
504 const char *devtype, const char *inst,
505 const char *var)
506 {
507 char *value = NULL;
508 char *buf = NULL;
509 unsigned int len;
511 buf = get_device_variable_path(devtype, inst, var);
512 if (NULL == buf)
513 goto out;
515 value = xs_read(handle, XBT_NULL, buf, &len);
517 free(buf);
519 out:
520 return value;
521 }
523 /*
524 Read the hotplug status variable from the backend given the type
525 of device and its instance.
526 */
527 char *xenstore_read_hotplug_status(struct xs_handle *handle,
528 const char *devtype, const char *inst)
529 {
530 return xenstore_backend_read_variable(handle, devtype, inst,
531 "hotplug-status");
532 }
534 /*
535 Subscribe to the hotplug status of a device given the type of device and
536 its instance.
537 In case an error occurrs, a negative number is returned.
538 */
539 int xenstore_subscribe_to_hotplug_status(struct xs_handle *handle,
540 const char *devtype,
541 const char *inst,
542 const char *token)
543 {
544 int rc = 0;
545 char *path = get_device_variable_path(devtype, inst, "hotplug-status");
547 if (path == NULL)
548 return -1;
550 if (0 == xs_watch(handle, path, token))
551 rc = -2;
553 free(path);
555 return rc;
556 }
558 /*
559 * Unsubscribe from a subscription to the status of a hotplug variable of
560 * a device.
561 */
562 int xenstore_unsubscribe_from_hotplug_status(struct xs_handle *handle,
563 const char *devtype,
564 const char *inst,
565 const char *token)
566 {
567 int rc = 0;
568 char *path;
569 path = get_device_variable_path(devtype, inst, "hotplug-status");
570 if (path == NULL)
571 return -1;
573 if (0 == xs_unwatch(handle, path, token))
574 rc = -2;
576 free(path);
578 return rc;
579 }