debuggers.hg

view tools/ioemu/xenstore.c @ 17984:b3d827e63a09

stubdom: PCI passthrough support via PV-PCI

Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Jul 02 13:54:20 2008 +0100 (2008-07-02)
parents 469d9b00382d
children
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 {
264 format = bdrv_find_format(drv);
265 if (!format) {
266 fprintf(stderr, "qemu: type (image format) '%s' unknown for vbd '%s' or image '%s'\n", drv, buf, params);
267 continue;
268 }
269 }
270 }
271 if (bdrv_open2(bs, params, 0 /* snapshot */, format) < 0)
272 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");
273 }
274 }
276 #ifdef CONFIG_STUBDOM
277 if (pasprintf(&buf, "%s/device/vkbd", path) == -1)
278 goto out;
280 free(e);
281 e = xs_directory(xsh, XBT_NULL, buf, &num);
283 if (e) {
284 for (i = 0; i < num; i++) {
285 if (pasprintf(&buf, "%s/device/vkbd/%s", path, e[i]) == -1)
286 continue;
287 xenfb_connect_vkbd(buf);
288 }
289 }
291 if (pasprintf(&buf, "%s/device/vfb", path) == -1)
292 goto out;
294 free(e);
295 e = xs_directory(xsh, XBT_NULL, buf, &num);
297 if (e) {
298 for (i = 0; i < num; i++) {
299 if (pasprintf(&buf, "%s/device/vfb/%s", path, e[i]) == -1)
300 continue;
301 xenfb_connect_vfb(buf);
302 }
303 }
304 #endif
307 /* Set a watch for log-dirty requests from the migration tools */
308 if (pasprintf(&buf, "/local/domain/0/device-model/%u/logdirty/next-active",
309 domid) != -1) {
310 xs_watch(xsh, buf, "logdirty");
311 fprintf(logfile, "Watching %s\n", buf);
312 }
314 /* Set a watch for suspend requests from the migration tools */
315 if (pasprintf(&buf,
316 "/local/domain/0/device-model/%u/command", domid) != -1) {
317 xs_watch(xsh, buf, "dm-command");
318 fprintf(logfile, "Watching %s\n", buf);
319 }
321 /* get the pci pass-through parameter */
322 if (pasprintf(&buf, "/local/domain/0/backend/pci/%u/%u/num_devs",
323 hvm_domid, pci_devid) == -1)
324 goto out;
326 free(params);
327 params = xs_read(xsh, XBT_NULL, buf, &len);
328 if (params == NULL)
329 goto out;
330 num = atoi(params);
332 for ( i = 0; i < num; i++ ) {
333 if (pasprintf(&buf, "/local/domain/0/backend/pci/%u/%u/dev-%d",
334 hvm_domid, pci_devid, i) != -1) {
335 free(dev);
336 dev = xs_read(xsh, XBT_NULL, buf, &len);
338 if ( strlen(dev) + strlen(direct_pci_str) > DIRECT_PCI_STR_LEN ) {
339 fprintf(stderr, "qemu: too many pci pass-through devices\n");
340 memset(direct_pci_str, 0, DIRECT_PCI_STR_LEN);
341 goto out;
342 }
344 /* append to direct_pci_str */
345 if ( dev ) {
346 strcat(direct_pci_str, dev);
347 strcat(direct_pci_str, "-");
348 }
349 }
350 }
353 out:
354 free(type);
355 free(params);
356 free(dev);
357 free(bpath);
358 free(buf);
359 free(path);
360 free(e);
361 free(drv);
362 return;
363 }
365 int xenstore_fd(void)
366 {
367 if (xsh)
368 return xs_fileno(xsh);
369 return -1;
370 }
372 unsigned long *logdirty_bitmap = NULL;
373 unsigned long logdirty_bitmap_size;
374 extern int vga_ram_size, bios_size;
376 void xenstore_process_logdirty_event(void)
377 {
378 char *act;
379 static char *active_path = NULL;
380 static char *next_active_path = NULL;
381 static char *seg = NULL;
382 unsigned int len;
383 int i;
385 if (!seg) {
386 char *path = NULL, *key_ascii, key_terminated[17] = {0,};
387 key_t key;
388 int shmid;
390 /* Find and map the shared memory segment for log-dirty bitmaps */
391 if (pasprintf(&path,
392 "/local/domain/0/device-model/%u/logdirty/key",
393 domid) == -1) {
394 fprintf(logfile, "Log-dirty: out of memory\n");
395 exit(1);
396 }
398 key_ascii = xs_read(xsh, XBT_NULL, path, &len);
399 free(path);
401 if (!key_ascii)
402 /* No key yet: wait for the next watch */
403 return;
405 #ifdef CONFIG_STUBDOM
406 /* We pass the writes to hypervisor */
407 seg = (void*)1;
408 #else
409 strncpy(key_terminated, key_ascii, 16);
410 free(key_ascii);
411 key = (key_t) strtoull(key_terminated, NULL, 16);
413 /* Figure out how bit the log-dirty bitmaps are */
414 logdirty_bitmap_size = xc_memory_op(xc_handle,
415 XENMEM_maximum_gpfn, &domid) + 1;
416 logdirty_bitmap_size = ((logdirty_bitmap_size + HOST_LONG_BITS - 1)
417 / HOST_LONG_BITS); /* longs */
418 logdirty_bitmap_size *= sizeof (unsigned long); /* bytes */
420 /* Map the shared-memory segment */
421 fprintf(logfile, "%s: key=%16.16llx size=%lu\n", __FUNCTION__,
422 (unsigned long long)key, logdirty_bitmap_size);
424 shmid = shmget(key, 2 * logdirty_bitmap_size, S_IRUSR|S_IWUSR);
425 if (shmid == -1) {
426 fprintf(logfile, "Log-dirty: shmget failed: segment %16.16llx "
427 "(%s)\n", (unsigned long long)key, strerror(errno));
428 exit(1);
429 }
431 seg = shmat(shmid, NULL, 0);
432 if (seg == (void *)-1) {
433 fprintf(logfile, "Log-dirty: shmat failed: segment %16.16llx "
434 "(%s)\n", (unsigned long long)key, strerror(errno));
435 exit(1);
436 }
438 fprintf(logfile, "Log-dirty: mapped segment at %p\n", seg);
440 /* Double-check that the bitmaps are the size we expect */
441 if (logdirty_bitmap_size != *(uint32_t *)seg) {
442 fprintf(logfile, "Log-dirty: got %u, calc %lu\n",
443 *(uint32_t *)seg, logdirty_bitmap_size);
444 /* Stale key: wait for next watch */
445 shmdt(seg);
446 seg = NULL;
447 return;
448 }
449 #endif
451 /* Remember the paths for the next-active and active entries */
452 if (pasprintf(&active_path,
453 "/local/domain/0/device-model/%u/logdirty/active",
454 domid) == -1) {
455 fprintf(logfile, "Log-dirty: out of memory\n");
456 exit(1);
457 }
458 if (pasprintf(&next_active_path,
459 "/local/domain/0/device-model/%u/logdirty/next-active",
460 domid) == -1) {
461 fprintf(logfile, "Log-dirty: out of memory\n");
462 exit(1);
463 }
464 }
466 fprintf(logfile, "Triggered log-dirty buffer switch\n");
468 /* Read the required active buffer from the store */
469 act = xs_read(xsh, XBT_NULL, next_active_path, &len);
470 if (!act) {
471 fprintf(logfile, "Log-dirty: can't read next-active\n");
472 exit(1);
473 }
475 /* Switch buffers */
476 i = act[0] - '0';
477 if (i != 0 && i != 1) {
478 fprintf(logfile, "Log-dirty: bad next-active entry: %s\n", act);
479 exit(1);
480 }
481 logdirty_bitmap = (unsigned long *)(seg + i * logdirty_bitmap_size);
483 /* Ack that we've switched */
484 xs_write(xsh, XBT_NULL, active_path, act, len);
485 free(act);
486 }
489 /* Accept state change commands from the control tools */
490 static void xenstore_process_dm_command_event(void)
491 {
492 char *path = NULL, *command = NULL, *par = NULL;
493 unsigned int len;
494 extern int suspend_requested;
496 if (pasprintf(&path,
497 "/local/domain/0/device-model/%u/command", domid) == -1) {
498 fprintf(logfile, "out of memory reading dm command\n");
499 goto out;
500 }
501 command = xs_read(xsh, XBT_NULL, path, &len);
502 if (!command)
503 goto out;
505 if (!strncmp(command, "save", len)) {
506 fprintf(logfile, "dm-command: pause and save state\n");
507 suspend_requested = 1;
508 } else if (!strncmp(command, "continue", len)) {
509 fprintf(logfile, "dm-command: continue after state save\n");
510 suspend_requested = 0;
511 } else if (!strncmp(command, "pci-rem", len)) {
512 fprintf(logfile, "dm-command: hot remove pass-through pci dev \n");
514 if (pasprintf(&path,
515 "/local/domain/0/device-model/%u/parameter", domid) == -1) {
516 fprintf(logfile, "out of memory reading dm command parameter\n");
517 goto out;
518 }
519 par = xs_read(xsh, XBT_NULL, path, &len);
520 if (!par)
521 goto out;
523 do_pci_del(par);
524 free(par);
525 } else if (!strncmp(command, "pci-ins", len)) {
526 fprintf(logfile, "dm-command: hot insert pass-through pci dev \n");
528 if (pasprintf(&path,
529 "/local/domain/0/device-model/%u/parameter", domid) == -1) {
530 fprintf(logfile, "out of memory reading dm command parameter\n");
531 goto out;
532 }
533 par = xs_read(xsh, XBT_NULL, path, &len);
534 if (!par)
535 goto out;
537 do_pci_add(par);
538 free(par);
539 } else {
540 fprintf(logfile, "dm-command: unknown command\"%*s\"\n", len, command);
541 }
543 out:
544 free(path);
545 free(command);
546 }
548 void xenstore_record_dm(char *subpath, char *state)
549 {
550 char *path = NULL;
552 if (pasprintf(&path,
553 "/local/domain/0/device-model/%u/%s", domid, subpath) == -1) {
554 fprintf(logfile, "out of memory recording dm \n");
555 goto out;
556 }
557 if (!xs_write(xsh, XBT_NULL, path, state, strlen(state)))
558 fprintf(logfile, "error recording dm \n");
560 out:
561 free(path);
562 }
564 void xenstore_record_dm_state(char *state)
565 {
566 xenstore_record_dm("state", state);
567 }
569 void xenstore_process_event(void *opaque)
570 {
571 char **vec, *offset, *bpath = NULL, *buf = NULL, *drv = NULL, *image = NULL;
572 unsigned int len, num, hd_index;
574 vec = xs_read_watch(xsh, &num);
575 if (!vec)
576 return;
578 if (!strcmp(vec[XS_WATCH_TOKEN], "logdirty")) {
579 xenstore_process_logdirty_event();
580 goto out;
581 }
583 if (!strcmp(vec[XS_WATCH_TOKEN], "dm-command")) {
584 xenstore_process_dm_command_event();
585 goto out;
586 }
588 if (strncmp(vec[XS_WATCH_TOKEN], "hd", 2) ||
589 strlen(vec[XS_WATCH_TOKEN]) != 3)
590 goto out;
591 hd_index = vec[XS_WATCH_TOKEN][2] - 'a';
592 image = xs_read(xsh, XBT_NULL, vec[XS_WATCH_PATH], &len);
593 if (image == NULL)
594 goto out; /* gone */
596 /* Strip off blktap sub-type prefix */
597 bpath = strdup(vec[XS_WATCH_PATH]);
598 if (bpath == NULL)
599 goto out;
600 if ((offset = strrchr(bpath, '/')) != NULL)
601 *offset = '\0';
602 if (pasprintf(&buf, "%s/type", bpath) == -1)
603 goto out;
604 drv = xs_read(xsh, XBT_NULL, buf, &len);
605 if (drv && !strcmp(drv, "tap") && ((offset = strchr(image, ':')) != NULL))
606 memmove(image, offset+1, strlen(offset+1)+1);
608 if (!strcmp(image, bs_table[hd_index]->filename))
609 goto out; /* identical */
611 do_eject(0, vec[XS_WATCH_TOKEN]);
612 bs_table[hd_index]->filename[0] = 0;
613 if (media_filename[hd_index]) {
614 free(media_filename[hd_index]);
615 media_filename[hd_index] = NULL;
616 }
618 if (image[0]) {
619 media_filename[hd_index] = strdup(image);
620 xenstore_check_new_media_present(5000);
621 }
623 out:
624 free(drv);
625 free(buf);
626 free(bpath);
627 free(image);
628 free(vec);
629 }
631 void xenstore_write_vncport(int display)
632 {
633 char *buf = NULL, *path;
634 char *portstr = NULL;
636 if (xsh == NULL)
637 return;
639 path = xs_get_domain_path(xsh, domid);
640 if (path == NULL) {
641 fprintf(logfile, "xs_get_domain_path() error\n");
642 goto out;
643 }
645 if (pasprintf(&buf, "%s/console/vnc-port", path) == -1)
646 goto out;
648 if (pasprintf(&portstr, "%d", display) == -1)
649 goto out;
651 if (xs_write(xsh, XBT_NULL, buf, portstr, strlen(portstr)) == 0)
652 fprintf(logfile, "xs_write() vncport failed\n");
654 out:
655 free(portstr);
656 free(buf);
657 }
659 void xenstore_write_vslots(char *vslots)
660 {
661 char *path = NULL;
662 int pci_devid = 0;
664 if (pasprintf(&path,
665 "/local/domain/0/backend/pci/%u/%u/vslots", domid, pci_devid) == -1) {
666 fprintf(logfile, "out of memory when updating vslots.\n");
667 goto out;
668 }
669 if (!xs_write(xsh, XBT_NULL, path, vslots, strlen(vslots)))
670 fprintf(logfile, "error updating vslots \n");
672 out:
673 free(path);
674 }
676 void xenstore_read_vncpasswd(int domid, char *pwbuf, size_t pwbuflen)
677 {
678 char *buf = NULL, *path, *uuid = NULL, *passwd = NULL;
679 unsigned int i, len;
681 pwbuf[0] = '\0';
683 if (xsh == NULL)
684 return;
686 path = xs_get_domain_path(xsh, domid);
687 if (path == NULL) {
688 fprintf(logfile, "xs_get_domain_path() error. domid %d.\n", domid);
689 return;
690 }
692 pasprintf(&buf, "%s/vm", path);
693 free(path);
694 uuid = xs_read(xsh, XBT_NULL, buf, &len);
695 if (uuid == NULL) {
696 fprintf(logfile, "xs_read(): uuid get error. %s.\n", buf);
697 free(buf);
698 return;
699 }
701 pasprintf(&buf, "%s/vncpasswd", uuid);
702 free(uuid);
703 passwd = xs_read(xsh, XBT_NULL, buf, &len);
704 if (passwd == NULL) {
705 fprintf(logfile, "xs_read(): vncpasswd get error. %s.\n", buf);
706 free(buf);
707 return;
708 }
710 if (len >= pwbuflen)
711 {
712 fprintf(logfile, "xenstore_read_vncpasswd(): truncated password to avoid buffer overflow\n");
713 len = pwbuflen - 1;
714 }
716 for (i=0; i<len; i++)
717 pwbuf[i] = passwd[i];
718 pwbuf[len] = '\0';
719 passwd[0] = '\0';
720 if (xs_write(xsh, XBT_NULL, buf, passwd, 1) == 0)
721 fprintf(logfile, "xs_write() vncpasswd failed.\n");
723 free(passwd);
724 free(buf);
725 }
728 /*
729 * get all device instances of a certain type
730 */
731 char **xenstore_domain_get_devices(struct xs_handle *handle,
732 const char *devtype, unsigned int *num)
733 {
734 char *path;
735 char *buf = NULL;
736 char **e = NULL;
738 path = xs_get_domain_path(handle, domid);
739 if (path == NULL)
740 goto out;
742 if (pasprintf(&buf, "%s/device/%s", path,devtype) == -1)
743 goto out;
745 e = xs_directory(handle, XBT_NULL, buf, num);
747 out:
748 free(path);
749 free(buf);
750 return e;
751 }
753 /*
754 * Check whether a domain has devices of the given type
755 */
756 int xenstore_domain_has_devtype(struct xs_handle *handle, const char *devtype)
757 {
758 int rc = 0;
759 unsigned int num;
760 char **e = xenstore_domain_get_devices(handle, devtype, &num);
761 if (e)
762 rc = 1;
763 free(e);
764 return rc;
765 }
767 /*
768 * Function that creates a path to a variable of an instance of a
769 * certain device
770 */
771 static char *get_device_variable_path(const char *devtype, const char *inst,
772 const char *var)
773 {
774 char *buf = NULL;
775 if (pasprintf(&buf, "/local/domain/0/backend/%s/%d/%s/%s",
776 devtype,
777 domid,
778 inst,
779 var) == -1) {
780 free(buf);
781 buf = NULL;
782 }
783 return buf;
784 }
786 char *xenstore_backend_read_variable(struct xs_handle *handle,
787 const char *devtype, const char *inst,
788 const char *var)
789 {
790 char *value = NULL;
791 char *buf = NULL;
792 unsigned int len;
794 buf = get_device_variable_path(devtype, inst, var);
795 if (NULL == buf)
796 goto out;
798 value = xs_read(handle, XBT_NULL, buf, &len);
800 free(buf);
802 out:
803 return value;
804 }
806 /*
807 Read the hotplug status variable from the backend given the type
808 of device and its instance.
809 */
810 char *xenstore_read_hotplug_status(struct xs_handle *handle,
811 const char *devtype, const char *inst)
812 {
813 return xenstore_backend_read_variable(handle, devtype, inst,
814 "hotplug-status");
815 }
817 /*
818 Subscribe to the hotplug status of a device given the type of device and
819 its instance.
820 In case an error occurrs, a negative number is returned.
821 */
822 int xenstore_subscribe_to_hotplug_status(struct xs_handle *handle,
823 const char *devtype,
824 const char *inst,
825 const char *token)
826 {
827 int rc = 0;
828 char *path = get_device_variable_path(devtype, inst, "hotplug-status");
830 if (path == NULL)
831 return -1;
833 if (0 == xs_watch(handle, path, token))
834 rc = -2;
836 free(path);
838 return rc;
839 }
841 /*
842 * Unsubscribe from a subscription to the status of a hotplug variable of
843 * a device.
844 */
845 int xenstore_unsubscribe_from_hotplug_status(struct xs_handle *handle,
846 const char *devtype,
847 const char *inst,
848 const char *token)
849 {
850 int rc = 0;
851 char *path;
852 path = get_device_variable_path(devtype, inst, "hotplug-status");
853 if (path == NULL)
854 return -1;
856 if (0 == xs_unwatch(handle, path, token))
857 rc = -2;
859 free(path);
861 return rc;
862 }
864 char *xenstore_vm_read(int domid, char *key, unsigned int *len)
865 {
866 char *buf = NULL, *path = NULL, *value = NULL;
868 if (xsh == NULL)
869 goto out;
871 path = xs_get_domain_path(xsh, domid);
872 if (path == NULL) {
873 fprintf(logfile, "xs_get_domain_path(%d): error\n", domid);
874 goto out;
875 }
877 pasprintf(&buf, "%s/vm", path);
878 free(path);
879 path = xs_read(xsh, XBT_NULL, buf, NULL);
880 if (path == NULL) {
881 fprintf(logfile, "xs_read(%s): read error\n", buf);
882 goto out;
883 }
885 pasprintf(&buf, "%s/%s", path, key);
886 value = xs_read(xsh, XBT_NULL, buf, len);
887 if (value == NULL) {
888 fprintf(logfile, "xs_read(%s): read error\n", buf);
889 goto out;
890 }
892 out:
893 free(path);
894 free(buf);
895 return value;
896 }
898 int xenstore_vm_write(int domid, char *key, char *value)
899 {
900 char *buf = NULL, *path = NULL;
901 int rc = -1;
903 if (xsh == NULL)
904 goto out;
906 path = xs_get_domain_path(xsh, domid);
907 if (path == NULL) {
908 fprintf(logfile, "xs_get_domain_path: error\n");
909 goto out;
910 }
912 pasprintf(&buf, "%s/vm", path);
913 free(path);
914 path = xs_read(xsh, XBT_NULL, buf, NULL);
915 if (path == NULL) {
916 fprintf(logfile, "xs_read(%s): read error\n", buf);
917 goto out;
918 }
920 pasprintf(&buf, "%s/%s", path, key);
921 rc = xs_write(xsh, XBT_NULL, buf, value, strlen(value));
922 if (rc == 0) {
923 fprintf(logfile, "xs_write(%s, %s): write error\n", buf, key);
924 goto out;
925 }
927 out:
928 free(path);
929 free(buf);
930 return rc;
931 }