mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
libxenlight: implement cdrom insert/eject
This patch implements functions in libxenlight to change the cdrom in a VM at run time and to handle cdrom eject requests from guests. This patch adds two new commands to xl: cd-insert and cd-eject; it also modifies xl to handle cdrom eject requests coming from guests (actually coming from qemu). Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
This commit is contained in:
1 parent
4baca0b560
commit
7b4effff89
7 files changed
+406
-31
No files matched your search
+183
-11
@@ -460,25 +460,80 @@ int libxl_domain_shutdown(struct libxl_ctx *ctx, uint32_t domid, int req)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libxl_wait_for_domain_death(struct libxl_ctx *ctx, uint32_t domid, int *fd)
|
||||
int libxl_get_wait_fd(struct libxl_ctx *ctx, int *fd)
|
||||
{
|
||||
if (!xs_watch(ctx->xsh, "@releaseDomain", "domain_death"))
|
||||
return -1;
|
||||
*fd = xs_fileno(ctx->xsh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libxl_is_domain_dead(struct libxl_ctx *ctx, uint32_t domid, xc_dominfo_t *info)
|
||||
int libxl_wait_for_domain_death(struct libxl_ctx *ctx, uint32_t domid, libxl_waiter *waiter)
|
||||
{
|
||||
waiter->path = strdup("@releaseDomain");
|
||||
asprintf(&(waiter->token), "%d", DOMAIN_DEATH);
|
||||
if (!xs_watch(ctx->xsh, waiter->path, waiter->token))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libxl_wait_for_disk_ejects(struct libxl_ctx *ctx, uint32_t guest_domid, libxl_device_disk *disks, int num_disks, libxl_waiter *waiter)
|
||||
{
|
||||
int i;
|
||||
uint32_t domid = libxl_get_stubdom_id(ctx, guest_domid);
|
||||
|
||||
if (!domid)
|
||||
domid = guest_domid;
|
||||
|
||||
for (i = 0; i < num_disks; i++) {
|
||||
asprintf(&(waiter[i].path), "%s/device/vbd/%d/eject", libxl_xs_get_dompath(ctx, domid), device_disk_dev_number(disks[i].virtpath));
|
||||
asprintf(&(waiter[i].token), "%d", DISK_EJECT);
|
||||
xs_watch(ctx->xsh, waiter->path, waiter->token);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libxl_get_event(struct libxl_ctx *ctx, libxl_event *event)
|
||||
{
|
||||
unsigned int num;
|
||||
char **events = xs_read_watch(ctx->xsh, &num);
|
||||
if (num != 2) {
|
||||
free(events);
|
||||
return -1;
|
||||
}
|
||||
event->path = strdup(events[XS_WATCH_PATH]);
|
||||
event->token = strdup(events[XS_WATCH_TOKEN]);
|
||||
event->type = atoi(event->token);
|
||||
free(events);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libxl_stop_waiting(struct libxl_ctx *ctx, libxl_waiter *waiter)
|
||||
{
|
||||
if (!xs_unwatch(ctx->xsh, waiter->path, waiter->token))
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libxl_free_event(libxl_event *event)
|
||||
{
|
||||
free(event->path);
|
||||
free(event->token);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libxl_free_waiter(libxl_waiter *waiter)
|
||||
{
|
||||
free(waiter->path);
|
||||
free(waiter->token);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libxl_event_get_domain_death_info(struct libxl_ctx *ctx, uint32_t domid, libxl_event *event, xc_dominfo_t *info)
|
||||
{
|
||||
int nb_domain, i, rc = 0;
|
||||
char **vec = NULL;
|
||||
xc_dominfo_t *list = NULL;
|
||||
|
||||
vec = xs_read_watch(ctx->xsh, &num);
|
||||
if (!vec)
|
||||
return 0;
|
||||
if (!strcmp(vec[XS_WATCH_TOKEN], "domain_death")) {
|
||||
if (event && event->type == DOMAIN_DEATH) {
|
||||
list = libxl_domain_infolist(ctx, &nb_domain);
|
||||
for (i = 0; i < nb_domain; i++) {
|
||||
if (domid == list[i].domid) {
|
||||
@@ -493,13 +548,41 @@ int libxl_is_domain_dead(struct libxl_ctx *ctx, uint32_t domid, xc_dominfo_t *in
|
||||
rc = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
free(list);
|
||||
free(vec);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int libxl_event_get_disk_eject_info(struct libxl_ctx *ctx, uint32_t domid, libxl_event *event, libxl_device_disk *disk)
|
||||
{
|
||||
if (event && event->type == DISK_EJECT) {
|
||||
char *path;
|
||||
char *backend;
|
||||
char *value = libxl_xs_read(ctx, XBT_NULL, event->path);
|
||||
|
||||
if (!value || strcmp(value, "eject"))
|
||||
return 0;
|
||||
|
||||
path = strdup(event->path);
|
||||
path[strlen(path) - 6] = '\0';
|
||||
backend = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/backend", path));
|
||||
|
||||
disk->backend_domid = 0;
|
||||
disk->domid = domid;
|
||||
disk->physpath = NULL;
|
||||
disk->phystype = 0;
|
||||
/* this value is returned to the user: do not free right away */
|
||||
disk->virtpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/dev", backend));
|
||||
disk->unpluggable = 1;
|
||||
disk->readwrite = 0;
|
||||
disk->is_cdrom = 1;
|
||||
|
||||
free(path);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int libxl_destroy_device_model(struct libxl_ctx *ctx, uint32_t domid)
|
||||
{
|
||||
char *pid;
|
||||
@@ -1421,6 +1504,95 @@ int libxl_device_vkb_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid)
|
||||
return ERROR_NI;
|
||||
}
|
||||
|
||||
libxl_device_disk *libxl_device_disk_list(struct libxl_ctx *ctx, uint32_t domid, int *num)
|
||||
{
|
||||
char *be_path_tap, *be_path_vbd;
|
||||
libxl_device_disk *disks = NULL;
|
||||
char **l = NULL;
|
||||
unsigned int numl;
|
||||
int num_disks = 0, i;
|
||||
char *type;
|
||||
|
||||
be_path_vbd = libxl_sprintf(ctx, "%s/backend/vbd/%d", libxl_xs_get_dompath(ctx, 0), domid);
|
||||
be_path_tap = libxl_sprintf(ctx, "%s/backend/tap/%d", libxl_xs_get_dompath(ctx, 0), domid);
|
||||
|
||||
l = libxl_xs_directory(ctx, XBT_NULL, be_path_vbd, &numl);
|
||||
if (l) {
|
||||
num_disks += numl;
|
||||
disks = realloc(disks, sizeof(libxl_device_disk) * num_disks);
|
||||
for (i = 0; i < numl; i++) {
|
||||
disks[i].backend_domid = 0;
|
||||
disks[i].domid = domid;
|
||||
disks[i].physpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/params", be_path_vbd, l[i]));
|
||||
libxl_string_to_phystype(ctx, libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/type", be_path_vbd, l[i])), &(disks[i].phystype));
|
||||
disks[i].virtpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/dev", be_path_vbd, l[i]));
|
||||
disks[i].unpluggable = atoi(libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/removable", be_path_vbd, l[i])));
|
||||
if (!strcmp(libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/mode", be_path_vbd, l[i])), "w"))
|
||||
disks[i].readwrite = 1;
|
||||
else
|
||||
disks[i].readwrite = 0;
|
||||
type = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/device-type", libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/frontend", be_path_vbd, l[i]))));
|
||||
disks[i].is_cdrom = !strcmp(type, "cdrom");
|
||||
}
|
||||
free(l);
|
||||
}
|
||||
l = libxl_xs_directory(ctx, XBT_NULL, be_path_tap, &numl);
|
||||
if (l) {
|
||||
num_disks += numl;
|
||||
disks = realloc(disks, sizeof(libxl_device_disk) * num_disks);
|
||||
for (i = 0; i < numl; i++) {
|
||||
disks[i].backend_domid = 0;
|
||||
disks[i].domid = domid;
|
||||
disks[i].physpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/params", be_path_tap, l[i]));
|
||||
libxl_string_to_phystype(ctx, libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/type", be_path_tap, l[i])), &(disks[i].phystype));
|
||||
disks[i].virtpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/dev", be_path_tap, l[i]));
|
||||
disks[i].unpluggable = atoi(libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/removable", be_path_tap, l[i])));
|
||||
if (!strcmp(libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/mode", be_path_tap, l[i])), "w"))
|
||||
disks[i].readwrite = 1;
|
||||
else
|
||||
disks[i].readwrite = 0;
|
||||
type = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/device-type", libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/frontend", be_path_vbd, l[i]))));
|
||||
disks[i].is_cdrom = !strcmp(type, "cdrom");
|
||||
}
|
||||
free(l);
|
||||
}
|
||||
*num = num_disks;
|
||||
return disks;
|
||||
}
|
||||
|
||||
int libxl_cdrom_insert(struct libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk)
|
||||
{
|
||||
int num, i;
|
||||
uint32_t stubdomid;
|
||||
libxl_device_disk *disks;
|
||||
|
||||
if (!disk->physpath) {
|
||||
disk->physpath = "";
|
||||
disk->phystype = PHYSTYPE_PHY;
|
||||
}
|
||||
disks = libxl_device_disk_list(ctx, domid, &num);
|
||||
for (i = 0; i < num; i++) {
|
||||
if (disks[i].is_cdrom && !strcmp(disk->virtpath, disks[i].virtpath))
|
||||
/* found */
|
||||
break;
|
||||
}
|
||||
if (i == num) {
|
||||
XL_LOG(ctx, XL_LOG_ERROR, "Virtual device not found");
|
||||
return -1;
|
||||
}
|
||||
libxl_device_disk_del(ctx, disks + i, 1);
|
||||
libxl_device_disk_add(ctx, domid, disk);
|
||||
stubdomid = libxl_get_stubdom_id(ctx, domid);
|
||||
if (stubdomid) {
|
||||
disk_info_domid_fixup(disks + i, stubdomid);
|
||||
libxl_device_disk_del(ctx, disks + i, 1);
|
||||
disk_info_domid_fixup(disk, stubdomid);
|
||||
libxl_device_disk_add(ctx, stubdomid, disk);
|
||||
disk_info_domid_fixup(disk, domid);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
static int libxl_build_xenpv_qemu_args(struct libxl_ctx *ctx,
|
||||
libxl_device_vfb *vfb,
|
||||
|
||||
+36
-2
@@ -267,8 +267,40 @@ int libxl_domain_resume(struct libxl_ctx *ctx, uint32_t domid);
|
||||
int libxl_domain_shutdown(struct libxl_ctx *ctx, uint32_t domid, int req);
|
||||
int libxl_domain_destroy(struct libxl_ctx *ctx, uint32_t domid, int force);
|
||||
|
||||
int libxl_wait_for_domain_death(struct libxl_ctx *ctx, uint32_t domid, int *fd);
|
||||
int libxl_is_domain_dead(struct libxl_ctx *ctx, uint32_t domid, xc_dominfo_t *info);
|
||||
/* events handling */
|
||||
|
||||
typedef enum {
|
||||
DOMAIN_DEATH,
|
||||
DISK_EJECT,
|
||||
} libxl_event_type;
|
||||
|
||||
typedef struct {
|
||||
/* event type */
|
||||
libxl_event_type type;
|
||||
/* data for internal use of the library */
|
||||
char *path;
|
||||
char *token;
|
||||
} libxl_event;
|
||||
|
||||
typedef struct {
|
||||
char *path;
|
||||
char *token;
|
||||
} libxl_waiter;
|
||||
|
||||
|
||||
int libxl_get_wait_fd(struct libxl_ctx *ctx, int *fd);
|
||||
/* waiter is allocated by the caller */
|
||||
int libxl_wait_for_domain_death(struct libxl_ctx *ctx, uint32_t domid, libxl_waiter *waiter);
|
||||
/* waiter is a preallocated array of num_disks libxl_waiter elements */
|
||||
int libxl_wait_for_disk_ejects(struct libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disks, int num_disks, libxl_waiter *waiter);
|
||||
int libxl_get_event(struct libxl_ctx *ctx, libxl_event *event);
|
||||
int libxl_stop_waiting(struct libxl_ctx *ctx, libxl_waiter *waiter);
|
||||
int libxl_free_event(libxl_event *event);
|
||||
int libxl_free_waiter(libxl_waiter *waiter);
|
||||
|
||||
int libxl_event_get_domain_death_info(struct libxl_ctx *ctx, uint32_t domid, libxl_event *event, xc_dominfo_t *info);
|
||||
int libxl_event_get_disk_eject_info(struct libxl_ctx *ctx, uint32_t domid, libxl_event *event, libxl_device_disk *disk);
|
||||
|
||||
|
||||
int libxl_domain_pause(struct libxl_ctx *ctx, uint32_t domid);
|
||||
int libxl_domain_unpause(struct libxl_ctx *ctx, uint32_t domid);
|
||||
@@ -299,6 +331,8 @@ int libxl_detach_device_model(struct libxl_ctx *ctx,
|
||||
|
||||
int libxl_device_disk_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk);
|
||||
int libxl_device_disk_del(struct libxl_ctx *ctx, libxl_device_disk *disk, int wait);
|
||||
libxl_device_disk *libxl_device_disk_list(struct libxl_ctx *ctx, uint32_t domid, int *num);
|
||||
int libxl_cdrom_insert(struct libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk);
|
||||
|
||||
int libxl_device_nic_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic);
|
||||
int libxl_device_nic_del(struct libxl_ctx *ctx, libxl_device_nic *nic, int wait);
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "libxl.h"
|
||||
#include "libxl_internal.h"
|
||||
|
||||
char *string_of_kinds[] = {
|
||||
const char *string_of_kinds[] = {
|
||||
[DEVICE_VIF] = "vif",
|
||||
[DEVICE_VBD] = "vbd",
|
||||
[DEVICE_TAP] = "tap",
|
||||
|
||||
@@ -45,6 +45,8 @@ typedef enum {
|
||||
DEVICE_CONSOLE,
|
||||
} libxl_device_kinds;
|
||||
|
||||
extern const char *string_of_kinds[];
|
||||
|
||||
typedef struct {
|
||||
uint32_t backend_devid;
|
||||
uint32_t backend_domid;
|
||||
|
||||
@@ -214,3 +214,33 @@ int libxl_create_logfile(struct libxl_ctx *ctx, char *name, char **full_name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libxl_string_to_phystype(struct libxl_ctx *ctx, char *s, libxl_disk_phystype *phystype)
|
||||
{
|
||||
char *p;
|
||||
int rc = 0;
|
||||
|
||||
if (!strcmp(s, "phy")) {
|
||||
*phystype = PHYSTYPE_PHY;
|
||||
} else if (!strcmp(s, "file")) {
|
||||
*phystype = PHYSTYPE_FILE;
|
||||
} else if (!strcmp(s, "tap")) {
|
||||
p = strchr(s, ':');
|
||||
if (!p) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
p++;
|
||||
if (!strcmp(p, "aio")) {
|
||||
*phystype = PHYSTYPE_AIO;
|
||||
} else if (!strcmp(p, "vhd")) {
|
||||
*phystype = PHYSTYPE_VHD;
|
||||
} else if (!strcmp(p, "qcow")) {
|
||||
*phystype = PHYSTYPE_QCOW;
|
||||
} else if (!strcmp(p, "qcow2")) {
|
||||
*phystype = PHYSTYPE_QCOW2;
|
||||
}
|
||||
}
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ int libxl_param_to_domid(struct libxl_ctx *ctx, char *p, uint32_t *domid);
|
||||
int libxl_get_stubdom_id(struct libxl_ctx *ctx, int guest_domid);
|
||||
int libxl_is_stubdom(struct libxl_ctx *ctx, int domid);
|
||||
int libxl_create_logfile(struct libxl_ctx *ctx, char *name, char **full_name);
|
||||
int libxl_string_to_phystype(struct libxl_ctx *ctx, char *s, libxl_disk_phystype *phystype);
|
||||
|
||||
#endif
|
||||
|
||||
+153
-17
@@ -356,12 +356,14 @@ static void parse_config_file(const char *filename,
|
||||
if (p2 == NULL) {
|
||||
(*disks)[*num_disks].virtpath = strdup(p);
|
||||
(*disks)[*num_disks].is_cdrom = 0;
|
||||
(*disks)[*num_disks].unpluggable = 1;
|
||||
} else {
|
||||
*p2 = '\0';
|
||||
(*disks)[*num_disks].virtpath = strdup(p);
|
||||
if (!strcmp(p2 + 1, "cdrom"))
|
||||
if (!strcmp(p2 + 1, "cdrom")) {
|
||||
(*disks)[*num_disks].is_cdrom = 1;
|
||||
else
|
||||
(*disks)[*num_disks].unpluggable = 1;
|
||||
} else
|
||||
(*disks)[*num_disks].is_cdrom = 0;
|
||||
}
|
||||
p = strtok(NULL, ",");
|
||||
@@ -594,6 +596,7 @@ static void create_domain(int debug, const char *config_file, const char *restor
|
||||
int i, fd;
|
||||
int need_daemon = 1;
|
||||
libxl_device_model_starting *dm_starting = 0;
|
||||
libxl_waiter *w1 = NULL, *w2 = NULL;
|
||||
memset(&dm_info, 0x00, sizeof(dm_info));
|
||||
|
||||
printf("Parsing config file %s\n", config_file);
|
||||
@@ -671,12 +674,17 @@ start:
|
||||
need_daemon = 0;
|
||||
}
|
||||
XL_LOG(&ctx, XL_LOG_DEBUG, "Waiting for domain %s (domid %d) to die", info1.name, domid);
|
||||
|
||||
libxl_wait_for_domain_death(&ctx, domid, &fd);
|
||||
w1 = (libxl_waiter*) malloc(sizeof(libxl_waiter) * num_disks);
|
||||
w2 = (libxl_waiter*) malloc(sizeof(libxl_waiter));
|
||||
libxl_wait_for_disk_ejects(&ctx, domid, disks, num_disks, w1);
|
||||
libxl_wait_for_domain_death(&ctx, domid, w2);
|
||||
libxl_get_wait_fd(&ctx, &fd);
|
||||
while (1) {
|
||||
int ret;
|
||||
fd_set rfds;
|
||||
xc_dominfo_t info;
|
||||
libxl_event event;
|
||||
libxl_device_disk disk;
|
||||
memset(&info, 0x00, sizeof(xc_dominfo_t));
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
@@ -685,21 +693,35 @@ start:
|
||||
ret = select(fd + 1, &rfds, NULL, NULL, NULL);
|
||||
if (!ret)
|
||||
continue;
|
||||
if (libxl_is_domain_dead(&ctx, domid, &info)) {
|
||||
XL_LOG(&ctx, XL_LOG_DEBUG, "Domain %d is dead", domid);
|
||||
if (info.crashed || info.dying || (info.shutdown && (info.shutdown_reason != SHUTDOWN_suspend))) {
|
||||
XL_LOG(&ctx, XL_LOG_DEBUG, "Domain %d needs to be clean: destroying the domain", domid);
|
||||
libxl_domain_destroy(&ctx, domid, 0);
|
||||
if (info.shutdown && (info.shutdown_reason == SHUTDOWN_reboot)) {
|
||||
libxl_ctx_free(&ctx);
|
||||
XL_LOG(&ctx, XL_LOG_DEBUG, "Done. Rebooting now");
|
||||
goto start;
|
||||
libxl_get_event(&ctx, &event);
|
||||
switch (event.type) {
|
||||
case DOMAIN_DEATH:
|
||||
if (libxl_event_get_domain_death_info(&ctx, domid, &event, &info)) {
|
||||
XL_LOG(&ctx, XL_LOG_DEBUG, "Domain %d is dead", domid);
|
||||
if (info.crashed || info.dying || (info.shutdown && (info.shutdown_reason != SHUTDOWN_suspend))) {
|
||||
XL_LOG(&ctx, XL_LOG_DEBUG, "Domain %d needs to be clean: destroying the domain", domid);
|
||||
libxl_domain_destroy(&ctx, domid, 0);
|
||||
if (info.shutdown && (info.shutdown_reason == SHUTDOWN_reboot)) {
|
||||
libxl_free_waiter(w1);
|
||||
libxl_free_waiter(w2);
|
||||
free(w1);
|
||||
free(w2);
|
||||
libxl_ctx_free(&ctx);
|
||||
XL_LOG(&ctx, XL_LOG_DEBUG, "Done. Rebooting now");
|
||||
goto start;
|
||||
}
|
||||
XL_LOG(&ctx, XL_LOG_DEBUG, "Done. Exiting now");
|
||||
}
|
||||
XL_LOG(&ctx, XL_LOG_DEBUG, "Domain %d does not need to be clean, exiting now", domid);
|
||||
exit(0);
|
||||
}
|
||||
XL_LOG(&ctx, XL_LOG_DEBUG, "Done. Exiting now");
|
||||
}
|
||||
XL_LOG(&ctx, XL_LOG_DEBUG, "Domain %d does not need to be clean, exiting now", domid);
|
||||
exit(0);
|
||||
break;
|
||||
case DISK_EJECT:
|
||||
if (libxl_event_get_disk_eject_info(&ctx, domid, &event, &disk))
|
||||
libxl_cdrom_insert(&ctx, domid, &disk);
|
||||
break;
|
||||
}
|
||||
libxl_free_event(&event);
|
||||
}
|
||||
|
||||
close(logfile);
|
||||
@@ -730,6 +752,8 @@ static void help(char *command)
|
||||
printf(" console attach to domain's console\n\n");
|
||||
printf(" save save a domain state to restore later\n\n");
|
||||
printf(" restore restore a domain from a saved state\n\n");
|
||||
printf(" cd-insert insert a cdrom into a guest's cd drive\n\n");
|
||||
printf(" cd-eject eject a cdrom from a guest's cd drive\n\n");
|
||||
} else if(!strcmp(command, "create")) {
|
||||
printf("Usage: xl create <ConfigFile> [options] [vars]\n\n");
|
||||
printf("Create a domain based on <ConfigFile>.\n\n");
|
||||
@@ -772,6 +796,12 @@ static void help(char *command)
|
||||
} else if (!strcmp(command, "console")) {
|
||||
printf("Usage: xl console <Domain>\n\n");
|
||||
printf("Attach to domain's console.\n\n");
|
||||
} else if (!strcmp(command, "cd-insert")) {
|
||||
printf("Usage: xl cd-insert <Domain> <VirtualDevice> <type:path>\n\n");
|
||||
printf("Insert a cdrom into a guest's cd drive.\n\n");
|
||||
} else if (!strcmp(command, "cd-eject")) {
|
||||
printf("Usage: xl cd-eject <Domain> <VirtualDevice>\n\n");
|
||||
printf("Eject a cdrom from a guest's cd drive.\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -790,6 +820,108 @@ void console(char *p, int cons_num)
|
||||
libxl_console_attach(&ctx, domid, cons_num);
|
||||
}
|
||||
|
||||
void cd_insert(char *dom, char *virtdev, char *phys)
|
||||
{
|
||||
struct libxl_ctx ctx;
|
||||
uint32_t domid;
|
||||
libxl_device_disk disk;
|
||||
char *p;
|
||||
|
||||
libxl_ctx_init(&ctx);
|
||||
libxl_ctx_set_log(&ctx, log_callback, NULL);
|
||||
|
||||
if (libxl_param_to_domid(&ctx, dom, &domid) < 0) {
|
||||
fprintf(stderr, "%s is an invalid domain identifier\n", dom);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
disk.backend_domid = 0;
|
||||
disk.domid = domid;
|
||||
if (phys) {
|
||||
p = strchr(phys, ':');
|
||||
if (!p) {
|
||||
fprintf(stderr, "No type specified, ");
|
||||
disk.physpath = phys;
|
||||
if (!strncmp(phys, "/dev", 4)) {
|
||||
fprintf(stderr, "assuming phy:\n");
|
||||
disk.phystype = PHYSTYPE_PHY;
|
||||
} else {
|
||||
fprintf(stderr, "assuming file:\n");
|
||||
disk.phystype = PHYSTYPE_FILE;
|
||||
}
|
||||
} else {
|
||||
p = '\0';
|
||||
disk.physpath = strdup(p);
|
||||
p++;
|
||||
libxl_string_to_phystype(&ctx, p, &disk.phystype);
|
||||
}
|
||||
} else {
|
||||
disk.physpath = NULL;
|
||||
disk.phystype = 0;
|
||||
}
|
||||
disk.virtpath = virtdev;
|
||||
disk.unpluggable = 1;
|
||||
disk.readwrite = 0;
|
||||
disk.is_cdrom = 1;
|
||||
|
||||
libxl_cdrom_insert(&ctx, domid, &disk);
|
||||
}
|
||||
|
||||
int main_cd_eject(int argc, char **argv)
|
||||
{
|
||||
int opt = 0;
|
||||
char *p = NULL, *virtdev;
|
||||
|
||||
while ((opt = getopt(argc, argv, "hn:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
help("cd-eject");
|
||||
exit(0);
|
||||
default:
|
||||
fprintf(stderr, "option not supported\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (optind >= argc - 1) {
|
||||
help("cd-eject");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
p = argv[optind];
|
||||
virtdev = argv[optind + 1];
|
||||
|
||||
cd_insert(p, virtdev, NULL);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main_cd_insert(int argc, char **argv)
|
||||
{
|
||||
int opt = 0;
|
||||
char *p = NULL, *file = NULL, *virtdev;
|
||||
|
||||
while ((opt = getopt(argc, argv, "hn:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
help("cd-insert");
|
||||
exit(0);
|
||||
default:
|
||||
fprintf(stderr, "option not supported\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (optind >= argc - 2) {
|
||||
help("cd-insert");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
p = argv[optind];
|
||||
virtdev = argv[optind + 1];
|
||||
file = argv[optind + 2];
|
||||
|
||||
cd_insert(p, virtdev, file);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main_console(int argc, char **argv)
|
||||
{
|
||||
int opt = 0, cons_num = 0;
|
||||
@@ -1298,6 +1430,10 @@ int main(int argc, char **argv)
|
||||
main_save(argc - 1, argv + 1);
|
||||
} else if (!strcmp(argv[1], "restore")) {
|
||||
main_restore(argc - 1, argv + 1);
|
||||
} else if (!strcmp(argv[1], "cd-insert")) {
|
||||
main_cd_insert(argc - 1, argv + 1);
|
||||
} else if (!strcmp(argv[1], "cd-eject")) {
|
||||
main_cd_eject(argc - 1, argv + 1);
|
||||
} else if (!strcmp(argv[1], "help")) {
|
||||
if (argc > 2)
|
||||
help(argv[2]);
|
||||
|
||||