source: trunk/packages/xen-3.1/xen-3.1/tools/ioemu/xenstore.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 16.7 KB
Line 
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 */
10
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>
19
20static struct xs_handle *xsh = NULL;
21static char *media_filename[MAX_DISKS + MAX_SCSI_DISKS];
22static QEMUTimer *insert_timer = NULL;
23
24#define UWAIT_MAX (30*1000000) /* thirty seconds */
25#define UWAIT     (100000)     /* 1/10th second  */
26
27static int pasprintf(char **buf, const char *fmt, ...)
28{
29    va_list ap;
30    int ret = 0;
31
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}
42
43static void insert_media(void *opaque)
44{
45    int i;
46
47    for (i = 0; i < MAX_DISKS + MAX_SCSI_DISKS; i++) {
48        if (media_filename[i] && bs_table[i]) {
49            do_change(bs_table[i]->device_name, media_filename[i]);
50            free(media_filename[i]);
51            media_filename[i] = NULL;
52        }
53    }
54}
55
56void xenstore_check_new_media_present(int timeout)
57{
58
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}
63
64static void waitForDevice(char *fn)
65{ 
66    struct stat sbuf;
67    int status;
68    int uwait = UWAIT_MAX;
69
70    do {
71        status = stat(fn, &sbuf);
72        if (!status) break;
73        usleep(UWAIT);
74        uwait -= UWAIT;
75    } while (uwait > 0);
76
77    return;
78}
79
80void 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, is_scsi;
87    unsigned int len, num, hd_index;
88
89    for(i = 0; i < MAX_DISKS + MAX_SCSI_DISKS; i++)
90        media_filename[i] = NULL;
91
92    xsh = xs_daemon_open();
93    if (xsh == NULL) {
94        fprintf(logfile, "Could not contact xenstore for domain config\n");
95        return;
96    }
97
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    }
103
104    if (pasprintf(&buf, "%s/device/vbd", path) == -1)
105        goto out;
106
107    e = xs_directory(xsh, XBT_NULL, buf, &num);
108    if (e == NULL)
109        goto out;
110
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        is_scsi = !strncmp(dev, "sd", 2);
127        if ((strncmp(dev, "hd", 2) && !is_scsi) || strlen(dev) != 3 )
128            continue;
129        hd_index = dev[2] - 'a';
130        if (hd_index >= (is_scsi ? MAX_SCSI_DISKS : MAX_DISKS))
131            continue;
132        /* read the type of the device */
133        if (pasprintf(&buf, "%s/device/vbd/%s/device-type", path, e[i]) == -1)
134            continue;
135        free(type);
136        type = xs_read(xsh, XBT_NULL, buf, &len);
137        if (pasprintf(&buf, "%s/params", bpath) == -1)
138            continue;
139        free(params);
140        params = xs_read(xsh, XBT_NULL, buf, &len);
141        if (params == NULL)
142            continue;
143        /*
144         * check if device has a phantom vbd; the phantom is hooked
145         * to the frontend device (for ease of cleanup), so lookup
146         * the frontend device, and see if there is a phantom_vbd
147         * if there is, we will use resolution as the filename
148         */
149        if (pasprintf(&buf, "%s/device/vbd/%s/phantom_vbd", path, e[i]) == -1)
150            continue;
151        free(fpath);
152        fpath = xs_read(xsh, XBT_NULL, buf, &len);
153        if (fpath) {
154            if (pasprintf(&buf, "%s/dev", fpath) == -1)
155                continue;
156            free(params);
157            params = xs_read(xsh, XBT_NULL, buf , &len);
158            if (params) {
159                /*
160                 * wait for device, on timeout silently fail because we will
161                 * fail to open below
162                 */
163                waitForDevice(params);
164            }
165        }
166
167        bs_table[hd_index + (is_scsi ? MAX_DISKS : 0)] = bdrv_new(dev);
168        /* check if it is a cdrom */
169        if (type && !strcmp(type, "cdrom")) {
170            bdrv_set_type_hint(bs_table[hd_index], BDRV_TYPE_CDROM);
171            if (pasprintf(&buf, "%s/params", bpath) != -1)
172                xs_watch(xsh, buf, dev);
173        }
174        /* open device now if media present */
175        if (params[0]) {
176            if (bdrv_open(bs_table[hd_index + (is_scsi ? MAX_DISKS : 0)],
177                          params, 0 /* snapshot */) < 0)
178                fprintf(stderr, "qemu: could not open hard disk image '%s'\n",
179                        params);
180        }
181    }
182
183    /* Set a watch for log-dirty requests from the migration tools */
184    if (pasprintf(&buf, "%s/logdirty/next-active", path) != -1) {
185        xs_watch(xsh, buf, "logdirty");
186        fprintf(logfile, "Watching %s\n", buf);
187    }
188
189
190 out:
191    free(type);
192    free(params);
193    free(dev);
194    free(bpath);
195    free(buf);
196    free(path);
197    free(e);
198    return;
199}
200
201int xenstore_fd(void)
202{
203    if (xsh)
204        return xs_fileno(xsh);
205    return -1;
206}
207
208unsigned long *logdirty_bitmap = NULL;
209unsigned long logdirty_bitmap_size;
210extern int vga_ram_size, bios_size;
211
212void xenstore_process_logdirty_event(void)
213{
214    char *act;
215    static char *active_path = NULL;
216    static char *next_active_path = NULL;
217    static char *seg = NULL;
218    unsigned int len;
219    int i;
220
221    fprintf(logfile, "Triggered log-dirty buffer switch\n");
222
223    if (!seg) {
224        char *path, *p, *key_ascii, key_terminated[17] = {0,};
225        key_t key;
226        int shmid;
227
228        /* Find and map the shared memory segment for log-dirty bitmaps */
229        if (!(path = xs_get_domain_path(xsh, domid))) {           
230            fprintf(logfile, "Log-dirty: can't get domain path in store\n");
231            exit(1);
232        }
233        if (!(path = realloc(path, strlen(path) 
234                             + strlen("/logdirty/next-active") + 1))) {
235            fprintf(logfile, "Log-dirty: out of memory\n");
236            exit(1);
237        }
238        strcat(path, "/logdirty/");
239        p = path + strlen(path);
240        strcpy(p, "key");
241       
242        key_ascii = xs_read(xsh, XBT_NULL, path, &len);
243        if (!key_ascii) {
244            /* No key yet: wait for the next watch */
245            free(path);
246            return;
247        }
248        strncpy(key_terminated, key_ascii, 16);
249        free(key_ascii);
250        key = (key_t) strtoull(key_terminated, NULL, 16);
251
252        /* Figure out how bit the log-dirty bitmaps are */
253        logdirty_bitmap_size = xc_memory_op(xc_handle, 
254                                            XENMEM_maximum_gpfn, &domid) + 1;
255        logdirty_bitmap_size = ((logdirty_bitmap_size + HOST_LONG_BITS - 1)
256                                / HOST_LONG_BITS); /* longs */
257        logdirty_bitmap_size *= sizeof (unsigned long); /* bytes */
258
259        /* Map the shared-memory segment */
260        if ((shmid = shmget(key, 
261                            2 * logdirty_bitmap_size, 
262                            S_IRUSR|S_IWUSR)) == -1 
263            || (seg = shmat(shmid, NULL, 0)) == (void *)-1) {
264            fprintf(logfile, "Log-dirty: can't map segment %16.16llx (%s)\n",
265                    (unsigned long long) key, strerror(errno));
266            exit(1);
267        }
268
269        fprintf(logfile, "Log-dirty: mapped segment at %p\n", seg);
270
271        /* Double-check that the bitmaps are the size we expect */
272        if (logdirty_bitmap_size != *(uint32_t *)seg) {
273            fprintf(logfile, "Log-dirty: got %u, calc %lu\n", 
274                    *(uint32_t *)seg, logdirty_bitmap_size);
275            return;
276        }
277
278        /* Remember the paths for the next-active and active entries */
279        strcpy(p, "active");
280        if (!(active_path = strdup(path))) {
281            fprintf(logfile, "Log-dirty: out of memory\n");
282            exit(1);
283        }
284        strcpy(p, "next-active");
285        if (!(next_active_path = strdup(path))) {
286            fprintf(logfile, "Log-dirty: out of memory\n");
287            exit(1);
288        }
289        free(path);
290    }
291   
292    /* Read the required active buffer from the store */
293    act = xs_read(xsh, XBT_NULL, next_active_path, &len);
294    if (!act) {
295        fprintf(logfile, "Log-dirty: can't read next-active\n");
296        exit(1);
297    }
298
299    /* Switch buffers */
300    i = act[0] - '0';
301    if (i != 0 && i != 1) {
302        fprintf(logfile, "Log-dirty: bad next-active entry: %s\n", act);
303        exit(1);
304    }
305    logdirty_bitmap = (unsigned long *)(seg + i * logdirty_bitmap_size);
306
307    /* Ack that we've switched */
308    xs_write(xsh, XBT_NULL, active_path, act, len);
309    free(act);
310}
311
312
313
314void xenstore_process_event(void *opaque)
315{
316    char **vec, *image = NULL;
317    unsigned int len, num, hd_index;
318
319    vec = xs_read_watch(xsh, &num);
320    if (!vec)
321        return;
322
323    if (!strcmp(vec[XS_WATCH_TOKEN], "logdirty")) {
324        xenstore_process_logdirty_event();
325        goto out;
326    }
327
328    if (strncmp(vec[XS_WATCH_TOKEN], "hd", 2) ||
329        strlen(vec[XS_WATCH_TOKEN]) != 3)
330        goto out;
331    hd_index = vec[XS_WATCH_TOKEN][2] - 'a';
332    image = xs_read(xsh, XBT_NULL, vec[XS_WATCH_PATH], &len);
333    if (image == NULL || !strcmp(image, bs_table[hd_index]->filename))
334        goto out;  /* gone or identical */
335
336    do_eject(0, vec[XS_WATCH_TOKEN]);
337    bs_table[hd_index]->filename[0] = 0;
338    if (media_filename[hd_index]) {
339        free(media_filename[hd_index]);
340        media_filename[hd_index] = NULL;
341    }
342
343    if (image[0]) {
344        media_filename[hd_index] = strdup(image);
345        xenstore_check_new_media_present(5000);
346    }
347
348 out:
349    free(image);
350    free(vec);
351}
352
353void xenstore_write_vncport(int display)
354{
355    char *buf = NULL, *path;
356    char *portstr = NULL;
357
358    if (xsh == NULL)
359        return;
360
361    path = xs_get_domain_path(xsh, domid);
362    if (path == NULL) {
363        fprintf(logfile, "xs_get_domain_path() error\n");
364        goto out;
365    }
366
367    if (pasprintf(&buf, "%s/console/vnc-port", path) == -1)
368        goto out;
369
370    if (pasprintf(&portstr, "%d", 5900 + display) == -1)
371        goto out;
372
373    if (xs_write(xsh, XBT_NULL, buf, portstr, strlen(portstr)) == 0)
374        fprintf(logfile, "xs_write() vncport failed\n");
375
376 out:
377    free(portstr);
378    free(buf);
379}
380
381int xenstore_read_vncpasswd(int domid)
382{
383    extern char vncpasswd[64];
384    char *buf = NULL, *path, *uuid = NULL, *passwd = NULL;
385    unsigned int i, len, rc = 0;
386
387    if (xsh == NULL) {
388        return -1;
389    }
390
391    path = xs_get_domain_path(xsh, domid);
392    if (path == NULL) {
393        fprintf(logfile, "xs_get_domain_path() error. domid %d.\n", domid);
394        return -1;
395    }
396
397    pasprintf(&buf, "%s/vm", path);
398    uuid = xs_read(xsh, XBT_NULL, buf, &len);
399    if (uuid == NULL) {
400        fprintf(logfile, "xs_read(): uuid get error. %s.\n", buf);
401        free(path);
402        return -1;
403    }
404
405    pasprintf(&buf, "%s/vncpasswd", uuid);
406    passwd = xs_read(xsh, XBT_NULL, buf, &len);
407    if (passwd == NULL) {
408        fprintf(logfile, "xs_read(): vncpasswd get error. %s.\n", buf);
409        free(uuid);
410        free(path);
411        return rc;
412    }
413
414    for (i=0; i<len && i<63; i++) {
415        vncpasswd[i] = passwd[i];
416        passwd[i] = '\0';
417    }
418    vncpasswd[len] = '\0';
419    pasprintf(&buf, "%s/vncpasswd", uuid);
420    if (xs_write(xsh, XBT_NULL, buf, passwd, len) == 0) {
421        fprintf(logfile, "xs_write() vncpasswd failed.\n");
422        rc = -1;
423    }
424
425    free(passwd);
426    free(uuid);
427    free(path);
428
429    return rc;
430}
431
432
433/*
434 * get all device instances of a certain type
435 */
436char **xenstore_domain_get_devices(struct xs_handle *handle,
437                                   const char *devtype, unsigned int *num)
438{
439    char *path;
440    char *buf = NULL;
441    char **= NULL;
442
443    path = xs_get_domain_path(handle, domid);
444    if (path == NULL)
445        goto out;
446
447    if (pasprintf(&buf, "%s/device/%s", path,devtype) == -1)
448        goto out;
449
450    e = xs_directory(handle, XBT_NULL, buf, num);
451
452 out:
453    free(path);
454    free(buf);
455    return e;
456}
457
458/*
459 * Check whether a domain has devices of the given type
460 */
461int xenstore_domain_has_devtype(struct xs_handle *handle, const char *devtype)
462{
463    int rc = 0;
464    unsigned int num;
465    char **e = xenstore_domain_get_devices(handle, devtype, &num);
466    if (e)
467        rc = 1;
468    free(e);
469    return rc;
470}
471
472/*
473 * Function that creates a path to a variable of an instance of a
474 * certain device
475 */
476static char *get_device_variable_path(const char *devtype, const char *inst,
477                                      const char *var)
478{
479    char *buf = NULL;
480    if (pasprintf(&buf, "/local/domain/0/backend/%s/%d/%s/%s",
481                  devtype,
482                  domid,
483                  inst,
484                  var) == -1) {
485        free(buf);
486        buf = NULL;
487    }
488    return buf;
489}
490
491char *xenstore_backend_read_variable(struct xs_handle *handle,
492                                     const char *devtype, const char *inst,
493                                     const char *var)
494{
495    char *value = NULL;
496    char *buf = NULL;
497    unsigned int len;
498
499    buf = get_device_variable_path(devtype, inst, var);
500    if (NULL == buf)
501        goto out;
502
503    value = xs_read(handle, XBT_NULL, buf, &len);
504
505    free(buf);
506
507 out:
508    return value;
509}
510
511/*
512  Read the hotplug status variable from the backend given the type
513  of device and its instance.
514*/
515char *xenstore_read_hotplug_status(struct xs_handle *handle,
516                                   const char *devtype, const char *inst)
517{
518    return xenstore_backend_read_variable(handle, devtype, inst,
519                                          "hotplug-status");
520}
521
522/*
523   Subscribe to the hotplug status of a device given the type of device and
524   its instance.
525   In case an error occurrs, a negative number is returned.
526 */
527int xenstore_subscribe_to_hotplug_status(struct xs_handle *handle,
528                                         const char *devtype,
529                                         const char *inst,
530                                         const char *token)
531{
532    int rc = 0;
533    char *path = get_device_variable_path(devtype, inst, "hotplug-status");
534
535    if (path == NULL)
536        return -1;
537
538    if (0 == xs_watch(handle, path, token))
539        rc = -2;
540
541    free(path);
542
543    return rc;
544}
545
546/*
547 * Unsubscribe from a subscription to the status of a hotplug variable of
548 * a device.
549 */
550int xenstore_unsubscribe_from_hotplug_status(struct xs_handle *handle,
551                                             const char *devtype,
552                                             const char *inst,
553                                             const char *token)
554{
555    int rc = 0;
556    char *path;
557    path = get_device_variable_path(devtype, inst, "hotplug-status");
558    if (path == NULL)
559        return -1;
560
561    if (0 == xs_unwatch(handle, path, token))
562        rc = -2;
563
564    free(path);
565
566    return rc;
567}
568
569char *xenstore_vm_read(int domid, char *key, int *len)
570{
571    char *buf = NULL, *path = NULL, *value = NULL;
572
573    if (xsh == NULL)
574        goto out;
575
576    path = xs_get_domain_path(xsh, domid);
577    if (path == NULL) {
578        fprintf(logfile, "xs_get_domain_path(%d): error\n", domid);
579        goto out;
580    }
581
582    pasprintf(&buf, "%s/vm", path);
583    free(path);
584    path = xs_read(xsh, XBT_NULL, buf, NULL);
585    if (path == NULL) {
586        fprintf(logfile, "xs_read(%s): read error\n", buf);
587        goto out;
588    }
589
590    pasprintf(&buf, "%s/%s", path, key);
591    value = xs_read(xsh, XBT_NULL, buf, len);
592    if (value == NULL) {
593        fprintf(logfile, "xs_read(%s): read error\n", buf);
594        goto out;
595    }
596
597 out:
598    free(path);
599    free(buf);
600    return value;
601}
602
603int xenstore_vm_write(int domid, char *key, char *value)
604{
605    char *buf = NULL, *path = NULL;
606    int rc = -1;
607
608    if (xsh == NULL)
609        goto out;
610
611    path = xs_get_domain_path(xsh, domid);
612    if (path == NULL) {
613        fprintf(logfile, "xs_get_domain_path: error\n");
614        goto out;
615    }
616
617    pasprintf(&buf, "%s/vm", path);
618    free(path);
619    path = xs_read(xsh, XBT_NULL, buf, NULL);
620    if (path == NULL) {
621        fprintf(logfile, "xs_read(%s): read error\n", buf);
622        goto out;
623    }
624
625    pasprintf(&buf, "%s/%s", path, key);
626    rc = xs_write(xsh, XBT_NULL, buf, value, strlen(value));
627    if (rc) {
628        fprintf(logfile, "xs_write(%s, %s): write error\n", buf, key);
629        goto out;
630    }
631
632 out:
633    free(path);
634    free(buf);
635    return rc;
636}
Note: See TracBrowser for help on using the repository browser.