xref: /aosp_15_r20/external/trace-cmd/tracecmd/trace-setup-guest.c (revision 58e6ee5f017f6a8912852c892d18457e4bafb554)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2019 VMware Inc, Slavomir Kaslev <[email protected]>
4  *
5  */
6 
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <getopt.h>
10 #include <grp.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/stat.h>
15 #include <unistd.h>
16 
17 #include "trace-local.h"
18 #include "trace-msg.h"
19 
make_dir(const char * path,mode_t mode)20 static int make_dir(const char *path, mode_t mode)
21 {
22 	char buf[PATH_MAX+2], *p;
23 
24 	strncpy(buf, path, sizeof(buf));
25 	if (buf[PATH_MAX])
26 		return -E2BIG;
27 
28 	for (p = buf; *p; p++) {
29 		p += strspn(p, "/");
30 		p += strcspn(p, "/");
31 		*p = '\0';
32 		if (mkdir(buf, mode) < 0 && errno != EEXIST)
33 			return -errno;
34 		*p = '/';
35 	}
36 
37 	return 0;
38 }
39 
make_fifo(const char * path,mode_t mode)40 static int make_fifo(const char *path, mode_t mode)
41 {
42 	struct stat st;
43 
44 	if (!stat(path, &st)) {
45 		if (S_ISFIFO(st.st_mode))
46 			return 0;
47 		return -EEXIST;
48 	}
49 
50 	if (mkfifo(path, mode))
51 		return -errno;
52 	return 0;
53 }
54 
make_guest_dir(const char * guest)55 static int make_guest_dir(const char *guest)
56 {
57 	char path[PATH_MAX];
58 
59 	snprintf(path, sizeof(path), GUEST_DIR_FMT, guest);
60 	return make_dir(path, 0750);
61 }
62 
make_guest_fifo(const char * guest,int cpu,mode_t mode)63 static int make_guest_fifo(const char *guest, int cpu, mode_t mode)
64 {
65 	static const char *exts[] = {".in", ".out"};
66 	char path[PATH_MAX];
67 	int i, ret = 0;
68 
69 	for (i = 0; i < ARRAY_SIZE(exts); i++) {
70 		snprintf(path, sizeof(path), GUEST_FIFO_FMT "%s",
71 			 guest, cpu, exts[i]);
72 		ret = make_fifo(path, mode);
73 		if (ret < 0)
74 			break;
75 	}
76 
77 	return ret;
78 }
79 
make_guest_fifos(const char * guest,int nr_cpus,mode_t mode)80 static int make_guest_fifos(const char *guest, int nr_cpus, mode_t mode)
81 {
82 	int i, ret = 0;
83 	mode_t mask;
84 
85 	mask = umask(0);
86 	for (i = 0; i < nr_cpus; i++) {
87 		ret = make_guest_fifo(guest, i, mode);
88 		if (ret < 0)
89 			break;
90 	}
91 	umask(mask);
92 
93 	return ret;
94 }
95 
get_guest_cpu_count(const char * guest)96 static int get_guest_cpu_count(const char *guest)
97 {
98 	const char *cmd_fmt = "virsh vcpucount --maximum '%s' 2>/dev/null";
99 	int nr_cpus = -1;
100 	char cmd[1024];
101 	FILE *f;
102 
103 	snprintf(cmd, sizeof(cmd), cmd_fmt, guest);
104 	f = popen(cmd, "r");
105 	if (!f)
106 		return -errno;
107 
108 	fscanf(f, "%d", &nr_cpus);
109 	pclose(f);
110 
111 	return nr_cpus;
112 }
113 
attach_guest_fifos(const char * guest,int nr_cpus)114 static int attach_guest_fifos(const char *guest, int nr_cpus)
115 {
116 	const char *cmd_fmt =
117 		"virsh attach-device --config '%s' '%s' >/dev/null 2>/dev/null";
118 	const char *xml_fmt =
119 		"<channel type='pipe'>\n"
120 		"  <source path='%s'/>\n"
121 		"  <target type='virtio' name='%s%d'/>\n"
122 		"</channel>";
123 	char tmp_path[PATH_MAX], path[PATH_MAX];
124 	char cmd[PATH_MAX], xml[PATH_MAX];
125 	int i, fd, ret = 0;
126 
127 #ifdef __ANDROID__
128 	strcpy(tmp_path, "/data/local/tmp/pipexmlXXXXXX");
129 #else	/* !__ANDROID__ */
130 	strcpy(tmp_path, "/tmp/pipexmlXXXXXX");
131 #endif	/* __ANDROID__ */
132 
133 	fd = mkstemp(tmp_path);
134 	if (fd < 0)
135 		return fd;
136 
137 	for (i = 0; i < nr_cpus; i++) {
138 		snprintf(path, sizeof(path), GUEST_FIFO_FMT, guest, i);
139 		snprintf(xml, sizeof(xml), xml_fmt, path, GUEST_PIPE_NAME, i);
140 		pwrite(fd, xml, strlen(xml), 0);
141 
142 		snprintf(cmd, sizeof(cmd), cmd_fmt, guest, tmp_path);
143 		errno = 0;
144 		if (system(cmd) != 0) {
145 			ret = -errno;
146 			break;
147 		}
148 	}
149 
150 	close(fd);
151 	unlink(tmp_path);
152 
153 	return ret;
154 }
155 
do_setup_guest(const char * guest,int nr_cpus,mode_t mode,gid_t gid,bool attach)156 static void do_setup_guest(const char *guest, int nr_cpus,
157 			   mode_t mode, gid_t gid, bool attach)
158 {
159 	gid_t save_egid;
160 	int ret;
161 
162 	if (gid != -1) {
163 		save_egid = getegid();
164 		ret = setegid(gid);
165 		if (ret < 0)
166 			die("failed to set effective group ID");
167 	}
168 
169 	ret = make_guest_dir(guest);
170 	if (ret < 0)
171 		die("failed to create guest directory for %s", guest);
172 
173 	ret = make_guest_fifos(guest, nr_cpus, mode);
174 	if (ret < 0)
175 		die("failed to create FIFOs for %s", guest);
176 
177 	if (attach) {
178 		ret = attach_guest_fifos(guest, nr_cpus);
179 		if (ret < 0)
180 			die("failed to attach FIFOs to %s", guest);
181 	}
182 
183 	if (gid != -1) {
184 		ret = setegid(save_egid);
185 		if (ret < 0)
186 			die("failed to restore effective group ID");
187 	}
188 }
189 
trace_setup_guest(int argc,char ** argv)190 void trace_setup_guest(int argc, char **argv)
191 {
192 	bool attach = false;
193 	struct group *group;
194 	mode_t mode = 0660;
195 	int nr_cpus = -1;
196 	gid_t gid = -1;
197 	char *guest;
198 
199 	if (argc < 2)
200 		usage(argv);
201 
202 	if (strcmp(argv[1], "setup-guest") != 0)
203 		usage(argv);
204 
205 	for (;;) {
206 		int c, option_index = 0;
207 		static struct option long_options[] = {
208 			{"help", no_argument, NULL, '?'},
209 			{NULL, 0, NULL, 0}
210 		};
211 
212 		c = getopt_long(argc-1, argv+1, "+hc:p:g:a",
213 				long_options, &option_index);
214 		if (c == -1)
215 			break;
216 		switch (c) {
217 		case 'h':
218 			usage(argv);
219 			break;
220 		case 'c':
221 			nr_cpus = atoi(optarg);
222 			break;
223 		case 'p':
224 			mode = strtol(optarg, NULL, 8);
225 			break;
226 		case 'g':
227 			group = getgrnam(optarg);
228 			if (!group)
229 				die("group %s does not exist", optarg);
230 			gid = group->gr_gid;
231 			break;
232 		case 'a':
233 			attach = true;
234 			break;
235 		default:
236 			usage(argv);
237 		}
238 	}
239 
240 	if (optind != argc-2)
241 		usage(argv);
242 
243 	guest = argv[optind+1];
244 
245 	if (nr_cpus <= 0)
246 		nr_cpus = get_guest_cpu_count(guest);
247 
248 	if (nr_cpus <= 0)
249 		die("invalid number of cpus for guest %s", guest);
250 
251 	do_setup_guest(guest, nr_cpus, mode, gid, attach);
252 }
253