Bug Summary

File:src/usr.sbin/vmctl/main.c
Warning:line 687, column 9
Although the value stored to 'rlen' is used in the enclosing expression, the value is never actually read from 'rlen'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name main.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/vmctl/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/vmctl -I /usr/src/usr.sbin/vmctl/../vmd -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/vmctl/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/vmctl/main.c
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(*__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" "raw"
45#define QCOW2_FMT"qcow2" "qcow2"
46
47static const char *socket_name = SOCKET_NAME"/var/run/vmd.sock";
48static int ctl_sock = -1;
49static int tty_autoconnect = 0;
50
51__dead__attribute__((__noreturn__)) void usage(void);
52__dead__attribute__((__noreturn__)) void ctl_usage(struct ctl_command *);
53
54int vmm_action(struct parse_result *);
55
56int ctl_console(struct parse_result *, int, char *[]);
57int ctl_convert(const char *, const char *, int, size_t);
58int ctl_create(struct parse_result *, int, char *[]);
59int ctl_load(struct parse_result *, int, char *[]);
60int ctl_log(struct parse_result *, int, char *[]);
61int ctl_reload(struct parse_result *, int, char *[]);
62int ctl_reset(struct parse_result *, int, char *[]);
63int ctl_start(struct parse_result *, int, char *[]);
64int ctl_status(struct parse_result *, int, char *[]);
65int ctl_stop(struct parse_result *, int, char *[]);
66int ctl_waitfor(struct parse_result *, int, char *[]);
67int ctl_pause(struct parse_result *, int, char *[]);
68int ctl_unpause(struct parse_result *, int, char *[]);
69int ctl_send(struct parse_result *, int, char *[]);
70int ctl_receive(struct parse_result *, int, char *[]);
71
72struct 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((void *)0) }
92};
93
94__dead__attribute__((__noreturn__)) void
95usage(void)
96{
97 extern char *__progname;
98
99 fprintf(stderr(&__sF[2]), "usage:\t%s [-v] command [arg ...]\n", __progname);
100
101 exit(1);
102}
103
104__dead__attribute__((__noreturn__)) void
105ctl_usage(struct ctl_command *ctl)
106{
107 extern char *__progname;
108
109 fprintf(stderr(&__sF[2]), "usage:\t%s [-v] %s %s\n", __progname,
110 ctl->name, ctl->usage);
111 exit(1);
112}
113
114int
115main(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(3<<3));
138
139 return (parse(argc, argv));
140}
141
142int
143parse(int argc, char *argv[])
144{
145 struct ctl_command *ctl = NULL((void *)0);
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((void *)0); i++) {
153 if (strncmp(ctl_commands[i].name,
154 argv[0], strlen(argv[0])) == 0) {
155 if (ctl != NULL((void *)0)) {
156 fprintf(stderr(&__sF[2]),
157 "ambiguous argument: %s\n", argv[0]);
158 usage();
159 }
160 ctl = &ctl_commands[i];
161 }
162 }
163
164 if (ctl == NULL((void *)0)) {
165 fprintf(stderr(&__sF[2]), "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((void *)0)) == -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
188int
189vmmaction(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"/var/run/vmd.sock", "r") == -1)
200 err(1, "unveil %s", SOCKET_NAME"/var/run/vmd.sock");
201 if ((ctl_sock = socket(AF_UNIX1,
202 SOCK_STREAM1|SOCK_CLOEXEC0x8000, 0)) == -1)
203 err(1, "socket");
204
205 memset(&sun, 0, sizeof(sun));
206 sun.sun_family = AF_UNIX1;
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((void *)0))
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(*__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((void *)0), 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(*__errno()) != EAGAIN35)
281 err(1, "write error");
282
283 while (!done) {
284 if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35)
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)((&imsg)->hdr.len - sizeof(struct imsg_hdr)) == sizeof(ret))
297 memcpy(&ret, imsg.data, sizeof(ret));
298 else
299 ret = 0;
300 if (ret != 0) {
301 errno(*__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_WAIT0x02;
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
349void
350parse_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
365int
366parse_ifs(struct parse_result *res, char *word, int val)
367{
368 const char *error;
369
370 if (word != NULL((void *)0)) {
371 val = strtonum(word, 1, INT_MAX2147483647, &error);
372 if (error != NULL((void *)0)) {
373 warnx("count is %s: %s", error, word);
374 return (-1);
375 }
376 }
377 res->nifs = val;
378
379 return (0);
380}
381
382int
383parse_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((void *)0)) {
390 warn("reallocarray");
391 return (-1);
392 }
393 if ((s = strdup(word)) == NULL((void *)0)) {
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
404int
405parse_size(struct parse_result *res, char *word)
406{
407 long long val = 0;
408
409 if (word != NULL((void *)0)) {
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
428int
429parse_disktype(const char *s, const char **ret)
430{
431 char buf[BUFSIZ1024];
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"raw") == s && *(s + strlen(RAW_FMT"raw")) == ':') {
440 *ret = s + strlen(RAW_FMT"raw") + 1;
441 return (VMDF_RAW0x01);
442 }
443 if (strstr(s, QCOW2_FMT"qcow2") == s && *(s + strlen(QCOW2_FMT"qcow2")) == ':') {
444 *ret = s + strlen(QCOW2_FMT"qcow2") + 1;
445 return (VMDF_QCOW20x02);
446 }
447
448 /* Or try to derive the format from the file signature */
449 if ((fd = open(s, O_RDONLY0x0000)) != -1) {
450 len = read(fd, buf, sizeof(buf));
451 close(fd);
452
453 if (len >= (ssize_t)strlen(VM_MAGIC_QCOW"QFI\xfb") &&
454 strncmp(buf, VM_MAGIC_QCOW"QFI\xfb",
455 strlen(VM_MAGIC_QCOW"QFI\xfb")) == 0) {
456 /* Return qcow2, the version will be checked later */
457 return (VMDF_QCOW20x02);
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((void *)0) && *(++ext) != '\0') {
467 if (strcasecmp(ext, RAW_FMT"raw") == 0)
468 return (VMDF_RAW0x01);
469 else if (strcasecmp(ext, QCOW2_FMT"qcow2") == 0)
470 return (VMDF_QCOW20x02);
471 }
472
473 /* Fallback to raw */
474 return (VMDF_RAW0x01);
475}
476
477int
478parse_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((void *)0)) {
486 warn("reallocarray");
487 return (-1);
488 }
489 if ((disktypes = reallocarray(res->disktypes, res->ndisks + 1,
490 sizeof(int))) == NULL((void *)0)) {
491 warn("reallocarray");
492 return -1;
493 }
494 if ((s = strdup(word)) == NULL((void *)0)) {
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
507int
508parse_vmid(struct parse_result *res, char *word, int needname)
509{
510 const char *error;
511 uint32_t id;
512
513 if (word == NULL((void *)0)) {
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_MAX0xffffffffU, &error);
522 if (error == NULL((void *)0)) {
523 if (needname) {
524 warnx("invalid vm name");
525 return (-1);
526 } else {
527 res->id = id;
528 res->name = NULL((void *)0);
529 }
530 } else {
531 if (strlen(word) >= VMM_MAX_NAME_LEN64) {
532 warnx("name too long");
533 return (-1);
534 }
535 res->id = 0;
536 if ((res->name = strdup(word)) == NULL((void *)0))
537 errx(1, "strdup");
538 }
539
540 return (0);
541}
542
543int
544parse_instance(struct parse_result *res, char *word)
545{
546 if (strlen(word) >= VMM_MAX_NAME_LEN64) {
547 warnx("instance vm name too long");
548 return (-1);
549 }
550 res->id = 0;
551 if ((res->instance = strdup(word)) == NULL((void *)0))
552 errx(1, "strdup");
553
554 return (0);
555}
556
557int
558ctl_create(struct parse_result *res, int argc, char *argv[])
559{
560 int ch, ret, type;
561 const char *disk, *format, *base = NULL((void *)0), *input = NULL((void *)0);
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((void *)0)) == -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_QCOW20x02)
598 errx(1, "base images require qcow2 disk format");
599 if (res->size == 0 && !base) {
600 fprintf(stderr(&__sF[2]), "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(*__errno()) = ret;
607 err(1, "create imagefile operation failed");
608 } else
609 warnx("%s imagefile created", format);
610
611 return (0);
612}
613
614int
615ctl_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((void *)0);
626 uint8_t *buf = NULL((void *)0), *zerobuf = NULL((void *)0);
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_RDONLY0x0000,
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)((dstsize + 1048576 - 1) & ~(1048576 - 1));
655
656 if ((ret = create_imagefile(dst.type, dst.disk, NULL((void *)0),
657 dst.size / 1048576, &format)) != 0) {
658 errno(*__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_RDWR0x0002,
664 &dst.file, &dst.size)) == -1) {
665 errstr = "failed to open destination image file";
666 goto done;
667 }
668
669 if (pledge("stdio", NULL((void *)0)) == -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((void *)0) ||
678 (zerobuf = calloc(1, buflen)) == NULL((void *)0)) {
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)((((off_t)buflen)<(src.size - off))?((off_t)buflen):(src.size
- off))
;
687 if ((rlen = src.file.pread(src.file.p,
Although the value stored to 'rlen' is used in the enclosing expression, the value is never actually read from 'rlen'
688 buf, (size_t)len, off)) != len) {
689 errno(*__errno()) = EIO5;
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(*__errno()) = EIO5;
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((void *)0))
731 src.file.close(src.file.p, 0);
732 if (dst.file.p != NULL((void *)0))
733 dst.file.close(dst.file.p, 0);
734 if (errstr != NULL((void *)0))
735 errx(1, "%s", errstr);
736 else
737 warnx("%s imagefile created", format);
738
739 return (0);
740}
741
742int
743ctl_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
754int
755ctl_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((void *)0))
761 err(1, "strdup");
762
763 return (vmmaction(res));
764}
765
766int
767ctl_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
782int
783ctl_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
791int
792ctl_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_ALL0xff;
797 else if (strcasecmp("vms", argv[1]) == 0)
798 res->mode = CONFIG_VMS0x01;
799 else if (strcasecmp("switches", argv[1]) == 0)
800 res->mode = CONFIG_SWITCHES0x02;
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_ALL0xff;
808
809 return (vmmaction(res));
810}
811
812int
813ctl_start(struct parse_result *res, int argc, char *argv[])
814{
815 int ch, i, type;
816 char path[PATH_MAX1024];
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((void *)0))
825 err(1, "invalid boot image path");
826 if ((res->path = strdup(path)) == NULL((void *)0))
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_DISK1;
834 else if (strcmp("cdrom", optarg) == 0)
835 res->bootdevice = VMBOOTDEV_CDROM2;
836 else if (strcmp("net", optarg) == 0)
837 res->bootdevice = VMBOOTDEV_NET3;
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((void *)0))
845 err(1, "invalid iso image path");
846 if ((res->isopath = strdup(path)) == NULL((void *)0))
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((void *)0))
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
908int
909ctl_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_FORCE0x01;
917 break;
918 case 'w':
919 res->flags |= VMOP_WAIT0x02;
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
945int
946ctl_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
957int
958ctl_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
969int
970ctl_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
981int
982ctl_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
993int
994ctl_send(struct parse_result *res, int argc, char *argv[])
995{
996 if (pledge("stdio unix sendfd unveil", NULL((void *)0)) == -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
1007int
1008ctl_receive(struct parse_result *res, int argc, char *argv[])
1009{
1010 if (pledge("stdio unix sendfd unveil", NULL((void *)0)) == -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__attribute__((__noreturn__)) void
1022ctl_openconsole(const char *name)
1023{
1024 closefrom(STDERR_FILENO2 + 1);
1025 if (unveil(VMCTL_CU"/usr/bin/cu", "x") == -1)
1026 err(1, "unveil %s", VMCTL_CU"/usr/bin/cu");
1027 execl(VMCTL_CU"/usr/bin/cu", VMCTL_CU"/usr/bin/cu", "-r", "-l", name, "-s", "115200",
1028 (char *)NULL((void *)0));
1029 err(1, "failed to open the console");
1030}