1 /* $OpenBSD: main.c,v 1.68 2021/07/12 15:09:22 beck Exp $ */ 2 3 /* 4 * Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/socket.h> 21 #include <sys/queue.h> 22 #include <sys/un.h> 23 24 #include <machine/vmmvar.h> 25 26 #include <err.h> 27 #include <errno.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <stdint.h> 31 #include <limits.h> 32 #include <string.h> 33 #include <syslog.h> 34 #include <unistd.h> 35 #include <fcntl.h> 36 #include <util.h> 37 #include <imsg.h> 38 39 #include "vmd.h" 40 #include "virtio.h" 41 #include "proc.h" 42 #include "vmctl.h" 43 44 #define RAW_FMT "raw" 45 #define QCOW2_FMT "qcow2" 46 47 static const char *socket_name = SOCKET_NAME; 48 static int ctl_sock = -1; 49 static int tty_autoconnect = 0; 50 51 __dead void usage(void); 52 __dead void ctl_usage(struct ctl_command *); 53 54 int vmm_action(struct parse_result *); 55 56 int ctl_console(struct parse_result *, int, char *[]); 57 int ctl_convert(const char *, const char *, int, size_t); 58 int ctl_create(struct parse_result *, int, char *[]); 59 int ctl_load(struct parse_result *, int, char *[]); 60 int ctl_log(struct parse_result *, int, char *[]); 61 int ctl_reload(struct parse_result *, int, char *[]); 62 int ctl_reset(struct parse_result *, int, char *[]); 63 int ctl_start(struct parse_result *, int, char *[]); 64 int ctl_status(struct parse_result *, int, char *[]); 65 int ctl_stop(struct parse_result *, int, char *[]); 66 int ctl_waitfor(struct parse_result *, int, char *[]); 67 int ctl_pause(struct parse_result *, int, char *[]); 68 int ctl_unpause(struct parse_result *, int, char *[]); 69 int ctl_send(struct parse_result *, int, char *[]); 70 int ctl_receive(struct parse_result *, int, char *[]); 71 72 struct ctl_command ctl_commands[] = { 73 { "console", CMD_CONSOLE, ctl_console, "id" }, 74 { "create", CMD_CREATE, ctl_create, 75 "[-b base | -i disk] [-s size] disk", 1 }, 76 { "load", CMD_LOAD, ctl_load, "filename" }, 77 { "log", CMD_LOG, ctl_log, "[brief | verbose]" }, 78 { "pause", CMD_PAUSE, ctl_pause, "id" }, 79 { "receive", CMD_RECEIVE, ctl_receive, "name" , 1}, 80 { "reload", CMD_RELOAD, ctl_reload, "" }, 81 { "reset", CMD_RESET, ctl_reset, "[all | switches | vms]" }, 82 { "send", CMD_SEND, ctl_send, "id", 1}, 83 { "show", CMD_STATUS, ctl_status, "[id]" }, 84 { "start", CMD_START, ctl_start, 85 "[-cL] [-B device] [-b path] [-d disk] [-i count]\n" 86 "\t\t[-m size] [-n switch] [-r path] [-t name] id | name" }, 87 { "status", CMD_STATUS, ctl_status, "[id]" }, 88 { "stop", CMD_STOP, ctl_stop, "[-fw] [id | -a]" }, 89 { "unpause", CMD_UNPAUSE, ctl_unpause, "id" }, 90 { "wait", CMD_WAITFOR, ctl_waitfor, "id" }, 91 { NULL } 92 }; 93 94 __dead void 95 usage(void) 96 { 97 extern char *__progname; 98 99 fprintf(stderr, "usage:\t%s [-v] command [arg ...]\n", __progname); 100 101 exit(1); 102 } 103 104 __dead void 105 ctl_usage(struct ctl_command *ctl) 106 { 107 extern char *__progname; 108 109 fprintf(stderr, "usage:\t%s [-v] %s %s\n", __progname, 110 ctl->name, ctl->usage); 111 exit(1); 112 } 113 114 int 115 main(int argc, char *argv[]) 116 { 117 int ch, verbose = 1; 118 119 while ((ch = getopt(argc, argv, "v")) != -1) { 120 switch (ch) { 121 case 'v': 122 verbose = 2; 123 break; 124 default: 125 usage(); 126 /* NOTREACHED */ 127 } 128 } 129 argc -= optind; 130 argv += optind; 131 optreset = 1; 132 optind = 1; 133 134 if (argc < 1) 135 usage(); 136 137 log_init(verbose, LOG_DAEMON); 138 139 return (parse(argc, argv)); 140 } 141 142 int 143 parse(int argc, char *argv[]) 144 { 145 struct ctl_command *ctl = NULL; 146 struct parse_result res; 147 int i; 148 149 memset(&res, 0, sizeof(res)); 150 res.nifs = -1; 151 152 for (i = 0; ctl_commands[i].name != NULL; i++) { 153 if (strncmp(ctl_commands[i].name, 154 argv[0], strlen(argv[0])) == 0) { 155 if (ctl != NULL) { 156 fprintf(stderr, 157 "ambiguous argument: %s\n", argv[0]); 158 usage(); 159 } 160 ctl = &ctl_commands[i]; 161 } 162 } 163 164 if (ctl == NULL) { 165 fprintf(stderr, "unknown argument: %s\n", argv[0]); 166 usage(); 167 } 168 169 res.action = ctl->action; 170 res.ctl = ctl; 171 172 if (!ctl->has_pledge) { 173 /* pledge(2) default if command doesn't have its own pledge */ 174 if (pledge("stdio rpath exec unix getpw unveil", NULL) == -1) 175 err(1, "pledge"); 176 } 177 if (ctl->main(&res, argc, argv) != 0) 178 exit(1); 179 180 if (ctl_sock != -1) { 181 close(ibuf->fd); 182 free(ibuf); 183 } 184 185 return (0); 186 } 187 188 int 189 vmmaction(struct parse_result *res) 190 { 191 struct sockaddr_un sun; 192 struct imsg imsg; 193 int done = 0; 194 int n; 195 int ret, action; 196 unsigned int flags; 197 198 if (ctl_sock == -1) { 199 if (unveil(SOCKET_NAME, "r") == -1) 200 err(1, "unveil %s", SOCKET_NAME); 201 if ((ctl_sock = socket(AF_UNIX, 202 SOCK_STREAM|SOCK_CLOEXEC, 0)) == -1) 203 err(1, "socket"); 204 205 memset(&sun, 0, sizeof(sun)); 206 sun.sun_family = AF_UNIX; 207 strlcpy(sun.sun_path, socket_name, sizeof(sun.sun_path)); 208 209 if (connect(ctl_sock, 210 (struct sockaddr *)&sun, sizeof(sun)) == -1) 211 err(1, "connect: %s", socket_name); 212 213 if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL) 214 err(1, "malloc"); 215 imsg_init(ibuf, ctl_sock); 216 } 217 218 switch (res->action) { 219 case CMD_START: 220 ret = vm_start(res->id, res->name, res->size, res->nifs, 221 res->nets, res->ndisks, res->disks, res->disktypes, 222 res->path, res->isopath, res->instance, res->bootdevice); 223 if (ret) { 224 errno = ret; 225 err(1, "start VM operation failed"); 226 } 227 break; 228 case CMD_STOP: 229 terminate_vm(res->id, res->name, res->flags); 230 break; 231 case CMD_STATUS: 232 case CMD_CONSOLE: 233 case CMD_STOPALL: 234 get_info_vm(res->id, res->name, res->action, res->flags); 235 break; 236 case CMD_LOAD: 237 imsg_compose(ibuf, IMSG_VMDOP_LOAD, 0, 0, -1, 238 res->path, strlen(res->path) + 1); 239 break; 240 case CMD_LOG: 241 imsg_compose(ibuf, IMSG_CTL_VERBOSE, 0, 0, -1, 242 &res->verbose, sizeof(res->verbose)); 243 break; 244 case CMD_RELOAD: 245 imsg_compose(ibuf, IMSG_VMDOP_RELOAD, 0, 0, -1, NULL, 0); 246 break; 247 case CMD_RESET: 248 imsg_compose(ibuf, IMSG_CTL_RESET, 0, 0, -1, 249 &res->mode, sizeof(res->mode)); 250 break; 251 case CMD_WAITFOR: 252 waitfor_vm(res->id, res->name); 253 break; 254 case CMD_PAUSE: 255 pause_vm(res->id, res->name); 256 break; 257 case CMD_UNPAUSE: 258 unpause_vm(res->id, res->name); 259 break; 260 case CMD_SEND: 261 send_vm(res->id, res->name); 262 done = 1; 263 ret = 0; 264 break; 265 case CMD_RECEIVE: 266 vm_receive(res->id, res->name); 267 break; 268 case CMD_CREATE: 269 case NONE: 270 /* The action is not expected here */ 271 errx(1, "invalid action %u", res->action); 272 break; 273 } 274 275 action = res->action; 276 flags = res->flags; 277 parse_free(res); 278 279 while (ibuf->w.queued) 280 if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) 281 err(1, "write error"); 282 283 while (!done) { 284 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 285 errx(1, "imsg_read error"); 286 if (n == 0) 287 errx(1, "pipe closed"); 288 289 while (!done) { 290 if ((n = imsg_get(ibuf, &imsg)) == -1) 291 errx(1, "imsg_get error"); 292 if (n == 0) 293 break; 294 295 if (imsg.hdr.type == IMSG_CTL_FAIL) { 296 if (IMSG_DATA_SIZE(&imsg) == sizeof(ret)) 297 memcpy(&ret, imsg.data, sizeof(ret)); 298 else 299 ret = 0; 300 if (ret != 0) { 301 errno = ret; 302 err(1, "command failed"); 303 } else 304 errx(1, "command failed"); 305 } 306 307 ret = 0; 308 switch (action) { 309 case CMD_START: 310 done = vm_start_complete(&imsg, &ret, 311 tty_autoconnect); 312 break; 313 case CMD_WAITFOR: 314 flags = VMOP_WAIT; 315 /* FALLTHROUGH */ 316 case CMD_STOP: 317 done = terminate_vm_complete(&imsg, &ret, 318 flags); 319 break; 320 case CMD_CONSOLE: 321 case CMD_STATUS: 322 case CMD_STOPALL: 323 done = add_info(&imsg, &ret); 324 break; 325 case CMD_PAUSE: 326 done = pause_vm_complete(&imsg, &ret); 327 break; 328 case CMD_RECEIVE: 329 done = vm_start_complete(&imsg, &ret, 0); 330 break; 331 case CMD_UNPAUSE: 332 done = unpause_vm_complete(&imsg, &ret); 333 break; 334 default: 335 done = 1; 336 break; 337 } 338 339 imsg_free(&imsg); 340 } 341 } 342 343 if (ret) 344 return (1); 345 else 346 return (0); 347 } 348 349 void 350 parse_free(struct parse_result *res) 351 { 352 size_t i; 353 354 free(res->name); 355 free(res->path); 356 free(res->isopath); 357 free(res->instance); 358 for (i = 0; i < res->ndisks; i++) 359 free(res->disks[i]); 360 free(res->disks); 361 free(res->disktypes); 362 memset(res, 0, sizeof(*res)); 363 } 364 365 int 366 parse_ifs(struct parse_result *res, char *word, int val) 367 { 368 const char *error; 369 370 if (word != NULL) { 371 val = strtonum(word, 1, INT_MAX, &error); 372 if (error != NULL) { 373 warnx("count is %s: %s", error, word); 374 return (-1); 375 } 376 } 377 res->nifs = val; 378 379 return (0); 380 } 381 382 int 383 parse_network(struct parse_result *res, char *word) 384 { 385 char **nets; 386 char *s; 387 388 if ((nets = reallocarray(res->nets, res->nnets + 1, 389 sizeof(char *))) == NULL) { 390 warn("reallocarray"); 391 return (-1); 392 } 393 if ((s = strdup(word)) == NULL) { 394 warn("strdup"); 395 return (-1); 396 } 397 nets[res->nnets] = s; 398 res->nets = nets; 399 res->nnets++; 400 401 return (0); 402 } 403 404 int 405 parse_size(struct parse_result *res, char *word) 406 { 407 long long val = 0; 408 409 if (word != NULL) { 410 if (scan_scaled(word, &val) != 0) { 411 warn("invalid size: %s", word); 412 return (-1); 413 } 414 } 415 416 if (val < (1024 * 1024)) { 417 warnx("size must be at least one megabyte"); 418 return (-1); 419 } else 420 res->size = val / 1024 / 1024; 421 422 if ((res->size * 1024 * 1024) != val) 423 warnx("size rounded to %lld megabytes", res->size); 424 425 return (0); 426 } 427 428 int 429 parse_disktype(const char *s, const char **ret) 430 { 431 char buf[BUFSIZ]; 432 const char *ext; 433 int fd; 434 ssize_t len; 435 436 *ret = s; 437 438 /* Try to parse the explicit format (qcow2:disk.qc2) */ 439 if (strstr(s, RAW_FMT) == s && *(s + strlen(RAW_FMT)) == ':') { 440 *ret = s + strlen(RAW_FMT) + 1; 441 return (VMDF_RAW); 442 } 443 if (strstr(s, QCOW2_FMT) == s && *(s + strlen(QCOW2_FMT)) == ':') { 444 *ret = s + strlen(QCOW2_FMT) + 1; 445 return (VMDF_QCOW2); 446 } 447 448 /* Or try to derive the format from the file signature */ 449 if ((fd = open(s, O_RDONLY)) != -1) { 450 len = read(fd, buf, sizeof(buf)); 451 close(fd); 452 453 if (len >= (ssize_t)strlen(VM_MAGIC_QCOW) && 454 strncmp(buf, VM_MAGIC_QCOW, 455 strlen(VM_MAGIC_QCOW)) == 0) { 456 /* Return qcow2, the version will be checked later */ 457 return (VMDF_QCOW2); 458 } 459 } 460 461 /* 462 * Use the extension as a last option. This is needed for 463 * 'vmctl create' as the file, and the signature, doesn't 464 * exist yet. 465 */ 466 if ((ext = strrchr(s, '.')) != NULL && *(++ext) != '\0') { 467 if (strcasecmp(ext, RAW_FMT) == 0) 468 return (VMDF_RAW); 469 else if (strcasecmp(ext, QCOW2_FMT) == 0) 470 return (VMDF_QCOW2); 471 } 472 473 /* Fallback to raw */ 474 return (VMDF_RAW); 475 } 476 477 int 478 parse_disk(struct parse_result *res, char *word, int type) 479 { 480 char **disks; 481 int *disktypes; 482 char *s; 483 484 if ((disks = reallocarray(res->disks, res->ndisks + 1, 485 sizeof(char *))) == NULL) { 486 warn("reallocarray"); 487 return (-1); 488 } 489 if ((disktypes = reallocarray(res->disktypes, res->ndisks + 1, 490 sizeof(int))) == NULL) { 491 warn("reallocarray"); 492 return -1; 493 } 494 if ((s = strdup(word)) == NULL) { 495 warn("strdup"); 496 return (-1); 497 } 498 disks[res->ndisks] = s; 499 disktypes[res->ndisks] = type; 500 res->disks = disks; 501 res->disktypes = disktypes; 502 res->ndisks++; 503 504 return (0); 505 } 506 507 int 508 parse_vmid(struct parse_result *res, char *word, int needname) 509 { 510 const char *error; 511 uint32_t id; 512 513 if (word == NULL) { 514 warnx("missing vmid argument"); 515 return (-1); 516 } 517 if (*word == '-') { 518 /* don't print a warning to allow command line options */ 519 return (-1); 520 } 521 id = strtonum(word, 0, UINT32_MAX, &error); 522 if (error == NULL) { 523 if (needname) { 524 warnx("invalid vm name"); 525 return (-1); 526 } else { 527 res->id = id; 528 res->name = NULL; 529 } 530 } else { 531 if (strlen(word) >= VMM_MAX_NAME_LEN) { 532 warnx("name too long"); 533 return (-1); 534 } 535 res->id = 0; 536 if ((res->name = strdup(word)) == NULL) 537 errx(1, "strdup"); 538 } 539 540 return (0); 541 } 542 543 int 544 parse_instance(struct parse_result *res, char *word) 545 { 546 if (strlen(word) >= VMM_MAX_NAME_LEN) { 547 warnx("instance vm name too long"); 548 return (-1); 549 } 550 res->id = 0; 551 if ((res->instance = strdup(word)) == NULL) 552 errx(1, "strdup"); 553 554 return (0); 555 } 556 557 int 558 ctl_create(struct parse_result *res, int argc, char *argv[]) 559 { 560 int ch, ret, type; 561 const char *disk, *format, *base = NULL, *input = NULL; 562 563 while ((ch = getopt(argc, argv, "b:i:s:")) != -1) { 564 switch (ch) { 565 case 'b': 566 base = optarg; 567 break; 568 case 'i': 569 input = optarg; 570 break; 571 case 's': 572 if (parse_size(res, optarg) != 0) 573 errx(1, "invalid size: %s", optarg); 574 break; 575 default: 576 ctl_usage(res->ctl); 577 /* NOTREACHED */ 578 } 579 } 580 argc -= optind; 581 argv += optind; 582 583 if (argc < 1) 584 ctl_usage(res->ctl); 585 586 type = parse_disktype(argv[0], &disk); 587 588 if (pledge("stdio rpath wpath cpath", NULL) == -1) 589 err(1, "pledge"); 590 591 if (input) { 592 if (base && input) 593 errx(1, "conflicting -b and -i arguments"); 594 return ctl_convert(input, disk, type, res->size); 595 } 596 597 if (base && type != VMDF_QCOW2) 598 errx(1, "base images require qcow2 disk format"); 599 if (res->size == 0 && !base) { 600 fprintf(stderr, "could not create %s: missing size argument\n", 601 disk); 602 ctl_usage(res->ctl); 603 } 604 605 if ((ret = create_imagefile(type, disk, base, res->size, &format)) != 0) { 606 errno = ret; 607 err(1, "create imagefile operation failed"); 608 } else 609 warnx("%s imagefile created", format); 610 611 return (0); 612 } 613 614 int 615 ctl_convert(const char *srcfile, const char *dstfile, int dsttype, size_t dstsize) 616 { 617 struct { 618 int fd; 619 int type; 620 struct virtio_backing file; 621 const char *disk; 622 off_t size; 623 } src, dst; 624 int ret; 625 const char *format, *errstr = NULL; 626 uint8_t *buf = NULL, *zerobuf = NULL; 627 size_t buflen; 628 ssize_t len, rlen; 629 off_t off; 630 631 memset(&src, 0, sizeof(src)); 632 memset(&dst, 0, sizeof(dst)); 633 634 src.type = parse_disktype(srcfile, &src.disk); 635 dst.type = dsttype; 636 dst.disk = dstfile; 637 638 if ((src.fd = open_imagefile(src.type, src.disk, O_RDONLY, 639 &src.file, &src.size)) == -1) { 640 errstr = "failed to open source image file"; 641 goto done; 642 } 643 644 if (dstsize == 0) 645 dstsize = src.size; 646 else 647 dstsize *= 1048576; 648 if (dstsize < (size_t)src.size) { 649 errstr = "size cannot be smaller than input disk size"; 650 goto done; 651 } 652 653 /* align to megabytes */ 654 dst.size = ALIGNSZ(dstsize, 1048576); 655 656 if ((ret = create_imagefile(dst.type, dst.disk, NULL, 657 dst.size / 1048576, &format)) != 0) { 658 errno = ret; 659 errstr = "failed to create destination image file"; 660 goto done; 661 } 662 663 if ((dst.fd = open_imagefile(dst.type, dst.disk, O_RDWR, 664 &dst.file, &dst.size)) == -1) { 665 errstr = "failed to open destination image file"; 666 goto done; 667 } 668 669 if (pledge("stdio", NULL) == -1) 670 err(1, "pledge"); 671 672 /* 673 * Use 64k buffers by default. This could also be adjusted to 674 * the backend cluster size. 675 */ 676 buflen = 1 << 16; 677 if ((buf = calloc(1, buflen)) == NULL || 678 (zerobuf = calloc(1, buflen)) == NULL) { 679 errstr = "failed to allocated buffers"; 680 goto done; 681 } 682 683 for (off = 0; off < dst.size; off += len) { 684 /* Read input from the source image */ 685 if (off < src.size) { 686 len = MIN((off_t)buflen, src.size - off); 687 if ((rlen = src.file.pread(src.file.p, 688 buf, (size_t)len, off)) != len) { 689 errno = EIO; 690 errstr = "failed to read from source"; 691 goto done; 692 } 693 } else 694 len = 0; 695 696 /* and pad the remaining bytes */ 697 if (len < (ssize_t)buflen) { 698 log_debug("%s: padding %zd zero bytes at offset %lld", 699 format, buflen - len, off + len); 700 memset(buf + len, 0, buflen - len); 701 len = buflen; 702 } 703 704 /* 705 * No need to copy empty buffers. This allows the backend, 706 * sparse files or QCOW2 images, to save space in the 707 * destination file. 708 */ 709 if (memcmp(buf, zerobuf, buflen) == 0) 710 continue; 711 712 log_debug("%s: writing %zd of %lld bytes at offset %lld", 713 format, len, dst.size, off); 714 715 if ((rlen = dst.file.pwrite(dst.file.p, 716 buf, (size_t)len, off)) != len) { 717 errno = EIO; 718 errstr = "failed to write to destination"; 719 goto done; 720 } 721 } 722 723 if (dstsize < (size_t)dst.size) 724 warnx("destination size rounded to %lld megabytes", 725 dst.size / 1048576); 726 727 done: 728 free(buf); 729 free(zerobuf); 730 if (src.file.p != NULL) 731 src.file.close(src.file.p, 0); 732 if (dst.file.p != NULL) 733 dst.file.close(dst.file.p, 0); 734 if (errstr != NULL) 735 errx(1, "%s", errstr); 736 else 737 warnx("%s imagefile created", format); 738 739 return (0); 740 } 741 742 int 743 ctl_status(struct parse_result *res, int argc, char *argv[]) 744 { 745 if (argc == 2) { 746 if (parse_vmid(res, argv[1], 0) == -1) 747 errx(1, "invalid id: %s", argv[1]); 748 } else if (argc > 2) 749 ctl_usage(res->ctl); 750 751 return (vmmaction(res)); 752 } 753 754 int 755 ctl_load(struct parse_result *res, int argc, char *argv[]) 756 { 757 if (argc != 2) 758 ctl_usage(res->ctl); 759 760 if ((res->path = strdup(argv[1])) == NULL) 761 err(1, "strdup"); 762 763 return (vmmaction(res)); 764 } 765 766 int 767 ctl_log(struct parse_result *res, int argc, char *argv[]) 768 { 769 if (argc != 2) 770 ctl_usage(res->ctl); 771 772 if (strncasecmp("brief", argv[1], strlen(argv[1])) == 0) 773 res->verbose = 0; 774 else if (strncasecmp("verbose", argv[1], strlen(argv[1])) == 0) 775 res->verbose = 2; 776 else 777 ctl_usage(res->ctl); 778 779 return (vmmaction(res)); 780 } 781 782 int 783 ctl_reload(struct parse_result *res, int argc, char *argv[]) 784 { 785 if (argc != 1) 786 ctl_usage(res->ctl); 787 788 return (vmmaction(res)); 789 } 790 791 int 792 ctl_reset(struct parse_result *res, int argc, char *argv[]) 793 { 794 if (argc == 2) { 795 if (strcasecmp("all", argv[1]) == 0) 796 res->mode = CONFIG_ALL; 797 else if (strcasecmp("vms", argv[1]) == 0) 798 res->mode = CONFIG_VMS; 799 else if (strcasecmp("switches", argv[1]) == 0) 800 res->mode = CONFIG_SWITCHES; 801 else 802 ctl_usage(res->ctl); 803 } else if (argc > 2) 804 ctl_usage(res->ctl); 805 806 if (res->mode == 0) 807 res->mode = CONFIG_ALL; 808 809 return (vmmaction(res)); 810 } 811 812 int 813 ctl_start(struct parse_result *res, int argc, char *argv[]) 814 { 815 int ch, i, type; 816 char path[PATH_MAX]; 817 const char *s; 818 819 while ((ch = getopt(argc, argv, "b:B:cd:i:Lm:n:r:t:")) != -1) { 820 switch (ch) { 821 case 'b': 822 if (res->path) 823 errx(1, "boot image specified multiple times"); 824 if (realpath(optarg, path) == NULL) 825 err(1, "invalid boot image path"); 826 if ((res->path = strdup(path)) == NULL) 827 errx(1, "strdup"); 828 break; 829 case 'B': 830 if (res->bootdevice) 831 errx(1, "boot device specified multiple times"); 832 if (strcmp("disk", optarg) == 0) 833 res->bootdevice = VMBOOTDEV_DISK; 834 else if (strcmp("cdrom", optarg) == 0) 835 res->bootdevice = VMBOOTDEV_CDROM; 836 else if (strcmp("net", optarg) == 0) 837 res->bootdevice = VMBOOTDEV_NET; 838 else 839 errx(1, "unknown boot device %s", optarg); 840 break; 841 case 'r': 842 if (res->isopath) 843 errx(1, "iso image specified multiple times"); 844 if (realpath(optarg, path) == NULL) 845 err(1, "invalid iso image path"); 846 if ((res->isopath = strdup(path)) == NULL) 847 errx(1, "strdup"); 848 break; 849 case 'c': 850 tty_autoconnect = 1; 851 break; 852 case 'L': 853 if (parse_network(res, ".") != 0) 854 errx(1, "invalid network: %s", optarg); 855 break; 856 case 'm': 857 if (res->size) 858 errx(1, "memory specified multiple times"); 859 if (parse_size(res, optarg) != 0) 860 errx(1, "invalid memory size: %s", optarg); 861 break; 862 case 'n': 863 if (parse_network(res, optarg) != 0) 864 errx(1, "invalid network: %s", optarg); 865 break; 866 case 'd': 867 type = parse_disktype(optarg, &s); 868 if (realpath(s, path) == NULL) 869 err(1, "invalid disk path"); 870 if (parse_disk(res, path, type) != 0) 871 errx(1, "invalid disk: %s", optarg); 872 break; 873 case 'i': 874 if (res->nifs != -1) 875 errx(1, "interfaces specified multiple times"); 876 if (parse_ifs(res, optarg, 0) != 0) 877 errx(1, "invalid interface count: %s", optarg); 878 break; 879 case 't': 880 if (parse_instance(res, optarg) == -1) 881 errx(1, "invalid name: %s", optarg); 882 break; 883 default: 884 ctl_usage(res->ctl); 885 /* NOTREACHED */ 886 } 887 } 888 argc -= optind; 889 argv += optind; 890 891 if (argc != 1) 892 ctl_usage(res->ctl); 893 894 if (parse_vmid(res, argv[0], 0) == -1) 895 errx(1, "invalid id: %s", argv[0]); 896 897 for (i = res->nnets; i < res->nifs; i++) { 898 /* Add interface that is not attached to a switch */ 899 if (parse_network(res, "") == -1) 900 return (-1); 901 } 902 if (res->nnets > res->nifs) 903 res->nifs = res->nnets; 904 905 return (vmmaction(res)); 906 } 907 908 int 909 ctl_stop(struct parse_result *res, int argc, char *argv[]) 910 { 911 int ch; 912 913 while ((ch = getopt(argc, argv, "afw")) != -1) { 914 switch (ch) { 915 case 'f': 916 res->flags |= VMOP_FORCE; 917 break; 918 case 'w': 919 res->flags |= VMOP_WAIT; 920 break; 921 case 'a': 922 res->action = CMD_STOPALL; 923 break; 924 default: 925 ctl_usage(res->ctl); 926 /* NOTREACHED */ 927 } 928 } 929 argc -= optind; 930 argv += optind; 931 932 if (res->action == CMD_STOPALL) { 933 if (argc != 0) 934 ctl_usage(res->ctl); 935 } else { 936 if (argc != 1) 937 ctl_usage(res->ctl); 938 if (parse_vmid(res, argv[0], 0) == -1) 939 errx(1, "invalid id: %s", argv[0]); 940 } 941 942 return (vmmaction(res)); 943 } 944 945 int 946 ctl_console(struct parse_result *res, int argc, char *argv[]) 947 { 948 if (argc == 2) { 949 if (parse_vmid(res, argv[1], 0) == -1) 950 errx(1, "invalid id: %s", argv[1]); 951 } else if (argc != 2) 952 ctl_usage(res->ctl); 953 954 return (vmmaction(res)); 955 } 956 957 int 958 ctl_waitfor(struct parse_result *res, int argc, char *argv[]) 959 { 960 if (argc == 2) { 961 if (parse_vmid(res, argv[1], 0) == -1) 962 errx(1, "invalid id: %s", argv[1]); 963 } else if (argc != 2) 964 ctl_usage(res->ctl); 965 966 return (vmmaction(res)); 967 } 968 969 int 970 ctl_pause(struct parse_result *res, int argc, char *argv[]) 971 { 972 if (argc == 2) { 973 if (parse_vmid(res, argv[1], 0) == -1) 974 errx(1, "invalid id: %s", argv[1]); 975 } else if (argc != 2) 976 ctl_usage(res->ctl); 977 978 return (vmmaction(res)); 979 } 980 981 int 982 ctl_unpause(struct parse_result *res, int argc, char *argv[]) 983 { 984 if (argc == 2) { 985 if (parse_vmid(res, argv[1], 0) == -1) 986 errx(1, "invalid id: %s", argv[1]); 987 } else if (argc != 2) 988 ctl_usage(res->ctl); 989 990 return (vmmaction(res)); 991 } 992 993 int 994 ctl_send(struct parse_result *res, int argc, char *argv[]) 995 { 996 if (pledge("stdio unix sendfd unveil", NULL) == -1) 997 err(1, "pledge"); 998 if (argc == 2) { 999 if (parse_vmid(res, argv[1], 0) == -1) 1000 errx(1, "invalid id: %s", argv[1]); 1001 } else if (argc != 2) 1002 ctl_usage(res->ctl); 1003 1004 return (vmmaction(res)); 1005 } 1006 1007 int 1008 ctl_receive(struct parse_result *res, int argc, char *argv[]) 1009 { 1010 if (pledge("stdio unix sendfd unveil", NULL) == -1) 1011 err(1, "pledge"); 1012 if (argc == 2) { 1013 if (parse_vmid(res, argv[1], 1) == -1) 1014 errx(1, "invalid id: %s", argv[1]); 1015 } else if (argc != 2) 1016 ctl_usage(res->ctl); 1017 1018 return (vmmaction(res)); 1019 } 1020 1021 __dead void 1022 ctl_openconsole(const char *name) 1023 { 1024 closefrom(STDERR_FILENO + 1); 1025 if (unveil(VMCTL_CU, "x") == -1) 1026 err(1, "unveil %s", VMCTL_CU); 1027 execl(VMCTL_CU, VMCTL_CU, "-r", "-l", name, "-s", "115200", 1028 (char *)NULL); 1029 err(1, "failed to open the console"); 1030 } 1031