xref: /aosp_15_r20/external/libtracefs/src/tracefs-utils.c (revision 287e80b3a36113050663245e7f2c00d274188f18)
1*287e80b3SSadaf Ebrahimi // SPDX-License-Identifier: LGPL-2.1
2*287e80b3SSadaf Ebrahimi /*
3*287e80b3SSadaf Ebrahimi  * Copyright (C) 2008, 2009, 2010 Red Hat Inc, Steven Rostedt <[email protected]>
4*287e80b3SSadaf Ebrahimi  *
5*287e80b3SSadaf Ebrahimi  * Updates:
6*287e80b3SSadaf Ebrahimi  * Copyright (C) 2019, VMware, Tzvetomir Stoyanov <[email protected]>
7*287e80b3SSadaf Ebrahimi  *
8*287e80b3SSadaf Ebrahimi  */
9*287e80b3SSadaf Ebrahimi #include <stdlib.h>
10*287e80b3SSadaf Ebrahimi #include <sys/mount.h>
11*287e80b3SSadaf Ebrahimi #include <sys/stat.h>
12*287e80b3SSadaf Ebrahimi #include <linux/limits.h>
13*287e80b3SSadaf Ebrahimi #include <sys/stat.h>
14*287e80b3SSadaf Ebrahimi #include <fcntl.h>
15*287e80b3SSadaf Ebrahimi #include <unistd.h>
16*287e80b3SSadaf Ebrahimi #include <errno.h>
17*287e80b3SSadaf Ebrahimi 
18*287e80b3SSadaf Ebrahimi #include <event-parse.h>
19*287e80b3SSadaf Ebrahimi #include <event-utils.h>
20*287e80b3SSadaf Ebrahimi #include "tracefs.h"
21*287e80b3SSadaf Ebrahimi #include "tracefs-local.h"
22*287e80b3SSadaf Ebrahimi 
23*287e80b3SSadaf Ebrahimi #define TRACEFS_PATH "/sys/kernel/tracing"
24*287e80b3SSadaf Ebrahimi #define DEBUGFS_PATH "/sys/kernel/debug"
25*287e80b3SSadaf Ebrahimi 
26*287e80b3SSadaf Ebrahimi #define ERROR_LOG "error_log"
27*287e80b3SSadaf Ebrahimi 
28*287e80b3SSadaf Ebrahimi #define _STR(x) #x
29*287e80b3SSadaf Ebrahimi #define STR(x) _STR(x)
30*287e80b3SSadaf Ebrahimi 
31*287e80b3SSadaf Ebrahimi static int log_level = TEP_LOG_CRITICAL;
32*287e80b3SSadaf Ebrahimi static char *custom_tracing_dir;
33*287e80b3SSadaf Ebrahimi 
34*287e80b3SSadaf Ebrahimi /**
35*287e80b3SSadaf Ebrahimi  * tracefs_set_loglevel - set log level of the library
36*287e80b3SSadaf Ebrahimi  * @level: desired level of the library messages
37*287e80b3SSadaf Ebrahimi  */
tracefs_set_loglevel(enum tep_loglevel level)38*287e80b3SSadaf Ebrahimi void tracefs_set_loglevel(enum tep_loglevel level)
39*287e80b3SSadaf Ebrahimi {
40*287e80b3SSadaf Ebrahimi 	log_level = level;
41*287e80b3SSadaf Ebrahimi 	tep_set_loglevel(level);
42*287e80b3SSadaf Ebrahimi }
43*287e80b3SSadaf Ebrahimi 
tracefs_warning(const char * fmt,...)44*287e80b3SSadaf Ebrahimi void __weak tracefs_warning(const char *fmt, ...)
45*287e80b3SSadaf Ebrahimi {
46*287e80b3SSadaf Ebrahimi 	va_list ap;
47*287e80b3SSadaf Ebrahimi 
48*287e80b3SSadaf Ebrahimi 	if (log_level < TEP_LOG_WARNING)
49*287e80b3SSadaf Ebrahimi 		return;
50*287e80b3SSadaf Ebrahimi 
51*287e80b3SSadaf Ebrahimi 	va_start(ap, fmt);
52*287e80b3SSadaf Ebrahimi 	tep_vprint("libtracefs", TEP_LOG_WARNING, true, fmt, ap);
53*287e80b3SSadaf Ebrahimi 	va_end(ap);
54*287e80b3SSadaf Ebrahimi }
55*287e80b3SSadaf Ebrahimi 
mount_tracefs(void)56*287e80b3SSadaf Ebrahimi static int mount_tracefs(void)
57*287e80b3SSadaf Ebrahimi {
58*287e80b3SSadaf Ebrahimi 	struct stat st;
59*287e80b3SSadaf Ebrahimi 	int ret;
60*287e80b3SSadaf Ebrahimi 
61*287e80b3SSadaf Ebrahimi 	/* make sure debugfs exists */
62*287e80b3SSadaf Ebrahimi 	ret = stat(TRACEFS_PATH, &st);
63*287e80b3SSadaf Ebrahimi 	if (ret < 0)
64*287e80b3SSadaf Ebrahimi 		return -1;
65*287e80b3SSadaf Ebrahimi 
66*287e80b3SSadaf Ebrahimi 	ret = mount("nodev", TRACEFS_PATH,
67*287e80b3SSadaf Ebrahimi 		    "tracefs", 0, NULL);
68*287e80b3SSadaf Ebrahimi 
69*287e80b3SSadaf Ebrahimi 	return ret;
70*287e80b3SSadaf Ebrahimi }
71*287e80b3SSadaf Ebrahimi 
mount_debugfs(void)72*287e80b3SSadaf Ebrahimi static int mount_debugfs(void)
73*287e80b3SSadaf Ebrahimi {
74*287e80b3SSadaf Ebrahimi 	struct stat st;
75*287e80b3SSadaf Ebrahimi 	int ret;
76*287e80b3SSadaf Ebrahimi 
77*287e80b3SSadaf Ebrahimi 	/* make sure debugfs exists */
78*287e80b3SSadaf Ebrahimi 	ret = stat(DEBUGFS_PATH, &st);
79*287e80b3SSadaf Ebrahimi 	if (ret < 0)
80*287e80b3SSadaf Ebrahimi 		return -1;
81*287e80b3SSadaf Ebrahimi 
82*287e80b3SSadaf Ebrahimi 	ret = mount("nodev", DEBUGFS_PATH,
83*287e80b3SSadaf Ebrahimi 		    "debugfs", 0, NULL);
84*287e80b3SSadaf Ebrahimi 
85*287e80b3SSadaf Ebrahimi 	return ret;
86*287e80b3SSadaf Ebrahimi }
87*287e80b3SSadaf Ebrahimi 
88*287e80b3SSadaf Ebrahimi /* Exported for testing purpose only */
find_tracing_dir(bool debugfs,bool mount)89*287e80b3SSadaf Ebrahimi __hidden char *find_tracing_dir(bool debugfs, bool mount)
90*287e80b3SSadaf Ebrahimi {
91*287e80b3SSadaf Ebrahimi 	char *debug_str = NULL;
92*287e80b3SSadaf Ebrahimi 	char fspath[PATH_MAX+1];
93*287e80b3SSadaf Ebrahimi 	char *tracing_dir;
94*287e80b3SSadaf Ebrahimi 	char type[100];
95*287e80b3SSadaf Ebrahimi 	int use_debug = 0;
96*287e80b3SSadaf Ebrahimi 	FILE *fp;
97*287e80b3SSadaf Ebrahimi 
98*287e80b3SSadaf Ebrahimi 	fp = fopen("/proc/mounts", "r");
99*287e80b3SSadaf Ebrahimi 	if (!fp) {
100*287e80b3SSadaf Ebrahimi 		tracefs_warning("Can't open /proc/mounts for read");
101*287e80b3SSadaf Ebrahimi 		return NULL;
102*287e80b3SSadaf Ebrahimi 	}
103*287e80b3SSadaf Ebrahimi 
104*287e80b3SSadaf Ebrahimi 	while (fscanf(fp, "%*s %"
105*287e80b3SSadaf Ebrahimi 		      STR(PATH_MAX)
106*287e80b3SSadaf Ebrahimi 		      "s %99s %*s %*d %*d\n",
107*287e80b3SSadaf Ebrahimi 		      fspath, type) == 2) {
108*287e80b3SSadaf Ebrahimi 		if (!debugfs && strcmp(type, "tracefs") == 0)
109*287e80b3SSadaf Ebrahimi 			break;
110*287e80b3SSadaf Ebrahimi 		if (!debug_str && strcmp(type, "debugfs") == 0) {
111*287e80b3SSadaf Ebrahimi 			if (debugfs)
112*287e80b3SSadaf Ebrahimi 				break;
113*287e80b3SSadaf Ebrahimi 			debug_str = strdup(fspath);
114*287e80b3SSadaf Ebrahimi 			if (!debug_str) {
115*287e80b3SSadaf Ebrahimi 				fclose(fp);
116*287e80b3SSadaf Ebrahimi 				return NULL;
117*287e80b3SSadaf Ebrahimi 			}
118*287e80b3SSadaf Ebrahimi 		}
119*287e80b3SSadaf Ebrahimi 	}
120*287e80b3SSadaf Ebrahimi 	fclose(fp);
121*287e80b3SSadaf Ebrahimi 
122*287e80b3SSadaf Ebrahimi 	if (debugfs) {
123*287e80b3SSadaf Ebrahimi 		if (strcmp(type, "debugfs") != 0) {
124*287e80b3SSadaf Ebrahimi 			if (!mount || mount_debugfs() < 0)
125*287e80b3SSadaf Ebrahimi 				return NULL;
126*287e80b3SSadaf Ebrahimi 			strcpy(fspath, DEBUGFS_PATH);
127*287e80b3SSadaf Ebrahimi 		}
128*287e80b3SSadaf Ebrahimi 	} else if (strcmp(type, "tracefs") != 0) {
129*287e80b3SSadaf Ebrahimi 		if (!mount || mount_tracefs() < 0) {
130*287e80b3SSadaf Ebrahimi 			if (debug_str) {
131*287e80b3SSadaf Ebrahimi 				strncpy(fspath, debug_str, PATH_MAX);
132*287e80b3SSadaf Ebrahimi 				fspath[PATH_MAX] = 0;
133*287e80b3SSadaf Ebrahimi 			} else {
134*287e80b3SSadaf Ebrahimi 				if (!mount || mount_debugfs() < 0) {
135*287e80b3SSadaf Ebrahimi 					if (mount)
136*287e80b3SSadaf Ebrahimi 						tracefs_warning("debugfs not mounted, please mount");
137*287e80b3SSadaf Ebrahimi 					free(debug_str);
138*287e80b3SSadaf Ebrahimi 					return NULL;
139*287e80b3SSadaf Ebrahimi 				}
140*287e80b3SSadaf Ebrahimi 				strcpy(fspath, DEBUGFS_PATH);
141*287e80b3SSadaf Ebrahimi 			}
142*287e80b3SSadaf Ebrahimi 			use_debug = 1;
143*287e80b3SSadaf Ebrahimi 		} else
144*287e80b3SSadaf Ebrahimi 			strcpy(fspath, TRACEFS_PATH);
145*287e80b3SSadaf Ebrahimi 	}
146*287e80b3SSadaf Ebrahimi 	free(debug_str);
147*287e80b3SSadaf Ebrahimi 
148*287e80b3SSadaf Ebrahimi 	if (use_debug) {
149*287e80b3SSadaf Ebrahimi 		int ret;
150*287e80b3SSadaf Ebrahimi 
151*287e80b3SSadaf Ebrahimi 		ret = asprintf(&tracing_dir, "%s/tracing", fspath);
152*287e80b3SSadaf Ebrahimi 		if (ret < 0)
153*287e80b3SSadaf Ebrahimi 			return NULL;
154*287e80b3SSadaf Ebrahimi 	} else {
155*287e80b3SSadaf Ebrahimi 		tracing_dir = strdup(fspath);
156*287e80b3SSadaf Ebrahimi 		if (!tracing_dir)
157*287e80b3SSadaf Ebrahimi 			return NULL;
158*287e80b3SSadaf Ebrahimi 	}
159*287e80b3SSadaf Ebrahimi 
160*287e80b3SSadaf Ebrahimi 	return tracing_dir;
161*287e80b3SSadaf Ebrahimi }
162*287e80b3SSadaf Ebrahimi 
163*287e80b3SSadaf Ebrahimi /**
164*287e80b3SSadaf Ebrahimi  * tracefs_tracing_dir_is_mounted - test if the tracing dir is already mounted
165*287e80b3SSadaf Ebrahimi  * @mount: Mount it if it is not already mounted
166*287e80b3SSadaf Ebrahimi  * @path: the path to the tracing directory if mounted or was mounted
167*287e80b3SSadaf Ebrahimi  *
168*287e80b3SSadaf Ebrahimi  * Returns 1 if the tracing directory is already mounted and 0 if it is not.
169*287e80b3SSadaf Ebrahimi  * If @mount is set and it fails to mount, it returns -1.
170*287e80b3SSadaf Ebrahimi  *
171*287e80b3SSadaf Ebrahimi  * If path is not NULL, and the tracing directory is or was mounted, it holds
172*287e80b3SSadaf Ebrahimi  * the path to the tracing directory. It must not be freed.
173*287e80b3SSadaf Ebrahimi  */
tracefs_tracing_dir_is_mounted(bool mount,const char ** path)174*287e80b3SSadaf Ebrahimi int tracefs_tracing_dir_is_mounted(bool mount, const char **path)
175*287e80b3SSadaf Ebrahimi {
176*287e80b3SSadaf Ebrahimi 	const char *dir;
177*287e80b3SSadaf Ebrahimi 
178*287e80b3SSadaf Ebrahimi 	dir = find_tracing_dir(false, false);
179*287e80b3SSadaf Ebrahimi 	if (dir) {
180*287e80b3SSadaf Ebrahimi 		if (path)
181*287e80b3SSadaf Ebrahimi 			*path = dir;
182*287e80b3SSadaf Ebrahimi 		return 1;
183*287e80b3SSadaf Ebrahimi 	}
184*287e80b3SSadaf Ebrahimi 	if (!mount)
185*287e80b3SSadaf Ebrahimi 		return 0;
186*287e80b3SSadaf Ebrahimi 
187*287e80b3SSadaf Ebrahimi 	dir = find_tracing_dir(false, mount);
188*287e80b3SSadaf Ebrahimi 	if (!dir)
189*287e80b3SSadaf Ebrahimi 		return -1;
190*287e80b3SSadaf Ebrahimi 	if (path)
191*287e80b3SSadaf Ebrahimi 		*path = dir;
192*287e80b3SSadaf Ebrahimi 	return 0;
193*287e80b3SSadaf Ebrahimi }
194*287e80b3SSadaf Ebrahimi 
195*287e80b3SSadaf Ebrahimi /**
196*287e80b3SSadaf Ebrahimi  * trace_find_tracing_dir - Find tracing directory
197*287e80b3SSadaf Ebrahimi  * @debugfs: Boolean to just return the debugfs directory
198*287e80b3SSadaf Ebrahimi  *
199*287e80b3SSadaf Ebrahimi  * Returns string containing the full path to the system's tracing directory.
200*287e80b3SSadaf Ebrahimi  * The string must be freed by free()
201*287e80b3SSadaf Ebrahimi  */
trace_find_tracing_dir(bool debugfs)202*287e80b3SSadaf Ebrahimi __hidden char *trace_find_tracing_dir(bool debugfs)
203*287e80b3SSadaf Ebrahimi {
204*287e80b3SSadaf Ebrahimi 	return find_tracing_dir(debugfs, false);
205*287e80b3SSadaf Ebrahimi }
206*287e80b3SSadaf Ebrahimi 
207*287e80b3SSadaf Ebrahimi /**
208*287e80b3SSadaf Ebrahimi  * tracefs_set_tracing_dir - Set location of the tracing directory
209*287e80b3SSadaf Ebrahimi  * @tracing_dir: full path to the system's tracing directory mount point.
210*287e80b3SSadaf Ebrahimi  *
211*287e80b3SSadaf Ebrahimi  * Set the location to the system's tracing directory. This API should be used
212*287e80b3SSadaf Ebrahimi  * to set a custom location of the tracing directory. There is no need to call
213*287e80b3SSadaf Ebrahimi  * it if the location is standard, in that case the library will auto detect it.
214*287e80b3SSadaf Ebrahimi  *
215*287e80b3SSadaf Ebrahimi  * Returns 0 on success, -1 otherwise.
216*287e80b3SSadaf Ebrahimi  */
tracefs_set_tracing_dir(char * tracing_dir)217*287e80b3SSadaf Ebrahimi int tracefs_set_tracing_dir(char *tracing_dir)
218*287e80b3SSadaf Ebrahimi {
219*287e80b3SSadaf Ebrahimi 	if (custom_tracing_dir) {
220*287e80b3SSadaf Ebrahimi 		free(custom_tracing_dir);
221*287e80b3SSadaf Ebrahimi 		custom_tracing_dir = NULL;
222*287e80b3SSadaf Ebrahimi 	}
223*287e80b3SSadaf Ebrahimi 
224*287e80b3SSadaf Ebrahimi 	if (tracing_dir) {
225*287e80b3SSadaf Ebrahimi 		custom_tracing_dir = strdup(tracing_dir);
226*287e80b3SSadaf Ebrahimi 		if (!custom_tracing_dir)
227*287e80b3SSadaf Ebrahimi 			return -1;
228*287e80b3SSadaf Ebrahimi 	}
229*287e80b3SSadaf Ebrahimi 
230*287e80b3SSadaf Ebrahimi 	return 0;
231*287e80b3SSadaf Ebrahimi }
232*287e80b3SSadaf Ebrahimi 
233*287e80b3SSadaf Ebrahimi /* Used to check if the directory is still mounted */
test_dir(const char * dir,const char * file)234*287e80b3SSadaf Ebrahimi static int test_dir(const char *dir, const char *file)
235*287e80b3SSadaf Ebrahimi {
236*287e80b3SSadaf Ebrahimi 	char path[strlen(dir) + strlen(file) + 2];
237*287e80b3SSadaf Ebrahimi 	struct stat st;
238*287e80b3SSadaf Ebrahimi 
239*287e80b3SSadaf Ebrahimi 	sprintf(path, "%s/%s", dir, file);
240*287e80b3SSadaf Ebrahimi 	return stat(path, &st) < 0 ? 0 : 1;
241*287e80b3SSadaf Ebrahimi }
242*287e80b3SSadaf Ebrahimi 
243*287e80b3SSadaf Ebrahimi /**
244*287e80b3SSadaf Ebrahimi  * tracefs_tracing_dir - Get tracing directory
245*287e80b3SSadaf Ebrahimi  *
246*287e80b3SSadaf Ebrahimi  * Returns string containing the full path to the system's tracing directory.
247*287e80b3SSadaf Ebrahimi  * The returned string must *not* be freed.
248*287e80b3SSadaf Ebrahimi  */
tracefs_tracing_dir(void)249*287e80b3SSadaf Ebrahimi const char *tracefs_tracing_dir(void)
250*287e80b3SSadaf Ebrahimi {
251*287e80b3SSadaf Ebrahimi 	static const char *tracing_dir;
252*287e80b3SSadaf Ebrahimi 
253*287e80b3SSadaf Ebrahimi 	/* Do not check custom_tracing_dir */
254*287e80b3SSadaf Ebrahimi 	if (custom_tracing_dir)
255*287e80b3SSadaf Ebrahimi 		return custom_tracing_dir;
256*287e80b3SSadaf Ebrahimi 
257*287e80b3SSadaf Ebrahimi 	if (tracing_dir && test_dir(tracing_dir, "trace"))
258*287e80b3SSadaf Ebrahimi 		return tracing_dir;
259*287e80b3SSadaf Ebrahimi 
260*287e80b3SSadaf Ebrahimi 	tracing_dir = find_tracing_dir(false, true);
261*287e80b3SSadaf Ebrahimi 	return tracing_dir;
262*287e80b3SSadaf Ebrahimi }
263*287e80b3SSadaf Ebrahimi 
264*287e80b3SSadaf Ebrahimi /**
265*287e80b3SSadaf Ebrahimi  * tracefs_debug_dir - Get debugfs directory path
266*287e80b3SSadaf Ebrahimi  *
267*287e80b3SSadaf Ebrahimi  * Returns string containing the full path to the system's debugfs directory.
268*287e80b3SSadaf Ebrahimi  *
269*287e80b3SSadaf Ebrahimi  * The returned string must *not* be freed.
270*287e80b3SSadaf Ebrahimi  */
tracefs_debug_dir(void)271*287e80b3SSadaf Ebrahimi const char *tracefs_debug_dir(void)
272*287e80b3SSadaf Ebrahimi {
273*287e80b3SSadaf Ebrahimi 	static const char *debug_dir;
274*287e80b3SSadaf Ebrahimi 
275*287e80b3SSadaf Ebrahimi 	if (debug_dir && test_dir(debug_dir, "tracing"))
276*287e80b3SSadaf Ebrahimi 		return debug_dir;
277*287e80b3SSadaf Ebrahimi 
278*287e80b3SSadaf Ebrahimi 	debug_dir = find_tracing_dir(true, true);
279*287e80b3SSadaf Ebrahimi 	return debug_dir;
280*287e80b3SSadaf Ebrahimi }
281*287e80b3SSadaf Ebrahimi 
282*287e80b3SSadaf Ebrahimi /**
283*287e80b3SSadaf Ebrahimi  * tracefs_get_tracing_file - Get tracing file
284*287e80b3SSadaf Ebrahimi  * @name: tracing file name
285*287e80b3SSadaf Ebrahimi  *
286*287e80b3SSadaf Ebrahimi  * Returns string containing the full path to a tracing file in
287*287e80b3SSadaf Ebrahimi  * the system's tracing directory.
288*287e80b3SSadaf Ebrahimi  *
289*287e80b3SSadaf Ebrahimi  * Must use tracefs_put_tracing_file() to free the returned string.
290*287e80b3SSadaf Ebrahimi  */
tracefs_get_tracing_file(const char * name)291*287e80b3SSadaf Ebrahimi char *tracefs_get_tracing_file(const char *name)
292*287e80b3SSadaf Ebrahimi {
293*287e80b3SSadaf Ebrahimi 	const char *tracing;
294*287e80b3SSadaf Ebrahimi 	char *file;
295*287e80b3SSadaf Ebrahimi 	int ret;
296*287e80b3SSadaf Ebrahimi 
297*287e80b3SSadaf Ebrahimi 	if (!name)
298*287e80b3SSadaf Ebrahimi 		return NULL;
299*287e80b3SSadaf Ebrahimi 
300*287e80b3SSadaf Ebrahimi 	tracing = tracefs_tracing_dir();
301*287e80b3SSadaf Ebrahimi 	if (!tracing)
302*287e80b3SSadaf Ebrahimi 		return NULL;
303*287e80b3SSadaf Ebrahimi 
304*287e80b3SSadaf Ebrahimi 	ret = asprintf(&file, "%s/%s", tracing, name);
305*287e80b3SSadaf Ebrahimi 	if (ret < 0)
306*287e80b3SSadaf Ebrahimi 		return NULL;
307*287e80b3SSadaf Ebrahimi 
308*287e80b3SSadaf Ebrahimi 	return file;
309*287e80b3SSadaf Ebrahimi }
310*287e80b3SSadaf Ebrahimi 
311*287e80b3SSadaf Ebrahimi /**
312*287e80b3SSadaf Ebrahimi  * tracefs_put_tracing_file - Free tracing file or directory name
313*287e80b3SSadaf Ebrahimi  *
314*287e80b3SSadaf Ebrahimi  * Frees tracing file or directory, returned by
315*287e80b3SSadaf Ebrahimi  * tracefs_get_tracing_file()API.
316*287e80b3SSadaf Ebrahimi  */
tracefs_put_tracing_file(char * name)317*287e80b3SSadaf Ebrahimi void tracefs_put_tracing_file(char *name)
318*287e80b3SSadaf Ebrahimi {
319*287e80b3SSadaf Ebrahimi 	free(name);
320*287e80b3SSadaf Ebrahimi }
321*287e80b3SSadaf Ebrahimi 
str_read_file(const char * file,char ** buffer,bool warn)322*287e80b3SSadaf Ebrahimi __hidden int str_read_file(const char *file, char **buffer, bool warn)
323*287e80b3SSadaf Ebrahimi {
324*287e80b3SSadaf Ebrahimi 	char stbuf[BUFSIZ];
325*287e80b3SSadaf Ebrahimi 	char *buf = NULL;
326*287e80b3SSadaf Ebrahimi 	int size = 0;
327*287e80b3SSadaf Ebrahimi 	char *nbuf;
328*287e80b3SSadaf Ebrahimi 	int fd;
329*287e80b3SSadaf Ebrahimi 	int r;
330*287e80b3SSadaf Ebrahimi 
331*287e80b3SSadaf Ebrahimi 	fd = open(file, O_RDONLY);
332*287e80b3SSadaf Ebrahimi 	if (fd < 0) {
333*287e80b3SSadaf Ebrahimi 		if (warn)
334*287e80b3SSadaf Ebrahimi 			tracefs_warning("File %s not found", file);
335*287e80b3SSadaf Ebrahimi 		return -1;
336*287e80b3SSadaf Ebrahimi 	}
337*287e80b3SSadaf Ebrahimi 
338*287e80b3SSadaf Ebrahimi 	do {
339*287e80b3SSadaf Ebrahimi 		r = read(fd, stbuf, BUFSIZ);
340*287e80b3SSadaf Ebrahimi 		if (r <= 0)
341*287e80b3SSadaf Ebrahimi 			continue;
342*287e80b3SSadaf Ebrahimi 		nbuf = realloc(buf, size+r+1);
343*287e80b3SSadaf Ebrahimi 		if (!nbuf) {
344*287e80b3SSadaf Ebrahimi 			if (warn)
345*287e80b3SSadaf Ebrahimi 				tracefs_warning("Failed to allocate file buffer");
346*287e80b3SSadaf Ebrahimi 			size = -1;
347*287e80b3SSadaf Ebrahimi 			break;
348*287e80b3SSadaf Ebrahimi 		}
349*287e80b3SSadaf Ebrahimi 		buf = nbuf;
350*287e80b3SSadaf Ebrahimi 		memcpy(buf+size, stbuf, r);
351*287e80b3SSadaf Ebrahimi 		size += r;
352*287e80b3SSadaf Ebrahimi 	} while (r > 0);
353*287e80b3SSadaf Ebrahimi 
354*287e80b3SSadaf Ebrahimi 	close(fd);
355*287e80b3SSadaf Ebrahimi 	if (r == 0 && size > 0) {
356*287e80b3SSadaf Ebrahimi 		buf[size] = '\0';
357*287e80b3SSadaf Ebrahimi 		*buffer = buf;
358*287e80b3SSadaf Ebrahimi 	} else
359*287e80b3SSadaf Ebrahimi 		free(buf);
360*287e80b3SSadaf Ebrahimi 
361*287e80b3SSadaf Ebrahimi 	return size;
362*287e80b3SSadaf Ebrahimi }
363*287e80b3SSadaf Ebrahimi 
364*287e80b3SSadaf Ebrahimi /**
365*287e80b3SSadaf Ebrahimi  * tracefs_error_all - return the content of the error log
366*287e80b3SSadaf Ebrahimi  * @instance: The instance to read the error log from (NULL for top level)
367*287e80b3SSadaf Ebrahimi  *
368*287e80b3SSadaf Ebrahimi  * Return NULL if the log is empty, or on error (where errno will be
369*287e80b3SSadaf Ebrahimi  * set. Otherwise the content of the entire log is returned in a string
370*287e80b3SSadaf Ebrahimi  * that must be freed with free().
371*287e80b3SSadaf Ebrahimi  */
tracefs_error_all(struct tracefs_instance * instance)372*287e80b3SSadaf Ebrahimi char *tracefs_error_all(struct tracefs_instance *instance)
373*287e80b3SSadaf Ebrahimi {
374*287e80b3SSadaf Ebrahimi 	char *content;
375*287e80b3SSadaf Ebrahimi 	char *path;
376*287e80b3SSadaf Ebrahimi 	int size;
377*287e80b3SSadaf Ebrahimi 
378*287e80b3SSadaf Ebrahimi 	errno = 0;
379*287e80b3SSadaf Ebrahimi 
380*287e80b3SSadaf Ebrahimi 	path = tracefs_instance_get_file(instance, ERROR_LOG);
381*287e80b3SSadaf Ebrahimi 	if (!path)
382*287e80b3SSadaf Ebrahimi 		return NULL;
383*287e80b3SSadaf Ebrahimi 	size = str_read_file(path, &content, false);
384*287e80b3SSadaf Ebrahimi 	tracefs_put_tracing_file(path);
385*287e80b3SSadaf Ebrahimi 
386*287e80b3SSadaf Ebrahimi 	if (size <= 0)
387*287e80b3SSadaf Ebrahimi 		return NULL;
388*287e80b3SSadaf Ebrahimi 
389*287e80b3SSadaf Ebrahimi 	return content;
390*287e80b3SSadaf Ebrahimi }
391*287e80b3SSadaf Ebrahimi 
392*287e80b3SSadaf Ebrahimi enum line_states {
393*287e80b3SSadaf Ebrahimi 	START,
394*287e80b3SSadaf Ebrahimi 	CARROT,
395*287e80b3SSadaf Ebrahimi };
396*287e80b3SSadaf Ebrahimi 
397*287e80b3SSadaf Ebrahimi /**
398*287e80b3SSadaf Ebrahimi  * tracefs_error_last - return the last error logged
399*287e80b3SSadaf Ebrahimi  * @instance: The instance to read the error log from (NULL for top level)
400*287e80b3SSadaf Ebrahimi  *
401*287e80b3SSadaf Ebrahimi  * Return NULL if the log is empty, or on error (where errno will be
402*287e80b3SSadaf Ebrahimi  * set. Otherwise a string containing the content of the last error shown
403*287e80b3SSadaf Ebrahimi * in the log that must be freed with free().
404*287e80b3SSadaf Ebrahimi  */
tracefs_error_last(struct tracefs_instance * instance)405*287e80b3SSadaf Ebrahimi char *tracefs_error_last(struct tracefs_instance *instance)
406*287e80b3SSadaf Ebrahimi {
407*287e80b3SSadaf Ebrahimi 	enum line_states state = START;
408*287e80b3SSadaf Ebrahimi 	char *content;
409*287e80b3SSadaf Ebrahimi 	char *ret;
410*287e80b3SSadaf Ebrahimi 	bool done = false;
411*287e80b3SSadaf Ebrahimi 	int size;
412*287e80b3SSadaf Ebrahimi 	int i;
413*287e80b3SSadaf Ebrahimi 
414*287e80b3SSadaf Ebrahimi 	content = tracefs_error_all(instance);
415*287e80b3SSadaf Ebrahimi 	if (!content)
416*287e80b3SSadaf Ebrahimi 		return NULL;
417*287e80b3SSadaf Ebrahimi 
418*287e80b3SSadaf Ebrahimi 	size = strlen(content);
419*287e80b3SSadaf Ebrahimi 	if (!size) /* Should never happen */
420*287e80b3SSadaf Ebrahimi 		return content;
421*287e80b3SSadaf Ebrahimi 
422*287e80b3SSadaf Ebrahimi 	for (i = size - 1; i > 0; i--) {
423*287e80b3SSadaf Ebrahimi 		switch (state) {
424*287e80b3SSadaf Ebrahimi 		case START:
425*287e80b3SSadaf Ebrahimi 			if (content[i] == '\n') {
426*287e80b3SSadaf Ebrahimi 				/* Remove extra new lines */
427*287e80b3SSadaf Ebrahimi 				content[i] = '\0';
428*287e80b3SSadaf Ebrahimi 				break;
429*287e80b3SSadaf Ebrahimi 			}
430*287e80b3SSadaf Ebrahimi 			if (content[i] == '^')
431*287e80b3SSadaf Ebrahimi 				state = CARROT;
432*287e80b3SSadaf Ebrahimi 			break;
433*287e80b3SSadaf Ebrahimi 		case CARROT:
434*287e80b3SSadaf Ebrahimi 			if (content[i] == '\n') {
435*287e80b3SSadaf Ebrahimi 				/* Remember last new line */
436*287e80b3SSadaf Ebrahimi 				size = i;
437*287e80b3SSadaf Ebrahimi 				break;
438*287e80b3SSadaf Ebrahimi 			}
439*287e80b3SSadaf Ebrahimi 			if (content[i] == '^') {
440*287e80b3SSadaf Ebrahimi 				/* Go just passed the last newline */
441*287e80b3SSadaf Ebrahimi 				i = size + 1;
442*287e80b3SSadaf Ebrahimi 				done = true;
443*287e80b3SSadaf Ebrahimi 			}
444*287e80b3SSadaf Ebrahimi 			break;
445*287e80b3SSadaf Ebrahimi 		}
446*287e80b3SSadaf Ebrahimi 		if (done)
447*287e80b3SSadaf Ebrahimi 			break;
448*287e80b3SSadaf Ebrahimi 	}
449*287e80b3SSadaf Ebrahimi 
450*287e80b3SSadaf Ebrahimi 	if (i) {
451*287e80b3SSadaf Ebrahimi 		ret = strdup(content + i);
452*287e80b3SSadaf Ebrahimi 		free(content);
453*287e80b3SSadaf Ebrahimi 	} else {
454*287e80b3SSadaf Ebrahimi 		ret = content;
455*287e80b3SSadaf Ebrahimi 	}
456*287e80b3SSadaf Ebrahimi 
457*287e80b3SSadaf Ebrahimi 	return ret;
458*287e80b3SSadaf Ebrahimi }
459*287e80b3SSadaf Ebrahimi 
460*287e80b3SSadaf Ebrahimi /**
461*287e80b3SSadaf Ebrahimi  * tracefs_error_clear - clear the error log of an instance
462*287e80b3SSadaf Ebrahimi  * @instance: The instance to clear (NULL for top level)
463*287e80b3SSadaf Ebrahimi  *
464*287e80b3SSadaf Ebrahimi  * Clear the content of the error log.
465*287e80b3SSadaf Ebrahimi  *
466*287e80b3SSadaf Ebrahimi  * Returns 0 on success, -1 otherwise.
467*287e80b3SSadaf Ebrahimi  */
tracefs_error_clear(struct tracefs_instance * instance)468*287e80b3SSadaf Ebrahimi int tracefs_error_clear(struct tracefs_instance *instance)
469*287e80b3SSadaf Ebrahimi {
470*287e80b3SSadaf Ebrahimi 	return tracefs_instance_file_clear(instance, ERROR_LOG);
471*287e80b3SSadaf Ebrahimi }
472*287e80b3SSadaf Ebrahimi 
473*287e80b3SSadaf Ebrahimi /**
474*287e80b3SSadaf Ebrahimi  * tracefs_list_free - free list if strings, returned by APIs
475*287e80b3SSadaf Ebrahimi  *			tracefs_event_systems()
476*287e80b3SSadaf Ebrahimi  *			tracefs_system_events()
477*287e80b3SSadaf Ebrahimi  *
478*287e80b3SSadaf Ebrahimi  *@list pointer to a list of strings, the last one must be NULL
479*287e80b3SSadaf Ebrahimi  */
tracefs_list_free(char ** list)480*287e80b3SSadaf Ebrahimi void tracefs_list_free(char **list)
481*287e80b3SSadaf Ebrahimi {
482*287e80b3SSadaf Ebrahimi 	int i;
483*287e80b3SSadaf Ebrahimi 
484*287e80b3SSadaf Ebrahimi 	if (!list)
485*287e80b3SSadaf Ebrahimi 		return;
486*287e80b3SSadaf Ebrahimi 
487*287e80b3SSadaf Ebrahimi 	for (i = 0; list[i]; i++)
488*287e80b3SSadaf Ebrahimi 		free(list[i]);
489*287e80b3SSadaf Ebrahimi 
490*287e80b3SSadaf Ebrahimi 	/* The allocated list is before the user visible portion */
491*287e80b3SSadaf Ebrahimi 	list--;
492*287e80b3SSadaf Ebrahimi 	free(list);
493*287e80b3SSadaf Ebrahimi }
494*287e80b3SSadaf Ebrahimi 
495*287e80b3SSadaf Ebrahimi 
trace_list_create_empty(void)496*287e80b3SSadaf Ebrahimi __hidden char ** trace_list_create_empty(void)
497*287e80b3SSadaf Ebrahimi {
498*287e80b3SSadaf Ebrahimi 	char **list;
499*287e80b3SSadaf Ebrahimi 
500*287e80b3SSadaf Ebrahimi 	list = calloc(2, sizeof(*list));
501*287e80b3SSadaf Ebrahimi 
502*287e80b3SSadaf Ebrahimi 	return list ? &list[1] : NULL;
503*287e80b3SSadaf Ebrahimi }
504*287e80b3SSadaf Ebrahimi 
505*287e80b3SSadaf Ebrahimi /**
506*287e80b3SSadaf Ebrahimi  * tracefs_list_add - create or extend a string list
507*287e80b3SSadaf Ebrahimi  * @list: The list to add to (NULL to create a new one)
508*287e80b3SSadaf Ebrahimi  * @string: The string to append to @list.
509*287e80b3SSadaf Ebrahimi  *
510*287e80b3SSadaf Ebrahimi  * If @list is NULL, a new list is created with the first element
511*287e80b3SSadaf Ebrahimi  * a copy of @string, and the second element is NULL.
512*287e80b3SSadaf Ebrahimi  *
513*287e80b3SSadaf Ebrahimi  * If @list is not NULL, it is then reallocated to include
514*287e80b3SSadaf Ebrahimi  * a new element and a NULL terminator, and will return the new
515*287e80b3SSadaf Ebrahimi  * allocated array on success, and the one passed in should be
516*287e80b3SSadaf Ebrahimi  * ignored.
517*287e80b3SSadaf Ebrahimi  *
518*287e80b3SSadaf Ebrahimi  * Returns an allocated string array that must be freed with
519*287e80b3SSadaf Ebrahimi  * tracefs_list_free() on success. On failure, NULL is returned
520*287e80b3SSadaf Ebrahimi  * and the @list is untouched.
521*287e80b3SSadaf Ebrahimi  */
tracefs_list_add(char ** list,const char * string)522*287e80b3SSadaf Ebrahimi char **tracefs_list_add(char **list, const char *string)
523*287e80b3SSadaf Ebrahimi {
524*287e80b3SSadaf Ebrahimi 	unsigned long size = 0;
525*287e80b3SSadaf Ebrahimi 	char *str = strdup(string);
526*287e80b3SSadaf Ebrahimi 	char **new_list;
527*287e80b3SSadaf Ebrahimi 
528*287e80b3SSadaf Ebrahimi 	if (!str)
529*287e80b3SSadaf Ebrahimi 		return NULL;
530*287e80b3SSadaf Ebrahimi 
531*287e80b3SSadaf Ebrahimi 	/*
532*287e80b3SSadaf Ebrahimi 	 * The returned list is really the address of the
533*287e80b3SSadaf Ebrahimi 	 * second entry of the list (&list[1]), the first
534*287e80b3SSadaf Ebrahimi 	 * entry contains the number of strings in the list.
535*287e80b3SSadaf Ebrahimi 	 */
536*287e80b3SSadaf Ebrahimi 	if (list) {
537*287e80b3SSadaf Ebrahimi 		list--;
538*287e80b3SSadaf Ebrahimi 		size = *(unsigned long *)list;
539*287e80b3SSadaf Ebrahimi 	}
540*287e80b3SSadaf Ebrahimi 
541*287e80b3SSadaf Ebrahimi 	new_list = realloc(list, sizeof(*list) * (size + 3));
542*287e80b3SSadaf Ebrahimi 	if (!new_list) {
543*287e80b3SSadaf Ebrahimi 		free(str);
544*287e80b3SSadaf Ebrahimi 		return NULL;
545*287e80b3SSadaf Ebrahimi 	}
546*287e80b3SSadaf Ebrahimi 
547*287e80b3SSadaf Ebrahimi 	list = new_list;
548*287e80b3SSadaf Ebrahimi 	list[0] = (char *)(size + 1);
549*287e80b3SSadaf Ebrahimi 	list++;
550*287e80b3SSadaf Ebrahimi 	list[size++] = str;
551*287e80b3SSadaf Ebrahimi 	list[size] = NULL;
552*287e80b3SSadaf Ebrahimi 
553*287e80b3SSadaf Ebrahimi 	return list;
554*287e80b3SSadaf Ebrahimi }
555*287e80b3SSadaf Ebrahimi 
556*287e80b3SSadaf Ebrahimi /*
557*287e80b3SSadaf Ebrahimi  * trace_list_pop - Removes the last string added
558*287e80b3SSadaf Ebrahimi  * @list: The list to remove the last event from
559*287e80b3SSadaf Ebrahimi  *
560*287e80b3SSadaf Ebrahimi  * Returns 0 on success, -1 on error.
561*287e80b3SSadaf Ebrahimi  * Returns 1 if the list is empty or NULL.
562*287e80b3SSadaf Ebrahimi  */
trace_list_pop(char ** list)563*287e80b3SSadaf Ebrahimi __hidden int trace_list_pop(char **list)
564*287e80b3SSadaf Ebrahimi {
565*287e80b3SSadaf Ebrahimi 	unsigned long size;
566*287e80b3SSadaf Ebrahimi 
567*287e80b3SSadaf Ebrahimi 	if (!list || list[0])
568*287e80b3SSadaf Ebrahimi 		return 1;
569*287e80b3SSadaf Ebrahimi 
570*287e80b3SSadaf Ebrahimi 	list--;
571*287e80b3SSadaf Ebrahimi 	size = *(unsigned long *)list;
572*287e80b3SSadaf Ebrahimi 	/* size must be greater than zero */
573*287e80b3SSadaf Ebrahimi 	if (!size)
574*287e80b3SSadaf Ebrahimi 		return -1;
575*287e80b3SSadaf Ebrahimi 	size--;
576*287e80b3SSadaf Ebrahimi 	*list = (char *)size;
577*287e80b3SSadaf Ebrahimi 	list++;
578*287e80b3SSadaf Ebrahimi 	list[size] = NULL;
579*287e80b3SSadaf Ebrahimi 	return 0;
580*287e80b3SSadaf Ebrahimi }
581*287e80b3SSadaf Ebrahimi 
582*287e80b3SSadaf Ebrahimi /**
583*287e80b3SSadaf Ebrahimi  * tracefs_list_size - Return the number of strings in the list
584*287e80b3SSadaf Ebrahimi  * @list: The list to determine the size.
585*287e80b3SSadaf Ebrahimi  *
586*287e80b3SSadaf Ebrahimi  * Returns the number of elements in the list.
587*287e80b3SSadaf Ebrahimi  * If @list is NULL, then zero is returned.
588*287e80b3SSadaf Ebrahimi  */
tracefs_list_size(char ** list)589*287e80b3SSadaf Ebrahimi int tracefs_list_size(char **list)
590*287e80b3SSadaf Ebrahimi {
591*287e80b3SSadaf Ebrahimi 	if (!list)
592*287e80b3SSadaf Ebrahimi 		return 0;
593*287e80b3SSadaf Ebrahimi 
594*287e80b3SSadaf Ebrahimi 	list--;
595*287e80b3SSadaf Ebrahimi 	return (int)*(unsigned long *)list;
596*287e80b3SSadaf Ebrahimi }
597*287e80b3SSadaf Ebrahimi 
598*287e80b3SSadaf Ebrahimi /**
599*287e80b3SSadaf Ebrahimi  * tracefs_tracer_available - test if a tracer is available
600*287e80b3SSadaf Ebrahimi  * @tracing_dir: The directory that contains the tracing directory
601*287e80b3SSadaf Ebrahimi  * @tracer: The name of the tracer
602*287e80b3SSadaf Ebrahimi  *
603*287e80b3SSadaf Ebrahimi  * Return true if the tracer is available
604*287e80b3SSadaf Ebrahimi  */
tracefs_tracer_available(const char * tracing_dir,const char * tracer)605*287e80b3SSadaf Ebrahimi bool tracefs_tracer_available(const char *tracing_dir, const char *tracer)
606*287e80b3SSadaf Ebrahimi {
607*287e80b3SSadaf Ebrahimi 	bool ret = false;
608*287e80b3SSadaf Ebrahimi 	char **tracers = NULL;
609*287e80b3SSadaf Ebrahimi 	int i;
610*287e80b3SSadaf Ebrahimi 
611*287e80b3SSadaf Ebrahimi 	tracers = tracefs_tracers(tracing_dir);
612*287e80b3SSadaf Ebrahimi 	if (!tracers)
613*287e80b3SSadaf Ebrahimi 		return false;
614*287e80b3SSadaf Ebrahimi 
615*287e80b3SSadaf Ebrahimi 	for (i = 0; tracers[i]; i++) {
616*287e80b3SSadaf Ebrahimi 		if (strcmp(tracer, tracers[i]) == 0) {
617*287e80b3SSadaf Ebrahimi 			ret = true;
618*287e80b3SSadaf Ebrahimi 			break;
619*287e80b3SSadaf Ebrahimi 		}
620*287e80b3SSadaf Ebrahimi 	}
621*287e80b3SSadaf Ebrahimi 
622*287e80b3SSadaf Ebrahimi 	tracefs_list_free(tracers);
623*287e80b3SSadaf Ebrahimi 	return ret;
624*287e80b3SSadaf Ebrahimi }
625