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:
parent
c8581f3710
commit
6f89dc3650
2 changed files with 82 additions and 10 deletions
2
Makefile
2
Makefile
|
@ -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
90
qrap.c
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue