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