253 lines
4.7 KiB
C
253 lines
4.7 KiB
C
|
|
// SPDX-License-Identifier: GPL-2.0
|
||
|
|
/*
|
||
|
|
* Copyright (C) 2019 VMware Inc, Slavomir Kaslev <kaslevs@vmware.com>
|
||
|
|
*
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include <errno.h>
|
||
|
|
#include <fcntl.h>
|
||
|
|
#include <getopt.h>
|
||
|
|
#include <grp.h>
|
||
|
|
#include <stdio.h>
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <string.h>
|
||
|
|
#include <sys/stat.h>
|
||
|
|
#include <unistd.h>
|
||
|
|
|
||
|
|
#include "trace-local.h"
|
||
|
|
#include "trace-msg.h"
|
||
|
|
|
||
|
|
static int make_dir(const char *path, mode_t mode)
|
||
|
|
{
|
||
|
|
char buf[PATH_MAX+2], *p;
|
||
|
|
|
||
|
|
strncpy(buf, path, sizeof(buf));
|
||
|
|
if (buf[PATH_MAX])
|
||
|
|
return -E2BIG;
|
||
|
|
|
||
|
|
for (p = buf; *p; p++) {
|
||
|
|
p += strspn(p, "/");
|
||
|
|
p += strcspn(p, "/");
|
||
|
|
*p = '\0';
|
||
|
|
if (mkdir(buf, mode) < 0 && errno != EEXIST)
|
||
|
|
return -errno;
|
||
|
|
*p = '/';
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int make_fifo(const char *path, mode_t mode)
|
||
|
|
{
|
||
|
|
struct stat st;
|
||
|
|
|
||
|
|
if (!stat(path, &st)) {
|
||
|
|
if (S_ISFIFO(st.st_mode))
|
||
|
|
return 0;
|
||
|
|
return -EEXIST;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mkfifo(path, mode))
|
||
|
|
return -errno;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int make_guest_dir(const char *guest)
|
||
|
|
{
|
||
|
|
char path[PATH_MAX];
|
||
|
|
|
||
|
|
snprintf(path, sizeof(path), GUEST_DIR_FMT, guest);
|
||
|
|
return make_dir(path, 0750);
|
||
|
|
}
|
||
|
|
|
||
|
|
static int make_guest_fifo(const char *guest, int cpu, mode_t mode)
|
||
|
|
{
|
||
|
|
static const char *exts[] = {".in", ".out"};
|
||
|
|
char path[PATH_MAX];
|
||
|
|
int i, ret = 0;
|
||
|
|
|
||
|
|
for (i = 0; i < ARRAY_SIZE(exts); i++) {
|
||
|
|
snprintf(path, sizeof(path), GUEST_FIFO_FMT "%s",
|
||
|
|
guest, cpu, exts[i]);
|
||
|
|
ret = make_fifo(path, mode);
|
||
|
|
if (ret < 0)
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int make_guest_fifos(const char *guest, int nr_cpus, mode_t mode)
|
||
|
|
{
|
||
|
|
int i, ret = 0;
|
||
|
|
mode_t mask;
|
||
|
|
|
||
|
|
mask = umask(0);
|
||
|
|
for (i = 0; i < nr_cpus; i++) {
|
||
|
|
ret = make_guest_fifo(guest, i, mode);
|
||
|
|
if (ret < 0)
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
umask(mask);
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int get_guest_cpu_count(const char *guest)
|
||
|
|
{
|
||
|
|
const char *cmd_fmt = "virsh vcpucount --maximum '%s' 2>/dev/null";
|
||
|
|
int nr_cpus = -1;
|
||
|
|
char cmd[1024];
|
||
|
|
FILE *f;
|
||
|
|
|
||
|
|
snprintf(cmd, sizeof(cmd), cmd_fmt, guest);
|
||
|
|
f = popen(cmd, "r");
|
||
|
|
if (!f)
|
||
|
|
return -errno;
|
||
|
|
|
||
|
|
fscanf(f, "%d", &nr_cpus);
|
||
|
|
pclose(f);
|
||
|
|
|
||
|
|
return nr_cpus;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int attach_guest_fifos(const char *guest, int nr_cpus)
|
||
|
|
{
|
||
|
|
const char *cmd_fmt =
|
||
|
|
"virsh attach-device --config '%s' '%s' >/dev/null 2>/dev/null";
|
||
|
|
const char *xml_fmt =
|
||
|
|
"<channel type='pipe'>\n"
|
||
|
|
" <source path='%s'/>\n"
|
||
|
|
" <target type='virtio' name='%s%d'/>\n"
|
||
|
|
"</channel>";
|
||
|
|
char tmp_path[PATH_MAX], path[PATH_MAX];
|
||
|
|
char cmd[PATH_MAX], xml[PATH_MAX];
|
||
|
|
int i, fd, ret = 0;
|
||
|
|
|
||
|
|
#ifdef __ANDROID__
|
||
|
|
strcpy(tmp_path, "/data/local/tmp/pipexmlXXXXXX");
|
||
|
|
#else /* !__ANDROID__ */
|
||
|
|
strcpy(tmp_path, "/tmp/pipexmlXXXXXX");
|
||
|
|
#endif /* __ANDROID__ */
|
||
|
|
|
||
|
|
fd = mkstemp(tmp_path);
|
||
|
|
if (fd < 0)
|
||
|
|
return fd;
|
||
|
|
|
||
|
|
for (i = 0; i < nr_cpus; i++) {
|
||
|
|
snprintf(path, sizeof(path), GUEST_FIFO_FMT, guest, i);
|
||
|
|
snprintf(xml, sizeof(xml), xml_fmt, path, GUEST_PIPE_NAME, i);
|
||
|
|
pwrite(fd, xml, strlen(xml), 0);
|
||
|
|
|
||
|
|
snprintf(cmd, sizeof(cmd), cmd_fmt, guest, tmp_path);
|
||
|
|
errno = 0;
|
||
|
|
if (system(cmd) != 0) {
|
||
|
|
ret = -errno;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
close(fd);
|
||
|
|
unlink(tmp_path);
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void do_setup_guest(const char *guest, int nr_cpus,
|
||
|
|
mode_t mode, gid_t gid, bool attach)
|
||
|
|
{
|
||
|
|
gid_t save_egid;
|
||
|
|
int ret;
|
||
|
|
|
||
|
|
if (gid != -1) {
|
||
|
|
save_egid = getegid();
|
||
|
|
ret = setegid(gid);
|
||
|
|
if (ret < 0)
|
||
|
|
die("failed to set effective group ID");
|
||
|
|
}
|
||
|
|
|
||
|
|
ret = make_guest_dir(guest);
|
||
|
|
if (ret < 0)
|
||
|
|
die("failed to create guest directory for %s", guest);
|
||
|
|
|
||
|
|
ret = make_guest_fifos(guest, nr_cpus, mode);
|
||
|
|
if (ret < 0)
|
||
|
|
die("failed to create FIFOs for %s", guest);
|
||
|
|
|
||
|
|
if (attach) {
|
||
|
|
ret = attach_guest_fifos(guest, nr_cpus);
|
||
|
|
if (ret < 0)
|
||
|
|
die("failed to attach FIFOs to %s", guest);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (gid != -1) {
|
||
|
|
ret = setegid(save_egid);
|
||
|
|
if (ret < 0)
|
||
|
|
die("failed to restore effective group ID");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void trace_setup_guest(int argc, char **argv)
|
||
|
|
{
|
||
|
|
bool attach = false;
|
||
|
|
struct group *group;
|
||
|
|
mode_t mode = 0660;
|
||
|
|
int nr_cpus = -1;
|
||
|
|
gid_t gid = -1;
|
||
|
|
char *guest;
|
||
|
|
|
||
|
|
if (argc < 2)
|
||
|
|
usage(argv);
|
||
|
|
|
||
|
|
if (strcmp(argv[1], "setup-guest") != 0)
|
||
|
|
usage(argv);
|
||
|
|
|
||
|
|
for (;;) {
|
||
|
|
int c, option_index = 0;
|
||
|
|
static struct option long_options[] = {
|
||
|
|
{"help", no_argument, NULL, '?'},
|
||
|
|
{NULL, 0, NULL, 0}
|
||
|
|
};
|
||
|
|
|
||
|
|
c = getopt_long(argc-1, argv+1, "+hc:p:g:a",
|
||
|
|
long_options, &option_index);
|
||
|
|
if (c == -1)
|
||
|
|
break;
|
||
|
|
switch (c) {
|
||
|
|
case 'h':
|
||
|
|
usage(argv);
|
||
|
|
break;
|
||
|
|
case 'c':
|
||
|
|
nr_cpus = atoi(optarg);
|
||
|
|
break;
|
||
|
|
case 'p':
|
||
|
|
mode = strtol(optarg, NULL, 8);
|
||
|
|
break;
|
||
|
|
case 'g':
|
||
|
|
group = getgrnam(optarg);
|
||
|
|
if (!group)
|
||
|
|
die("group %s does not exist", optarg);
|
||
|
|
gid = group->gr_gid;
|
||
|
|
break;
|
||
|
|
case 'a':
|
||
|
|
attach = true;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
usage(argv);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (optind != argc-2)
|
||
|
|
usage(argv);
|
||
|
|
|
||
|
|
guest = argv[optind+1];
|
||
|
|
|
||
|
|
if (nr_cpus <= 0)
|
||
|
|
nr_cpus = get_guest_cpu_count(guest);
|
||
|
|
|
||
|
|
if (nr_cpus <= 0)
|
||
|
|
die("invalid number of cpus for guest %s", guest);
|
||
|
|
|
||
|
|
do_setup_guest(guest, nr_cpus, mode, gid, attach);
|
||
|
|
}
|