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