summaryrefslogtreecommitdiff
path: root/src/xen_monitor.c
blob: 0c8c1be582129c570f0e5783ec2ef2392905eadb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/**
 * @file
 * @section AUTHORS
 *
 *  Authors:
 *       Eamon Walsh <ewalsh@tycho.nsa.gov>
 *       Daniel De Graaf <dgdegra@tycho.nsa.gov>
 *
 * @section LICENSE
 *
 * This file is in the public domain.
 *
 * @section DESCRIPTION
 *
 * This is "glue" code between the functions from QEMU and the core
 * linpicker-monitor code.  The only thing here for linpicker-monitor is the
 * domain scanning code that listens in XenStore for new domains starting
 * up and handles them (not present in QEMU because each QEMU instance is for
 * a single domain).  In particular the calls to libxenlight to create the
 * initial device backend are made here (which triggers the frontend driver
 * to actually set up the device in the guest).
 */

#include <sys/types.h>
#include <sys/select.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#include <libxl.h>

#include "xen_backend.h"
#include "xen_linpicker.h"
#include "sys-queue.h"

static libxl_ctx *ctx;

/* -------------------------------------------------------------------- */

static int get_domid()
{
    char* str = xs_read(xenstore, 0, "domid", NULL);
    if (!str)
	return 0;
    int rv = atoi(str);
    free(str);
    return rv;
}

static void
domain_shutdown(int domid)
{
    /* XXX these don't actually, you know, work */
    libxl_device_vfb_hard_shutdown(ctx, domid);
    libxl_device_vkb_hard_shutdown(ctx, domid);
}

static int
domain_setup(struct xs_handle *xenstore, int domid, int newdom)
{
    int rc;
    int myself = get_domid();

    // don't try to set up vfb/vkbd for ourselves, or dom0
    if (domid == 0 || domid == myself)
	return 0;

    libxl_device_vfb vfb = {
	.backend_domid = myself,
	.devid = 0,
	.vnclisten = ""
    };
    libxl_device_vkb vkb = {
	.backend_domid = myself,
	.devid = 0,
    };

    /* set up backend devices */
    if (newdom) {
	rc = libxl_device_vfb_add(ctx, domid, &vfb);
	if (rc != 0)
	    return rc;

	rc = libxl_device_vkb_add(ctx, domid, &vkb);
	if (rc != 0)
	    return rc;
    }

//    xen_be_register(domid, "console", &xen_console_ops);
    xen_be_register(domid, "vkbd", &xen_kbdmouse_ops);
    xen_be_register(domid, "vfb", &xen_framebuffer_ops);

    return 0;
}

/* -------------------------------------------------------------------- */

static void
xen_linpicker_scan_domains(struct xs_handle *xenstore, int newdom)
{
    static fd_set doms;
    fd_set tmp;
    unsigned int n, i;
    int d;
    char** e;

    FD_ZERO(&tmp);
    if (!newdom)
	FD_ZERO(&doms);

    e = xs_directory(xenstore, XBT_NULL, "/local/domain", &n);
    if (!e) {
	XEN_BE_LOG(NULL, 0, "cannot list domains\n");
	return;
    }

    for (i = 0; i < n; i++) {
	d = atoi(e[i]);
	FD_SET(d, &tmp);
    }
    free(e);
    for (i = 0; i < FD_SETSIZE; i++) {
	if (FD_ISSET(i, &tmp) && !FD_ISSET(i, &doms))
	    domain_setup(xenstore, i, newdom);

	if (!FD_ISSET(i, &tmp) && FD_ISSET(i, &doms))
	    domain_shutdown(i);
    }

    memcpy(&doms, &tmp, sizeof(fd_set));
}

int
xen_linpicker_update(struct xs_handle *xenstore, xc_interface* xen_xc, const char *path)
{
    xen_linpicker_scan_domains(xenstore, 1);
    return 0;
}

int
xen_linpicker_init(struct xs_handle *xenstore, xc_interface* xen_xc)
{
    /* setup */
    libxl_ctx_alloc(&ctx, LIBXL_VERSION, 0);

    /* watch for domain add/remove */
    if (!xs_watch(xenstore, "/local/domain", LINPICKER_TOKEN))
	return -1;

    xen_linpicker_scan_domains(xenstore, 0);
    return 0;
}

int
xen_linpicker_be_set_state(struct XenDevice *xendev, enum xenbus_state state)
{
    if (state == XenbusStateInitWait)
	xenstore_write_be_str(xendev, "hotplug-status", "connected");

    return xenstore_write_be_int(xendev, "state", state);
}