summaryrefslogtreecommitdiff
path: root/usr.sbin/vmctl
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2018-09-27 17:15:37 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2018-09-27 17:15:37 +0000
commit459d6386c60d0185038a58bef6a2addcd2f00310 (patch)
tree674a240e43ebe49790318d225943eb23f8c1c6c8 /usr.sbin/vmctl
parent7334120249b2ef6640383f3df4f3d4dd8f0f219e (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.c37
-rw-r--r--usr.sbin/vmctl/vmctl.86
-rw-r--r--usr.sbin/vmctl/vmctl.c89
-rw-r--r--usr.sbin/vmctl/vmctl.h6
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);