diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2018-09-27 17:15:37 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2018-09-27 17:15:37 +0000 |
commit | 459d6386c60d0185038a58bef6a2addcd2f00310 (patch) | |
tree | 674a240e43ebe49790318d225943eb23f8c1c6c8 /usr.sbin/vmctl | |
parent | 7334120249b2ef6640383f3df4f3d4dd8f0f219e (diff) |
Add vmctl stop -a [-fw] option to stop or terminate all running VMs.
This is also be used to simplify the vmd rc stop script.
OK mlarkin@ ccardenas@
Diffstat (limited to 'usr.sbin/vmctl')
-rw-r--r-- | usr.sbin/vmctl/main.c | 37 | ||||
-rw-r--r-- | usr.sbin/vmctl/vmctl.8 | 6 | ||||
-rw-r--r-- | usr.sbin/vmctl/vmctl.c | 89 | ||||
-rw-r--r-- | usr.sbin/vmctl/vmctl.h | 6 |
4 files changed, 105 insertions, 33 deletions
diff --git a/usr.sbin/vmctl/main.c b/usr.sbin/vmctl/main.c index b26afd38589..0f06a9ed1d2 100644 --- a/usr.sbin/vmctl/main.c +++ b/usr.sbin/vmctl/main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: main.c,v 1.42 2018/09/13 03:53:33 ccardenas Exp $ */ +/* $OpenBSD: main.c,v 1.43 2018/09/27 17:15:36 reyk Exp $ */ /* * Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org> @@ -66,7 +66,7 @@ struct ctl_command ctl_commands[] = { { "create", CMD_CREATE, ctl_create, "\"path\" -s size [-f fmt]", 1 }, { "load", CMD_LOAD, ctl_load, "\"path\"" }, - { "log", CMD_LOG, ctl_log, "(verbose|brief)" }, + { "log", CMD_LOG, ctl_log, "[verbose|brief]" }, { "reload", CMD_RELOAD, ctl_reload, "" }, { "reset", CMD_RESET, ctl_reset, "[all|vms|switches]" }, { "show", CMD_STATUS, ctl_status, "[id]" }, @@ -74,7 +74,7 @@ struct ctl_command ctl_commands[] = { " [-Lc] [-b image] [-r image] [-m size]\n" "\t\t[-n switch] [-i count] [-d disk]* [-t name]" }, { "status", CMD_STATUS, ctl_status, "[id]" }, - { "stop", CMD_STOP, ctl_stop, "id [-fw]" }, + { "stop", CMD_STOP, ctl_stop, "[id|-a] [-fw]" }, { "pause", CMD_PAUSE, ctl_pause, "id" }, { "unpause", CMD_UNPAUSE, ctl_unpause, "id" }, { "send", CMD_SEND, ctl_send, "id", 1}, @@ -219,10 +219,9 @@ vmmaction(struct parse_result *res) terminate_vm(res->id, res->name, res->flags); break; case CMD_STATUS: - get_info_vm(res->id, res->name, 0); - break; case CMD_CONSOLE: - get_info_vm(res->id, res->name, 1); + case CMD_STOPALL: + get_info_vm(res->id, res->name, res->action, res->flags); break; case CMD_LOAD: imsg_compose(ibuf, IMSG_VMDOP_LOAD, 0, 0, -1, @@ -302,6 +301,7 @@ vmmaction(struct parse_result *res) break; case CMD_CONSOLE: case CMD_STATUS: + case CMD_STOPALL: done = add_info(&imsg, &ret); break; case CMD_PAUSE: @@ -460,6 +460,10 @@ parse_vmid(struct parse_result *res, char *word, int needname) warnx("missing vmid argument"); return (-1); } + if (*word == '-') { + /* don't print a warning to allow command line options */ + return (-1); + } id = strtonum(word, 0, UINT32_MAX, &error); if (error == NULL) { if (needname) { @@ -707,18 +711,17 @@ ctl_start(struct parse_result *res, int argc, char *argv[]) int ctl_stop(struct parse_result *res, int argc, char *argv[]) { - int ch; + int ch, ret; if (argc < 2) ctl_usage(res->ctl); - if (parse_vmid(res, argv[1], 0) == -1) - errx(1, "invalid id: %s", argv[1]); - - argc--; - argv++; + if ((ret = parse_vmid(res, argv[1], 0)) == 0) { + argc--; + argv++; + } - while ((ch = getopt(argc, argv, "fw")) != -1) { + while ((ch = getopt(argc, argv, "afw")) != -1) { switch (ch) { case 'f': res->flags |= VMOP_FORCE; @@ -726,12 +729,20 @@ ctl_stop(struct parse_result *res, int argc, char *argv[]) case 'w': res->flags |= VMOP_WAIT; break; + case 'a': + res->action = CMD_STOPALL; + break; default: ctl_usage(res->ctl); /* NOTREACHED */ } } + /* VM id is only expected without the -a flag */ + if ((res->action != CMD_STOPALL && ret == -1) || + (res->action == CMD_STOPALL && ret != -1)) + errx(1, "invalid id: %s", argv[1]); + return (vmmaction(res)); } diff --git a/usr.sbin/vmctl/vmctl.8 b/usr.sbin/vmctl/vmctl.8 index 61011942f40..4941cde3b07 100644 --- a/usr.sbin/vmctl/vmctl.8 +++ b/usr.sbin/vmctl/vmctl.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: vmctl.8,v 1.48 2018/09/21 14:04:37 solene Exp $ +.\" $OpenBSD: vmctl.8,v 1.49 2018/09/27 17:15:36 reyk Exp $ .\" .\" Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org> .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: September 21 2018 $ +.Dd $Mdocdate: September 27 2018 $ .Dt VMCTL 8 .Os .Sh NAME @@ -197,6 +197,8 @@ Forcefully stop the VM without attempting a graceful shutdown. .It Fl w Wait until the VM has been terminated. .El +.It Cm stop Fl a Op Fl fw +Stop all running VMs. .It Cm unpause Ar id Unpause (resume from a paused state) a VM with the specified .Ar id . diff --git a/usr.sbin/vmctl/vmctl.c b/usr.sbin/vmctl/vmctl.c index 4fffa110469..355bd4d0900 100644 --- a/usr.sbin/vmctl/vmctl.c +++ b/usr.sbin/vmctl/vmctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vmctl.c,v 1.58 2018/09/16 02:43:11 millert Exp $ */ +/* $OpenBSD: vmctl.c,v 1.59 2018/09/27 17:15:36 reyk Exp $ */ /* * Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org> @@ -45,7 +45,8 @@ extern char *__progname; uint32_t info_id; char info_name[VMM_MAX_NAME_LEN]; -int info_console; +enum actions info_action; +unsigned int info_flags; /* * vm_start @@ -440,8 +441,12 @@ terminate_vm(uint32_t terminate_id, const char *name, unsigned int flags) memset(&vid, 0, sizeof(vid)); vid.vid_id = terminate_id; - if (name != NULL) + if (name != NULL) { (void)strlcpy(vid.vid_name, name, sizeof(vid.vid_name)); + fprintf(stderr, "stopping vm %s: ", name); + } else { + fprintf(stderr, "stopping vm: "); + } vid.vid_flags = flags & (VMOP_FORCE|VMOP_WAIT); @@ -482,28 +487,32 @@ terminate_vm_complete(struct imsg *imsg, int *ret, unsigned int flags) if (res) { switch (res) { case VMD_VM_STOP_INVALID: - warnx("cannot stop vm that is not running"); + fprintf(stderr, + "cannot stop vm that is not running\n"); *ret = EINVAL; break; case ENOENT: - warnx("vm not found"); + fprintf(stderr, "vm not found\n"); *ret = EIO; break; default: errno = res; - warn("terminate vm command failed"); + fprintf(stderr, "failed: %s\n", + strerror(res)); *ret = EIO; } } else if (flags & VMOP_WAIT) { - warnx("terminated vm %d", vmr->vmr_id); + fprintf(stderr, "terminated vm %d\n", vmr->vmr_id); } else if (flags & VMOP_FORCE) { - warnx("requested to terminate vm %d", vmr->vmr_id); + fprintf(stderr, "forced to terminate vm %d\n", + vmr->vmr_id); } else { - warnx("requested to shutdown vm %d", vmr->vmr_id); + fprintf(stderr, "requested to shutdown vm %d\n", + vmr->vmr_id); *ret = 0; } } else { - warnx("unexpected response received from vmd"); + fprintf(stderr, "unexpected response received from vmd\n"); *ret = EINVAL; } errno = *ret; @@ -512,6 +521,44 @@ terminate_vm_complete(struct imsg *imsg, int *ret, unsigned int flags) } /* + * terminate_all + * + * Request to stop all VMs gracefully + * + * Parameters + * list: the vm information (consolidated) returned from vmd via imsg + * ct : the size (number of elements in 'list') of the result + * flags: VMOP_FORCE or VMOP_WAIT flags + */ +void +terminate_all(struct vmop_info_result *list, size_t ct, unsigned int flags) +{ + struct vm_info_result *vir; + struct vmop_info_result *vmi; + struct parse_result res; + size_t i; + + for (i = 0; i < ct; i++) { + vmi = &list[i]; + vir = &vmi->vir_info; + + /* The VM is already stopped */ + if (vir->vir_creator_pid == 0 || vir->vir_id == 0) + continue; + + memset(&res, 0, sizeof(res)); + res.action = CMD_STOP; + res.id = 0; + res.flags = info_flags; + + if ((res.name = strdup(vir->vir_name)) == NULL) + errx(1, "strdup"); + + vmmaction(&res); + } +} + +/* * get_info_vm * * Return the list of all running VMs or find a specific VM by ID or name. @@ -519,17 +566,20 @@ terminate_vm_complete(struct imsg *imsg, int *ret, unsigned int flags) * Parameters: * id: optional ID of a VM to list * name: optional name of a VM to list - * console: if true, open the console of the selected VM (by name or ID) + * action: if CMD_CONSOLE or CMD_STOP open a console or terminate the VM. + * flags: optional flags used by the CMD_STOP action. * * Request a list of running VMs from vmd */ void -get_info_vm(uint32_t id, const char *name, int console) +get_info_vm(uint32_t id, const char *name, enum actions action, + unsigned int flags) { info_id = id; if (name != NULL) (void)strlcpy(info_name, name, sizeof(info_name)); - info_console = console; + info_action = action; + info_flags = flags; imsg_compose(ibuf, IMSG_VMDOP_GET_INFO_VM_REQUEST, 0, 0, -1, NULL, 0); } @@ -574,7 +624,7 @@ check_info_id(const char *name, uint32_t id) * to the "list vm" data. The caller should check the value of * 'ret' to determine which case occurred. * - * This function does not return if a VM is found and info_console is set. + * This function does not return if a VM is found and info_action is CMD_CONSOLE * * The function also sets 'ret' to the error code as follows: * 0 : Message successfully processed @@ -599,10 +649,17 @@ add_info(struct imsg *imsg, int *ret) *ret = 0; return (0); } else if (imsg->hdr.type == IMSG_VMDOP_GET_INFO_VM_END_DATA) { - if (info_console) + switch (info_action) { + case CMD_CONSOLE: vm_console(vir, ct); - else + break; + case CMD_STOPALL: + terminate_all(vir, ct, info_flags); + break; + default: print_vm_info(vir, ct); + break; + } free(vir); *ret = 0; return (1); diff --git a/usr.sbin/vmctl/vmctl.h b/usr.sbin/vmctl/vmctl.h index 593108f1f70..27e094c26de 100644 --- a/usr.sbin/vmctl/vmctl.h +++ b/usr.sbin/vmctl/vmctl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vmctl.h,v 1.23 2018/09/11 04:03:16 ccardenas Exp $ */ +/* $OpenBSD: vmctl.h,v 1.24 2018/09/27 17:15:36 reyk Exp $ */ /* * Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org> @@ -32,6 +32,7 @@ enum actions { CMD_START, CMD_STATUS, CMD_STOP, + CMD_STOPALL, CMD_PAUSE, CMD_UNPAUSE, CMD_SEND, @@ -100,9 +101,10 @@ void send_vm(uint32_t, const char *); void vm_receive(uint32_t, const char *); int receive_vm_complete(struct imsg *, int *); int check_info_id(const char *, uint32_t); -void get_info_vm(uint32_t, const char *, int); +void get_info_vm(uint32_t, const char *, enum actions, unsigned int); int add_info(struct imsg *, int *); void print_vm_info(struct vmop_info_result *, size_t); +void terminate_all(struct vmop_info_result *, size_t, unsigned int); __dead void vm_console(struct vmop_info_result *, size_t); |