diff options
Diffstat (limited to 'examples/c/domain/suspend.c')
-rw-r--r-- | examples/c/domain/suspend.c | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/examples/c/domain/suspend.c b/examples/c/domain/suspend.c new file mode 100644 index 0000000000..af61129ecc --- /dev/null +++ b/examples/c/domain/suspend.c @@ -0,0 +1,289 @@ +/* + * suspend.c: Demo program showing how to suspend a domain + * + * Copyright (C) 2006-2013 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + */ + +#include <errno.h> +#include <getopt.h> +#include <libvirt/libvirt.h> +#include <libvirt/virterror.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static int debug; + +/* On mingw, there's a header file that poisons the well: + * + * + * CC domtop.o + *domtop.c:40:0: warning: "ERROR" redefined [enabled by default] + * #define ERROR(...) \ + * ^ + *In file included from /usr/i686-w64-mingw32/sys-root/mingw/include/windows.h:71:0, + * from /usr/i686-w64-mingw32/sys-root/mingw/include/winsock2.h:23, + * from ../../gnulib/lib/unistd.h:48, + * from domtop.c:35: + * /usr/i686-w64-mingw32/sys-root/mingw/include/wingdi.h:75:0: note: this is the location of the previous definition + * #define ERROR 0 + */ +#undef ERROR +#define ERROR(...) \ +do { \ + fprintf(stderr, "ERROR %s:%d : ", __FUNCTION__, __LINE__); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ +} while (0) + +#define DEBUG(...) \ +do { \ + if (!debug) \ + break; \ + fprintf(stderr, "DEBUG %s:%d : ", __FUNCTION__, __LINE__); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ +} while (0) + +static void +print_usage(const char *progname) +{ + const char *unified_progname; + + if (!(unified_progname = strrchr(progname, '/'))) + unified_progname = progname; + else + unified_progname++; + + printf("\n%s [options] [domain name]\n\n" + " options:\n" + " -d | --debug enable debug printings\n" + " -h | --help print this help\n" + " -c | --connect=URI hypervisor connection URI\n" + " -s | --seconds=X suspend domain for X seconds (default 1)\n", + unified_progname); +} + +static int +parse_argv(int argc, char *argv[], + const char **uri, + const char **dom_name, + unsigned int *seconds) +{ + int ret = -1; + int arg; + unsigned long val; + char *p; + struct option opt[] = { + {"debug", no_argument, NULL, 'd'}, + {"help", no_argument, NULL, 'h'}, + {"connect", required_argument, NULL, 'c'}, + {"seconds", required_argument, NULL, 's'}, + {NULL, 0, NULL, 0} + }; + + while ((arg = getopt_long(argc, argv, "+:dhc:s:", opt, NULL)) != -1) { + switch (arg) { + case 'd': + debug = 1; + break; + case 'h': + print_usage(argv[0]); + exit(EXIT_SUCCESS); + break; + case 'c': + *uri = optarg; + break; + case 's': + /* strtoul man page suggest clearing errno prior to call */ + errno = 0; + val = strtoul(optarg, &p, 10); + if (errno || *p || p == optarg) { + ERROR("Invalid number: '%s'", optarg); + goto cleanup; + } + *seconds = val; + if (*seconds != val) { + ERROR("Integer overflow: %ld", val); + goto cleanup; + } + break; + case ':': + ERROR("option '-%c' requires an argument", optopt); + exit(EXIT_FAILURE); + case '?': + if (optopt) + ERROR("unsupported option '-%c'. See --help.", optopt); + else + ERROR("unsupported option '%s'. See --help.", argv[optind - 1]); + exit(EXIT_FAILURE); + default: + ERROR("unknown option"); + exit(EXIT_FAILURE); + } + } + + if (argc > optind) + *dom_name = argv[optind]; + + ret = 0; + cleanup: + return ret; +} + +static int +fetch_domains(virConnectPtr conn) +{ + int num_domains, ret = -1; + virDomainPtr *domains = NULL; + ssize_t i; + const int list_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE; + + DEBUG("Fetching list of running domains"); + num_domains = virConnectListAllDomains(conn, &domains, list_flags); + + DEBUG("num_domains=%d", num_domains); + if (num_domains < 0) { + ERROR("Unable to fetch list of running domains"); + goto cleanup; + } + + printf("Running domains:\n"); + printf("----------------\n"); + for (i = 0; i < num_domains; i++) { + virDomainPtr dom = domains[i]; + const char *dom_name = virDomainGetName(dom); + printf("%s\n", dom_name); + virDomainFree(dom); + } + + ret = 0; + cleanup: + free(domains); + return ret; +} + +static int +suspend_and_resume(virConnectPtr conn, + const char *dom_name, + unsigned int seconds) +{ + int ret = -1; + virDomainPtr dom; + virDomainInfo dom_info; + + if (!(dom = virDomainLookupByName(conn, dom_name))) { + ERROR("Unable to find domain '%s'", dom_name); + goto cleanup; + } + + if (virDomainGetInfo(dom, &dom_info) < 0) { + ERROR("Unable to get domain info"); + goto cleanup; + } + + DEBUG("Domain state %d", dom_info.state); + + switch (dom_info.state) { + case VIR_DOMAIN_NOSTATE: + case VIR_DOMAIN_RUNNING: + case VIR_DOMAIN_BLOCKED: + /* In these states the domain can be suspended */ + DEBUG("Suspending domain"); + if (virDomainSuspend(dom) < 0) { + ERROR("Unable to suspend domain"); + goto cleanup; + } + + DEBUG("Domain suspended. Entering sleep for %u seconds.", seconds); + sleep(seconds); + DEBUG("Sleeping done. Resuming the domain."); + + if (virDomainResume(dom) < 0) { + ERROR("Unable to resume domain"); + goto cleanup; + } + break; + + default: + /* In all other states domain can't be suspended */ + ERROR("Domain is not in a state where it can be suspended: %d", + dom_info.state); + goto cleanup; + } + + ret = 0; + cleanup: + if (dom) + virDomainFree(dom); + return ret; +} + +int +main(int argc, char *argv[]) +{ + int ret = EXIT_FAILURE; + virConnectPtr conn = NULL; + const char *uri = NULL; + const char *dom_name = NULL; + unsigned int seconds = 1; /* Suspend domain for this long */ + const int connect_flags = 0; /* No connect flags for now */ + + if (parse_argv(argc, argv, &uri, &dom_name, &seconds) < 0) + goto cleanup; + + DEBUG("Proceeding with uri=%s dom_name=%s seconds=%u", + uri, dom_name, seconds); + + if (!(conn = virConnectOpenAuth(uri, + virConnectAuthPtrDefault, + connect_flags))) { + ERROR("Failed to connect to hypervisor"); + goto cleanup; + } + + DEBUG("Successfully connected"); + + if (!dom_name) { + if (fetch_domains(conn) == 0) + ret = EXIT_SUCCESS; + goto cleanup; + } + + if (suspend_and_resume(conn, dom_name, seconds) < 0) + goto cleanup; + + ret = EXIT_SUCCESS; + cleanup: + if (conn) { + int tmp; + tmp = virConnectClose(conn); + if (tmp < 0) { + ERROR("Failed to disconnect from the hypervisor"); + ret = EXIT_FAILURE; + } else if (tmp > 0) { + ERROR("One or more references were leaked after " + "disconnect from the hypervisor"); + ret = EXIT_FAILURE; + } else { + DEBUG("Connection successfully closed"); + } + } + return ret; +} |