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>
This commit is contained in:
Stefano Brivio 2021-05-10 12:38:50 +02:00
parent c8581f3710
commit 6f89dc3650
2 changed files with 82 additions and 10 deletions

View file

@ -6,7 +6,7 @@ passt: passt.c passt.h arp.c arp.h dhcp.c dhcp.h dhcpv6.c dhcpv6.h ndp.c ndp.h s
$(CC) $(CFLAGS) passt.c arp.c dhcp.c dhcpv6.c ndp.c siphash.c tap.c icmp.c tcp.c udp.c util.c -o passt
qrap: qrap.c passt.h
$(CC) $(CFLAGS) qrap.c -o qrap
$(CC) $(CFLAGS) -DARCH=\"$(shell uname -m)\" qrap.c -o qrap
.PHONY: clean
clean:

90
qrap.c
View file

@ -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];
fd = strtol(argv[1], NULL, 0);
if (fd < 3 || fd > INT_MAX || errno)
usage(argv[0]);
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;
}
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;