diff --git a/tools/acrn-manager/Makefile b/tools/acrn-manager/Makefile index cfdb0b1a8..0657beb84 100644 --- a/tools/acrn-manager/Makefile +++ b/tools/acrn-manager/Makefile @@ -9,8 +9,8 @@ $(OUT_DIR)/libacrn-mngr.a: acrn_mngr.c acrn_mngr.h ar -cr $@ $(OUT_DIR)/acrn_mngr.o cp ./acrn_mngr.h $(OUT_DIR)/ -$(OUT_DIR)/acrnctl: acrnctl.c - $(CC) -o $(OUT_DIR)/acrnctl acrnctl.c -I../../devicemodel/include -Wall -g +$(OUT_DIR)/acrnctl: acrnctl.c acrn_mngr.h + $(CC) -o $(OUT_DIR)/acrnctl acrnctl.c acrn_vm_ops.c -I../../devicemodel/include -L$(TOOLS_OUT) -lacrn-mngr -lpthread -Wall -g .PHONY: clean clean: diff --git a/tools/acrn-manager/acrn_vm_ops.c b/tools/acrn-manager/acrn_vm_ops.c new file mode 100644 index 000000000..68403b850 --- /dev/null +++ b/tools/acrn-manager/acrn_vm_ops.c @@ -0,0 +1,192 @@ +/** + * Copyright (C) 2018 Intel Corporation + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include "acrnctl.h" +#include "acrn_mngr.h" + +/* List head of all vm */ +static LIST_HEAD(vmmngr_list_struct, vmmngr_struct) vmmngr_head; + +static struct vmmngr_struct *vmmngr_list_add(char *name) +{ + struct vmmngr_struct *s; + + s = calloc(1, sizeof(struct vmmngr_struct)); + if (!s) { + perror("alloc vmmngr_struct"); + return NULL; + } + + strncpy(s->name, name, MAX_NAME_LEN - 1); + LIST_INSERT_HEAD(&vmmngr_head, s, list); + + return s; +} + +struct vmmngr_struct *vmmngr_find(char *name) +{ + struct vmmngr_struct *s; + + LIST_FOREACH(s, &vmmngr_head, list) + if (!strcmp(name, s->name)) + return s; + return NULL; +} + +void get_vm_list(void) +{ + char cmd[128] = { }; + char cmd_out[256] = { }; + char *vmname; + char *pvmname = NULL; + struct vmmngr_struct *s; + size_t len = sizeof(cmd_out); + + snprintf(cmd, sizeof(cmd), + "find %s/add/ -name \"*.sh\" | " + "sed \"s/\\/opt\\/acrn\\/conf\\/add\\///g\" | " + "sed \"s/.sh//g\"", ACRNCTL_OPT_ROOT); + shell_cmd(cmd, cmd_out, sizeof(cmd_out)); + + /* Properly null-terminate cmd_out */ + cmd_out[len - 1] = '\0'; + + vmname = strtok_r(cmd_out, "\n", &pvmname); + while (vmname) { + s = vmmngr_list_add(vmname); + if (!s) + continue; + s->state = VM_CREATED; + vmname = strtok_r(NULL, "\n", &pvmname); + } + + pvmname = NULL; + + snprintf(cmd, sizeof(cmd), + "find %s/ -name \"*monitor.*.socket\" | " + "sed \"s/\\/run\\/acrn\\/mngr\\///g\" | " + "awk -F. \'{ print $1 }\'", ACRN_DM_SOCK_ROOT); + shell_cmd(cmd, cmd_out, sizeof(cmd_out)); + + /* Properly null-terminate cmd_out */ + cmd_out[len - 1] = '\0'; + + vmname = strtok_r(cmd_out, "\n", &pvmname); + while (vmname) { + s = vmmngr_find(vmname); + if (s) + s->state = VM_STARTED; + else { + s = vmmngr_list_add(vmname); + if (s) + s->state = VM_UNTRACKED; + } + vmname = strtok_r(NULL, "\n", &pvmname); + } +} + +/* helper functions */ +int shell_cmd(const char *cmd, char *outbuf, int len) +{ + FILE *ptr; + char cmd_buf[256]; + int ret; + + if (!outbuf) + return system(cmd); + + memset(cmd_buf, 0, sizeof(cmd_buf)); + memset(outbuf, 0, len); + snprintf(cmd_buf, sizeof(cmd_buf), "%s 2>&1", cmd); + ptr = popen(cmd_buf, "re"); + if (!ptr) + return -1; + + ret = fread(outbuf, 1, len, ptr); + pclose(ptr); + + return ret; +} + +static int send_msg(char *vmname, struct mngr_msg *req, + struct mngr_msg *ack, size_t ack_len) +{ + int fd, ret; + + if (!vmname) { + printf("No vmname provided\n"); + return -EINVAL; + } + + fd = mngr_open_un(vmname, MNGR_CLIENT); + if (fd < 0) { + printf("%s: Unable to open %s. line %d\n", __FUNCTION__, + vmname, __LINE__); + return -1; + } + + ret = mngr_send_msg(fd, req, ack, ack_len, 1); + if (ret < 0) { + printf("%s: Unable to send msg\n", __FUNCTION__); + mngr_close(fd); + return ret; + } + + mngr_close(fd); + + return 0; +} + +int list_vm() +{ + struct vmmngr_struct *s; + int find = 0; + + LIST_FOREACH(s, &vmmngr_head, list) { + printf("%s\t\t%s\n", s->name, state_str[s->state]); + find++; + } + + if (!find) + printf("There are no VMs\n"); + + return 0; +} + +int start_vm(char *vmname) +{ + char cmd[128]; + + snprintf(cmd, sizeof(cmd), "bash %s/add/%s.sh $(cat %s/add/%s.args)", + ACRNCTL_OPT_ROOT, vmname, ACRNCTL_OPT_ROOT, vmname); + + return system(cmd); +} + +int stop_vm(char *vmname) +{ + struct req_dm_stop req; + struct ack_dm_stop ack; + + req.msg.magic = MNGR_MSG_MAGIC; + req.msg.msgid = DM_STOP; + req.msg.timestamp = time(NULL); + req.msg.len = sizeof(req); + + send_msg(vmname, (struct mngr_msg *)&req, + (struct mngr_msg *)&ack, sizeof(ack)); + if (ack.err) { + printf("Error happens when try to stop vm. errno(%d)\n", + ack.err); + } + + return ack.err; +} diff --git a/tools/acrn-manager/acrnctl.c b/tools/acrn-manager/acrnctl.c index 78a3b8d6e..01d203e33 100644 --- a/tools/acrn-manager/acrnctl.c +++ b/tools/acrn-manager/acrnctl.c @@ -19,9 +19,9 @@ #include #include #include "acrn_mngr.h" +#include "acrnctl.h" #define ACRNCTL_OPT_ROOT "/opt/acrn/conf" -#define MAX_NAME_LEN (128) #define ACMD(CMD,FUNC,DESC, VALID_ARGS) \ {.cmd = CMD, .func = FUNC, .desc = DESC, .valid_args = VALID_ARGS} @@ -41,166 +41,12 @@ struct acrnctl_cmd { int (*valid_args) (struct acrnctl_cmd * cmd, int argc, char *argv[]); }; -/* helper functions */ -static int shell_cmd(const char *cmd, char *outbuf, int len) -{ - FILE *ptr; - char cmd_buf[256]; - int ret; - - if (!outbuf) - return system(cmd); - - memset(cmd_buf, 0, sizeof(cmd_buf)); - memset(outbuf, 0, len); - snprintf(cmd_buf, sizeof(cmd_buf), "%s 2>&1", cmd); - ptr = popen(cmd_buf, "re"); - if (!ptr) - return -1; - - ret = fread(outbuf, 1, len, ptr); - pclose(ptr); - - return ret; -} - -static void process_msg(struct mngr_msg *msg) -{ - if (msg->len < sizeof(*msg)) - return; - - switch (msg->msgid) { - case MSG_STR: - printf("%s\n", msg->payload); - break; - default: - printf("Unknown msgid(%d) received\n", msg->msgid); - } -} - -/* vm states data and helper functions */ - -#define ACRN_DM_SOCK_ROOT "/run/acrn/mngr" - -struct vmm_struct { - char name[MAX_NAME_LEN]; - unsigned long state; - LIST_ENTRY(vmm_struct) list; -}; - -enum vm_state { - VM_STATE_UNKNOWN = 0, - VM_CREATED, /* VM created / awaiting start (boot) */ - VM_STARTED, /* VM started (booted) */ - VM_PAUSED, /* VM paused */ - VM_UNTRACKED, /* VM not created by acrnctl, or its launch script can change vm name */ -}; - -static const char *state_str[] = { - [VM_STATE_UNKNOWN] = "unknown", - [VM_CREATED] = "stopped", - [VM_STARTED] = "started", - [VM_PAUSED] = "paused", - [VM_UNTRACKED] = "untracked", -}; - -static LIST_HEAD(vmm_list_struct, vmm_struct) vmm_head; - -static struct vmm_struct *vmm_list_add(char *name) -{ - struct vmm_struct *s; - - s = calloc(1, sizeof(struct vmm_struct)); - if (!s) { - perror("alloc vmm_struct"); - return NULL; - } - - strncpy(s->name, name, MAX_NAME_LEN - 1); - LIST_INSERT_HEAD(&vmm_head, s, list); - - return s; -} - -static struct vmm_struct *vmm_find(char *name) -{ - struct vmm_struct *s; - - LIST_FOREACH(s, &vmm_head, list) - if (!strcmp(name, s->name)) - return s; - return NULL; -} - -static void vmm_update(void) -{ - char cmd[128] = { }; - char cmd_out[256] = { }; - char *vmname; - char *pvmname = NULL; - struct vmm_struct *s; - size_t len = sizeof(cmd_out); - - snprintf(cmd, sizeof(cmd), - "find %s/add/ -name \"*.sh\" | " - "sed \"s/\\/opt\\/acrn\\/conf\\/add\\///g\" | " - "sed \"s/.sh//g\"", ACRNCTL_OPT_ROOT); - shell_cmd(cmd, cmd_out, sizeof(cmd_out)); - - /* Properly null-terminate cmd_out */ - cmd_out[len - 1] = '\0'; - - vmname = strtok_r(cmd_out, "\n", &pvmname); - while (vmname) { - s = vmm_list_add(vmname); - if (!s) - continue; - s->state = VM_CREATED; - vmname = strtok_r(NULL, "\n", &pvmname); - } - - pvmname = NULL; - - snprintf(cmd, sizeof(cmd), - "find %s/ -name \"*monitor.*.socket\" | " - "sed \"s/\\/run\\/acrn\\/mngr\\///g\" | " - "awk -F. \'{ print $1 }\'", ACRN_DM_SOCK_ROOT); - shell_cmd(cmd, cmd_out, sizeof(cmd_out)); - - /* Properly null-terminate cmd_out */ - cmd_out[len - 1] = '\0'; - - vmname = strtok_r(cmd_out, "\n", &pvmname); - while (vmname) { - s = vmm_find(vmname); - if (s) - s->state = VM_STARTED; - else { - s = vmm_list_add(vmname); - if (s) - s->state = VM_UNTRACKED; - } - vmname = strtok_r(NULL, "\n", &pvmname); - } -} - /* There are acrnctl cmds */ /* command: list */ static int acrnctl_do_list(int argc, char *argv[]) { - struct vmm_struct *s; - int find = 0; - - vmm_update(); - LIST_FOREACH(s, &vmm_head, list) { - printf("%s\t\t%s\n", s->name, state_str[s->state]); - find++; - } - - if (!find) - printf("There are no VMs\n"); - - return 0; + get_vm_list(); + return list_vm(); } static int check_name(const char *name) @@ -283,7 +129,7 @@ static int write_tmp_file(int fd, int n, char *word[]) static int acrnctl_do_add(int argc, char *argv[]) { - struct vmm_struct *s; + struct vmmngr_struct *s; int fd, fd_tmp, ret = 0; char *buf; char *word[MAX_WORD], *line; @@ -419,8 +265,8 @@ static int acrnctl_do_add(int argc, char *argv[]) snprintf(cmd, sizeof(cmd), "mkdir -p %s/add", ACRNCTL_OPT_ROOT); system(cmd); - vmm_update(); - s = vmm_find(vmname); + get_vm_list(); + s = vmmngr_find(vmname); if (s) { printf("%s(%s) already exist, can't add %s%s\n", vmname, state_str[s->state], argv[1], args); @@ -462,78 +308,14 @@ static int acrnctl_do_add(int argc, char *argv[]) return ret; } -/* command: stop */ -static int send_stop_msg(char *vmname) -{ - int fd, ret; - struct sockaddr_un addr; - struct mngr_msg msg; - struct timeval timeout; - fd_set rfd, wfd; - char buf[128]; - - fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd < 0) { - printf("%s %d\n", __FUNCTION__, __LINE__); - ret = -1; - goto sock_err; - } - - addr.sun_family = AF_UNIX; - snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s-monitor.socket", - ACRN_DM_SOCK_ROOT, vmname); - - ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); - if (ret < 0) { - printf("%s %d\n", __FUNCTION__, __LINE__); - goto connect_err; - } - - msg.magic = MNGR_MSG_MAGIC; - msg.msgid = DM_STOP; - msg.len = sizeof(msg); - - timeout.tv_sec = 1; /* wait 1 second for read/write socket */ - timeout.tv_usec = 0; - FD_ZERO(&rfd); - FD_ZERO(&wfd); - FD_SET(fd, &rfd); - FD_SET(fd, &wfd); - - select(fd + 1, NULL, &wfd, NULL, &timeout); - - if (!FD_ISSET(fd, &wfd)) { - printf("%s %d\n", __FUNCTION__, __LINE__); - goto cant_write; - } - - ret = write(fd, &msg, sizeof(msg)); - - /* wait response */ - select(fd + 1, &rfd, NULL, NULL, &timeout); - - if (FD_ISSET(fd, &rfd)) { - memset(buf, 0, sizeof(buf)); - ret = read(fd, buf, sizeof(buf)); - if (ret <= sizeof(buf)) - process_msg((void *)&buf); - } - - cant_write: - connect_err: - close(fd); - sock_err: - return ret; -} - static int acrnctl_do_stop(int argc, char *argv[]) { - struct vmm_struct *s; + struct vmmngr_struct *s; int i; - vmm_update(); + get_vm_list(); for (i = 1; i < argc; i++) { - s = vmm_find(argv[i]); + s = vmmngr_find(argv[i]); if (!s) { printf("can't find %s\n", argv[i]); continue; @@ -543,7 +325,7 @@ static int acrnctl_do_stop(int argc, char *argv[]) state_str[s->state]); continue; } - send_stop_msg(argv[i]); + stop_vm(argv[i]); } return 0; @@ -552,13 +334,13 @@ static int acrnctl_do_stop(int argc, char *argv[]) /* command: delete */ static int acrnctl_do_del(int argc, char *argv[]) { - struct vmm_struct *s; + struct vmmngr_struct *s; int i; char cmd[128]; - vmm_update(); + get_vm_list(); for (i = 1; i < argc; i++) { - s = vmm_find(argv[i]); + s = vmmngr_find(argv[i]); if (!s) { printf("can't find %s\n", argv[i]); continue; @@ -581,11 +363,10 @@ static int acrnctl_do_del(int argc, char *argv[]) static int acrnctl_do_start(int argc, char *argv[]) { - struct vmm_struct *s; - char cmd[128]; + struct vmmngr_struct *s; - vmm_update(); - s = vmm_find(argv[1]); + get_vm_list(); + s = vmmngr_find(argv[1]); if (!s) { printf("can't find %s\n", argv[1]); return -1; @@ -596,10 +377,7 @@ static int acrnctl_do_start(int argc, char *argv[]) return -1; } - snprintf(cmd, sizeof(cmd), "bash %s/add/%s.sh $(cat %s/add/%s.args)", - ACRNCTL_OPT_ROOT, argv[1], ACRNCTL_OPT_ROOT, argv[1]); - - system(cmd); + start_vm(argv[1]); return 0; } diff --git a/tools/acrn-manager/acrnctl.h b/tools/acrn-manager/acrnctl.h new file mode 100644 index 000000000..df117d64a --- /dev/null +++ b/tools/acrn-manager/acrnctl.h @@ -0,0 +1,58 @@ +/** + * Copyright (C) 2018 Intel Corporation + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _ACRNCTL_H_ +#define _ACRNCTL_H_ + +#include + +#define ACRNCTL_OPT_ROOT "/opt/acrn/conf" +#define ACRN_DM_SOCK_ROOT "/run/acrn/mngr" + +#define MAX_NAME_LEN (16) + +enum vm_state { + VM_STATE_UNKNOWN = 0, + VM_CREATED, /* VM created / awaiting start (boot) */ + VM_STARTED, /* VM started (booted) */ + VM_PAUSED, /* VM paused */ + VM_UNTRACKED, /* VM not created by acrnctl, or its launch script can change vm name */ +}; + +static const char *state_str[] = { + [VM_STATE_UNKNOWN] = "unknown", + [VM_CREATED] = "stopped", + [VM_STARTED] = "started", + [VM_PAUSED] = "paused", + [VM_UNTRACKED] = "untracked", +}; + +/** + * @brief search all vm and store it in vmmngr_head + */ +void get_vm_list(void); + +/** + * @brief search vm indentified by vm from vmmngr_head + * + * @return vmmngr_struct * if find, NULL not find + */ +struct vmmngr_struct *vmmngr_find(char *vmname); + +/* Per-vm vm managerment struct */ +struct vmmngr_struct { + char name[MAX_NAME_LEN]; + unsigned long state; + LIST_ENTRY(vmmngr_struct) list; +}; + +int shell_cmd(const char *cmd, char *outbuf, int len); + +/* vm life cycle ops */ +int list_vm(void); +int stop_vm(char *vmname); +int start_vm(char *vmname); + +#endif /* _ACRNCTL_H_ */