ia64/xen-unstable

view tools/ioemu/xenstore.c @ 17750:c2fab221b3ec

ioemu: set up all xenstore watches even if there are no VBDs.

Signed-off-by: Tim Deegan <Tim.Deegan@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed May 28 12:22:36 2008 +0100 (2008-05-28)
parents e3b13e1ecf6c
children cebedb30a964
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 #ifndef CONFIG_STUBDOM
15 #include <sys/ipc.h>
16 #include <sys/shm.h>
17 #endif
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <fcntl.h>
22 struct xs_handle *xsh = NULL;
23 static char *media_filename[MAX_DISKS + MAX_SCSI_DISKS];
24 static QEMUTimer *insert_timer = NULL;
26 #define UWAIT_MAX (30*1000000) /* thirty seconds */
27 #define UWAIT (100000) /* 1/10th second */
29 static int pasprintf(char **buf, const char *fmt, ...)
30 {
31 va_list ap;
32 int ret = 0;
34 if (*buf)
35 free(*buf);
36 va_start(ap, fmt);
37 if (vasprintf(buf, fmt, ap) == -1) {
38 buf = NULL;
39 ret = -1;
40 }
41 va_end(ap);
42 return ret;
43 }
45 static void insert_media(void *opaque)
46 {
47 int i;
49 for (i = 0; i < MAX_DISKS + MAX_SCSI_DISKS; i++) {
50 if (media_filename[i] && bs_table[i]) {
51 do_change(bs_table[i]->device_name, media_filename[i]);
52 free(media_filename[i]);
53 media_filename[i] = NULL;
54 }
55 }
56 }
58 void xenstore_check_new_media_present(int timeout)
59 {
61 if (insert_timer == NULL)
62 insert_timer = qemu_new_timer(rt_clock, insert_media, NULL);
63 qemu_mod_timer(insert_timer, qemu_get_clock(rt_clock) + timeout);
64 }
66 static void waitForDevice(char *fn)
67 {
68 struct stat sbuf;
69 int status;
70 int uwait = UWAIT_MAX;
72 do {
73 status = stat(fn, &sbuf);
74 if (!status) break;
75 usleep(UWAIT);
76 uwait -= UWAIT;
77 } while (uwait > 0);
79 return;
80 }
82 #define DIRECT_PCI_STR_LEN 160
83 char direct_pci_str[DIRECT_PCI_STR_LEN];
84 void xenstore_parse_domain_config(int hvm_domid)
85 {
86 char **e = NULL;
87 char *buf = NULL, *path;
88 char *fpath = NULL, *bpath = NULL,
89 *dev = NULL, *params = NULL, *type = NULL, *drv = NULL;
90 int i, is_scsi, is_hdN = 0;
91 unsigned int len, num, hd_index, pci_devid = 0;
92 BlockDriverState *bs;
93 BlockDriver *format;
95 for(i = 0; i < MAX_DISKS + MAX_SCSI_DISKS; i++)
96 media_filename[i] = NULL;
98 xsh = xs_daemon_open();
99 if (xsh == NULL) {
100 fprintf(logfile, "Could not contact xenstore for domain config\n");
101 return;
102 }
104 path = xs_get_domain_path(xsh, hvm_domid);
105 if (path == NULL) {
106 fprintf(logfile, "xs_get_domain_path() error\n");
107 goto out;
108 }
110 if (pasprintf(&buf, "%s/device/vbd", path) == -1)
111 goto out;
113 e = xs_directory(xsh, XBT_NULL, buf, &num);
114 if (e == NULL)
115 num = 0;
117 for (i = 0; i < num; i++) {
118 /* read the backend path */
119 if (pasprintf(&buf, "%s/device/vbd/%s/backend", path, e[i]) == -1)
120 continue;
121 free(bpath);
122 bpath = xs_read(xsh, XBT_NULL, buf, &len);
123 if (bpath == NULL)
124 continue;
125 /* read the name of the device */
126 if (pasprintf(&buf, "%s/dev", bpath) == -1)
127 continue;
128 free(dev);
129 dev = xs_read(xsh, XBT_NULL, buf, &len);
130 if (dev == NULL)
131 continue;
132 if (!strncmp(dev, "hd", 2)) {
133 is_hdN = 1;
134 break;
135 }
136 }
138 for (i = 0; i < num; i++) {
139 format = NULL; /* don't know what the format is yet */
141 /* read the backend path */
142 if (pasprintf(&buf, "%s/device/vbd/%s/backend", path, e[i]) == -1)
143 continue;
144 free(bpath);
145 bpath = xs_read(xsh, XBT_NULL, buf, &len);
146 if (bpath == NULL)
147 continue;
148 /* read the name of the device */
149 if (pasprintf(&buf, "%s/dev", bpath) == -1)
150 continue;
151 free(dev);
152 dev = xs_read(xsh, XBT_NULL, buf, &len);
153 if (dev == NULL)
154 continue;
155 /* Change xvdN to look like hdN */
156 if (!is_hdN && !strncmp(dev, "xvd", 3)) {
157 fprintf(logfile, "Change xvd%c to look like hd%c\n",
158 dev[3], dev[3]);
159 memmove(dev, dev+1, strlen(dev));
160 dev[0] = 'h';
161 dev[1] = 'd';
162 }
163 is_scsi = !strncmp(dev, "sd", 2);
164 if ((strncmp(dev, "hd", 2) && !is_scsi) || strlen(dev) != 3 )
165 continue;
166 hd_index = dev[2] - 'a';
167 if (hd_index >= (is_scsi ? MAX_SCSI_DISKS : MAX_DISKS))
168 continue;
169 /* read the type of the device */
170 if (pasprintf(&buf, "%s/device/vbd/%s/device-type", path, e[i]) == -1)
171 continue;
172 free(type);
173 type = xs_read(xsh, XBT_NULL, buf, &len);
174 if (pasprintf(&buf, "%s/params", bpath) == -1)
175 continue;
176 free(params);
177 params = xs_read(xsh, XBT_NULL, buf, &len);
178 if (params == NULL)
179 continue;
180 /* read the name of the device */
181 if (pasprintf(&buf, "%s/type", bpath) == -1)
182 continue;
183 free(drv);
184 drv = xs_read(xsh, XBT_NULL, buf, &len);
185 if (drv == NULL)
186 continue;
187 /* Obtain blktap sub-type prefix */
188 if (!strcmp(drv, "tap") && params[0]) {
189 char *offset = strchr(params, ':');
190 if (!offset)
191 continue ;
192 free(drv);
193 drv = malloc(offset - params + 1);
194 memcpy(drv, params, offset - params);
195 drv[offset - params] = '\0';
196 if (!strcmp(drv, "aio"))
197 /* qemu does aio anyway if it can */
198 format = &bdrv_raw;
199 memmove(params, offset+1, strlen(offset+1)+1 );
200 fprintf(logfile, "Strip off blktap sub-type prefix to %s (drv '%s')\n", params, drv);
201 }
202 /* Prefix with /dev/ if needed */
203 if (!strcmp(drv, "phy") && params[0] != '/') {
204 char *newparams = malloc(5 + strlen(params) + 1);
205 sprintf(newparams, "/dev/%s", params);
206 free(params);
207 params = newparams;
208 format = &bdrv_raw;
209 }
211 /*
212 * check if device has a phantom vbd; the phantom is hooked
213 * to the frontend device (for ease of cleanup), so lookup
214 * the frontend device, and see if there is a phantom_vbd
215 * if there is, we will use resolution as the filename
216 */
217 if (pasprintf(&buf, "%s/device/vbd/%s/phantom_vbd", path, e[i]) == -1)
218 continue;
219 free(fpath);
220 fpath = xs_read(xsh, XBT_NULL, buf, &len);
221 if (fpath) {
222 if (pasprintf(&buf, "%s/dev", fpath) == -1)
223 continue;
224 free(params);
225 params = xs_read(xsh, XBT_NULL, buf , &len);
226 if (params) {
227 /*
228 * wait for device, on timeout silently fail because we will
229 * fail to open below
230 */
231 waitForDevice(params);
232 }
233 }
235 bs = bs_table[hd_index + (is_scsi ? MAX_DISKS : 0)] = bdrv_new(dev);
236 /* check if it is a cdrom */
237 if (type && !strcmp(type, "cdrom")) {
238 bdrv_set_type_hint(bs, BDRV_TYPE_CDROM);
239 if (pasprintf(&buf, "%s/params", bpath) != -1)
240 xs_watch(xsh, buf, dev);
241 }
243 /* open device now if media present */
244 #ifdef CONFIG_STUBDOM
245 if (pasprintf(&buf, "%s/device/vbd/%s", path, e[i]) == -1)
246 continue;
247 if (bdrv_open2(bs, buf, 0 /* snapshot */, &bdrv_vbd) == 0) {
248 pstrcpy(bs->filename, sizeof(bs->filename), params);
249 continue;
250 }
251 #endif
253 if (params[0]) {
254 if (!format) {
255 if (!drv) {
256 fprintf(stderr, "qemu: type (image format) not specified for vbd '%s' or image '%s'\n", buf, params);
257 continue;
258 }
259 if (!strcmp(drv,"qcow")) {
260 /* autoguess qcow vs qcow2 */
261 } else if (!strcmp(drv,"file") || !strcmp(drv,"phy")) {
262 format = &bdrv_raw;
263 } else if (!strcmp(drv,"phy")) {
264 format = &bdrv_raw;
265 } else {
266 format = bdrv_find_format(drv);
267 if (!format) {
268 fprintf(stderr, "qemu: type (image format) '%s' unknown for vbd '%s' or image '%s'\n", drv, buf, params);
269 continue;
270 }
271 }
272 }
273 if (bdrv_open2(bs, params, 0 /* snapshot */, format) < 0)
274 fprintf(stderr, "qemu: could not open vbd '%s' or hard disk image '%s' (drv '%s' format '%s')\n", buf, params, drv ? drv : "?", format ? format->format_name : "0");
275 }
276 }
278 #ifdef CONFIG_STUBDOM
279 if (pasprintf(&buf, "%s/device/vkbd", path) == -1)
280 goto out;
282 free(e);
283 e = xs_directory(xsh, XBT_NULL, buf, &num);
285 if (e) {
286 for (i = 0; i < num; i++) {
287 if (pasprintf(&buf, "%s/device/vkbd/%s", path, e[i]) == -1)
288 continue;
289 xenfb_connect_vkbd(buf);
290 }
291 }
293 if (pasprintf(&buf, "%s/device/vfb", path) == -1)
294 goto out;
296 free(e);
297 e = xs_directory(xsh, XBT_NULL, buf, &num);
299 if (e) {
300 for (i = 0; i < num; i++) {
301 if (pasprintf(&buf, "%s/device/vfb/%s", path, e[i]) == -1)
302 continue;
303 xenfb_connect_vfb(buf);
304 }
305 }
306 #endif
309 /* Set a watch for log-dirty requests from the migration tools */
310 if (pasprintf(&buf, "/local/domain/0/device-model/%u/logdirty/next-active",
311 domid) != -1) {
312 xs_watch(xsh, buf, "logdirty");
313 fprintf(logfile, "Watching %s\n", buf);
314 }
316 /* Set a watch for suspend requests from the migration tools */
317 if (pasprintf(&buf,
318 "/local/domain/0/device-model/%u/command", domid) != -1) {
319 xs_watch(xsh, buf, "dm-command");
320 fprintf(logfile, "Watching %s\n", buf);
321 }
323 /* get the pci pass-through parameter */
324 if (pasprintf(&buf, "/local/domain/0/backend/pci/%u/%u/num_devs",
325 domid, pci_devid) == -1)
326 goto out;
328 free(params);
329 params = xs_read(xsh, XBT_NULL, buf, &len);
330 if (params == NULL)
331 goto out;
332 num = atoi(params);
334 for ( i = 0; i < num; i++ ) {
335 if (pasprintf(&buf, "/local/domain/0/backend/pci/%u/%u/dev-%d",
336 domid, pci_devid, i) != -1) {
337 free(dev);
338 dev = xs_read(xsh, XBT_NULL, buf, &len);
340 if ( strlen(dev) + strlen(direct_pci_str) > DIRECT_PCI_STR_LEN ) {
341 fprintf(stderr, "qemu: too many pci pass-through devices\n");
342 memset(direct_pci_str, 0, DIRECT_PCI_STR_LEN);
343 goto out;
344 }
346 /* append to direct_pci_str */
347 if ( dev ) {
348 strcat(direct_pci_str, dev);
349 strcat(direct_pci_str, "-");
350 }
351 }
352 }
355 out:
356 free(type);
357 free(params);
358 free(dev);
359 free(bpath);
360 free(buf);
361 free(path);
362 free(e);
363 free(drv);
364 return;
365 }
367 int xenstore_fd(void)
368 {
369 if (xsh)
370 return xs_fileno(xsh);
371 return -1;
372 }
374 unsigned long *logdirty_bitmap = NULL;
375 unsigned long logdirty_bitmap_size;
376 extern int vga_ram_size, bios_size;
378 void xenstore_process_logdirty_event(void)
379 {
380 char *act;
381 static char *active_path = NULL;
382 static char *next_active_path = NULL;
383 static char *seg = NULL;
384 unsigned int len;
385 int i;
387 if (!seg) {
388 char *path = NULL, *key_ascii, key_terminated[17] = {0,};
389 key_t key;
390 int shmid;
392 /* Find and map the shared memory segment for log-dirty bitmaps */
393 if (pasprintf(&path,
394 "/local/domain/0/device-model/%u/logdirty/key",
395 domid) == -1) {
396 fprintf(logfile, "Log-dirty: out of memory\n");
397 exit(1);
398 }
400 key_ascii = xs_read(xsh, XBT_NULL, path, &len);
401 free(path);
403 if (!key_ascii)
404 /* No key yet: wait for the next watch */
405 return;
407 strncpy(key_terminated, key_ascii, 16);
408 free(key_ascii);
409 key = (key_t) strtoull(key_terminated, NULL, 16);
411 /* Figure out how bit the log-dirty bitmaps are */
412 logdirty_bitmap_size = xc_memory_op(xc_handle,
413 XENMEM_maximum_gpfn, &domid) + 1;
414 logdirty_bitmap_size = ((logdirty_bitmap_size + HOST_LONG_BITS - 1)
415 / HOST_LONG_BITS); /* longs */
416 logdirty_bitmap_size *= sizeof (unsigned long); /* bytes */
418 /* Map the shared-memory segment */
419 fprintf(logfile, "%s: key=%16.16llx size=%lu\n", __FUNCTION__,
420 (unsigned long long)key, logdirty_bitmap_size);
422 #ifdef CONFIG_STUBDOM
423 /* XXX we just can't use shm. */
424 fprintf(logfile, "Log dirty is not implemented in stub domains!\n");
425 return;
426 #else
427 shmid = shmget(key, 2 * logdirty_bitmap_size, S_IRUSR|S_IWUSR);
428 if (shmid == -1) {
429 fprintf(logfile, "Log-dirty: shmget failed: segment %16.16llx "
430 "(%s)\n", (unsigned long long)key, strerror(errno));
431 exit(1);
432 }
434 seg = shmat(shmid, NULL, 0);
435 if (seg == (void *)-1) {
436 fprintf(logfile, "Log-dirty: shmat failed: segment %16.16llx "
437 "(%s)\n", (unsigned long long)key, strerror(errno));
438 exit(1);
439 }
441 fprintf(logfile, "Log-dirty: mapped segment at %p\n", seg);
443 /* Double-check that the bitmaps are the size we expect */
444 if (logdirty_bitmap_size != *(uint32_t *)seg) {
445 fprintf(logfile, "Log-dirty: got %u, calc %lu\n",
446 *(uint32_t *)seg, logdirty_bitmap_size);
447 /* Stale key: wait for next watch */
448 shmdt(seg);
449 seg = NULL;
450 return;
451 }
452 #endif
454 /* Remember the paths for the next-active and active entries */
455 if (pasprintf(&active_path,
456 "/local/domain/0/device-model/%u/logdirty/active",
457 domid) == -1) {
458 fprintf(logfile, "Log-dirty: out of memory\n");
459 exit(1);
460 }
461 if (pasprintf(&next_active_path,
462 "/local/domain/0/device-model/%u/logdirty/next-active",
463 domid) == -1) {
464 fprintf(logfile, "Log-dirty: out of memory\n");
465 exit(1);
466 }
467 }
469 fprintf(logfile, "Triggered log-dirty buffer switch\n");
471 /* Read the required active buffer from the store */
472 act = xs_read(xsh, XBT_NULL, next_active_path, &len);
473 if (!act) {
474 fprintf(logfile, "Log-dirty: can't read next-active\n");
475 exit(1);
476 }
478 /* Switch buffers */
479 i = act[0] - '0';
480 if (i != 0 && i != 1) {
481 fprintf(logfile, "Log-dirty: bad next-active entry: %s\n", act);
482 exit(1);
483 }
484 logdirty_bitmap = (unsigned long *)(seg + i * logdirty_bitmap_size);
486 /* Ack that we've switched */
487 xs_write(xsh, XBT_NULL, active_path, act, len);
488 free(act);
489 }
492 /* Accept state change commands from the control tools */
493 static void xenstore_process_dm_command_event(void)
494 {
495 char *path = NULL, *command = NULL, *par = NULL;
496 unsigned int len;
497 extern int suspend_requested;
499 if (pasprintf(&path,
500 "/local/domain/0/device-model/%u/command", domid) == -1) {
501 fprintf(logfile, "out of memory reading dm command\n");
502 goto out;
503 }
504 command = xs_read(xsh, XBT_NULL, path, &len);
505 if (!command)
506 goto out;
508 if (!strncmp(command, "save", len)) {
509 fprintf(logfile, "dm-command: pause and save state\n");
510 suspend_requested = 1;
511 } else if (!strncmp(command, "continue", len)) {
512 fprintf(logfile, "dm-command: continue after state save\n");
513 suspend_requested = 0;
514 } else if (!strncmp(command, "pci-rem", len)) {
515 fprintf(logfile, "dm-command: hot remove pass-through pci dev \n");
517 if (pasprintf(&path,
518 "/local/domain/0/device-model/%u/parameter", domid) == -1) {
519 fprintf(logfile, "out of memory reading dm command parameter\n");
520 goto out;
521 }
522 par = xs_read(xsh, XBT_NULL, path, &len);
523 if (!par)
524 goto out;
526 do_pci_del(par);
527 free(par);
528 } else if (!strncmp(command, "pci-ins", len)) {
529 fprintf(logfile, "dm-command: hot insert pass-through pci dev \n");
531 if (pasprintf(&path,
532 "/local/domain/0/device-model/%u/parameter", domid) == -1) {
533 fprintf(logfile, "out of memory reading dm command parameter\n");
534 goto out;
535 }
536 par = xs_read(xsh, XBT_NULL, path, &len);
537 if (!par)
538 goto out;
540 do_pci_add(par);
541 free(par);
542 } else {
543 fprintf(logfile, "dm-command: unknown command\"%*s\"\n", len, command);
544 }
546 out:
547 free(path);
548 free(command);
549 }
551 void xenstore_record_dm(char *subpath, char *state)
552 {
553 char *path = NULL;
555 if (pasprintf(&path,
556 "/local/domain/0/device-model/%u/%s", domid, subpath) == -1) {
557 fprintf(logfile, "out of memory recording dm \n");
558 goto out;
559 }
560 if (!xs_write(xsh, XBT_NULL, path, state, strlen(state)))
561 fprintf(logfile, "error recording dm \n");
563 out:
564 free(path);
565 }
567 void xenstore_record_dm_state(char *state)
568 {
569 xenstore_record_dm("state", state);
570 }
572 void xenstore_process_event(void *opaque)
573 {
574 char **vec, *offset, *bpath = NULL, *buf = NULL, *drv = NULL, *image = NULL;
575 unsigned int len, num, hd_index;
577 vec = xs_read_watch(xsh, &num);
578 if (!vec)
579 return;
581 if (!strcmp(vec[XS_WATCH_TOKEN], "logdirty")) {
582 xenstore_process_logdirty_event();
583 goto out;
584 }
586 if (!strcmp(vec[XS_WATCH_TOKEN], "dm-command")) {
587 xenstore_process_dm_command_event();
588 goto out;
589 }
591 if (strncmp(vec[XS_WATCH_TOKEN], "hd", 2) ||
592 strlen(vec[XS_WATCH_TOKEN]) != 3)
593 goto out;
594 hd_index = vec[XS_WATCH_TOKEN][2] - 'a';
595 image = xs_read(xsh, XBT_NULL, vec[XS_WATCH_PATH], &len);
596 if (image == NULL)
597 goto out; /* gone */
599 /* Strip off blktap sub-type prefix */
600 bpath = strdup(vec[XS_WATCH_PATH]);
601 if (bpath == NULL)
602 goto out;
603 if ((offset = strrchr(bpath, '/')) != NULL)
604 *offset = '\0';
605 if (pasprintf(&buf, "%s/type", bpath) == -1)
606 goto out;
607 drv = xs_read(xsh, XBT_NULL, buf, &len);
608 if (drv && !strcmp(drv, "tap") && ((offset = strchr(image, ':')) != NULL))
609 memmove(image, offset+1, strlen(offset+1)+1);
611 if (!strcmp(image, bs_table[hd_index]->filename))
612 goto out; /* identical */
614 do_eject(0, vec[XS_WATCH_TOKEN]);
615 bs_table[hd_index]->filename[0] = 0;
616 if (media_filename[hd_index]) {
617 free(media_filename[hd_index]);
618 media_filename[hd_index] = NULL;
619 }
621 if (image[0]) {
622 media_filename[hd_index] = strdup(image);
623 xenstore_check_new_media_present(5000);
624 }
626 out:
627 free(drv);
628 free(buf);
629 free(bpath);
630 free(image);
631 free(vec);
632 }
634 void xenstore_write_vncport(int display)
635 {
636 char *buf = NULL, *path;
637 char *portstr = NULL;
639 if (xsh == NULL)
640 return;
642 path = xs_get_domain_path(xsh, domid);
643 if (path == NULL) {
644 fprintf(logfile, "xs_get_domain_path() error\n");
645 goto out;
646 }
648 if (pasprintf(&buf, "%s/console/vnc-port", path) == -1)
649 goto out;
651 if (pasprintf(&portstr, "%d", display) == -1)
652 goto out;
654 if (xs_write(xsh, XBT_NULL, buf, portstr, strlen(portstr)) == 0)
655 fprintf(logfile, "xs_write() vncport failed\n");
657 out:
658 free(portstr);
659 free(buf);
660 }
662 void xenstore_write_vslots(char *vslots)
663 {
664 char *path = NULL;
665 int pci_devid = 0;
667 if (pasprintf(&path,
668 "/local/domain/0/backend/pci/%u/%u/vslots", domid, pci_devid) == -1) {
669 fprintf(logfile, "out of memory when updating vslots.\n");
670 goto out;
671 }
672 if (!xs_write(xsh, XBT_NULL, path, vslots, strlen(vslots)))
673 fprintf(logfile, "error updating vslots \n");
675 out:
676 free(path);
677 }
679 void xenstore_read_vncpasswd(int domid, char *pwbuf, size_t pwbuflen)
680 {
681 char *buf = NULL, *path, *uuid = NULL, *passwd = NULL;
682 unsigned int i, len;
684 pwbuf[0] = '\0';
686 if (xsh == NULL)
687 return;
689 path = xs_get_domain_path(xsh, domid);
690 if (path == NULL) {
691 fprintf(logfile, "xs_get_domain_path() error. domid %d.\n", domid);
692 return;
693 }
695 pasprintf(&buf, "%s/vm", path);
696 free(path);
697 uuid = xs_read(xsh, XBT_NULL, buf, &len);
698 if (uuid == NULL) {
699 fprintf(logfile, "xs_read(): uuid get error. %s.\n", buf);
700 free(buf);
701 return;
702 }
704 pasprintf(&buf, "%s/vncpasswd", uuid);
705 free(uuid);
706 passwd = xs_read(xsh, XBT_NULL, buf, &len);
707 if (passwd == NULL) {
708 fprintf(logfile, "xs_read(): vncpasswd get error. %s.\n", buf);
709 free(buf);
710 return;
711 }
713 if (len >= pwbuflen)
714 {
715 fprintf(logfile, "xenstore_read_vncpasswd(): truncated password to avoid buffer overflow\n");
716 len = pwbuflen - 1;
717 }
719 for (i=0; i<len; i++)
720 pwbuf[i] = passwd[i];
721 pwbuf[len] = '\0';
722 passwd[0] = '\0';
723 if (xs_write(xsh, XBT_NULL, buf, passwd, 1) == 0)
724 fprintf(logfile, "xs_write() vncpasswd failed.\n");
726 free(passwd);
727 free(buf);
728 }
731 /*
732 * get all device instances of a certain type
733 */
734 char **xenstore_domain_get_devices(struct xs_handle *handle,
735 const char *devtype, unsigned int *num)
736 {
737 char *path;
738 char *buf = NULL;
739 char **e = NULL;
741 path = xs_get_domain_path(handle, domid);
742 if (path == NULL)
743 goto out;
745 if (pasprintf(&buf, "%s/device/%s", path,devtype) == -1)
746 goto out;
748 e = xs_directory(handle, XBT_NULL, buf, num);
750 out:
751 free(path);
752 free(buf);
753 return e;
754 }
756 /*
757 * Check whether a domain has devices of the given type
758 */
759 int xenstore_domain_has_devtype(struct xs_handle *handle, const char *devtype)
760 {
761 int rc = 0;
762 unsigned int num;
763 char **e = xenstore_domain_get_devices(handle, devtype, &num);
764 if (e)
765 rc = 1;
766 free(e);
767 return rc;
768 }
770 /*
771 * Function that creates a path to a variable of an instance of a
772 * certain device
773 */
774 static char *get_device_variable_path(const char *devtype, const char *inst,
775 const char *var)
776 {
777 char *buf = NULL;
778 if (pasprintf(&buf, "/local/domain/0/backend/%s/%d/%s/%s",
779 devtype,
780 domid,
781 inst,
782 var) == -1) {
783 free(buf);
784 buf = NULL;
785 }
786 return buf;
787 }
789 char *xenstore_backend_read_variable(struct xs_handle *handle,
790 const char *devtype, const char *inst,
791 const char *var)
792 {
793 char *value = NULL;
794 char *buf = NULL;
795 unsigned int len;
797 buf = get_device_variable_path(devtype, inst, var);
798 if (NULL == buf)
799 goto out;
801 value = xs_read(handle, XBT_NULL, buf, &len);
803 free(buf);
805 out:
806 return value;
807 }
809 /*
810 Read the hotplug status variable from the backend given the type
811 of device and its instance.
812 */
813 char *xenstore_read_hotplug_status(struct xs_handle *handle,
814 const char *devtype, const char *inst)
815 {
816 return xenstore_backend_read_variable(handle, devtype, inst,
817 "hotplug-status");
818 }
820 /*
821 Subscribe to the hotplug status of a device given the type of device and
822 its instance.
823 In case an error occurrs, a negative number is returned.
824 */
825 int xenstore_subscribe_to_hotplug_status(struct xs_handle *handle,
826 const char *devtype,
827 const char *inst,
828 const char *token)
829 {
830 int rc = 0;
831 char *path = get_device_variable_path(devtype, inst, "hotplug-status");
833 if (path == NULL)
834 return -1;
836 if (0 == xs_watch(handle, path, token))
837 rc = -2;
839 free(path);
841 return rc;
842 }
844 /*
845 * Unsubscribe from a subscription to the status of a hotplug variable of
846 * a device.
847 */
848 int xenstore_unsubscribe_from_hotplug_status(struct xs_handle *handle,
849 const char *devtype,
850 const char *inst,
851 const char *token)
852 {
853 int rc = 0;
854 char *path;
855 path = get_device_variable_path(devtype, inst, "hotplug-status");
856 if (path == NULL)
857 return -1;
859 if (0 == xs_unwatch(handle, path, token))
860 rc = -2;
862 free(path);
864 return rc;
865 }
867 char *xenstore_vm_read(int domid, char *key, unsigned int *len)
868 {
869 char *buf = NULL, *path = NULL, *value = NULL;
871 if (xsh == NULL)
872 goto out;
874 path = xs_get_domain_path(xsh, domid);
875 if (path == NULL) {
876 fprintf(logfile, "xs_get_domain_path(%d): error\n", domid);
877 goto out;
878 }
880 pasprintf(&buf, "%s/vm", path);
881 free(path);
882 path = xs_read(xsh, XBT_NULL, buf, NULL);
883 if (path == NULL) {
884 fprintf(logfile, "xs_read(%s): read error\n", buf);
885 goto out;
886 }
888 pasprintf(&buf, "%s/%s", path, key);
889 value = xs_read(xsh, XBT_NULL, buf, len);
890 if (value == NULL) {
891 fprintf(logfile, "xs_read(%s): read error\n", buf);
892 goto out;
893 }
895 out:
896 free(path);
897 free(buf);
898 return value;
899 }
901 int xenstore_vm_write(int domid, char *key, char *value)
902 {
903 char *buf = NULL, *path = NULL;
904 int rc = -1;
906 if (xsh == NULL)
907 goto out;
909 path = xs_get_domain_path(xsh, domid);
910 if (path == NULL) {
911 fprintf(logfile, "xs_get_domain_path: error\n");
912 goto out;
913 }
915 pasprintf(&buf, "%s/vm", path);
916 free(path);
917 path = xs_read(xsh, XBT_NULL, buf, NULL);
918 if (path == NULL) {
919 fprintf(logfile, "xs_read(%s): read error\n", buf);
920 goto out;
921 }
923 pasprintf(&buf, "%s/%s", path, key);
924 rc = xs_write(xsh, XBT_NULL, buf, value, strlen(value));
925 if (rc == 0) {
926 fprintf(logfile, "xs_write(%s, %s): write error\n", buf, key);
927 goto out;
928 }
930 out:
931 free(path);
932 free(buf);
933 return rc;
934 }