[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] libxenlight: implement cdrom insert/eject
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1260258472 0 # Node ID 91555131e235f814e68179dc5ffd6b698be882be # Parent d988dd0f05f24ad3c5b1f6b84b28b8b3e93f6005 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@xxxxxxxxxxxxx> --- tools/libxl/libxl.c | 202 +++++++++++++++++++++++++++++++++++++++---- tools/libxl/libxl.h | 38 +++++++- tools/libxl/libxl_device.c | 2 tools/libxl/libxl_internal.h | 2 tools/libxl/libxl_utils.c | 30 ++++++ tools/libxl/libxl_utils.h | 1 tools/libxl/xl.c | 172 ++++++++++++++++++++++++++++++++---- 7 files changed, 411 insertions(+), 36 deletions(-) diff -r d988dd0f05f2 -r 91555131e235 tools/libxl/libxl.c --- a/tools/libxl/libxl.c Tue Dec 08 07:45:15 2009 +0000 +++ b/tools/libxl/libxl.c Tue Dec 08 07:47:52 2009 +0000 @@ -460,25 +460,80 @@ int libxl_domain_shutdown(struct libxl_c return 0; } -int libxl_wait_for_domain_death(struct libxl_ctx *ctx, uint32_t domid, int *fd) -{ - if (!xs_watch(ctx->xsh, "@releaseDomain", "domain_death")) +int libxl_get_wait_fd(struct libxl_ctx *ctx, int *fd) +{ + *fd = xs_fileno(ctx->xsh); + return 0; +} + +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; - *fd = xs_fileno(ctx->xsh); - return 0; -} - -int libxl_is_domain_dead(struct libxl_ctx *ctx, uint32_t domid, xc_dominfo_t *info) + 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,11 +548,39 @@ int libxl_is_domain_dead(struct libxl_ct 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) @@ -1419,6 +1502,95 @@ int libxl_device_vkb_hard_shutdown(struc 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; } /******************************************************************************/ diff -r d988dd0f05f2 -r 91555131e235 tools/libxl/libxl.h --- a/tools/libxl/libxl.h Tue Dec 08 07:45:15 2009 +0000 +++ b/tools/libxl/libxl.h Tue Dec 08 07:47:52 2009 +0000 @@ -267,8 +267,40 @@ int libxl_domain_shutdown(struct libxl_c 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 lib 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); diff -r d988dd0f05f2 -r 91555131e235 tools/libxl/libxl_device.c --- a/tools/libxl/libxl_device.c Tue Dec 08 07:45:15 2009 +0000 +++ b/tools/libxl/libxl_device.c Tue Dec 08 07:47:52 2009 +0000 @@ -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", diff -r d988dd0f05f2 -r 91555131e235 tools/libxl/libxl_internal.h --- a/tools/libxl/libxl_internal.h Tue Dec 08 07:45:15 2009 +0000 +++ b/tools/libxl/libxl_internal.h Tue Dec 08 07:47:52 2009 +0000 @@ -44,6 +44,8 @@ typedef enum { DEVICE_VKBD, DEVICE_CONSOLE, } libxl_device_kinds; + +extern const char *string_of_kinds[]; typedef struct { uint32_t backend_devid; diff -r d988dd0f05f2 -r 91555131e235 tools/libxl/libxl_utils.c --- a/tools/libxl/libxl_utils.c Tue Dec 08 07:45:15 2009 +0000 +++ b/tools/libxl/libxl_utils.c Tue Dec 08 07:47:52 2009 +0000 @@ -214,3 +214,33 @@ int libxl_create_logfile(struct libxl_ct 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; +} + diff -r d988dd0f05f2 -r 91555131e235 tools/libxl/libxl_utils.h --- a/tools/libxl/libxl_utils.h Tue Dec 08 07:45:15 2009 +0000 +++ b/tools/libxl/libxl_utils.h Tue Dec 08 07:47:52 2009 +0000 @@ -32,6 +32,7 @@ int libxl_get_stubdom_id(struct libxl_ct 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 diff -r d988dd0f05f2 -r 91555131e235 tools/libxl/xl.c --- a/tools/libxl/xl.c Tue Dec 08 07:45:15 2009 +0000 +++ b/tools/libxl/xl.c Tue Dec 08 07:47:52 2009 +0000 @@ -356,12 +356,14 @@ static void parse_config_file(const char 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, con 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"); } } @@ -788,6 +818,108 @@ void console(char *p, int cons_num) exit(2); } 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) @@ -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]); _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |