1 /*
2  * Copyright (C)2021-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/file.h>
17 #include "uart_channel.h"
18 #include "command.h"
19 #include "socket.h"
20 #include "command_handler.h"
21 #include "log.h"
22 #include "config.h"
23 
24 #define NODE_SIZE 5
25 #define S5_SOCKET_DIR "/var/lib/life_mngr"
26 #define S5_SOCKET_FMT "%s/monitor.sock"
27 #define SERVICE_VM_NAME "service_vm"
28 
29 struct uart_channel *channel; /* uart server instance */
30 struct socket_dev *sock_server; /* socket server instance */
31 
32 FILE *log_fd;
33 
monitor_cmd_dispatch(const char * cmd_name,int fd)34 static void monitor_cmd_dispatch(const char *cmd_name, int fd)
35 {
36 	struct command *cmd;
37 
38 	cmd = find_command(cmd_name);
39 	if (cmd != NULL)
40 		dispatch_command_handlers(cmd, fd);
41 	else
42 		LOG_PRINTF("Command [%s] is not supported, fd=%d\n", cmd_name, fd);
43 }
44 /**
45  * @brief open uart channel according to device name
46  *
47  * @param uart_dev_name one or more device names
48  * @return int all uart channel devices are open or not
49  */
create_service_vm_uart_channel_dev(char * uart_dev_name)50 static int create_service_vm_uart_channel_dev(char *uart_dev_name)
51 {
52 	int ret = 0;
53 	struct channel_dev *c_dev;
54 	char *dev_name;
55 	char *saveptr;
56 
57 	saveptr = uart_dev_name;
58 	do {
59 		dev_name = strtok_r(saveptr, ",", &saveptr);
60 		c_dev = create_uart_channel_dev(channel, dev_name, monitor_cmd_dispatch);
61 		if (c_dev == NULL) {
62 			LOG_PRINTF("Failed to create uart channel device for %s\n", dev_name);
63 			ret = -1;
64 			break;
65 		}
66 		pthread_create(&c_dev->listen_thread, NULL, listen_uart_channel_dev, c_dev);
67 		pthread_create(&c_dev->pool_thread, NULL, poll_and_dispatch_uart_channel_events, c_dev);
68 	} while (strlen(saveptr) > 0U);
69 
70 	return ret;
71 }
72 /* TODO: will refine the name of init_socket_server_and_shutdown_commands */
init_socket_server_and_shutdown_commands(bool service_vm)73 int init_socket_server_and_shutdown_commands(bool service_vm)
74 {
75 	int ret = 0;
76 	char path[128] = S5_SOCKET_DIR;
77 
78 	ret = check_dir(path, CHK_CREAT);
79 	if (ret < 0) {
80 		LOG_PRINTF("%s %d\r\n", __func__, __LINE__);
81 		return ret;
82 	}
83 	snprintf(path, sizeof(path), S5_SOCKET_FMT, S5_SOCKET_DIR);
84 
85 	sock_server = init_socket(path);
86 	if (sock_server == NULL)
87 		return -1;
88 	ret = open_socket(sock_server, monitor_cmd_dispatch);
89 	if (ret < 0)
90 		return ret;
91 	if (service_vm) {
92 		register_command_handler(socket_req_shutdown_service_vm_handler,
93 						sock_server, REQ_SYS_SHUTDOWN);
94 		register_command_handler(socket_req_user_vm_shutdown_handler,
95 						sock_server, USER_VM_SHUTDOWN);
96 		register_command_handler(socket_req_user_vm_reboot_handler,
97 				sock_server, USER_VM_REBOOT);
98 	} else {
99 		register_command_handler(socket_req_system_shutdown_user_vm_handler,
100 						sock_server, REQ_SYS_SHUTDOWN);
101 		register_command_handler(socket_req_system_reboot_user_vm_handler,
102 						sock_server, REQ_SYS_REBOOT);
103 	}
104 	return ret;
105 }
106 /* TODO: will refine the name of init_uart_channel_devs_and_shutdown_commands */
init_uart_channel_devs_and_shutdown_commands(bool service_vm,char * uart_dev_name)107 int init_uart_channel_devs_and_shutdown_commands(bool service_vm, char *uart_dev_name)
108 {
109 	int ret = 0;
110 	struct channel_dev *c_dev;
111 
112 	channel = init_uart_channel(life_conf.vm_name);
113 	if (channel == NULL)
114 		return -1;
115 	/**
116 	 * Open one or more uart channel for lifecycle manager in the service VM,
117 	 * open one uart channel for lifecycle manager in the user VM.
118 	 */
119 	if (service_vm) {
120 		register_command_handler(sync_cmd_handler, channel, SYNC_CMD);
121 		register_command_handler(req_shutdown_handler, channel, REQ_SYS_SHUTDOWN);
122 		register_command_handler(req_reboot_handler, channel, REQ_SYS_REBOOT);
123 		register_command_handler(ack_poweroff_handler, channel, ACK_POWEROFF);
124 		register_command_handler(ack_timeout_handler, channel, ACK_TIMEOUT);
125 		register_command_handler(ack_user_vm_shutdown_cmd_handler, channel, ACK_USER_VM_SHUTDOWN);
126 		register_command_handler(ack_user_vm_reboot_cmd_handler, channel, ACK_USER_VM_REBOOT);
127 
128 		ret = create_service_vm_uart_channel_dev(uart_dev_name);
129 		if (ret < 0)
130 			return ret;
131 	} else {
132 		register_command_handler(acked_sync_handler, channel, ACK_SYNC);
133 		register_command_handler(poweroff_cmd_handler, channel, POWEROFF_CMD);
134 		register_command_handler(user_vm_shutdown_cmd_handler, channel, USER_VM_SHUTDOWN);
135 		register_command_handler(user_vm_reboot_cmd_handler, channel, USER_VM_REBOOT);
136 		register_command_handler(acked_req_shutdown_reboot_handler, channel, ACK_REQ_SYS_SHUTDOWN);
137 		register_command_handler(acked_req_shutdown_reboot_handler, channel, ACK_REQ_SYS_REBOOT);
138 		register_command_handler(ack_timeout_default_handler, channel, ACK_TIMEOUT);
139 
140 		c_dev = create_uart_channel_dev(channel, uart_dev_name, monitor_cmd_dispatch);
141 		if (c_dev == NULL)
142 			return -1;
143 		strncpy(c_dev->name, SERVICE_VM_NAME, CHANNEL_DEV_NAME_MAX - 1U);
144 		/* TODO: will refine this connect_uart_channel_dev for pre-lauched VM later*/
145 		pthread_create(&c_dev->listen_thread, NULL, connect_uart_channel_dev, c_dev);
146 		pthread_create(&c_dev->pool_thread, NULL, poll_and_dispatch_uart_channel_events, c_dev);
147 	}
148 	return ret;
149 }
150 /**
151  * @brief Parse communication channel device type from configuration file
152  *
153  * @param dev_conf communication channel device configuration
154  */
parse_cmd_channel_conf(char * dev_conf)155 static int parse_cmd_channel_conf(char *dev_conf)
156 {
157 	char *channel_name;
158 	char *saveptr;
159 	int ret = -1;
160 
161 	channel_name = strtok_r(dev_conf, ":", &saveptr);
162 
163 	if (strncmp(channel_name, "tty", sizeof("tty")) == 0)
164 		ret = 0;
165 	else
166 		LOG_WRITE("Invalid channel type in config file\n");
167 
168 	memcpy(dev_conf, saveptr, strlen(saveptr) + 1);
169 	return ret;
170 }
start_life_mngr(void)171 static int start_life_mngr(void)
172 {
173 	int ret = 0;
174 
175 	if (!open_log("/var/log/life_mngr.log")) {
176 		printf("Open log file failed\r\n");
177 		return -ENOENT;
178 	}
179 	LOG_WRITE("------Lifecycle Manager start----------\n");
180 	memset(&life_conf, 0x0, sizeof(struct life_mngr_config));
181 	if (!load_config(LIFE_MNGR_CONFIG_PATH)) {
182 		LOG_WRITE("Failed to load configuration file\n");
183 		return -ENOENT;
184 	}
185 
186 	if ((ret = parse_cmd_channel_conf(life_conf.dev_names)) < 0)
187 		return ret;
188 	if (strncmp("service_vm", life_conf.vm_type, MAX_CONFIG_VALUE_LEN) == 0) {
189 		if ((ret = init_socket_server_and_shutdown_commands(true)) < 0)
190 			return ret;
191 		ret = init_uart_channel_devs_and_shutdown_commands(true, life_conf.dev_names);
192 	} else if (strncmp("user_vm", life_conf.vm_type, MAX_CONFIG_VALUE_LEN) == 0) {
193 		if ((ret = init_socket_server_and_shutdown_commands(false)) < 0)
194 			return ret;
195 		ret = init_uart_channel_devs_and_shutdown_commands(false, life_conf.dev_names);
196 	} else {
197 		LOG_WRITE("Invalid VM type in config file\n");
198 		close_log();
199 		return -EINVAL;
200 	}
201 	/* Wait all uart channel threads exit */
202 	wait_uart_channel_devs_threads(channel);
203 	return ret;
204 }
stop_life_mngr(void)205 static void stop_life_mngr(void)
206 {
207 	deinit_uart_channel(channel);
208 	deinit_socket(sock_server);
209 	close_log();
210 }
main(int argc,char * argv[])211 int main(int argc, char *argv[])
212 {
213 	int ret;
214 
215 	ret = start_life_mngr();
216 	if (ret < 0) {
217 		printf("Failed to start lifecycle Manager, ret=%d\n", ret);
218 		return ret;
219 	}
220 	stop_life_mngr();
221 	if (get_system_shutdown_flag()) {
222 		do {
223 			ret = system(POWEROFF);
224 		} while (ret < 0);
225 	}
226 	if (get_vm_reboot_flag()) {
227 		do {
228 			ret = system(REBOOT);
229 		} while (ret < 0);
230 	}
231 	return 0;
232 }
233 
234