1 /*
2  * Copyright (C) 2022 Intel Corporation.
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <stdbool.h>
11 #include <string.h>
12 #include <termios.h>
13 #include <unistd.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <sys/socket.h>
17 #include <pthread.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
20 #include <sys/un.h>
21 #include <cjson/cJSON.h>
22 #include "socket.h"
23 #include "command.h"
24 #include "vmmapi.h"
25 #include "cmd_monitor.h"
26 #include "log.h"
27 #include "dm.h"
28 #include "command_handler.h"
29 
30 struct socket_dev *sock_server; /* socket server instance */
31 static char socket_path[UNIX_SOCKET_PATH_MAX];
32 
parse_command(char * cmd_msg,int fd)33 static struct command *parse_command(char *cmd_msg, int fd)
34 {
35 	struct command *cmd = NULL;
36 	const cJSON *execute;
37 	const cJSON *arguments;
38 	cJSON *cmd_json;
39 
40 	cmd_json = cJSON_Parse(cmd_msg);
41 	if (cmd_json == NULL) {
42 		const char *error_ptr = cJSON_GetErrorPtr();
43 		if (error_ptr != NULL) {
44 			fprintf(stderr, "Error before: %s\n", error_ptr);
45         }
46         return NULL;
47 	}
48 	execute = cJSON_GetObjectItemCaseSensitive(cmd_json, "command");
49 	if (cJSON_IsString(execute) && (execute->valuestring != NULL)) {
50 		pr_info("Command name: \"%s\"\n", execute->valuestring);
51 
52 		cmd = find_command(execute->valuestring);
53 		if (cmd != NULL) {
54 			cmd->para.fd = fd;
55 			arguments = cJSON_GetObjectItemCaseSensitive(cmd_json, "arguments");
56 			if (cJSON_IsString(arguments) && (arguments->valuestring != NULL)) {
57 				pr_info("Command arguments: \"%s\"\n", arguments->valuestring);
58 				strncpy(cmd->para.option, arguments->valuestring, CMD_ARG_MAX - 1U);
59 			}
60 		} else {
61 			pr_err("Command [%s] is not supported.\n", execute->valuestring);
62 		}
63 	}
64 	cJSON_Delete(cmd_json);
65 	return cmd;
66 }
monitor_cmd_dispatch(char * cmd_msg,int fd)67 static void monitor_cmd_dispatch(char *cmd_msg, int fd)
68 {
69 	struct command *cmd;
70 
71 	cmd = parse_command(cmd_msg, fd);
72 	if (cmd != NULL) {
73 		dispatch_command_handlers(cmd);
74 	}
75 	return;
76 }
77 
init_socket_server(void)78 int init_socket_server(void)
79 {
80 	int ret = 0;
81 
82 	if (strnlen(socket_path, UNIX_SOCKET_PATH_MAX) == 0) {
83 		pr_err("Failed to initialize command monitor due to invalid socket path.\n");
84 	}
85 
86 	sock_server = init_socket(socket_path);
87 	if (sock_server == NULL)
88 		return -1;
89 	ret = open_socket(sock_server, monitor_cmd_dispatch);
90 	if (ret < 0)
91 		return ret;
92 	return ret;
93 }
94 
register_socket_message_handlers(struct vmctx * ctx)95 static void register_socket_message_handlers(struct vmctx *ctx)
96 {
97 	struct handler_args arg;
98 	arg.channel_arg = sock_server;
99 	arg.ctx_arg = ctx;
100 	register_command_handler(user_vm_destroy_handler, &arg, DESTROY);
101 	register_command_handler(user_vm_blkrescan_handler, &arg, BLKRESCAN);
102 	register_command_handler(user_vm_register_vm_event_client_handler, &arg, REGISTER_VM_EVENT_CLIENT);
103 }
104 
init_cmd_monitor(struct vmctx * ctx)105 int init_cmd_monitor(struct vmctx *ctx)
106 {
107 	int ret;
108 	ret = init_socket_server();
109 	register_socket_message_handlers(ctx);
110 	return ret;
111 }
deinit_cmd_monitor(void)112 void deinit_cmd_monitor(void)
113 {
114 	if (sock_server != NULL) {
115 		close_socket(sock_server);
116 		deinit_socket(sock_server);
117 	}
118 }
acrn_parse_cmd_monitor(char * arg)119 int acrn_parse_cmd_monitor(char *arg)
120 {
121 	int err = -1;
122 	size_t len = strnlen(arg, UNIX_SOCKET_PATH_MAX);
123 
124 	if (len < UNIX_SOCKET_PATH_MAX) {
125 		strncpy(socket_path, arg, len + 1);
126 		pr_notice("Command monitor: using soket path %s\n", socket_path);
127 		err = 0;
128 	}
129 	return err;
130 }
131