diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c index 1627cac..b900811 100644 --- a/tools/libxl/xl_cmdimpl.c +++ b/tools/libxl/xl_cmdimpl.c @@ -2686,63 +2686,94 @@ static void destroy_domain(uint32_t domid) if (rc) { fprintf(stderr,"destroy failed (rc=%d)\n",rc); exit(-1); } } -static void shutdown_domain(uint32_t domid, int wait_for_it, - int fallback_trigger) +static int shutdown_domain(const libxl_dominfo *dominfo, int nb_domain, + int wait_for_it, int fallback_trigger) { - int rc; - libxl_event *event; + int i, rc, nb_shutdown_pending; + int ret = 0; + libxl_evgen_domain_death *domains_wait_shutdown[nb_domain]; + + for (i = 0; i < nb_domain; i++) { + uint32_t domid = dominfo[i].domid; + if(!libxl_domid_valid_guest(domid)) + continue; - rc=libxl_domain_shutdown(ctx, domid); - if (rc == ERROR_NOPARAVIRT) { - if (fallback_trigger) { - fprintf(stderr, "PV control interface not available:" - " sending ACPI power button event.\n"); - rc = libxl_send_trigger(ctx, domid, LIBXL_TRIGGER_POWER, 0); - } else { - fprintf(stderr, "PV control interface not available:" - " external graceful shutdown not possible.\n"); - fprintf(stderr, "Use \"-F\" to fallback to ACPI power event.\n"); + rc = libxl_domain_shutdown(ctx, domid); + + if (rc == ERROR_NOPARAVIRT) { + if (fallback_trigger) { + fprintf(stderr, "PV control interface not available:" + " sending ACPI power button event.\n"); + rc = libxl_send_trigger(ctx, domid, LIBXL_TRIGGER_POWER, 0); + } else { + fprintf(stderr, "PV control interface not available:" + " external graceful shutdown not possible.\n"); + fprintf(stderr, + "Use \"-F\" to fallback to ACPI power event.\n"); + } + } + + if (rc) { + fprintf(stderr,"shutdown of domain %d failed (rc=%d)\n", domid, rc); + ret = -1; + continue; + } + + if (wait_for_it) { + rc = libxl_evenable_domain_death(ctx, domid, 0, &domains_wait_shutdown[i]); + if (rc) { + fprintf(stderr,"wait for death of domain %d failed" + " (evgen, rc=%d)\n", domid, rc); + ret = -1; + } else { + nb_shutdown_pending++; + } } - } - if (rc) { - fprintf(stderr,"shutdown failed (rc=%d)\n",rc);exit(-1); } if (wait_for_it) { - libxl_evgen_domain_death *deathw; + while (nb_shutdown_pending > 0) { + libxl_event *event; + rc = libxl_event_wait(ctx, &event, LIBXL_EVENTMASK_ALL, 0,0); + if (rc) { + LOG("Failed to get event (rc=%d)", rc); + return -1; + } - rc = libxl_evenable_domain_death(ctx, domid, 0, &deathw); - if (rc) { - fprintf(stderr,"wait for death failed (evgen, rc=%d)\n",rc); - exit(-1); - } + uint32_t event_domid = event->domid; + switch (event->type) { - for (;;) { - rc = domain_wait_event(domid, &event); - if (rc) exit(-1); + case LIBXL_EVENT_TYPE_DOMAIN_DEATH: + LOG("Domain %d has been destroyed", event_domid); + break; - switch (event->type) { + case LIBXL_EVENT_TYPE_DOMAIN_SHUTDOWN: + LOG("Domain %d has been shut down, reason code %d %x", + event_domid, + event->u.domain_shutdown.shutdown_reason, + event->u.domain_shutdown.shutdown_reason); + break; - case LIBXL_EVENT_TYPE_DOMAIN_DEATH: - LOG("Domain %d has been destroyed", domid); - goto done; + default: + continue; + break; + } - case LIBXL_EVENT_TYPE_DOMAIN_SHUTDOWN: - LOG("Domain %d has been shut down, reason code %d %x", domid, - event->u.domain_shutdown.shutdown_reason, - event->u.domain_shutdown.shutdown_reason); - goto done; + for (i = 0; i < nb_domain; i++) { + if (!domains_wait_shutdown[i]) + continue; - default: - LOG("Unexpected event type %d", event->type); - break; + if (domains_wait_shutdown[i]->domid == event_domid){ + libxl_evdisable_domain_death(ctx, domains_wait_shutdown[i]); + domains_wait_shutdown[i] = NULL; + nb_shutdown_pending--; + } } libxl_event_free(ctx, event); } - done: - libxl_event_free(ctx, event); - libxl_evdisable_domain_death(ctx, deathw); } + + return ret; } static void reboot_domain(uint32_t domid, int fallback_trigger) @@ -3676,14 +3707,27 @@ int main_destroy(int argc, char **argv) int main_shutdown(int argc, char **argv) { + libxl_dominfo dominfo_buf; + libxl_dominfo *dominfo, *dominfo_free = NULL; + int nb_domain, rc; int opt; + int option_index = 0; + int all = 0; int wait_for_it = 0; int fallback_trigger = 0; + static struct option long_options[] = { + {"all", 0, 0, 'a'}, + {"wait", 0, 0, 'w'}, + {0, 0, 0, 0} + }; - while ((opt = def_getopt(argc, argv, "wF", "shutdown", 1)) != -1) { + while ((opt = getopt_long(argc, argv, "awF", long_options, &option_index)) != -1) { switch (opt) { case 0: case 2: return opt; + case 'a': + all = 1; + break; case 'w': wait_for_it = 1; break; @@ -3693,8 +3737,48 @@ int main_shutdown(int argc, char **argv) } } - shutdown_domain(find_domain(argv[optind]), wait_for_it, fallback_trigger); - return 0; + if (!argv[optind] && !all) { + fprintf(stderr, "You must specify -a or a valid domain id.\n\n"); + return opt; + } + + if (all) { + dominfo = libxl_list_domain(ctx, &nb_domain); + if (!dominfo) { + fprintf(stderr, "libxl_domain_infolist failed.\n"); + return -1; + } + dominfo_free = dominfo; + } else { + uint32_t domid = find_domain(argv[optind]); + if (domid == 0) { + fprintf(stderr, "Error: Domain-0 can't be shutdown by this command\n"); + return -1; + } + + rc = libxl_domain_info(ctx, &dominfo_buf, domid); + + if (rc == ERROR_INVAL) { + fprintf(stderr, "Error: Domain \'%s\' does not exist.\n", + argv[optind]); + return -rc; + } + if (rc) { + fprintf(stderr, "libxl_domain_info failed (code %d).\n", rc); + return -rc; + } + dominfo = &dominfo_buf; + nb_domain = 1; + } + + rc = shutdown_domain(dominfo, nb_domain, wait_for_it, fallback_trigger); + + if (dominfo_free) + libxl_dominfo_list_free(dominfo_free, nb_domain); + else + libxl_dominfo_dispose(dominfo); + + return -rc; } int main_reboot(int argc, char **argv)