aboutsummaryrefslogtreecommitdiff
path: root/tracecmd/trace-setup-guest.c
diff options
context:
space:
mode:
Diffstat (limited to 'tracecmd/trace-setup-guest.c')
-rw-r--r--tracecmd/trace-setup-guest.c252
1 files changed, 252 insertions, 0 deletions
diff --git a/tracecmd/trace-setup-guest.c b/tracecmd/trace-setup-guest.c
new file mode 100644
index 00000000..f20b48e2
--- /dev/null
+++ b/tracecmd/trace-setup-guest.c
@@ -0,0 +1,252 @@
+// 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);
+}