@@ -35,6 +35,7 @@ TRACE_CMD_OBJS += trace-msg.o
ifeq ($(VSOCK_DEFINED), 1)
TRACE_CMD_OBJS += trace-agent.o
+TRACE_CMD_OBJS += trace-setup-guest.o
endif
ALL_OBJS := $(TRACE_CMD_OBJS:%.o=$(bdir)/%.o)
@@ -14,6 +14,10 @@
#define TRACE_AGENT_DEFAULT_PORT 823
+#define GUEST_PIPE_NAME "trace-pipe-cpu"
+#define GUEST_DIR_FMT "/var/lib/trace-cmd/virt/%s"
+#define GUEST_FIFO_FMT GUEST_DIR_FMT "/" GUEST_PIPE_NAME "%d"
+
extern int debug;
extern int quiet;
@@ -68,6 +72,8 @@ void trace_listen(int argc, char **argv);
void trace_agent(int argc, char **argv);
+void trace_setup_guest(int argc, char **argv);
+
void trace_restore(int argc, char **argv);
void trace_clear(int argc, char **argv);
@@ -85,6 +85,7 @@ struct command commands[] = {
{"listen", trace_listen},
#ifdef VSOCK
{"agent", trace_agent},
+ {"setup-guest", trace_setup_guest},
#endif
{"split", trace_split},
{"restore", trace_restore},
new file mode 100644
@@ -0,0 +1,178 @@
+// 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 void do_setup_guest(const char *guest, int nr_cpus, mode_t mode, gid_t gid)
+{
+ gid_t save_egid;
+ int ret;
+
+ if (gid != -1) {
+ save_egid = getegid();
+ ret = setegid(gid);
+ if (ret < 0)
+ pdie("failed to set effective group ID");
+ }
+
+ ret = make_guest_dir(guest);
+ if (ret < 0)
+ pdie("failed to create guest directory for %s", guest);
+
+ ret = make_guest_fifos(guest, nr_cpus, mode);
+ if (ret < 0)
+ pdie("failed to create FIFOs for %s", guest);
+
+ if (gid != -1) {
+ ret = setegid(save_egid);
+ if (ret < 0)
+ pdie("failed to restore effective group ID");
+ }
+}
+
+void trace_setup_guest(int argc, char **argv)
+{
+ 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:",
+ 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)
+ pdie("group %s does not exist", optarg);
+ gid = group->gr_gid;
+ break;
+ default:
+ usage(argv);
+ }
+ }
+
+ if (optind != argc-2)
+ usage(argv);
+
+ guest = argv[optind+1];
+
+ if (nr_cpus <= 0)
+ pdie("invalid number of cpus for guest %s", guest);
+
+ do_setup_guest(guest, nr_cpus, mode, gid);
+}
@@ -248,6 +248,14 @@ static struct usage_help usage_help[] = {
" -p port number to listen on.\n"
" -D run in daemon mode.\n"
},
+ {
+ "setup-guest",
+ "create FIFOs for tracing guest VMs",
+ " %s setup-guest -c cpus[-p perm][-g group] guest\n"
+ " -c number of guest virtual CPUs\n"
+ " -p FIFOs permissions (default: 0660)\n"
+ " -g FIFOs group owner\n"
+ },
#endif
{
"list",