1 /*
2  * ProjectAcrn
3  * Acrnctl
4  *
5  * Copyright (C) 2018-2022 Intel Corporation.
6  *
7  * SPDX-License-Identifier: BSD-3-Clause
8  *
9  *
10  * Author: Tao Yuhong <yuhong.tao@intel.com>
11  */
12 
13 #include <stdio.h>
14 #include <string.h>
15 #include <unistd.h>
16 #include <fcntl.h>
17 #include <stdlib.h>
18 #include <sys/queue.h>
19 #include <sys/socket.h>
20 #include <sys/un.h>
21 #include <stdbool.h>
22 #include "acrn_mngr.h"
23 #include "acrnctl.h"
24 #include "ioc.h"
25 
26 #define ACMD(CMD,FUNC,DESC, VALID_ARGS) \
27 {.cmd = CMD, .func = FUNC, .desc = DESC, .valid_args = VALID_ARGS}
28 
29 /* vm life cycle cmd description */
30 #define LIST_DESC      "List all the virtual machines added"
31 #define START_DESC     "Start virtual machine VM_NAME"
32 #define STOP_DESC      "Stop virtual machine VM_NAME, [--force/-f, force to stop VM]"
33 #define DEL_DESC       "Delete virtual machine VM_NAME"
34 #define ADD_DESC       "Add one virtual machine with SCRIPTS and OPTIONS"
35 #define RESET_DESC     "Stop and then start virtual machine VM_NAME"
36 #define BLKRESCAN_DESC  "Rescan virtio-blk device attached to a virtual machine"
37 
38 #define VM_NAME (1)
39 #define CMD_ARGS (2)
40 
41 #define STOP_TIMEOUT	30U
42 
43 struct acrnctl_cmd {
44 	const char *cmd;
45 	const char desc[128];	/* Description of the cmd */
46 	int (*func) (int argc, char *argv[]);
47 	/* Callback function to check whether args is valid */
48 	int (*valid_args) (struct acrnctl_cmd * cmd, int argc, char *argv[]);
49 };
50 
51 /* There are acrnctl cmds */
52 /* command: list */
acrnctl_do_list(int argc,char * argv[])53 static int acrnctl_do_list(int argc, char *argv[])
54 {
55 	return list_vm();
56 }
57 
check_name(const char * name)58 static int check_name(const char *name)
59 {
60 	int i = 0, j = 0;
61 	char illegal[] = "!@#$%^&*, ";
62 
63 	/* Name should start with a letter */
64 	if ((name[0] < 'a' || name[0] > 'z')
65 	    && (name[0] < 'A' || name[0] > 'Z')) {
66 		printf("name not started with letter!\n");
67 		return -1;
68 	}
69 
70 	/* no illegal charactoer */
71 	while (name[i]) {
72 		j = 0;
73 		while (illegal[j]) {
74 			if (name[i] == illegal[j]) {
75 				printf("vmname[%d] is '%c'!\n", i, name[i]);
76 				return -1;
77 			}
78 			j++;
79 		}
80 		i++;
81 	}
82 
83 	if (!strcmp(name, "help"))
84 		return -1;
85 	if (!strcmp(name, "nothing"))
86 		return -1;
87 
88 	if (strnlen(name, MAX_VM_NAME_LEN) >= MAX_VM_NAME_LEN) {
89 		printf("(%s) size exceed MAX_VM_NAME_LEN:%u\n", name, MAX_VM_NAME_LEN);
90 		return -1;
91 	}
92 
93 	return 0;
94 }
95 
96 static const char *acrnctl_bin_path;
97 static int find_acrn_dm;
98 #define MAX_WORD   64
99 
write_tmp_file(int fd,int n,char * word[])100 static int write_tmp_file(int fd, int n, char *word[])
101 {
102 	int len, ret, i = 0;
103 	char buf[PATH_LEN];
104 
105 	if (!n)
106 		return 0;
107 
108 	len = strnlen(word[0], MAX_WORD);
109 	if (len >= strlen("acrn-dm")) {
110 		if (!strcmp(word[0] + len - strlen("acrn-dm"), "acrn-dm")) {
111 			find_acrn_dm++;
112 			memset(buf, 0, sizeof(buf));
113 			if (snprintf(buf, sizeof(buf), "%s gentmpfile",
114 						acrnctl_bin_path) >= sizeof(buf)) {
115 				printf("ERROR: acrnctl bin path is truncated\n");
116 				return -1;
117 			}
118 			ret = write(fd, buf, strnlen(buf, sizeof(buf)));
119 			if (ret < 0)
120 				return -1;
121 			i++;
122 		}
123 	}
124 
125 	while (i < n) {
126 		memset(buf, 0, sizeof(buf));
127 		if (snprintf(buf, sizeof(buf), " %s", word[i]) >= sizeof(buf))
128 			printf("WARN: buf is truncated\n");
129 		i++;
130 		ret = write(fd, buf, strnlen(buf, sizeof(buf)));
131 		if (ret < 0)
132 			return -1;
133 	}
134 	ret = write(fd, "\n", 1);
135 	if (ret < 0)
136 		return -1;
137 	return 0;
138 }
139 
140 /*
141  * get vmname from the string src, and src
142  * format is "acrnctl: [vmname]"
143  */
_get_vmname(const char * src,char * vmname,int max_len_vmname)144 static inline int _get_vmname(const char *src, char *vmname, int max_len_vmname)
145 {
146 	const char *vmname_p = NULL;
147 
148 	if (!strncmp("acrnctl: ", src, strlen("acrnctl: "))) {
149 		vmname_p = src + strlen("acrnctl: ");
150 
151 		memset(vmname, 0, max_len_vmname);
152 		strncpy(vmname, vmname_p, max_len_vmname);
153 		if(vmname[max_len_vmname - 1]) {
154 			/* vmname is truncated */
155 			printf("get vmname failed, vmname is truncated\n");
156 			return -1;
157 		}
158 	} else {
159 		/* the prefix of the string "src" isn't "acrnctl: " */
160 		printf("can't found prefix 'acrnctl: '\n");
161 		return -1;
162 	}
163 
164 	return 0;
165 }
166 
167 #define MAX_FILE_SIZE   (4096 * 5)
168 
169 #define TMP_FILE_SUFFIX		".acrnctl"
170 
acrnctl_do_add(int argc,char * argv[])171 static int acrnctl_do_add(int argc, char *argv[])
172 {
173 	struct vmmngr_struct *s;
174 	int fd, fd_tmp, ret = 0;
175 	char *buf;
176 	char *word[MAX_WORD], *line;
177 	char *word_p = NULL, *line_p = NULL;
178 	int n_word;
179 	char fname[PATH_LEN + sizeof(TMP_FILE_SUFFIX)];
180 	char cmd[PATH_LEN];
181 	char args[PATH_LEN];
182 	int p, i, len_cmd_out = 0, c_flag = 0;
183 	char cmd_out[PATH_LEN * 2];
184 	char vmname[PATH_LEN];
185 	size_t len = sizeof(cmd_out);
186 
187 	if (strnlen(argv[1], PATH_LEN) == PATH_LEN) {
188 		printf("File name too long (maximum len %d)\n", PATH_LEN);
189 		return -1;
190 	}
191 
192 	memset(args, 0, sizeof(args));
193 	p = 0;
194 	for (i = 2; i < argc; i++) {
195 		if (p >= sizeof(args) - 1) {
196 			args[sizeof(args) - 1] = 0;
197 			printf("Too many input options\n");
198 			return -1;
199 		}
200 
201 		/*
202 		 * If there's "-C" parameter in acrnctl add command
203 		 * check if the SoS support runC container at first, then
204 		 * strip "-C" and set the flag.
205 		*/
206 		if (strncmp(argv[i], "-C", 2) == 0) {
207 			if (access("/sbin/runc", F_OK) != 0) {
208 				printf("runC command not supproted\n");
209 				return -1;
210 			}
211                         c_flag = 1;
212                         continue;
213                 }
214 
215 		p += snprintf(&args[p], sizeof(args) - p, " %s", argv[i]);
216 	}
217 	args[p] = ' ';
218 
219 	fd = open(argv[1], O_RDONLY);
220 	if (fd < 0) {
221 		perror(argv[1]);
222 		ret = -1;
223 		goto open_read_file;
224 	}
225 
226 	buf = calloc(1, MAX_FILE_SIZE);
227 	if (!buf) {
228 		perror("calloc for add vm");
229 		ret = -1;
230 		goto calloc_err;
231 	}
232 
233 	ret = read(fd, buf, MAX_FILE_SIZE);
234 	if (ret >= MAX_FILE_SIZE) {
235 		printf("%s exceed MAX_FILE_SIZE:%d", argv[1], MAX_FILE_SIZE);
236 		ret = -1;
237 		goto file_exceed;
238 	}
239 
240 	/* open tmp file for write */
241 	memset(fname, 0, sizeof(fname));
242 	if (snprintf(fname, sizeof(fname), "%s%s", argv[1], TMP_FILE_SUFFIX)
243 			>= sizeof(fname)) {
244 		printf("ERROR: file name is truncated\n");
245 		ret = -1;
246 		goto file_exceed;
247 	}
248 	fd_tmp = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0666);
249 	if (fd_tmp < 0) {
250 		perror(fname);
251 		ret = -1;
252 		goto open_tmp_file;
253 	}
254 
255 	find_acrn_dm = 0;
256 
257 	/* Properly null-terminate buf */
258 	buf[MAX_FILE_SIZE - 1] = '\0';
259 
260 	line = strtok_r(buf, "\n", &line_p);
261 	while (line) {
262 		word_p = NULL;
263 		n_word = 0;
264 		word[n_word] = strtok_r(line, " ", &word_p);
265 		while ((n_word < (MAX_WORD-1)) && word[n_word]) {
266 			n_word++;
267 			word[n_word] = strtok_r(NULL, " ", &word_p);
268 		}
269 		if (write_tmp_file(fd_tmp, n_word, word)) {
270 			ret = -1;
271 			perror(fname);
272 			goto write_tmpfile;
273 		}
274 		line = strtok_r(NULL, "\n", &line_p);
275 	}
276 
277 	if (!find_acrn_dm) {
278 		printf("No 'acrn-dm' found in %s, expecting 'acrn-dm' command to get vmname.\n", argv[1]);
279 		ret = -1;
280 		goto no_acrn_dm;
281 	}
282 
283 	if (snprintf(cmd, sizeof(cmd), "mv %s %s.back", argv[1], argv[1])
284 			>= sizeof(cmd)) {
285 		printf("ERROR: cmd is truncated\n");
286 		ret = -1;
287 		goto get_vmname;
288 	}
289 	system(cmd);
290 
291 	if (snprintf(cmd, sizeof(cmd), "mv %s %s", fname, argv[1]) >= sizeof(cmd)) {
292 		printf("ERROR: cmd is truncated\n");
293 		ret = -1;
294 		goto get_vmname;
295 	}
296 	system(cmd);
297 
298 	if (snprintf(cmd, sizeof(cmd), "bash %s%s > %s.result", argv[1],
299 			args, argv[1]) >= sizeof(cmd)) {
300 		printf("ERROR: cmd is truncated\n");
301 		ret = -1 ;
302 		goto get_vmname;
303 	}
304 	ret = shell_cmd(cmd, cmd_out, sizeof(cmd_out));
305 	if (ret < 0)
306 		goto get_vmname;
307 
308 	if (snprintf(cmd, sizeof(cmd), "grep -a \"acrnctl: \" %s.result",
309 			argv[1]) >= sizeof(cmd)) {
310 		printf("ERROR: cmd is truncated\n");
311 		ret = -1;
312 		goto get_vmname;
313 	}
314 	len_cmd_out = shell_cmd(cmd, cmd_out, sizeof(cmd_out));
315 	if (len_cmd_out < 0) {
316 		ret = len_cmd_out;
317 		goto get_vmname;
318 	}
319 
320 	if(cmd_out[len_cmd_out - 1] == '\n')
321 		cmd_out[len_cmd_out - 1] = '\0';
322 
323 	ret = _get_vmname(cmd_out, vmname, sizeof(vmname));
324 	if (ret < 0) {
325 		/* failed to get vmname */
326 		if (snprintf(cmd, sizeof(cmd), "cat %s.result", argv[1]) >= sizeof(cmd)) {
327 			printf("ERROR: cmd is truncated\n");
328 			goto get_vmname;
329 		}
330 		shell_cmd(cmd, cmd_out, sizeof(cmd_out));
331 
332 		/* Properly null-terminate cmd_out */
333 		cmd_out[len - 1] = '\0';
334 
335 		printf("No executable acrn-dm found: %s, ,please make sure it can launch an User VM\n"
336 		       "result:\n%s\n", argv[1], cmd_out);
337 		goto get_vmname;
338 	}
339 
340 	ret = check_name(vmname);
341 	if (ret) {
342 		printf("\"%s\" is a bad name, please select another name\n",
343 		       vmname);
344 		goto get_vmname;
345 	}
346 
347 	s = vmmngr_find(vmname);
348 	if (s) {
349 		printf("%s(%s) already exist, can't add %s%s\n",
350 		       vmname, state_str[s->state], argv[1], args);
351 		ret = -1;
352 		goto vm_exist;
353 	}
354 
355 	if (snprintf(cmd, sizeof(cmd), "cp %s.back %s/%s.sh", argv[1],
356 		 ACRN_CONF_PATH_ADD, vmname) >= sizeof(cmd)) {
357 		printf("ERROR: cmd is truncated\n");
358 		ret = -1;
359 		goto vm_exist;
360 	}
361 	system(cmd);
362 
363 	/* If c_flag have been seted, add stripped "-C" to args file */
364 	if (c_flag)
365 		strncpy(args + p + 1, "-C", 2);
366 	if (snprintf(cmd, sizeof(cmd), "echo %s >%s/%s.args", args,
367 		 ACRN_CONF_PATH_ADD, vmname) >= sizeof(cmd)) {
368 		printf("ERROR: cmd is truncated\n");
369 		ret = -1;
370 		goto vm_exist;
371 	}
372 	system(cmd);
373 	printf("%s added\n", vmname);
374 
375  vm_exist:
376  get_vmname:
377 	if (snprintf(cmd, sizeof(cmd), "rm -f %s.result", argv[1]) >= sizeof(cmd)) {
378 		printf("WARN: cmd is truncated\n");
379 	} else
380 		system(cmd);
381 
382 	if (snprintf(cmd, sizeof(cmd), "mv %s %s", argv[1], fname) >= sizeof(cmd)) {
383 		printf("ERROR: cmd is truncated\n");
384 		ret = -1;
385 	} else
386 		system(cmd);
387 
388 	if (snprintf(cmd, sizeof(cmd), "mv %s.back %s", argv[1], argv[1]) >= sizeof(cmd)) {
389 		printf("ERROR: cmd is truncated\n");
390 		ret = -1;
391 	} else
392 		system(cmd);
393 
394  no_acrn_dm:
395 	if (snprintf(cmd, sizeof(cmd), "rm -f %s", fname) >= sizeof(cmd)) {
396 		 printf("WARN: cmd is truncated\n");
397 	} else
398 		system(cmd);
399  write_tmpfile:
400 	close(fd_tmp);
401  open_tmp_file:
402  file_exceed:
403 	free(buf);
404  calloc_err:
405 	close(fd);
406  open_read_file:
407 	return ret;
408 }
409 
acrnctl_do_blkrescan(int argc,char * argv[])410 static int acrnctl_do_blkrescan(int argc, char *argv[])
411 {
412 	struct vmmngr_struct *s;
413 
414 	s = vmmngr_find(argv[VM_NAME]);
415 	if (!s) {
416 		printf("can't find %s\n", argv[VM_NAME]);
417 		return -1;
418 	}
419 	if (s->state != VM_STARTED) {
420 		printf("%s is in %s state but should be in %s state for blockrescan\n",
421 			argv[VM_NAME], state_str[s->state], state_str[VM_STARTED]);
422 		return -1;
423 	}
424 
425 	blkrescan_vm(argv[VM_NAME], argv[CMD_ARGS]);
426 
427 	return 0;
428 }
429 
acrnctl_do_stop(int argc,char * argv[])430 static int acrnctl_do_stop(int argc, char *argv[])
431 {
432 	struct vmmngr_struct *s;
433 	int i, force = 0;
434 	const char *vmname = NULL;
435 
436 	for (i = 1; i < argc; i++) {
437 		if (strcmp(argv[i], "--force") && strcmp(argv[i], "-f")) {
438 			if (vmname == NULL)
439 				vmname = argv[i];
440 		} else {
441 			force = 1;
442 		}
443 	}
444 
445 	if (!vmname) {
446 		printf("Please give a VM name\n");
447 		return -1;
448 	}
449 
450 	s = vmmngr_find(vmname);
451 	if (!s) {
452 		printf("can't find %s\n", vmname);
453 		return -1;
454 	}
455 	if (s->state == VM_CREATED) {
456 		printf("%s is already (%s)\n", vmname, state_str[s->state]);
457 		return -1;
458 	}
459 
460 	return stop_vm(vmname, force);
461 
462 }
463 
464 /* Function: Delete runC configuration */
del_runC(char * argv)465 static inline int del_runC(char *argv)
466 {
467 	char cmd[PATH_LEN];
468 	char cmd_out[PATH_LEN * 2];
469 	char runc_path[PATH_LEN];
470 
471 	/* The configuration added by launch_uos script */
472 	if (snprintf(runc_path, sizeof(runc_path), "%s/runc/%s",
473 			ACRN_CONF_PATH_ADD, argv) >= sizeof(runc_path)) {
474 		printf("ERROR: runC path %s is truncated\n", runc_path);
475 		return -1;
476 	}
477 	if (access(runc_path, F_OK) != 0)
478 		return 0;
479 
480 	/* Check if there is a container */
481 	if (snprintf(cmd, sizeof(cmd), "runc list | grep %s",
482 				argv) >= sizeof(cmd)) {
483 		printf("ERROR: runc cmd: %s is truncated\n", cmd);
484 		return -1;
485 	}
486 	shell_cmd(cmd, cmd_out, sizeof(cmd_out));
487 	cmd_out[PATH_LEN * 2 - 1] = '\0';
488 	if (strstr(cmd_out, argv) != NULL) {
489 		/* If the container is still running stop it by runc pause */
490 		if (strstr(cmd_out, "stopped") == NULL) {
491 			printf("Pls stop the runC before del it !!\n");
492 			return -1;
493 		}
494 		if (snprintf(cmd, sizeof(cmd), "runc delete %s",
495 				argv) >= sizeof(cmd)) {
496 			printf("ERROR: del container: %s trancated!", cmd);
497 			return -1;
498 		}
499 		system(cmd);
500 		if (snprintf(cmd, sizeof(cmd), "rm -f %s/runc/%s -rf",
501 				ACRN_CONF_PATH_ADD, argv) >= sizeof(cmd)) {
502 			printf("ERROR: delete cmd: %s trancated!\n", cmd);
503 			return -1;
504 		}
505 		system(cmd);
506 	}
507 
508 	return 0;
509 }
510 
511 /* command: delete */
acrnctl_do_del(int argc,char * argv[])512 static int acrnctl_do_del(int argc, char *argv[])
513 {
514 	struct vmmngr_struct *s;
515 	char cmd[PATH_LEN];
516 
517 	s = vmmngr_find(argv[1]);
518 	if (!s) {
519 		printf("can't find %s\n", argv[1]);
520 		return -1;
521 	}
522 	if (s->state != VM_CREATED) {
523 		printf("can't delete %s(%s)\n", argv[1], state_str[s->state]);
524 		return -1;
525 	}
526 	if (snprintf(cmd, sizeof(cmd), "rm -f %s/%s.sh", ACRN_CONF_PATH_ADD, argv[1]) >= sizeof(cmd)) {
527 		printf("WARN: cmd is truncated\n");
528 		return -1;
529 	}
530 	system(cmd);
531 	if (snprintf(cmd, sizeof(cmd), "rm -f %s/%s.args", ACRN_CONF_PATH_ADD, argv[1]) >= sizeof(cmd)) {
532 		printf("WARN: cmd is truncated\n");
533 		return -1;
534 	}
535 	system(cmd);
536 	if (del_runC(argv[1]) < 0) {
537 		printf("ERROR: del runC failed!\n");
538 		return -1;
539 	}
540 
541 	return 0;
542 }
543 
acrnctl_do_start(int argc,char * argv[])544 static int acrnctl_do_start(int argc, char *argv[])
545 {
546 	struct vmmngr_struct *s;
547 
548 	s = vmmngr_find(argv[1]);
549 	if (!s) {
550 		printf("can't find %s\n", argv[1]);
551 		return -1;
552 	}
553 
554 	if (s->state != VM_CREATED) {
555 		printf("can't start %s(%s)\n", argv[1], state_str[s->state]);
556 		return -1;
557 	}
558 
559 	return start_vm(argv[1]);
560 
561 }
562 
wait_vm_stop(const char * vmname,unsigned int timeout)563 static int wait_vm_stop(const char * vmname, unsigned int timeout)
564 {
565 	unsigned long t = timeout;
566 	struct vmmngr_struct *s;
567 
568 	do {
569 		/* list and update the vm status */
570 		vmmngr_update();
571 
572 		s =  vmmngr_find(vmname);
573 		if (s == NULL) {
574 			printf("%s: vm %s not found\n", __func__, vmname);
575 			return -1;
576 		} else {
577 			if (s->state == VM_CREATED) {
578 				sleep(2);
579 				return 0;
580 			}
581 		}
582 
583 		sleep(1);
584 	} while (t--);
585 
586 	return -1;
587 }
588 
acrnctl_do_reset(int argc,char * argv[])589 static int acrnctl_do_reset(int argc, char *argv[])
590 {
591 	struct vmmngr_struct *s;
592 	int ret = -1;
593 
594 	s = vmmngr_find(argv[1]);
595 	if (!s) {
596 		printf("Can't find vm %s\n", argv[1]);
597 		return ret;
598 	}
599 
600 	switch(s->state) {
601 		case VM_STARTED:
602 		case VM_SUSPENDED:
603 			ret = stop_vm(argv[1], 0);
604 			if (ret != 0) {
605 				break;
606 			}
607 			if (wait_vm_stop(argv[1], STOP_TIMEOUT)) {
608 				printf("Failed to stop %s in %u sec, reset failed\n", argv[1], STOP_TIMEOUT);
609 				break;
610 			}
611 			ret = start_vm(argv[1]);
612 			break;
613 		default:
614 			printf("%s current state: %s, can't reset\n", argv[1], state_str[s->state]);
615 	}
616 	return ret;
617 }
618 
619 /* Default args validation function */
df_valid_args(struct acrnctl_cmd * cmd,int argc,char * argv[])620 int df_valid_args(struct acrnctl_cmd *cmd, int argc, char *argv[])
621 {
622 	char df_opt[32] = "VM_NAME VM_NAME ...";
623 
624 	if (argc < 2 || !strcmp(argv[1], "help")) {
625 		printf("acrnctl %s %s\n", cmd->cmd, df_opt);
626 		return -1;
627 	}
628 
629 	return 0;
630 }
631 
valid_blkrescan_args(struct acrnctl_cmd * cmd,int argc,char * argv[])632 static int valid_blkrescan_args(struct acrnctl_cmd *cmd, int argc, char *argv[])
633 {
634 	char df_opt[] = "VM_NAME slot,newpath";
635 
636 	if (argc != 3 || !strcmp(argv[1], "help")) {
637 		printf("acrnctl %s %s\n", cmd->cmd, df_opt);
638 		return -1;
639 	}
640 
641 	return 0;
642 }
643 
valid_add_args(struct acrnctl_cmd * cmd,int argc,char * argv[])644 static int valid_add_args(struct acrnctl_cmd *cmd, int argc, char *argv[])
645 {
646 	char df_opt[32] = "launch_scripts options";
647 
648 	if (argc < 2 || !strcmp(argv[1], "help")) {
649 		printf("acrnctl %s %s\n", cmd->cmd, df_opt);
650 		return -1;
651 	}
652 
653 	return 0;
654 }
655 
valid_start_args(struct acrnctl_cmd * cmd,int argc,char * argv[])656 static int valid_start_args(struct acrnctl_cmd *cmd, int argc, char *argv[])
657 {
658 	char df_opt[16] = "VM_NAME";
659 
660 	if (argc != 2 || !strcmp(argv[1], "help")) {
661 		printf("acrnctl %s %s\n", cmd->cmd, df_opt);
662 		return -1;
663 	}
664 
665 	return 0;
666 }
667 
valid_list_args(struct acrnctl_cmd * cmd,int argc,char * argv[])668 static int valid_list_args(struct acrnctl_cmd *cmd, int argc, char *argv[])
669 {
670 	if (argc != 1) {
671 		printf("acrnctl %s\n", cmd->cmd);
672 		return -1;
673 	}
674 
675 	return 0;
676 }
677 
678 struct acrnctl_cmd acmds[] = {
679 	ACMD("list", acrnctl_do_list, LIST_DESC, valid_list_args),
680 	ACMD("start", acrnctl_do_start, START_DESC, valid_start_args),
681 	ACMD("stop", acrnctl_do_stop, STOP_DESC, df_valid_args),
682 	ACMD("del", acrnctl_do_del, DEL_DESC, df_valid_args),
683 	ACMD("add", acrnctl_do_add, ADD_DESC, valid_add_args),
684 	ACMD("reset", acrnctl_do_reset, RESET_DESC, df_valid_args),
685 	ACMD("blkrescan", acrnctl_do_blkrescan, BLKRESCAN_DESC, valid_blkrescan_args),
686 };
687 
688 #define NCMD	(sizeof(acmds)/sizeof(struct acrnctl_cmd))
689 
usage(void)690 static void usage(void)
691 {
692 	int i;
693 
694 	printf("\nUsage: acrnctl SUB-CMD "
695 		"{ VM_NAME | SCRIPTS OPTIONS | help }\n\n");
696 	for (i = 0; i < NCMD; i++)
697 		printf("\t%-12s%s\n", acmds[i].cmd, acmds[i].desc);
698 }
699 
main(int argc,char * argv[])700 int main(int argc, char *argv[])
701 {
702 	int i, err;
703 	char cmd[PATH_LEN];
704 
705 	if (argc == 1 || !strcmp(argv[1], "help")) {
706 		usage();
707 		return 0;
708 	}
709 
710 	if (getuid() != 0) {
711 		printf("Please run acrnctl with root privileges. Exiting.\n");
712 		return -1;
713 	}
714 
715 	acrnctl_bin_path = argv[0];
716 
717 	/* Create the acrnctl conf folder if it does not exist yet */
718 	if (snprintf(cmd, sizeof(cmd), "mkdir -p %s", ACRN_CONF_PATH_ADD)
719 			>= sizeof(cmd)) {
720 		printf("ERROR: cmd is truncated\n");
721 		return -1;
722 	}
723 	system(cmd);
724 
725 	/* first check acrnctl reserved operations */
726 	if (!strcmp(argv[1], "gentmpfile")) {
727 		printf("\nacrnctl: %s\n", argv[argc - 1]);
728 		return 0;
729 	}
730 
731 	for (i = 0; i < NCMD; i++)
732 		if (!strcmp(argv[1], acmds[i].cmd)) {
733 			if (acmds[i].valid_args(&acmds[i], argc - 1, &argv[1])) {
734 				return -1;
735 			} else {
736 				vmmngr_update();
737 				err = acmds[i].func(argc - 1, &argv[1]);
738 				return err;
739 			}
740 		}
741 
742 	/* Reach here means unsupported command */
743 	printf("Unknown command: %s\n", argv[1]);
744 	usage();
745 
746 	return -1;
747 }
748