diff options
author | Stefano Brivio <sbrivio@redhat.com> | 2021-05-10 12:38:50 +0200 |
---|---|---|
committer | Stefano Brivio <sbrivio@redhat.com> | 2021-05-10 12:38:50 +0200 |
commit | 6f89dc3650847e970dd9d0d5c986793e22b73a00 (patch) | |
tree | 7b110d3cf5374a5cc68274ec31eea12c9f1978dd /qrap.c | |
parent | c8581f3710335ae6be68909c1c8307aa66990428 (diff) | |
download | passt-6f89dc3650847e970dd9d0d5c986793e22b73a00.tar passt-6f89dc3650847e970dd9d0d5c986793e22b73a00.tar.gz passt-6f89dc3650847e970dd9d0d5c986793e22b73a00.tar.bz2 passt-6f89dc3650847e970dd9d0d5c986793e22b73a00.tar.lz passt-6f89dc3650847e970dd9d0d5c986793e22b73a00.tar.xz passt-6f89dc3650847e970dd9d0d5c986793e22b73a00.tar.zst passt-6f89dc3650847e970dd9d0d5c986793e22b73a00.zip |
qrap: Find qemu command if not passed, patch command line
It might be impractical to pass options to qrap when using libvirt,
because the <emulator/> tag expects a path to an executable, without
further arguments.
If the first argument is not a plausible socket number, and the
second argument is not a valid executable, look up a qemu command
from a list of possible names, then start it patching the command line
to include the -netdev fd= parameter corresponding to the AF_UNIX
domain socket we just opened.
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Diffstat (limited to 'qrap.c')
-rw-r--r-- | qrap.c | 90 |
1 files changed, 81 insertions, 9 deletions
@@ -19,20 +19,36 @@ #include <sys/socket.h> #include <sys/un.h> #include <errno.h> -#include <limits.h> #include <linux/if_ether.h> #include <linux/ipv6.h> +#include <linux/limits.h> +#include <limits.h> #include <net/if.h> #include "passt.h" +static char *qemu_names[] = { + "kvm", + "qemu-kvm", +#ifdef ARCH + "qemu-system-" ARCH, +#endif + NULL, +}; + +#define DEFAULT_FD 5 + /** * usage() - Print usage and exit * @name: Executable name */ void usage(const char *name) { - fprintf(stderr, "Usage: %s FDNUM QEMU_CMD ...\n", name); + fprintf(stderr, "Usage: %s [FDNUM QEMU_CMD] ...\n", name); + fprintf(stderr, "\n"); + fprintf(stderr, "If first and second arguments aren't a socket number\n" + "and a path, %s will try to locate a qemu binary\n" + "and directly patch the command line\n", name); exit(EXIT_FAILURE); } @@ -46,20 +62,60 @@ void usage(const char *name) */ int main(int argc, char **argv) { + char *qemu_argv[ARG_MAX], net_id[ARG_MAX] = { 0 }, *net_id_end; struct sockaddr_un addr = { .sun_family = AF_UNIX, .sun_path = UNIX_SOCK_PATH, }; + int i, s, qemu_argc = 0; + char fd_str[ARG_MAX]; long fd; - int s; - if (argc < 3) - usage(argv[0]); + if (argc >= 3) { + fd = strtol(argv[1], NULL, 0); + if (fd >= 3 && fd < INT_MAX && !errno) { + char env_path[ARG_MAX], *p, command[ARG_MAX]; + + strncpy(env_path, getenv("PATH"), ARG_MAX); + p = strtok(env_path, ":"); + while (p) { + snprintf(command, ARG_MAX, "%s/%s", p, argv[2]); + if (!access(command, X_OK)) + goto valid_args; + + p = strtok(NULL, ":"); + } + } + } + + fd = DEFAULT_FD; + for (qemu_argc = 1, i = 1; i < argc; i++) { + char *p; + + if (!strcmp(argv[i], "-net") || (!strcmp(argv[i], "-netdev"))) { + i++; + continue; + } - fd = strtol(argv[1], NULL, 0); - if (fd < 3 || fd > INT_MAX || errno) - usage(argv[0]); + if (!*net_id && (p = strstr(argv[i], ",netdev="))) + strncpy(net_id, p + strlen(",netdev="), ARG_MAX); + qemu_argv[qemu_argc++] = argv[i]; + } + + if (*net_id) { + net_id_end = strpbrk(net_id, ", "); + if (net_id_end) + *net_id_end = 0; + } + + qemu_argv[qemu_argc++] = "-netdev"; + snprintf(fd_str, ARG_MAX, "socket,fd=%u,id=%s", DEFAULT_FD, + *net_id ? net_id : "hostnet0"); + qemu_argv[qemu_argc++] = fd_str; + qemu_argv[qemu_argc] = NULL; + +valid_args: s = socket(AF_UNIX, SOCK_STREAM, 0); if (s < 0) { perror("socket"); @@ -78,7 +134,23 @@ int main(int argc, char **argv) close(s); - execvp(argv[2], argv + 2); + if (qemu_argc) { + char *name; + + for (name = qemu_names[0]; name; name++) { + qemu_argv[0] = name; + execvp(name, qemu_argv); + if (errno != ENOENT) { + perror("execvp"); + usage(argv[0]); + } + } + if (errno == ENOENT) + fprintf(stderr, "Couldn't find qemu command\n"); + } else { + execvp(argv[2], argv + 2); + } + perror("execvp"); return EXIT_FAILURE; |