xref: /aosp_15_r20/external/libtracefs/src/tracefs-events.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 <stdio.h>
10*287e80b3SSadaf Ebrahimi #include <stdlib.h>
11*287e80b3SSadaf Ebrahimi #include <dirent.h>
12*287e80b3SSadaf Ebrahimi #include <unistd.h>
13*287e80b3SSadaf Ebrahimi #include <errno.h>
14*287e80b3SSadaf Ebrahimi #include <sys/stat.h>
15*287e80b3SSadaf Ebrahimi #include <fcntl.h>
16*287e80b3SSadaf Ebrahimi #include <limits.h>
17*287e80b3SSadaf Ebrahimi 
18*287e80b3SSadaf Ebrahimi #include <kbuffer.h>
19*287e80b3SSadaf Ebrahimi 
20*287e80b3SSadaf Ebrahimi #include "tracefs.h"
21*287e80b3SSadaf Ebrahimi #include "tracefs-local.h"
22*287e80b3SSadaf Ebrahimi 
23*287e80b3SSadaf Ebrahimi static struct follow_event *root_followers;
24*287e80b3SSadaf Ebrahimi static int nr_root_followers;
25*287e80b3SSadaf Ebrahimi 
26*287e80b3SSadaf Ebrahimi static struct follow_event *root_missed_followers;
27*287e80b3SSadaf Ebrahimi static int nr_root_missed_followers;
28*287e80b3SSadaf Ebrahimi 
29*287e80b3SSadaf Ebrahimi struct cpu_iterate {
30*287e80b3SSadaf Ebrahimi 	struct tracefs_cpu *tcpu;
31*287e80b3SSadaf Ebrahimi 	struct tep_record record;
32*287e80b3SSadaf Ebrahimi 	struct tep_event *event;
33*287e80b3SSadaf Ebrahimi 	struct kbuffer *kbuf;
34*287e80b3SSadaf Ebrahimi 	void *page;
35*287e80b3SSadaf Ebrahimi 	int psize;
36*287e80b3SSadaf Ebrahimi 	int cpu;
37*287e80b3SSadaf Ebrahimi };
38*287e80b3SSadaf Ebrahimi 
read_kbuf_record(struct cpu_iterate * cpu)39*287e80b3SSadaf Ebrahimi static int read_kbuf_record(struct cpu_iterate *cpu)
40*287e80b3SSadaf Ebrahimi {
41*287e80b3SSadaf Ebrahimi 	unsigned long long ts;
42*287e80b3SSadaf Ebrahimi 	void *ptr;
43*287e80b3SSadaf Ebrahimi 
44*287e80b3SSadaf Ebrahimi 	if (!cpu || !cpu->kbuf)
45*287e80b3SSadaf Ebrahimi 		return -1;
46*287e80b3SSadaf Ebrahimi 	ptr = kbuffer_read_event(cpu->kbuf, &ts);
47*287e80b3SSadaf Ebrahimi 	if (!ptr)
48*287e80b3SSadaf Ebrahimi 		return -1;
49*287e80b3SSadaf Ebrahimi 
50*287e80b3SSadaf Ebrahimi 	memset(&cpu->record, 0, sizeof(cpu->record));
51*287e80b3SSadaf Ebrahimi 	cpu->record.ts = ts;
52*287e80b3SSadaf Ebrahimi 	cpu->record.size = kbuffer_event_size(cpu->kbuf);
53*287e80b3SSadaf Ebrahimi 	cpu->record.record_size = kbuffer_curr_size(cpu->kbuf);
54*287e80b3SSadaf Ebrahimi 	cpu->record.missed_events = kbuffer_missed_events(cpu->kbuf);
55*287e80b3SSadaf Ebrahimi 	cpu->record.cpu = cpu->cpu;
56*287e80b3SSadaf Ebrahimi 	cpu->record.data = ptr;
57*287e80b3SSadaf Ebrahimi 	cpu->record.ref_count = 1;
58*287e80b3SSadaf Ebrahimi 
59*287e80b3SSadaf Ebrahimi 	kbuffer_next_event(cpu->kbuf, NULL);
60*287e80b3SSadaf Ebrahimi 
61*287e80b3SSadaf Ebrahimi 	return 0;
62*287e80b3SSadaf Ebrahimi }
63*287e80b3SSadaf Ebrahimi 
read_next_page(struct tep_handle * tep,struct cpu_iterate * cpu)64*287e80b3SSadaf Ebrahimi int read_next_page(struct tep_handle *tep, struct cpu_iterate *cpu)
65*287e80b3SSadaf Ebrahimi {
66*287e80b3SSadaf Ebrahimi 	enum kbuffer_long_size long_size;
67*287e80b3SSadaf Ebrahimi 	enum kbuffer_endian endian;
68*287e80b3SSadaf Ebrahimi 	int r;
69*287e80b3SSadaf Ebrahimi 
70*287e80b3SSadaf Ebrahimi 	if (!cpu->tcpu)
71*287e80b3SSadaf Ebrahimi 		return -1;
72*287e80b3SSadaf Ebrahimi 
73*287e80b3SSadaf Ebrahimi 	r = tracefs_cpu_buffered_read(cpu->tcpu, cpu->page, true);
74*287e80b3SSadaf Ebrahimi 	/*
75*287e80b3SSadaf Ebrahimi 	 * tracefs_cpu_buffered_read() only reads in full subbuffer size,
76*287e80b3SSadaf Ebrahimi 	 * but this wants partial buffers as well. If the function returns
77*287e80b3SSadaf Ebrahimi 	 * empty (-1 for EAGAIN), try tracefs_cpu_read() next, as that can
78*287e80b3SSadaf Ebrahimi 	 * read partially filled buffers too, but isn't as efficient.
79*287e80b3SSadaf Ebrahimi 	 */
80*287e80b3SSadaf Ebrahimi 	if (r <= 0)
81*287e80b3SSadaf Ebrahimi 		r = tracefs_cpu_read(cpu->tcpu, cpu->page, true);
82*287e80b3SSadaf Ebrahimi 	if (r <= 0)
83*287e80b3SSadaf Ebrahimi 		return -1;
84*287e80b3SSadaf Ebrahimi 
85*287e80b3SSadaf Ebrahimi 	if (!cpu->kbuf) {
86*287e80b3SSadaf Ebrahimi 		if (tep_is_file_bigendian(tep))
87*287e80b3SSadaf Ebrahimi 			endian = KBUFFER_ENDIAN_BIG;
88*287e80b3SSadaf Ebrahimi 		else
89*287e80b3SSadaf Ebrahimi 			endian = KBUFFER_ENDIAN_LITTLE;
90*287e80b3SSadaf Ebrahimi 
91*287e80b3SSadaf Ebrahimi 		if (tep_get_header_page_size(tep) == 8)
92*287e80b3SSadaf Ebrahimi 			long_size = KBUFFER_LSIZE_8;
93*287e80b3SSadaf Ebrahimi 		else
94*287e80b3SSadaf Ebrahimi 			long_size = KBUFFER_LSIZE_4;
95*287e80b3SSadaf Ebrahimi 
96*287e80b3SSadaf Ebrahimi 		cpu->kbuf = kbuffer_alloc(long_size, endian);
97*287e80b3SSadaf Ebrahimi 		if (!cpu->kbuf)
98*287e80b3SSadaf Ebrahimi 			return -1;
99*287e80b3SSadaf Ebrahimi 	}
100*287e80b3SSadaf Ebrahimi 
101*287e80b3SSadaf Ebrahimi 	kbuffer_load_subbuffer(cpu->kbuf, cpu->page);
102*287e80b3SSadaf Ebrahimi 	if (kbuffer_subbuffer_size(cpu->kbuf) > r) {
103*287e80b3SSadaf Ebrahimi 		tracefs_warning("%s: page_size > %d", __func__, r);
104*287e80b3SSadaf Ebrahimi 		return -1;
105*287e80b3SSadaf Ebrahimi 	}
106*287e80b3SSadaf Ebrahimi 
107*287e80b3SSadaf Ebrahimi 	return 0;
108*287e80b3SSadaf Ebrahimi }
109*287e80b3SSadaf Ebrahimi 
read_next_record(struct tep_handle * tep,struct cpu_iterate * cpu)110*287e80b3SSadaf Ebrahimi int read_next_record(struct tep_handle *tep, struct cpu_iterate *cpu)
111*287e80b3SSadaf Ebrahimi {
112*287e80b3SSadaf Ebrahimi 	int id;
113*287e80b3SSadaf Ebrahimi 
114*287e80b3SSadaf Ebrahimi 	do {
115*287e80b3SSadaf Ebrahimi 		while (!read_kbuf_record(cpu)) {
116*287e80b3SSadaf Ebrahimi 			id = tep_data_type(tep, &(cpu->record));
117*287e80b3SSadaf Ebrahimi 			cpu->event = tep_find_event(tep, id);
118*287e80b3SSadaf Ebrahimi 			if (cpu->event)
119*287e80b3SSadaf Ebrahimi 				return 0;
120*287e80b3SSadaf Ebrahimi 		}
121*287e80b3SSadaf Ebrahimi 	} while (!read_next_page(tep, cpu));
122*287e80b3SSadaf Ebrahimi 
123*287e80b3SSadaf Ebrahimi 	return -1;
124*287e80b3SSadaf Ebrahimi }
125*287e80b3SSadaf Ebrahimi 
126*287e80b3SSadaf Ebrahimi /**
127*287e80b3SSadaf Ebrahimi  * tracefs_follow_missed_events - Add callback for missed events for iterators
128*287e80b3SSadaf Ebrahimi  * @instance: The instance to follow
129*287e80b3SSadaf Ebrahimi  * @callback: The function to call when missed events is detected
130*287e80b3SSadaf Ebrahimi  * @callback_data: The data to pass to @callback
131*287e80b3SSadaf Ebrahimi  *
132*287e80b3SSadaf Ebrahimi  * This attaches a callback to an @instance or the root instance if @instance
133*287e80b3SSadaf Ebrahimi  * is NULL, where if tracefs_iterate_raw_events() is called, that if missed
134*287e80b3SSadaf Ebrahimi  * events are detected, it will call @callback, with the following parameters:
135*287e80b3SSadaf Ebrahimi  *  @event: The event pointer of the record with the missing events
136*287e80b3SSadaf Ebrahimi  *  @record; The event instance of @event.
137*287e80b3SSadaf Ebrahimi  *  @cpu: The cpu that the event happened on.
138*287e80b3SSadaf Ebrahimi  *  @callback_data: The same as @callback_data passed to the function.
139*287e80b3SSadaf Ebrahimi  *
140*287e80b3SSadaf Ebrahimi  * If the count of missing events is available, @record->missed_events
141*287e80b3SSadaf Ebrahimi  * will have a positive number holding the number of missed events since
142*287e80b3SSadaf Ebrahimi  * the last event on the same CPU, or just -1 if that number is unknown
143*287e80b3SSadaf Ebrahimi  * but missed events did happen.
144*287e80b3SSadaf Ebrahimi  *
145*287e80b3SSadaf Ebrahimi  * Returns 0 on success and -1 on error.
146*287e80b3SSadaf Ebrahimi  */
tracefs_follow_missed_events(struct tracefs_instance * instance,int (* callback)(struct tep_event *,struct tep_record *,int,void *),void * callback_data)147*287e80b3SSadaf Ebrahimi int tracefs_follow_missed_events(struct tracefs_instance *instance,
148*287e80b3SSadaf Ebrahimi 				 int (*callback)(struct tep_event *,
149*287e80b3SSadaf Ebrahimi 						 struct tep_record *,
150*287e80b3SSadaf Ebrahimi 						 int, void *),
151*287e80b3SSadaf Ebrahimi 				 void *callback_data)
152*287e80b3SSadaf Ebrahimi {
153*287e80b3SSadaf Ebrahimi 	struct follow_event **followers;
154*287e80b3SSadaf Ebrahimi 	struct follow_event *follower;
155*287e80b3SSadaf Ebrahimi 	struct follow_event follow;
156*287e80b3SSadaf Ebrahimi 	int *nr_followers;
157*287e80b3SSadaf Ebrahimi 
158*287e80b3SSadaf Ebrahimi 	follow.event = NULL;
159*287e80b3SSadaf Ebrahimi 	follow.callback = callback;
160*287e80b3SSadaf Ebrahimi 	follow.callback_data = callback_data;
161*287e80b3SSadaf Ebrahimi 
162*287e80b3SSadaf Ebrahimi 	if (instance) {
163*287e80b3SSadaf Ebrahimi 		followers = &instance->missed_followers;
164*287e80b3SSadaf Ebrahimi 		nr_followers = &instance->nr_missed_followers;
165*287e80b3SSadaf Ebrahimi 	} else {
166*287e80b3SSadaf Ebrahimi 		followers = &root_missed_followers;
167*287e80b3SSadaf Ebrahimi 		nr_followers = &nr_root_missed_followers;
168*287e80b3SSadaf Ebrahimi 	}
169*287e80b3SSadaf Ebrahimi 	follower = realloc(*followers, sizeof(*follower) *
170*287e80b3SSadaf Ebrahimi 			    ((*nr_followers) + 1));
171*287e80b3SSadaf Ebrahimi 	if (!follower)
172*287e80b3SSadaf Ebrahimi 		return -1;
173*287e80b3SSadaf Ebrahimi 
174*287e80b3SSadaf Ebrahimi 	*followers = follower;
175*287e80b3SSadaf Ebrahimi 	follower[(*nr_followers)++] = follow;
176*287e80b3SSadaf Ebrahimi 
177*287e80b3SSadaf Ebrahimi 	return 0;
178*287e80b3SSadaf Ebrahimi }
179*287e80b3SSadaf Ebrahimi 
call_missed_events(struct tracefs_instance * instance,struct tep_event * event,struct tep_record * record,int cpu)180*287e80b3SSadaf Ebrahimi static int call_missed_events(struct tracefs_instance *instance,
181*287e80b3SSadaf Ebrahimi 			      struct tep_event *event, struct tep_record *record, int cpu)
182*287e80b3SSadaf Ebrahimi {
183*287e80b3SSadaf Ebrahimi 	struct follow_event *followers;
184*287e80b3SSadaf Ebrahimi 	int nr_followers;
185*287e80b3SSadaf Ebrahimi 	int ret = 0;
186*287e80b3SSadaf Ebrahimi 	int i;
187*287e80b3SSadaf Ebrahimi 
188*287e80b3SSadaf Ebrahimi 	if (instance) {
189*287e80b3SSadaf Ebrahimi 		followers = instance->missed_followers;
190*287e80b3SSadaf Ebrahimi 		nr_followers = instance->nr_missed_followers;
191*287e80b3SSadaf Ebrahimi 	} else {
192*287e80b3SSadaf Ebrahimi 		followers = root_missed_followers;
193*287e80b3SSadaf Ebrahimi 		nr_followers = nr_root_missed_followers;
194*287e80b3SSadaf Ebrahimi 	}
195*287e80b3SSadaf Ebrahimi 
196*287e80b3SSadaf Ebrahimi 	if (!followers)
197*287e80b3SSadaf Ebrahimi 		return 0;
198*287e80b3SSadaf Ebrahimi 
199*287e80b3SSadaf Ebrahimi 	for (i = 0; i < nr_followers; i++) {
200*287e80b3SSadaf Ebrahimi 		ret |= followers[i].callback(event, record,
201*287e80b3SSadaf Ebrahimi 					     cpu, followers[i].callback_data);
202*287e80b3SSadaf Ebrahimi 	}
203*287e80b3SSadaf Ebrahimi 
204*287e80b3SSadaf Ebrahimi 	return ret;
205*287e80b3SSadaf Ebrahimi }
206*287e80b3SSadaf Ebrahimi 
call_followers(struct tracefs_instance * instance,struct tep_event * event,struct tep_record * record,int cpu)207*287e80b3SSadaf Ebrahimi static int call_followers(struct tracefs_instance *instance,
208*287e80b3SSadaf Ebrahimi 			  struct tep_event *event, struct tep_record *record, int cpu)
209*287e80b3SSadaf Ebrahimi {
210*287e80b3SSadaf Ebrahimi 	struct follow_event *followers;
211*287e80b3SSadaf Ebrahimi 	int nr_followers;
212*287e80b3SSadaf Ebrahimi 	int ret = 0;
213*287e80b3SSadaf Ebrahimi 	int i;
214*287e80b3SSadaf Ebrahimi 
215*287e80b3SSadaf Ebrahimi 	if (record->missed_events)
216*287e80b3SSadaf Ebrahimi 		ret = call_missed_events(instance, event, record, cpu);
217*287e80b3SSadaf Ebrahimi 	if (ret)
218*287e80b3SSadaf Ebrahimi 		return ret;
219*287e80b3SSadaf Ebrahimi 
220*287e80b3SSadaf Ebrahimi 	if (instance) {
221*287e80b3SSadaf Ebrahimi 		followers = instance->followers;
222*287e80b3SSadaf Ebrahimi 		nr_followers = instance->nr_followers;
223*287e80b3SSadaf Ebrahimi 	} else {
224*287e80b3SSadaf Ebrahimi 		followers = root_followers;
225*287e80b3SSadaf Ebrahimi 		nr_followers = nr_root_followers;
226*287e80b3SSadaf Ebrahimi 	}
227*287e80b3SSadaf Ebrahimi 
228*287e80b3SSadaf Ebrahimi 	if (!followers)
229*287e80b3SSadaf Ebrahimi 		return 0;
230*287e80b3SSadaf Ebrahimi 
231*287e80b3SSadaf Ebrahimi 	for (i = 0; i < nr_followers; i++) {
232*287e80b3SSadaf Ebrahimi 		if (followers[i].event == event)
233*287e80b3SSadaf Ebrahimi 			ret |= followers[i].callback(event, record,
234*287e80b3SSadaf Ebrahimi 						     cpu, followers[i].callback_data);
235*287e80b3SSadaf Ebrahimi 	}
236*287e80b3SSadaf Ebrahimi 
237*287e80b3SSadaf Ebrahimi 	return ret;
238*287e80b3SSadaf Ebrahimi }
239*287e80b3SSadaf Ebrahimi 
read_cpu_pages(struct tep_handle * tep,struct tracefs_instance * instance,struct cpu_iterate * cpus,int count,int (* callback)(struct tep_event *,struct tep_record *,int,void *),void * callback_context,bool * keep_going)240*287e80b3SSadaf Ebrahimi static int read_cpu_pages(struct tep_handle *tep, struct tracefs_instance *instance,
241*287e80b3SSadaf Ebrahimi 			  struct cpu_iterate *cpus, int count,
242*287e80b3SSadaf Ebrahimi 			  int (*callback)(struct tep_event *,
243*287e80b3SSadaf Ebrahimi 					  struct tep_record *,
244*287e80b3SSadaf Ebrahimi 					  int, void *),
245*287e80b3SSadaf Ebrahimi 			  void *callback_context,
246*287e80b3SSadaf Ebrahimi 			  bool *keep_going)
247*287e80b3SSadaf Ebrahimi {
248*287e80b3SSadaf Ebrahimi 	bool has_data = false;
249*287e80b3SSadaf Ebrahimi 	int ret;
250*287e80b3SSadaf Ebrahimi 	int i, j;
251*287e80b3SSadaf Ebrahimi 
252*287e80b3SSadaf Ebrahimi 	for (i = 0; i < count; i++) {
253*287e80b3SSadaf Ebrahimi 		ret = read_next_record(tep, cpus + i);
254*287e80b3SSadaf Ebrahimi 		if (!ret)
255*287e80b3SSadaf Ebrahimi 			has_data = true;
256*287e80b3SSadaf Ebrahimi 	}
257*287e80b3SSadaf Ebrahimi 
258*287e80b3SSadaf Ebrahimi 	while (has_data && *(volatile bool *)keep_going) {
259*287e80b3SSadaf Ebrahimi 		j = count;
260*287e80b3SSadaf Ebrahimi 		for (i = 0; i < count; i++) {
261*287e80b3SSadaf Ebrahimi 			if (!cpus[i].event)
262*287e80b3SSadaf Ebrahimi 				continue;
263*287e80b3SSadaf Ebrahimi 			if (j == count || cpus[j].record.ts > cpus[i].record.ts)
264*287e80b3SSadaf Ebrahimi 				j = i;
265*287e80b3SSadaf Ebrahimi 		}
266*287e80b3SSadaf Ebrahimi 		if (j < count) {
267*287e80b3SSadaf Ebrahimi 			if (call_followers(instance, cpus[j].event, &cpus[j].record, cpus[j].cpu))
268*287e80b3SSadaf Ebrahimi 				break;
269*287e80b3SSadaf Ebrahimi 			if (callback &&
270*287e80b3SSadaf Ebrahimi 			    callback(cpus[j].event, &cpus[j].record, cpus[j].cpu, callback_context))
271*287e80b3SSadaf Ebrahimi 				break;
272*287e80b3SSadaf Ebrahimi 			cpus[j].event = NULL;
273*287e80b3SSadaf Ebrahimi 			read_next_record(tep, cpus + j);
274*287e80b3SSadaf Ebrahimi 		} else {
275*287e80b3SSadaf Ebrahimi 			has_data = false;
276*287e80b3SSadaf Ebrahimi 		}
277*287e80b3SSadaf Ebrahimi 	}
278*287e80b3SSadaf Ebrahimi 
279*287e80b3SSadaf Ebrahimi 	return 0;
280*287e80b3SSadaf Ebrahimi }
281*287e80b3SSadaf Ebrahimi 
open_cpu_files(struct tracefs_instance * instance,cpu_set_t * cpus,int cpu_size,struct cpu_iterate ** all_cpus,int * count)282*287e80b3SSadaf Ebrahimi static int open_cpu_files(struct tracefs_instance *instance, cpu_set_t *cpus,
283*287e80b3SSadaf Ebrahimi 			  int cpu_size, struct cpu_iterate **all_cpus, int *count)
284*287e80b3SSadaf Ebrahimi {
285*287e80b3SSadaf Ebrahimi 	struct tracefs_cpu *tcpu;
286*287e80b3SSadaf Ebrahimi 	struct cpu_iterate *tmp;
287*287e80b3SSadaf Ebrahimi 	int nr_cpus;
288*287e80b3SSadaf Ebrahimi 	int cpu;
289*287e80b3SSadaf Ebrahimi 	int i = 0;
290*287e80b3SSadaf Ebrahimi 
291*287e80b3SSadaf Ebrahimi 	*all_cpus = NULL;
292*287e80b3SSadaf Ebrahimi 
293*287e80b3SSadaf Ebrahimi 	nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
294*287e80b3SSadaf Ebrahimi 	for (cpu = 0; cpu < nr_cpus; cpu++) {
295*287e80b3SSadaf Ebrahimi 		if (cpus && !CPU_ISSET_S(cpu, cpu_size, cpus))
296*287e80b3SSadaf Ebrahimi 			continue;
297*287e80b3SSadaf Ebrahimi 		tcpu = tracefs_cpu_open(instance, cpu, true);
298*287e80b3SSadaf Ebrahimi 		tmp = realloc(*all_cpus, (i + 1) * sizeof(*tmp));
299*287e80b3SSadaf Ebrahimi 		if (!tmp) {
300*287e80b3SSadaf Ebrahimi 			i--;
301*287e80b3SSadaf Ebrahimi 			goto error;
302*287e80b3SSadaf Ebrahimi 		}
303*287e80b3SSadaf Ebrahimi 
304*287e80b3SSadaf Ebrahimi 		*all_cpus = tmp;
305*287e80b3SSadaf Ebrahimi 
306*287e80b3SSadaf Ebrahimi 		memset(tmp + i, 0, sizeof(*tmp));
307*287e80b3SSadaf Ebrahimi 
308*287e80b3SSadaf Ebrahimi 		if (!tcpu)
309*287e80b3SSadaf Ebrahimi 			goto error;
310*287e80b3SSadaf Ebrahimi 
311*287e80b3SSadaf Ebrahimi 		tmp[i].tcpu = tcpu;
312*287e80b3SSadaf Ebrahimi 		tmp[i].cpu = cpu;
313*287e80b3SSadaf Ebrahimi 		tmp[i].psize = tracefs_cpu_read_size(tcpu);
314*287e80b3SSadaf Ebrahimi 		tmp[i].page =  malloc(tmp[i].psize);
315*287e80b3SSadaf Ebrahimi 
316*287e80b3SSadaf Ebrahimi 		if (!tmp[i++].page)
317*287e80b3SSadaf Ebrahimi 			goto error;
318*287e80b3SSadaf Ebrahimi 	}
319*287e80b3SSadaf Ebrahimi 	*count = i;
320*287e80b3SSadaf Ebrahimi 	return 0;
321*287e80b3SSadaf Ebrahimi  error:
322*287e80b3SSadaf Ebrahimi 	tmp = *all_cpus;
323*287e80b3SSadaf Ebrahimi 	for (; i >= 0; i--) {
324*287e80b3SSadaf Ebrahimi 		tracefs_cpu_close(tmp[i].tcpu);
325*287e80b3SSadaf Ebrahimi 		free(tmp[i].page);
326*287e80b3SSadaf Ebrahimi 	}
327*287e80b3SSadaf Ebrahimi 	free(tmp);
328*287e80b3SSadaf Ebrahimi 	*all_cpus = NULL;
329*287e80b3SSadaf Ebrahimi 	return -1;
330*287e80b3SSadaf Ebrahimi }
331*287e80b3SSadaf Ebrahimi 
332*287e80b3SSadaf Ebrahimi /**
333*287e80b3SSadaf Ebrahimi  * tracefs_follow_event - Add callback for specific events for iterators
334*287e80b3SSadaf Ebrahimi  * @tep: a handle to the trace event parser context
335*287e80b3SSadaf Ebrahimi  * @instance: The instance to follow
336*287e80b3SSadaf Ebrahimi  * @system: The system of the event to track
337*287e80b3SSadaf Ebrahimi  * @event_name: The name of the event to track
338*287e80b3SSadaf Ebrahimi  * @callback: The function to call when the event is hit in an iterator
339*287e80b3SSadaf Ebrahimi  * @callback_data: The data to pass to @callback
340*287e80b3SSadaf Ebrahimi  *
341*287e80b3SSadaf Ebrahimi  * This attaches a callback to an @instance or the root instance if @instance
342*287e80b3SSadaf Ebrahimi  * is NULL, where if tracefs_iterate_raw_events() is called, that if the specified
343*287e80b3SSadaf Ebrahimi  * event is hit, it will call @callback, with the following parameters:
344*287e80b3SSadaf Ebrahimi  *  @event: The event pointer that was found by @system and @event_name.
345*287e80b3SSadaf Ebrahimi  *  @record; The event instance of @event.
346*287e80b3SSadaf Ebrahimi  *  @cpu: The cpu that the event happened on.
347*287e80b3SSadaf Ebrahimi  *  @callback_data: The same as @callback_data passed to the function.
348*287e80b3SSadaf Ebrahimi  *
349*287e80b3SSadaf Ebrahimi  * Returns 0 on success and -1 on error.
350*287e80b3SSadaf Ebrahimi  */
tracefs_follow_event(struct tep_handle * tep,struct tracefs_instance * instance,const char * system,const char * event_name,int (* callback)(struct tep_event *,struct tep_record *,int,void *),void * callback_data)351*287e80b3SSadaf Ebrahimi int tracefs_follow_event(struct tep_handle *tep, struct tracefs_instance *instance,
352*287e80b3SSadaf Ebrahimi 			  const char *system, const char *event_name,
353*287e80b3SSadaf Ebrahimi 			  int (*callback)(struct tep_event *,
354*287e80b3SSadaf Ebrahimi 					  struct tep_record *,
355*287e80b3SSadaf Ebrahimi 					  int, void *),
356*287e80b3SSadaf Ebrahimi 			  void *callback_data)
357*287e80b3SSadaf Ebrahimi {
358*287e80b3SSadaf Ebrahimi 	struct follow_event **followers;
359*287e80b3SSadaf Ebrahimi 	struct follow_event *follower;
360*287e80b3SSadaf Ebrahimi 	struct follow_event follow;
361*287e80b3SSadaf Ebrahimi 	int *nr_followers;
362*287e80b3SSadaf Ebrahimi 
363*287e80b3SSadaf Ebrahimi 	if (!tep) {
364*287e80b3SSadaf Ebrahimi 		errno = EINVAL;
365*287e80b3SSadaf Ebrahimi 		return -1;
366*287e80b3SSadaf Ebrahimi 	}
367*287e80b3SSadaf Ebrahimi 
368*287e80b3SSadaf Ebrahimi 	follow.event = tep_find_event_by_name(tep, system, event_name);
369*287e80b3SSadaf Ebrahimi 	if (!follow.event) {
370*287e80b3SSadaf Ebrahimi 		errno = ENOENT;
371*287e80b3SSadaf Ebrahimi 		return -1;
372*287e80b3SSadaf Ebrahimi 	}
373*287e80b3SSadaf Ebrahimi 
374*287e80b3SSadaf Ebrahimi 	follow.callback = callback;
375*287e80b3SSadaf Ebrahimi 	follow.callback_data = callback_data;
376*287e80b3SSadaf Ebrahimi 
377*287e80b3SSadaf Ebrahimi 	if (instance) {
378*287e80b3SSadaf Ebrahimi 		followers = &instance->followers;
379*287e80b3SSadaf Ebrahimi 		nr_followers = &instance->nr_followers;
380*287e80b3SSadaf Ebrahimi 	} else {
381*287e80b3SSadaf Ebrahimi 		followers = &root_followers;
382*287e80b3SSadaf Ebrahimi 		nr_followers = &nr_root_followers;
383*287e80b3SSadaf Ebrahimi 	}
384*287e80b3SSadaf Ebrahimi 	follower = realloc(*followers, sizeof(*follower) *
385*287e80b3SSadaf Ebrahimi 			    ((*nr_followers) + 1));
386*287e80b3SSadaf Ebrahimi 	if (!follower)
387*287e80b3SSadaf Ebrahimi 		return -1;
388*287e80b3SSadaf Ebrahimi 
389*287e80b3SSadaf Ebrahimi 	*followers = follower;
390*287e80b3SSadaf Ebrahimi 	follower[(*nr_followers)++] = follow;
391*287e80b3SSadaf Ebrahimi 
392*287e80b3SSadaf Ebrahimi 	return 0;
393*287e80b3SSadaf Ebrahimi }
394*287e80b3SSadaf Ebrahimi 
395*287e80b3SSadaf Ebrahimi static bool top_iterate_keep_going;
396*287e80b3SSadaf Ebrahimi 
397*287e80b3SSadaf Ebrahimi /*
398*287e80b3SSadaf Ebrahimi  * tracefs_iterate_raw_events - Iterate through events in trace_pipe_raw,
399*287e80b3SSadaf Ebrahimi  *				per CPU trace buffers
400*287e80b3SSadaf Ebrahimi  * @tep: a handle to the trace event parser context
401*287e80b3SSadaf Ebrahimi  * @instance: ftrace instance, can be NULL for the top instance
402*287e80b3SSadaf Ebrahimi  * @cpus: Iterate only through the buffers of CPUs, set in the mask.
403*287e80b3SSadaf Ebrahimi  *	  If NULL, iterate through all CPUs.
404*287e80b3SSadaf Ebrahimi  * @cpu_size: size of @cpus set
405*287e80b3SSadaf Ebrahimi  * @callback: A user function, called for each record from the file
406*287e80b3SSadaf Ebrahimi  * @callback_context: A custom context, passed to the user callback function
407*287e80b3SSadaf Ebrahimi  *
408*287e80b3SSadaf Ebrahimi  * If the @callback returns non-zero, the iteration stops - in that case all
409*287e80b3SSadaf Ebrahimi  * records from the current page will be lost from future reads
410*287e80b3SSadaf Ebrahimi  * The events are iterated in sorted order, oldest first.
411*287e80b3SSadaf Ebrahimi  *
412*287e80b3SSadaf Ebrahimi  * Returns -1 in case of an error, or 0 otherwise
413*287e80b3SSadaf Ebrahimi  */
tracefs_iterate_raw_events(struct tep_handle * tep,struct tracefs_instance * instance,cpu_set_t * cpus,int cpu_size,int (* callback)(struct tep_event *,struct tep_record *,int,void *),void * callback_context)414*287e80b3SSadaf Ebrahimi int tracefs_iterate_raw_events(struct tep_handle *tep,
415*287e80b3SSadaf Ebrahimi 				struct tracefs_instance *instance,
416*287e80b3SSadaf Ebrahimi 				cpu_set_t *cpus, int cpu_size,
417*287e80b3SSadaf Ebrahimi 				int (*callback)(struct tep_event *,
418*287e80b3SSadaf Ebrahimi 						struct tep_record *,
419*287e80b3SSadaf Ebrahimi 						int, void *),
420*287e80b3SSadaf Ebrahimi 				void *callback_context)
421*287e80b3SSadaf Ebrahimi {
422*287e80b3SSadaf Ebrahimi 	bool *keep_going = instance ? &instance->iterate_keep_going :
423*287e80b3SSadaf Ebrahimi 				      &top_iterate_keep_going;
424*287e80b3SSadaf Ebrahimi 	struct follow_event *followers;
425*287e80b3SSadaf Ebrahimi 	struct cpu_iterate *all_cpus;
426*287e80b3SSadaf Ebrahimi 	int count = 0;
427*287e80b3SSadaf Ebrahimi 	int ret;
428*287e80b3SSadaf Ebrahimi 	int i;
429*287e80b3SSadaf Ebrahimi 
430*287e80b3SSadaf Ebrahimi 	(*(volatile bool *)keep_going) = true;
431*287e80b3SSadaf Ebrahimi 
432*287e80b3SSadaf Ebrahimi 	if (!tep)
433*287e80b3SSadaf Ebrahimi 		return -1;
434*287e80b3SSadaf Ebrahimi 
435*287e80b3SSadaf Ebrahimi 	if (instance)
436*287e80b3SSadaf Ebrahimi 		followers = instance->followers;
437*287e80b3SSadaf Ebrahimi 	else
438*287e80b3SSadaf Ebrahimi 		followers = root_followers;
439*287e80b3SSadaf Ebrahimi 	if (!callback && !followers)
440*287e80b3SSadaf Ebrahimi 		return -1;
441*287e80b3SSadaf Ebrahimi 
442*287e80b3SSadaf Ebrahimi 	ret = open_cpu_files(instance, cpus, cpu_size, &all_cpus, &count);
443*287e80b3SSadaf Ebrahimi 	if (ret < 0)
444*287e80b3SSadaf Ebrahimi 		goto out;
445*287e80b3SSadaf Ebrahimi 	ret = read_cpu_pages(tep, instance, all_cpus, count,
446*287e80b3SSadaf Ebrahimi 			     callback, callback_context,
447*287e80b3SSadaf Ebrahimi 			     keep_going);
448*287e80b3SSadaf Ebrahimi 
449*287e80b3SSadaf Ebrahimi out:
450*287e80b3SSadaf Ebrahimi 	if (all_cpus) {
451*287e80b3SSadaf Ebrahimi 		for (i = 0; i < count; i++) {
452*287e80b3SSadaf Ebrahimi 			kbuffer_free(all_cpus[i].kbuf);
453*287e80b3SSadaf Ebrahimi 			tracefs_cpu_close(all_cpus[i].tcpu);
454*287e80b3SSadaf Ebrahimi 			free(all_cpus[i].page);
455*287e80b3SSadaf Ebrahimi 		}
456*287e80b3SSadaf Ebrahimi 		free(all_cpus);
457*287e80b3SSadaf Ebrahimi 	}
458*287e80b3SSadaf Ebrahimi 
459*287e80b3SSadaf Ebrahimi 	return ret;
460*287e80b3SSadaf Ebrahimi }
461*287e80b3SSadaf Ebrahimi 
462*287e80b3SSadaf Ebrahimi /**
463*287e80b3SSadaf Ebrahimi  * tracefs_iterate_stop - stop the iteration over the raw events.
464*287e80b3SSadaf Ebrahimi  * @instance: ftrace instance, can be NULL for top tracing instance.
465*287e80b3SSadaf Ebrahimi  */
tracefs_iterate_stop(struct tracefs_instance * instance)466*287e80b3SSadaf Ebrahimi void tracefs_iterate_stop(struct tracefs_instance *instance)
467*287e80b3SSadaf Ebrahimi {
468*287e80b3SSadaf Ebrahimi 	if (instance)
469*287e80b3SSadaf Ebrahimi 		instance->iterate_keep_going = false;
470*287e80b3SSadaf Ebrahimi 	else
471*287e80b3SSadaf Ebrahimi 		top_iterate_keep_going = false;
472*287e80b3SSadaf Ebrahimi }
473*287e80b3SSadaf Ebrahimi 
add_list_string(char *** list,const char * name)474*287e80b3SSadaf Ebrahimi static int add_list_string(char ***list, const char *name)
475*287e80b3SSadaf Ebrahimi {
476*287e80b3SSadaf Ebrahimi 	char **tmp;
477*287e80b3SSadaf Ebrahimi 
478*287e80b3SSadaf Ebrahimi 	tmp = tracefs_list_add(*list, name);
479*287e80b3SSadaf Ebrahimi 	if (!tmp) {
480*287e80b3SSadaf Ebrahimi 		tracefs_list_free(*list);
481*287e80b3SSadaf Ebrahimi 		*list = NULL;
482*287e80b3SSadaf Ebrahimi 		return -1;
483*287e80b3SSadaf Ebrahimi 	}
484*287e80b3SSadaf Ebrahimi 
485*287e80b3SSadaf Ebrahimi 	*list = tmp;
486*287e80b3SSadaf Ebrahimi 	return 0;
487*287e80b3SSadaf Ebrahimi }
488*287e80b3SSadaf Ebrahimi 
trace_append_file(const char * dir,const char * name)489*287e80b3SSadaf Ebrahimi __hidden char *trace_append_file(const char *dir, const char *name)
490*287e80b3SSadaf Ebrahimi {
491*287e80b3SSadaf Ebrahimi 	char *file;
492*287e80b3SSadaf Ebrahimi 	int ret;
493*287e80b3SSadaf Ebrahimi 
494*287e80b3SSadaf Ebrahimi 	ret = asprintf(&file, "%s/%s", dir, name);
495*287e80b3SSadaf Ebrahimi 
496*287e80b3SSadaf Ebrahimi 	return ret < 0 ? NULL : file;
497*287e80b3SSadaf Ebrahimi }
498*287e80b3SSadaf Ebrahimi 
event_file(char ** path,const char * system,const char * event,const char * file)499*287e80b3SSadaf Ebrahimi static int event_file(char **path, const char *system,
500*287e80b3SSadaf Ebrahimi 		      const char *event, const char *file)
501*287e80b3SSadaf Ebrahimi {
502*287e80b3SSadaf Ebrahimi 	if (!system || !event || !file)
503*287e80b3SSadaf Ebrahimi 		return -1;
504*287e80b3SSadaf Ebrahimi 
505*287e80b3SSadaf Ebrahimi 	return asprintf(path, "events/%s/%s/%s",
506*287e80b3SSadaf Ebrahimi 			system, event, file);
507*287e80b3SSadaf Ebrahimi }
508*287e80b3SSadaf Ebrahimi 
509*287e80b3SSadaf Ebrahimi /**
510*287e80b3SSadaf Ebrahimi  * tracefs_event_get_file - return a file in an event directory
511*287e80b3SSadaf Ebrahimi  * @instance: The instance the event is in (NULL for top level)
512*287e80b3SSadaf Ebrahimi  * @system: The system name that the event file is in
513*287e80b3SSadaf Ebrahimi  * @event: The event name of the event
514*287e80b3SSadaf Ebrahimi  * @file: The name of the file in the event directory.
515*287e80b3SSadaf Ebrahimi  *
516*287e80b3SSadaf Ebrahimi  * Returns a path to a file in the event director.
517*287e80b3SSadaf Ebrahimi  * or NULL on error. The path returned must be freed with
518*287e80b3SSadaf Ebrahimi  * tracefs_put_tracing_file().
519*287e80b3SSadaf Ebrahimi  */
tracefs_event_get_file(struct tracefs_instance * instance,const char * system,const char * event,const char * file)520*287e80b3SSadaf Ebrahimi char *tracefs_event_get_file(struct tracefs_instance *instance,
521*287e80b3SSadaf Ebrahimi 			     const char *system, const char *event,
522*287e80b3SSadaf Ebrahimi 			     const char *file)
523*287e80b3SSadaf Ebrahimi {
524*287e80b3SSadaf Ebrahimi 	char *instance_path;
525*287e80b3SSadaf Ebrahimi 	char *path;
526*287e80b3SSadaf Ebrahimi 	int ret;
527*287e80b3SSadaf Ebrahimi 
528*287e80b3SSadaf Ebrahimi 	ret = event_file(&path, system, event, file);
529*287e80b3SSadaf Ebrahimi 	if (ret < 0)
530*287e80b3SSadaf Ebrahimi 		return NULL;
531*287e80b3SSadaf Ebrahimi 
532*287e80b3SSadaf Ebrahimi 	instance_path = tracefs_instance_get_file(instance, path);
533*287e80b3SSadaf Ebrahimi 	free(path);
534*287e80b3SSadaf Ebrahimi 
535*287e80b3SSadaf Ebrahimi 	return instance_path;
536*287e80b3SSadaf Ebrahimi }
537*287e80b3SSadaf Ebrahimi 
538*287e80b3SSadaf Ebrahimi /**
539*287e80b3SSadaf Ebrahimi  * tracefs_event_file_read - read the content from an event file
540*287e80b3SSadaf Ebrahimi  * @instance: The instance the event is in (NULL for top level)
541*287e80b3SSadaf Ebrahimi  * @system: The system name that the event file is in
542*287e80b3SSadaf Ebrahimi  * @event: The event name of the event
543*287e80b3SSadaf Ebrahimi  * @file: The name of the file in the event directory.
544*287e80b3SSadaf Ebrahimi  * @psize: the size of the content read.
545*287e80b3SSadaf Ebrahimi  *
546*287e80b3SSadaf Ebrahimi  * Reads the content of the event file that is passed via the
547*287e80b3SSadaf Ebrahimi  * arguments and returns the content.
548*287e80b3SSadaf Ebrahimi  *
549*287e80b3SSadaf Ebrahimi  * Return a string containing the content of the file or NULL
550*287e80b3SSadaf Ebrahimi  * on error. The string returned must be freed with free().
551*287e80b3SSadaf Ebrahimi  */
tracefs_event_file_read(struct tracefs_instance * instance,const char * system,const char * event,const char * file,int * psize)552*287e80b3SSadaf Ebrahimi char *tracefs_event_file_read(struct tracefs_instance *instance,
553*287e80b3SSadaf Ebrahimi 			      const char *system, const char *event,
554*287e80b3SSadaf Ebrahimi 			      const char *file, int *psize)
555*287e80b3SSadaf Ebrahimi {
556*287e80b3SSadaf Ebrahimi 	char *content;
557*287e80b3SSadaf Ebrahimi 	char *path;
558*287e80b3SSadaf Ebrahimi 	int ret;
559*287e80b3SSadaf Ebrahimi 
560*287e80b3SSadaf Ebrahimi 	ret = event_file(&path, system, event, file);
561*287e80b3SSadaf Ebrahimi 	if (ret < 0)
562*287e80b3SSadaf Ebrahimi 		return NULL;
563*287e80b3SSadaf Ebrahimi 
564*287e80b3SSadaf Ebrahimi 	content = tracefs_instance_file_read(instance, path, psize);
565*287e80b3SSadaf Ebrahimi 	free(path);
566*287e80b3SSadaf Ebrahimi 	return content;
567*287e80b3SSadaf Ebrahimi }
568*287e80b3SSadaf Ebrahimi 
569*287e80b3SSadaf Ebrahimi /**
570*287e80b3SSadaf Ebrahimi  * tracefs_event_file_write - write to an event file
571*287e80b3SSadaf Ebrahimi  * @instance: The instance the event is in (NULL for top level)
572*287e80b3SSadaf Ebrahimi  * @system: The system name that the event file is in
573*287e80b3SSadaf Ebrahimi  * @event: The event name of the event
574*287e80b3SSadaf Ebrahimi  * @file: The name of the file in the event directory.
575*287e80b3SSadaf Ebrahimi  * @str: The string to write into the file
576*287e80b3SSadaf Ebrahimi  *
577*287e80b3SSadaf Ebrahimi  * Writes the content of @str to a file in the instance directory.
578*287e80b3SSadaf Ebrahimi  * The content of the file will be overwritten by @str.
579*287e80b3SSadaf Ebrahimi  *
580*287e80b3SSadaf Ebrahimi  * Return 0 on success, and -1 on error.
581*287e80b3SSadaf Ebrahimi  */
tracefs_event_file_write(struct tracefs_instance * instance,const char * system,const char * event,const char * file,const char * str)582*287e80b3SSadaf Ebrahimi int tracefs_event_file_write(struct tracefs_instance *instance,
583*287e80b3SSadaf Ebrahimi 			     const char *system, const char *event,
584*287e80b3SSadaf Ebrahimi 			     const char *file, const char *str)
585*287e80b3SSadaf Ebrahimi {
586*287e80b3SSadaf Ebrahimi 	char *path;
587*287e80b3SSadaf Ebrahimi 	int ret;
588*287e80b3SSadaf Ebrahimi 
589*287e80b3SSadaf Ebrahimi 	ret = event_file(&path, system, event, file);
590*287e80b3SSadaf Ebrahimi 	if (ret < 0)
591*287e80b3SSadaf Ebrahimi 		return -1;
592*287e80b3SSadaf Ebrahimi 
593*287e80b3SSadaf Ebrahimi 	ret = tracefs_instance_file_write(instance, path, str);
594*287e80b3SSadaf Ebrahimi 	free(path);
595*287e80b3SSadaf Ebrahimi 	return ret;
596*287e80b3SSadaf Ebrahimi }
597*287e80b3SSadaf Ebrahimi 
598*287e80b3SSadaf Ebrahimi /**
599*287e80b3SSadaf Ebrahimi  * tracefs_event_file_append - write to an event file
600*287e80b3SSadaf Ebrahimi  * @instance: The instance the event is in (NULL for top level)
601*287e80b3SSadaf Ebrahimi  * @system: The system name that the event file is in
602*287e80b3SSadaf Ebrahimi  * @event: The event name of the event
603*287e80b3SSadaf Ebrahimi  * @file: The name of the file in the event directory.
604*287e80b3SSadaf Ebrahimi  * @str: The string to write into the file
605*287e80b3SSadaf Ebrahimi  *
606*287e80b3SSadaf Ebrahimi  * Writes the content of @str to a file in the instance directory.
607*287e80b3SSadaf Ebrahimi  * The content of @str will be appended to the content of the file.
608*287e80b3SSadaf Ebrahimi  * The current content should not be lost.
609*287e80b3SSadaf Ebrahimi  *
610*287e80b3SSadaf Ebrahimi  * Return 0 on success, and -1 on error.
611*287e80b3SSadaf Ebrahimi  */
tracefs_event_file_append(struct tracefs_instance * instance,const char * system,const char * event,const char * file,const char * str)612*287e80b3SSadaf Ebrahimi int tracefs_event_file_append(struct tracefs_instance *instance,
613*287e80b3SSadaf Ebrahimi 			      const char *system, const char *event,
614*287e80b3SSadaf Ebrahimi 			      const char *file, const char *str)
615*287e80b3SSadaf Ebrahimi {
616*287e80b3SSadaf Ebrahimi 	char *path;
617*287e80b3SSadaf Ebrahimi 	int ret;
618*287e80b3SSadaf Ebrahimi 
619*287e80b3SSadaf Ebrahimi 	ret = event_file(&path, system, event, file);
620*287e80b3SSadaf Ebrahimi 	if (ret < 0)
621*287e80b3SSadaf Ebrahimi 		return -1;
622*287e80b3SSadaf Ebrahimi 
623*287e80b3SSadaf Ebrahimi 	ret = tracefs_instance_file_append(instance, path, str);
624*287e80b3SSadaf Ebrahimi 	free(path);
625*287e80b3SSadaf Ebrahimi 	return ret;
626*287e80b3SSadaf Ebrahimi }
627*287e80b3SSadaf Ebrahimi 
628*287e80b3SSadaf Ebrahimi /**
629*287e80b3SSadaf Ebrahimi  * tracefs_event_file_clear - clear an event file
630*287e80b3SSadaf Ebrahimi  * @instance: The instance the event is in (NULL for top level)
631*287e80b3SSadaf Ebrahimi  * @system: The system name that the event file is in
632*287e80b3SSadaf Ebrahimi  * @event: The event name of the event
633*287e80b3SSadaf Ebrahimi  * @file: The name of the file in the event directory.
634*287e80b3SSadaf Ebrahimi  *
635*287e80b3SSadaf Ebrahimi  * Clears the content of the event file. That is, it is opened
636*287e80b3SSadaf Ebrahimi  * with O_TRUNC and then closed.
637*287e80b3SSadaf Ebrahimi  *
638*287e80b3SSadaf Ebrahimi  * Return 0 on success, and -1 on error.
639*287e80b3SSadaf Ebrahimi  */
tracefs_event_file_clear(struct tracefs_instance * instance,const char * system,const char * event,const char * file)640*287e80b3SSadaf Ebrahimi int tracefs_event_file_clear(struct tracefs_instance *instance,
641*287e80b3SSadaf Ebrahimi 			     const char *system, const char *event,
642*287e80b3SSadaf Ebrahimi 			     const char *file)
643*287e80b3SSadaf Ebrahimi {
644*287e80b3SSadaf Ebrahimi 	char *path;
645*287e80b3SSadaf Ebrahimi 	int ret;
646*287e80b3SSadaf Ebrahimi 
647*287e80b3SSadaf Ebrahimi 	ret = event_file(&path, system, event, file);
648*287e80b3SSadaf Ebrahimi 	if (ret < 0)
649*287e80b3SSadaf Ebrahimi 		return -1;
650*287e80b3SSadaf Ebrahimi 
651*287e80b3SSadaf Ebrahimi 	ret = tracefs_instance_file_clear(instance, path);
652*287e80b3SSadaf Ebrahimi 	free(path);
653*287e80b3SSadaf Ebrahimi 	return ret;
654*287e80b3SSadaf Ebrahimi }
655*287e80b3SSadaf Ebrahimi 
656*287e80b3SSadaf Ebrahimi /**
657*287e80b3SSadaf Ebrahimi  * tracefs_event_file_exits - test if a file exists
658*287e80b3SSadaf Ebrahimi  * @instance: The instance the event is in (NULL for top level)
659*287e80b3SSadaf Ebrahimi  * @system: The system name that the event file is in
660*287e80b3SSadaf Ebrahimi  * @event: The event name of the event
661*287e80b3SSadaf Ebrahimi  * @file: The name of the file in the event directory.
662*287e80b3SSadaf Ebrahimi  *
663*287e80b3SSadaf Ebrahimi  * Return true if the file exists, false if it odes not or
664*287e80b3SSadaf Ebrahimi  * an error occurred.
665*287e80b3SSadaf Ebrahimi  */
tracefs_event_file_exists(struct tracefs_instance * instance,const char * system,const char * event,const char * file)666*287e80b3SSadaf Ebrahimi bool tracefs_event_file_exists(struct tracefs_instance *instance,
667*287e80b3SSadaf Ebrahimi 			       const char *system, const char *event,
668*287e80b3SSadaf Ebrahimi 			       const char *file)
669*287e80b3SSadaf Ebrahimi {
670*287e80b3SSadaf Ebrahimi 	char *path;
671*287e80b3SSadaf Ebrahimi 	bool ret;
672*287e80b3SSadaf Ebrahimi 
673*287e80b3SSadaf Ebrahimi 	if (event_file(&path, system, event, file) < 0)
674*287e80b3SSadaf Ebrahimi 		return false;
675*287e80b3SSadaf Ebrahimi 
676*287e80b3SSadaf Ebrahimi 	ret = tracefs_file_exists(instance, path);
677*287e80b3SSadaf Ebrahimi 	free(path);
678*287e80b3SSadaf Ebrahimi 	return ret;
679*287e80b3SSadaf Ebrahimi }
680*287e80b3SSadaf Ebrahimi 
681*287e80b3SSadaf Ebrahimi /**
682*287e80b3SSadaf Ebrahimi  * tracefs_event_systems - return list of systems for tracing
683*287e80b3SSadaf Ebrahimi  * @tracing_dir: directory holding the "events" directory
684*287e80b3SSadaf Ebrahimi  *		 if NULL, top tracing directory is used
685*287e80b3SSadaf Ebrahimi  *
686*287e80b3SSadaf Ebrahimi  * Returns an allocated list of system names. Both the names and
687*287e80b3SSadaf Ebrahimi  * the list must be freed with tracefs_list_free()
688*287e80b3SSadaf Ebrahimi  * The list returned ends with a "NULL" pointer
689*287e80b3SSadaf Ebrahimi  */
tracefs_event_systems(const char * tracing_dir)690*287e80b3SSadaf Ebrahimi char **tracefs_event_systems(const char *tracing_dir)
691*287e80b3SSadaf Ebrahimi {
692*287e80b3SSadaf Ebrahimi 	struct dirent *dent;
693*287e80b3SSadaf Ebrahimi 	char **systems = NULL;
694*287e80b3SSadaf Ebrahimi 	char *events_dir;
695*287e80b3SSadaf Ebrahimi 	struct stat st;
696*287e80b3SSadaf Ebrahimi 	DIR *dir;
697*287e80b3SSadaf Ebrahimi 	int ret;
698*287e80b3SSadaf Ebrahimi 
699*287e80b3SSadaf Ebrahimi 	if (!tracing_dir)
700*287e80b3SSadaf Ebrahimi 		tracing_dir = tracefs_tracing_dir();
701*287e80b3SSadaf Ebrahimi 
702*287e80b3SSadaf Ebrahimi 	if (!tracing_dir)
703*287e80b3SSadaf Ebrahimi 		return NULL;
704*287e80b3SSadaf Ebrahimi 
705*287e80b3SSadaf Ebrahimi 	events_dir = trace_append_file(tracing_dir, "events");
706*287e80b3SSadaf Ebrahimi 	if (!events_dir)
707*287e80b3SSadaf Ebrahimi 		return NULL;
708*287e80b3SSadaf Ebrahimi 
709*287e80b3SSadaf Ebrahimi 	/*
710*287e80b3SSadaf Ebrahimi 	 * Search all the directories in the events directory,
711*287e80b3SSadaf Ebrahimi 	 * and collect the ones that have the "enable" file.
712*287e80b3SSadaf Ebrahimi 	 */
713*287e80b3SSadaf Ebrahimi 	ret = stat(events_dir, &st);
714*287e80b3SSadaf Ebrahimi 	if (ret < 0 || !S_ISDIR(st.st_mode))
715*287e80b3SSadaf Ebrahimi 		goto out_free;
716*287e80b3SSadaf Ebrahimi 
717*287e80b3SSadaf Ebrahimi 	dir = opendir(events_dir);
718*287e80b3SSadaf Ebrahimi 	if (!dir)
719*287e80b3SSadaf Ebrahimi 		goto out_free;
720*287e80b3SSadaf Ebrahimi 
721*287e80b3SSadaf Ebrahimi 	while ((dent = readdir(dir))) {
722*287e80b3SSadaf Ebrahimi 		const char *name = dent->d_name;
723*287e80b3SSadaf Ebrahimi 		char *enable;
724*287e80b3SSadaf Ebrahimi 		char *sys;
725*287e80b3SSadaf Ebrahimi 
726*287e80b3SSadaf Ebrahimi 		if (strcmp(name, ".") == 0 ||
727*287e80b3SSadaf Ebrahimi 		    strcmp(name, "..") == 0)
728*287e80b3SSadaf Ebrahimi 			continue;
729*287e80b3SSadaf Ebrahimi 
730*287e80b3SSadaf Ebrahimi 		sys = trace_append_file(events_dir, name);
731*287e80b3SSadaf Ebrahimi 		ret = stat(sys, &st);
732*287e80b3SSadaf Ebrahimi 		if (ret < 0 || !S_ISDIR(st.st_mode)) {
733*287e80b3SSadaf Ebrahimi 			free(sys);
734*287e80b3SSadaf Ebrahimi 			continue;
735*287e80b3SSadaf Ebrahimi 		}
736*287e80b3SSadaf Ebrahimi 
737*287e80b3SSadaf Ebrahimi 		enable = trace_append_file(sys, "enable");
738*287e80b3SSadaf Ebrahimi 
739*287e80b3SSadaf Ebrahimi 		ret = stat(enable, &st);
740*287e80b3SSadaf Ebrahimi 		if (ret >= 0) {
741*287e80b3SSadaf Ebrahimi 			if (add_list_string(&systems, name) < 0)
742*287e80b3SSadaf Ebrahimi 				goto out_free;
743*287e80b3SSadaf Ebrahimi 		}
744*287e80b3SSadaf Ebrahimi 		free(enable);
745*287e80b3SSadaf Ebrahimi 		free(sys);
746*287e80b3SSadaf Ebrahimi 	}
747*287e80b3SSadaf Ebrahimi 
748*287e80b3SSadaf Ebrahimi 	closedir(dir);
749*287e80b3SSadaf Ebrahimi 
750*287e80b3SSadaf Ebrahimi  out_free:
751*287e80b3SSadaf Ebrahimi 	free(events_dir);
752*287e80b3SSadaf Ebrahimi 	return systems;
753*287e80b3SSadaf Ebrahimi }
754*287e80b3SSadaf Ebrahimi 
755*287e80b3SSadaf Ebrahimi /**
756*287e80b3SSadaf Ebrahimi  * tracefs_system_events - return list of events for system
757*287e80b3SSadaf Ebrahimi  * @tracing_dir: directory holding the "events" directory
758*287e80b3SSadaf Ebrahimi  * @system: the system to return the events for
759*287e80b3SSadaf Ebrahimi  *
760*287e80b3SSadaf Ebrahimi  * Returns an allocated list of event names. Both the names and
761*287e80b3SSadaf Ebrahimi  * the list must be freed with tracefs_list_free()
762*287e80b3SSadaf Ebrahimi  * The list returned ends with a "NULL" pointer
763*287e80b3SSadaf Ebrahimi  */
tracefs_system_events(const char * tracing_dir,const char * system)764*287e80b3SSadaf Ebrahimi char **tracefs_system_events(const char *tracing_dir, const char *system)
765*287e80b3SSadaf Ebrahimi {
766*287e80b3SSadaf Ebrahimi 	struct dirent *dent;
767*287e80b3SSadaf Ebrahimi 	char **events = NULL;
768*287e80b3SSadaf Ebrahimi 	char *system_dir = NULL;
769*287e80b3SSadaf Ebrahimi 	struct stat st;
770*287e80b3SSadaf Ebrahimi 	DIR *dir;
771*287e80b3SSadaf Ebrahimi 	int ret;
772*287e80b3SSadaf Ebrahimi 
773*287e80b3SSadaf Ebrahimi 	if (!tracing_dir)
774*287e80b3SSadaf Ebrahimi 		tracing_dir = tracefs_tracing_dir();
775*287e80b3SSadaf Ebrahimi 
776*287e80b3SSadaf Ebrahimi 	if (!tracing_dir || !system)
777*287e80b3SSadaf Ebrahimi 		return NULL;
778*287e80b3SSadaf Ebrahimi 
779*287e80b3SSadaf Ebrahimi 	asprintf(&system_dir, "%s/events/%s", tracing_dir, system);
780*287e80b3SSadaf Ebrahimi 	if (!system_dir)
781*287e80b3SSadaf Ebrahimi 		return NULL;
782*287e80b3SSadaf Ebrahimi 
783*287e80b3SSadaf Ebrahimi 	ret = stat(system_dir, &st);
784*287e80b3SSadaf Ebrahimi 	if (ret < 0 || !S_ISDIR(st.st_mode))
785*287e80b3SSadaf Ebrahimi 		goto out_free;
786*287e80b3SSadaf Ebrahimi 
787*287e80b3SSadaf Ebrahimi 	dir = opendir(system_dir);
788*287e80b3SSadaf Ebrahimi 	if (!dir)
789*287e80b3SSadaf Ebrahimi 		goto out_free;
790*287e80b3SSadaf Ebrahimi 
791*287e80b3SSadaf Ebrahimi 	while ((dent = readdir(dir))) {
792*287e80b3SSadaf Ebrahimi 		const char *name = dent->d_name;
793*287e80b3SSadaf Ebrahimi 		char *event;
794*287e80b3SSadaf Ebrahimi 
795*287e80b3SSadaf Ebrahimi 		if (strcmp(name, ".") == 0 ||
796*287e80b3SSadaf Ebrahimi 		    strcmp(name, "..") == 0)
797*287e80b3SSadaf Ebrahimi 			continue;
798*287e80b3SSadaf Ebrahimi 
799*287e80b3SSadaf Ebrahimi 		event = trace_append_file(system_dir, name);
800*287e80b3SSadaf Ebrahimi 		ret = stat(event, &st);
801*287e80b3SSadaf Ebrahimi 		if (ret < 0 || !S_ISDIR(st.st_mode)) {
802*287e80b3SSadaf Ebrahimi 			free(event);
803*287e80b3SSadaf Ebrahimi 			continue;
804*287e80b3SSadaf Ebrahimi 		}
805*287e80b3SSadaf Ebrahimi 
806*287e80b3SSadaf Ebrahimi 		if (add_list_string(&events, name) < 0)
807*287e80b3SSadaf Ebrahimi 			goto out_free;
808*287e80b3SSadaf Ebrahimi 
809*287e80b3SSadaf Ebrahimi 		free(event);
810*287e80b3SSadaf Ebrahimi 	}
811*287e80b3SSadaf Ebrahimi 
812*287e80b3SSadaf Ebrahimi 	closedir(dir);
813*287e80b3SSadaf Ebrahimi 
814*287e80b3SSadaf Ebrahimi  out_free:
815*287e80b3SSadaf Ebrahimi 	free(system_dir);
816*287e80b3SSadaf Ebrahimi 
817*287e80b3SSadaf Ebrahimi 	return events;
818*287e80b3SSadaf Ebrahimi }
819*287e80b3SSadaf Ebrahimi 
820*287e80b3SSadaf Ebrahimi /**
821*287e80b3SSadaf Ebrahimi  * tracefs_tracers - returns an array of available tracers
822*287e80b3SSadaf Ebrahimi  * @tracing_dir: The directory that contains the tracing directory
823*287e80b3SSadaf Ebrahimi  *
824*287e80b3SSadaf Ebrahimi  * Returns an allocate list of plugins. The array ends with NULL
825*287e80b3SSadaf Ebrahimi  * Both the plugin names and array must be freed with tracefs_list_free()
826*287e80b3SSadaf Ebrahimi  */
tracefs_tracers(const char * tracing_dir)827*287e80b3SSadaf Ebrahimi char **tracefs_tracers(const char *tracing_dir)
828*287e80b3SSadaf Ebrahimi {
829*287e80b3SSadaf Ebrahimi 	char *available_tracers;
830*287e80b3SSadaf Ebrahimi 	struct stat st;
831*287e80b3SSadaf Ebrahimi 	char **plugins = NULL;
832*287e80b3SSadaf Ebrahimi 	char *buf;
833*287e80b3SSadaf Ebrahimi 	char *str, *saveptr;
834*287e80b3SSadaf Ebrahimi 	char *plugin;
835*287e80b3SSadaf Ebrahimi 	int slen;
836*287e80b3SSadaf Ebrahimi 	int len;
837*287e80b3SSadaf Ebrahimi 	int ret;
838*287e80b3SSadaf Ebrahimi 
839*287e80b3SSadaf Ebrahimi 	if (!tracing_dir)
840*287e80b3SSadaf Ebrahimi 		tracing_dir = tracefs_tracing_dir();
841*287e80b3SSadaf Ebrahimi 
842*287e80b3SSadaf Ebrahimi 	if (!tracing_dir)
843*287e80b3SSadaf Ebrahimi 		return NULL;
844*287e80b3SSadaf Ebrahimi 
845*287e80b3SSadaf Ebrahimi 	available_tracers = trace_append_file(tracing_dir, "available_tracers");
846*287e80b3SSadaf Ebrahimi 	if (!available_tracers)
847*287e80b3SSadaf Ebrahimi 		return NULL;
848*287e80b3SSadaf Ebrahimi 
849*287e80b3SSadaf Ebrahimi 	ret = stat(available_tracers, &st);
850*287e80b3SSadaf Ebrahimi 	if (ret < 0)
851*287e80b3SSadaf Ebrahimi 		goto out_free;
852*287e80b3SSadaf Ebrahimi 
853*287e80b3SSadaf Ebrahimi 	len = str_read_file(available_tracers, &buf, true);
854*287e80b3SSadaf Ebrahimi 	if (len <= 0)
855*287e80b3SSadaf Ebrahimi 		goto out_free;
856*287e80b3SSadaf Ebrahimi 
857*287e80b3SSadaf Ebrahimi 	for (str = buf; ; str = NULL) {
858*287e80b3SSadaf Ebrahimi 		plugin = strtok_r(str, " ", &saveptr);
859*287e80b3SSadaf Ebrahimi 		if (!plugin)
860*287e80b3SSadaf Ebrahimi 			break;
861*287e80b3SSadaf Ebrahimi 		slen = strlen(plugin);
862*287e80b3SSadaf Ebrahimi 		if (!slen)
863*287e80b3SSadaf Ebrahimi 			continue;
864*287e80b3SSadaf Ebrahimi 
865*287e80b3SSadaf Ebrahimi 		/* chop off any newlines */
866*287e80b3SSadaf Ebrahimi 		if (plugin[slen - 1] == '\n')
867*287e80b3SSadaf Ebrahimi 			plugin[slen - 1] = '\0';
868*287e80b3SSadaf Ebrahimi 
869*287e80b3SSadaf Ebrahimi 		/* Skip the non tracers */
870*287e80b3SSadaf Ebrahimi 		if (strcmp(plugin, "nop") == 0 ||
871*287e80b3SSadaf Ebrahimi 		    strcmp(plugin, "none") == 0)
872*287e80b3SSadaf Ebrahimi 			continue;
873*287e80b3SSadaf Ebrahimi 
874*287e80b3SSadaf Ebrahimi 		if (add_list_string(&plugins, plugin) < 0)
875*287e80b3SSadaf Ebrahimi 			break;
876*287e80b3SSadaf Ebrahimi 	}
877*287e80b3SSadaf Ebrahimi 	free(buf);
878*287e80b3SSadaf Ebrahimi 
879*287e80b3SSadaf Ebrahimi  out_free:
880*287e80b3SSadaf Ebrahimi 	free(available_tracers);
881*287e80b3SSadaf Ebrahimi 
882*287e80b3SSadaf Ebrahimi 	return plugins;
883*287e80b3SSadaf Ebrahimi }
884*287e80b3SSadaf Ebrahimi 
load_events(struct tep_handle * tep,const char * tracing_dir,const char * system,bool check)885*287e80b3SSadaf Ebrahimi static int load_events(struct tep_handle *tep,
886*287e80b3SSadaf Ebrahimi 		       const char *tracing_dir, const char *system, bool check)
887*287e80b3SSadaf Ebrahimi {
888*287e80b3SSadaf Ebrahimi 	int ret = 0, failure = 0;
889*287e80b3SSadaf Ebrahimi 	char **events = NULL;
890*287e80b3SSadaf Ebrahimi 	struct stat st;
891*287e80b3SSadaf Ebrahimi 	int len = 0;
892*287e80b3SSadaf Ebrahimi 	int i;
893*287e80b3SSadaf Ebrahimi 
894*287e80b3SSadaf Ebrahimi 	if (!tracing_dir)
895*287e80b3SSadaf Ebrahimi 		tracing_dir = tracefs_tracing_dir();
896*287e80b3SSadaf Ebrahimi 
897*287e80b3SSadaf Ebrahimi 	events = tracefs_system_events(tracing_dir, system);
898*287e80b3SSadaf Ebrahimi 	if (!events)
899*287e80b3SSadaf Ebrahimi 		return -ENOENT;
900*287e80b3SSadaf Ebrahimi 
901*287e80b3SSadaf Ebrahimi 	for (i = 0; events[i]; i++) {
902*287e80b3SSadaf Ebrahimi 		char *format;
903*287e80b3SSadaf Ebrahimi 		char *buf;
904*287e80b3SSadaf Ebrahimi 
905*287e80b3SSadaf Ebrahimi 		ret = asprintf(&format, "%s/events/%s/%s/format",
906*287e80b3SSadaf Ebrahimi 			       tracing_dir, system, events[i]);
907*287e80b3SSadaf Ebrahimi 		if (ret < 0) {
908*287e80b3SSadaf Ebrahimi 			failure = -ENOMEM;
909*287e80b3SSadaf Ebrahimi 			break;
910*287e80b3SSadaf Ebrahimi 		}
911*287e80b3SSadaf Ebrahimi 
912*287e80b3SSadaf Ebrahimi 		ret = stat(format, &st);
913*287e80b3SSadaf Ebrahimi 		if (ret < 0)
914*287e80b3SSadaf Ebrahimi 			goto next_event;
915*287e80b3SSadaf Ebrahimi 
916*287e80b3SSadaf Ebrahimi 		/* check if event is already added, to avoid duplicates */
917*287e80b3SSadaf Ebrahimi 		if (check && tep_find_event_by_name(tep, system, events[i]))
918*287e80b3SSadaf Ebrahimi 			goto next_event;
919*287e80b3SSadaf Ebrahimi 
920*287e80b3SSadaf Ebrahimi 		len = str_read_file(format, &buf, true);
921*287e80b3SSadaf Ebrahimi 		if (len <= 0)
922*287e80b3SSadaf Ebrahimi 			goto next_event;
923*287e80b3SSadaf Ebrahimi 
924*287e80b3SSadaf Ebrahimi 		ret = tep_parse_event(tep, buf, len, system);
925*287e80b3SSadaf Ebrahimi 		free(buf);
926*287e80b3SSadaf Ebrahimi next_event:
927*287e80b3SSadaf Ebrahimi 		free(format);
928*287e80b3SSadaf Ebrahimi 		if (ret)
929*287e80b3SSadaf Ebrahimi 			failure = ret;
930*287e80b3SSadaf Ebrahimi 	}
931*287e80b3SSadaf Ebrahimi 
932*287e80b3SSadaf Ebrahimi 	tracefs_list_free(events);
933*287e80b3SSadaf Ebrahimi 	return failure;
934*287e80b3SSadaf Ebrahimi }
935*287e80b3SSadaf Ebrahimi 
trace_rescan_events(struct tep_handle * tep,const char * tracing_dir,const char * system)936*287e80b3SSadaf Ebrahimi __hidden int trace_rescan_events(struct tep_handle *tep,
937*287e80b3SSadaf Ebrahimi 				const char *tracing_dir, const char *system)
938*287e80b3SSadaf Ebrahimi {
939*287e80b3SSadaf Ebrahimi 	/* ToDo: add here logic for deleting removed events from tep handle */
940*287e80b3SSadaf Ebrahimi 	return load_events(tep, tracing_dir, system, true);
941*287e80b3SSadaf Ebrahimi }
942*287e80b3SSadaf Ebrahimi 
trace_load_events(struct tep_handle * tep,const char * tracing_dir,const char * system)943*287e80b3SSadaf Ebrahimi __hidden int trace_load_events(struct tep_handle *tep,
944*287e80b3SSadaf Ebrahimi 			       const char *tracing_dir, const char *system)
945*287e80b3SSadaf Ebrahimi {
946*287e80b3SSadaf Ebrahimi 	return load_events(tep, tracing_dir, system, false);
947*287e80b3SSadaf Ebrahimi }
948*287e80b3SSadaf Ebrahimi 
get_tep_event(struct tep_handle * tep,const char * system,const char * name)949*287e80b3SSadaf Ebrahimi __hidden struct tep_event *get_tep_event(struct tep_handle *tep,
950*287e80b3SSadaf Ebrahimi 					 const char *system, const char *name)
951*287e80b3SSadaf Ebrahimi {
952*287e80b3SSadaf Ebrahimi 	struct tep_event *event;
953*287e80b3SSadaf Ebrahimi 
954*287e80b3SSadaf Ebrahimi 	/* Check if event exists in the system */
955*287e80b3SSadaf Ebrahimi 	if (!tracefs_event_file_exists(NULL, system, name, "format"))
956*287e80b3SSadaf Ebrahimi 		return NULL;
957*287e80b3SSadaf Ebrahimi 
958*287e80b3SSadaf Ebrahimi 	/* If the event is already loaded in the tep, return it */
959*287e80b3SSadaf Ebrahimi 	event = tep_find_event_by_name(tep, system, name);
960*287e80b3SSadaf Ebrahimi 	if (event)
961*287e80b3SSadaf Ebrahimi 		return event;
962*287e80b3SSadaf Ebrahimi 
963*287e80b3SSadaf Ebrahimi 	/* Try to load any new events from the given system */
964*287e80b3SSadaf Ebrahimi 	if (trace_rescan_events(tep, NULL, system))
965*287e80b3SSadaf Ebrahimi 		return NULL;
966*287e80b3SSadaf Ebrahimi 
967*287e80b3SSadaf Ebrahimi 	return tep_find_event_by_name(tep, system, name);
968*287e80b3SSadaf Ebrahimi }
969*287e80b3SSadaf Ebrahimi 
read_header(struct tep_handle * tep,const char * tracing_dir)970*287e80b3SSadaf Ebrahimi static int read_header(struct tep_handle *tep, const char *tracing_dir)
971*287e80b3SSadaf Ebrahimi {
972*287e80b3SSadaf Ebrahimi 	struct stat st;
973*287e80b3SSadaf Ebrahimi 	char *header;
974*287e80b3SSadaf Ebrahimi 	char *buf;
975*287e80b3SSadaf Ebrahimi 	int len;
976*287e80b3SSadaf Ebrahimi 	int ret = -1;
977*287e80b3SSadaf Ebrahimi 
978*287e80b3SSadaf Ebrahimi 	header = trace_append_file(tracing_dir, "events/header_page");
979*287e80b3SSadaf Ebrahimi 
980*287e80b3SSadaf Ebrahimi 	ret = stat(header, &st);
981*287e80b3SSadaf Ebrahimi 	if (ret < 0)
982*287e80b3SSadaf Ebrahimi 		goto out;
983*287e80b3SSadaf Ebrahimi 
984*287e80b3SSadaf Ebrahimi 	len = str_read_file(header, &buf, true);
985*287e80b3SSadaf Ebrahimi 	if (len <= 0)
986*287e80b3SSadaf Ebrahimi 		goto out;
987*287e80b3SSadaf Ebrahimi 
988*287e80b3SSadaf Ebrahimi 	tep_parse_header_page(tep, buf, len, sizeof(long));
989*287e80b3SSadaf Ebrahimi 
990*287e80b3SSadaf Ebrahimi 	free(buf);
991*287e80b3SSadaf Ebrahimi 
992*287e80b3SSadaf Ebrahimi 	ret = 0;
993*287e80b3SSadaf Ebrahimi  out:
994*287e80b3SSadaf Ebrahimi 	free(header);
995*287e80b3SSadaf Ebrahimi 	return ret;
996*287e80b3SSadaf Ebrahimi }
997*287e80b3SSadaf Ebrahimi 
contains(const char * name,const char * const * names)998*287e80b3SSadaf Ebrahimi static bool contains(const char *name, const char * const *names)
999*287e80b3SSadaf Ebrahimi {
1000*287e80b3SSadaf Ebrahimi 	if (!names)
1001*287e80b3SSadaf Ebrahimi 		return false;
1002*287e80b3SSadaf Ebrahimi 	for (; *names; names++)
1003*287e80b3SSadaf Ebrahimi 		if (strcmp(name, *names) == 0)
1004*287e80b3SSadaf Ebrahimi 			return true;
1005*287e80b3SSadaf Ebrahimi 	return false;
1006*287e80b3SSadaf Ebrahimi }
1007*287e80b3SSadaf Ebrahimi 
load_kallsyms(struct tep_handle * tep)1008*287e80b3SSadaf Ebrahimi static void load_kallsyms(struct tep_handle *tep)
1009*287e80b3SSadaf Ebrahimi {
1010*287e80b3SSadaf Ebrahimi 	char *buf;
1011*287e80b3SSadaf Ebrahimi 
1012*287e80b3SSadaf Ebrahimi 	if (str_read_file("/proc/kallsyms", &buf, false) <= 0)
1013*287e80b3SSadaf Ebrahimi 		return;
1014*287e80b3SSadaf Ebrahimi 
1015*287e80b3SSadaf Ebrahimi 	tep_parse_kallsyms(tep, buf);
1016*287e80b3SSadaf Ebrahimi 	free(buf);
1017*287e80b3SSadaf Ebrahimi }
1018*287e80b3SSadaf Ebrahimi 
load_saved_cmdlines(const char * tracing_dir,struct tep_handle * tep,bool warn)1019*287e80b3SSadaf Ebrahimi static int load_saved_cmdlines(const char *tracing_dir,
1020*287e80b3SSadaf Ebrahimi 			       struct tep_handle *tep, bool warn)
1021*287e80b3SSadaf Ebrahimi {
1022*287e80b3SSadaf Ebrahimi 	char *path;
1023*287e80b3SSadaf Ebrahimi 	char *buf;
1024*287e80b3SSadaf Ebrahimi 	int ret;
1025*287e80b3SSadaf Ebrahimi 
1026*287e80b3SSadaf Ebrahimi 	path = trace_append_file(tracing_dir, "saved_cmdlines");
1027*287e80b3SSadaf Ebrahimi 	if (!path)
1028*287e80b3SSadaf Ebrahimi 		return -1;
1029*287e80b3SSadaf Ebrahimi 
1030*287e80b3SSadaf Ebrahimi 	ret = str_read_file(path, &buf, false);
1031*287e80b3SSadaf Ebrahimi 	free(path);
1032*287e80b3SSadaf Ebrahimi 	if (ret <= 0)
1033*287e80b3SSadaf Ebrahimi 		return -1;
1034*287e80b3SSadaf Ebrahimi 
1035*287e80b3SSadaf Ebrahimi 	ret = tep_parse_saved_cmdlines(tep, buf);
1036*287e80b3SSadaf Ebrahimi 	free(buf);
1037*287e80b3SSadaf Ebrahimi 
1038*287e80b3SSadaf Ebrahimi 	return ret;
1039*287e80b3SSadaf Ebrahimi }
1040*287e80b3SSadaf Ebrahimi 
load_printk_formats(const char * tracing_dir,struct tep_handle * tep)1041*287e80b3SSadaf Ebrahimi static void load_printk_formats(const char *tracing_dir,
1042*287e80b3SSadaf Ebrahimi 				struct tep_handle *tep)
1043*287e80b3SSadaf Ebrahimi {
1044*287e80b3SSadaf Ebrahimi 	char *path;
1045*287e80b3SSadaf Ebrahimi 	char *buf;
1046*287e80b3SSadaf Ebrahimi 	int ret;
1047*287e80b3SSadaf Ebrahimi 
1048*287e80b3SSadaf Ebrahimi 	path = trace_append_file(tracing_dir, "printk_formats");
1049*287e80b3SSadaf Ebrahimi 	if (!path)
1050*287e80b3SSadaf Ebrahimi 		return;
1051*287e80b3SSadaf Ebrahimi 
1052*287e80b3SSadaf Ebrahimi 	ret = str_read_file(path, &buf, false);
1053*287e80b3SSadaf Ebrahimi 	free(path);
1054*287e80b3SSadaf Ebrahimi 	if (ret <= 0)
1055*287e80b3SSadaf Ebrahimi 		return;
1056*287e80b3SSadaf Ebrahimi 
1057*287e80b3SSadaf Ebrahimi 	tep_parse_printk_formats(tep, buf);
1058*287e80b3SSadaf Ebrahimi 	free(buf);
1059*287e80b3SSadaf Ebrahimi }
1060*287e80b3SSadaf Ebrahimi 
1061*287e80b3SSadaf Ebrahimi /*
1062*287e80b3SSadaf Ebrahimi  * Do a best effort attempt to load kallsyms, saved_cmdlines and
1063*287e80b3SSadaf Ebrahimi  * printk_formats. If they can not be loaded, then this will not
1064*287e80b3SSadaf Ebrahimi  * do the mappings. But this does not fail the loading of events.
1065*287e80b3SSadaf Ebrahimi  */
load_mappings(const char * tracing_dir,struct tep_handle * tep)1066*287e80b3SSadaf Ebrahimi static void load_mappings(const char *tracing_dir,
1067*287e80b3SSadaf Ebrahimi 			  struct tep_handle *tep)
1068*287e80b3SSadaf Ebrahimi {
1069*287e80b3SSadaf Ebrahimi 	load_kallsyms(tep);
1070*287e80b3SSadaf Ebrahimi 
1071*287e80b3SSadaf Ebrahimi 	/* If there's no tracing_dir no reason to go further */
1072*287e80b3SSadaf Ebrahimi 	if (!tracing_dir)
1073*287e80b3SSadaf Ebrahimi 		tracing_dir = tracefs_tracing_dir();
1074*287e80b3SSadaf Ebrahimi 
1075*287e80b3SSadaf Ebrahimi 	if (!tracing_dir)
1076*287e80b3SSadaf Ebrahimi 		return;
1077*287e80b3SSadaf Ebrahimi 
1078*287e80b3SSadaf Ebrahimi 	load_saved_cmdlines(tracing_dir, tep, false);
1079*287e80b3SSadaf Ebrahimi 	load_printk_formats(tracing_dir, tep);
1080*287e80b3SSadaf Ebrahimi }
1081*287e80b3SSadaf Ebrahimi 
tracefs_load_cmdlines(const char * tracing_dir,struct tep_handle * tep)1082*287e80b3SSadaf Ebrahimi int tracefs_load_cmdlines(const char *tracing_dir, struct tep_handle *tep)
1083*287e80b3SSadaf Ebrahimi {
1084*287e80b3SSadaf Ebrahimi 
1085*287e80b3SSadaf Ebrahimi 	if (!tracing_dir)
1086*287e80b3SSadaf Ebrahimi 		tracing_dir = tracefs_tracing_dir();
1087*287e80b3SSadaf Ebrahimi 
1088*287e80b3SSadaf Ebrahimi 	if (!tracing_dir)
1089*287e80b3SSadaf Ebrahimi 		return -1;
1090*287e80b3SSadaf Ebrahimi 
1091*287e80b3SSadaf Ebrahimi 	return load_saved_cmdlines(tracing_dir, tep, true);
1092*287e80b3SSadaf Ebrahimi }
1093*287e80b3SSadaf Ebrahimi 
fill_local_events_system(const char * tracing_dir,struct tep_handle * tep,const char * const * sys_names,int * parsing_failures)1094*287e80b3SSadaf Ebrahimi static int fill_local_events_system(const char *tracing_dir,
1095*287e80b3SSadaf Ebrahimi 				    struct tep_handle *tep,
1096*287e80b3SSadaf Ebrahimi 				    const char * const *sys_names,
1097*287e80b3SSadaf Ebrahimi 				    int *parsing_failures)
1098*287e80b3SSadaf Ebrahimi {
1099*287e80b3SSadaf Ebrahimi 	char **systems = NULL;
1100*287e80b3SSadaf Ebrahimi 	int ret;
1101*287e80b3SSadaf Ebrahimi 	int i;
1102*287e80b3SSadaf Ebrahimi 
1103*287e80b3SSadaf Ebrahimi 	if (!tracing_dir)
1104*287e80b3SSadaf Ebrahimi 		tracing_dir = tracefs_tracing_dir();
1105*287e80b3SSadaf Ebrahimi 	if (!tracing_dir)
1106*287e80b3SSadaf Ebrahimi 		return -1;
1107*287e80b3SSadaf Ebrahimi 
1108*287e80b3SSadaf Ebrahimi 	systems = tracefs_event_systems(tracing_dir);
1109*287e80b3SSadaf Ebrahimi 	if (!systems)
1110*287e80b3SSadaf Ebrahimi 		return -1;
1111*287e80b3SSadaf Ebrahimi 
1112*287e80b3SSadaf Ebrahimi 	ret = read_header(tep, tracing_dir);
1113*287e80b3SSadaf Ebrahimi 	if (ret < 0) {
1114*287e80b3SSadaf Ebrahimi 		ret = -1;
1115*287e80b3SSadaf Ebrahimi 		goto out;
1116*287e80b3SSadaf Ebrahimi 	}
1117*287e80b3SSadaf Ebrahimi 
1118*287e80b3SSadaf Ebrahimi 	if (parsing_failures)
1119*287e80b3SSadaf Ebrahimi 		*parsing_failures = 0;
1120*287e80b3SSadaf Ebrahimi 
1121*287e80b3SSadaf Ebrahimi 	for (i = 0; systems[i]; i++) {
1122*287e80b3SSadaf Ebrahimi 		if (sys_names && !contains(systems[i], sys_names))
1123*287e80b3SSadaf Ebrahimi 			continue;
1124*287e80b3SSadaf Ebrahimi 		ret = trace_load_events(tep, tracing_dir, systems[i]);
1125*287e80b3SSadaf Ebrahimi 		if (ret && parsing_failures)
1126*287e80b3SSadaf Ebrahimi 			(*parsing_failures)++;
1127*287e80b3SSadaf Ebrahimi 	}
1128*287e80b3SSadaf Ebrahimi 
1129*287e80b3SSadaf Ebrahimi 	/* Include ftrace, as it is excluded for not having "enable" file */
1130*287e80b3SSadaf Ebrahimi 	if (!sys_names || contains("ftrace", sys_names))
1131*287e80b3SSadaf Ebrahimi 		trace_load_events(tep, tracing_dir, "ftrace");
1132*287e80b3SSadaf Ebrahimi 
1133*287e80b3SSadaf Ebrahimi 	load_mappings(tracing_dir, tep);
1134*287e80b3SSadaf Ebrahimi 
1135*287e80b3SSadaf Ebrahimi 	/* always succeed because parsing failures are not critical */
1136*287e80b3SSadaf Ebrahimi 	ret = 0;
1137*287e80b3SSadaf Ebrahimi out:
1138*287e80b3SSadaf Ebrahimi 	tracefs_list_free(systems);
1139*287e80b3SSadaf Ebrahimi 	return ret;
1140*287e80b3SSadaf Ebrahimi }
1141*287e80b3SSadaf Ebrahimi 
set_tep_cpus(const char * tracing_dir,struct tep_handle * tep)1142*287e80b3SSadaf Ebrahimi static void set_tep_cpus(const char *tracing_dir, struct tep_handle *tep)
1143*287e80b3SSadaf Ebrahimi {
1144*287e80b3SSadaf Ebrahimi 	struct stat st;
1145*287e80b3SSadaf Ebrahimi 	char path[PATH_MAX];
1146*287e80b3SSadaf Ebrahimi 	int cpus = sysconf(_SC_NPROCESSORS_CONF);
1147*287e80b3SSadaf Ebrahimi 	int max_cpu = 0;
1148*287e80b3SSadaf Ebrahimi 	int ret;
1149*287e80b3SSadaf Ebrahimi 	int i;
1150*287e80b3SSadaf Ebrahimi 
1151*287e80b3SSadaf Ebrahimi 	if (!tracing_dir)
1152*287e80b3SSadaf Ebrahimi 		tracing_dir = tracefs_tracing_dir();
1153*287e80b3SSadaf Ebrahimi 
1154*287e80b3SSadaf Ebrahimi 	/*
1155*287e80b3SSadaf Ebrahimi 	 * Paranoid: in case sysconf() above does not work.
1156*287e80b3SSadaf Ebrahimi 	 * And we also only care about the number of tracing
1157*287e80b3SSadaf Ebrahimi 	 * buffers that exist. If cpus is 32, but the top half
1158*287e80b3SSadaf Ebrahimi 	 * is offline, there may only be 16 tracing buffers.
1159*287e80b3SSadaf Ebrahimi 	 * That's what we want to know.
1160*287e80b3SSadaf Ebrahimi 	 */
1161*287e80b3SSadaf Ebrahimi 	for (i = 0; !cpus || i < cpus; i++) {
1162*287e80b3SSadaf Ebrahimi 		snprintf(path, PATH_MAX, "%s/per_cpu/cpu%d", tracing_dir, i);
1163*287e80b3SSadaf Ebrahimi 		ret = stat(path, &st);
1164*287e80b3SSadaf Ebrahimi 		if (!ret && S_ISDIR(st.st_mode))
1165*287e80b3SSadaf Ebrahimi 			max_cpu = i + 1;
1166*287e80b3SSadaf Ebrahimi 		else if (i >= cpus)
1167*287e80b3SSadaf Ebrahimi 			break;
1168*287e80b3SSadaf Ebrahimi 	}
1169*287e80b3SSadaf Ebrahimi 
1170*287e80b3SSadaf Ebrahimi 	if (!max_cpu)
1171*287e80b3SSadaf Ebrahimi 		max_cpu = cpus;
1172*287e80b3SSadaf Ebrahimi 
1173*287e80b3SSadaf Ebrahimi 	tep_set_cpus(tep, max_cpu);
1174*287e80b3SSadaf Ebrahimi }
1175*287e80b3SSadaf Ebrahimi 
1176*287e80b3SSadaf Ebrahimi /**
1177*287e80b3SSadaf Ebrahimi  * tracefs_local_events_system - create a tep from the events of the specified subsystem.
1178*287e80b3SSadaf Ebrahimi  *
1179*287e80b3SSadaf Ebrahimi  * @tracing_dir: The directory that contains the events.
1180*287e80b3SSadaf Ebrahimi  * @sys_name: Array of system names, to load the events from.
1181*287e80b3SSadaf Ebrahimi  * The last element from the array must be NULL
1182*287e80b3SSadaf Ebrahimi  *
1183*287e80b3SSadaf Ebrahimi  * Returns a tep structure that contains the tep local to
1184*287e80b3SSadaf Ebrahimi  * the system.
1185*287e80b3SSadaf Ebrahimi  */
tracefs_local_events_system(const char * tracing_dir,const char * const * sys_names)1186*287e80b3SSadaf Ebrahimi struct tep_handle *tracefs_local_events_system(const char *tracing_dir,
1187*287e80b3SSadaf Ebrahimi 					       const char * const *sys_names)
1188*287e80b3SSadaf Ebrahimi {
1189*287e80b3SSadaf Ebrahimi 	struct tep_handle *tep = NULL;
1190*287e80b3SSadaf Ebrahimi 
1191*287e80b3SSadaf Ebrahimi 	tep = tep_alloc();
1192*287e80b3SSadaf Ebrahimi 	if (!tep)
1193*287e80b3SSadaf Ebrahimi 		return NULL;
1194*287e80b3SSadaf Ebrahimi 
1195*287e80b3SSadaf Ebrahimi 	if (fill_local_events_system(tracing_dir, tep, sys_names, NULL)) {
1196*287e80b3SSadaf Ebrahimi 		tep_free(tep);
1197*287e80b3SSadaf Ebrahimi 		tep = NULL;
1198*287e80b3SSadaf Ebrahimi 	}
1199*287e80b3SSadaf Ebrahimi 
1200*287e80b3SSadaf Ebrahimi 	set_tep_cpus(tracing_dir, tep);
1201*287e80b3SSadaf Ebrahimi 
1202*287e80b3SSadaf Ebrahimi 	/* Set the long size for this tep handle */
1203*287e80b3SSadaf Ebrahimi 	tep_set_long_size(tep, tep_get_header_page_size(tep));
1204*287e80b3SSadaf Ebrahimi 
1205*287e80b3SSadaf Ebrahimi 	return tep;
1206*287e80b3SSadaf Ebrahimi }
1207*287e80b3SSadaf Ebrahimi 
1208*287e80b3SSadaf Ebrahimi /**
1209*287e80b3SSadaf Ebrahimi  * tracefs_local_events - create a tep from the events on system
1210*287e80b3SSadaf Ebrahimi  * @tracing_dir: The directory that contains the events.
1211*287e80b3SSadaf Ebrahimi  *
1212*287e80b3SSadaf Ebrahimi  * Returns a tep structure that contains the teps local to
1213*287e80b3SSadaf Ebrahimi  * the system.
1214*287e80b3SSadaf Ebrahimi  */
tracefs_local_events(const char * tracing_dir)1215*287e80b3SSadaf Ebrahimi struct tep_handle *tracefs_local_events(const char *tracing_dir)
1216*287e80b3SSadaf Ebrahimi {
1217*287e80b3SSadaf Ebrahimi 	return tracefs_local_events_system(tracing_dir, NULL);
1218*287e80b3SSadaf Ebrahimi }
1219*287e80b3SSadaf Ebrahimi 
1220*287e80b3SSadaf Ebrahimi /**
1221*287e80b3SSadaf Ebrahimi  * tracefs_fill_local_events - Fill a tep with the events on system
1222*287e80b3SSadaf Ebrahimi  * @tracing_dir: The directory that contains the events.
1223*287e80b3SSadaf Ebrahimi  * @tep: Allocated tep handler which will be filled
1224*287e80b3SSadaf Ebrahimi  * @parsing_failures: return number of failures while parsing the event files
1225*287e80b3SSadaf Ebrahimi  *
1226*287e80b3SSadaf Ebrahimi  * Returns whether the operation succeeded
1227*287e80b3SSadaf Ebrahimi  */
tracefs_fill_local_events(const char * tracing_dir,struct tep_handle * tep,int * parsing_failures)1228*287e80b3SSadaf Ebrahimi int tracefs_fill_local_events(const char *tracing_dir,
1229*287e80b3SSadaf Ebrahimi 			       struct tep_handle *tep, int *parsing_failures)
1230*287e80b3SSadaf Ebrahimi {
1231*287e80b3SSadaf Ebrahimi 	return fill_local_events_system(tracing_dir, tep,
1232*287e80b3SSadaf Ebrahimi 					NULL, parsing_failures);
1233*287e80b3SSadaf Ebrahimi }
1234*287e80b3SSadaf Ebrahimi 
match(const char * str,regex_t * re)1235*287e80b3SSadaf Ebrahimi static bool match(const char *str, regex_t *re)
1236*287e80b3SSadaf Ebrahimi {
1237*287e80b3SSadaf Ebrahimi 	return regexec(re, str, 0, NULL, 0) == 0;
1238*287e80b3SSadaf Ebrahimi }
1239*287e80b3SSadaf Ebrahimi 
1240*287e80b3SSadaf Ebrahimi enum event_state {
1241*287e80b3SSadaf Ebrahimi 	STATE_INIT,
1242*287e80b3SSadaf Ebrahimi 	STATE_ENABLED,
1243*287e80b3SSadaf Ebrahimi 	STATE_DISABLED,
1244*287e80b3SSadaf Ebrahimi 	STATE_MIXED,
1245*287e80b3SSadaf Ebrahimi 	STATE_ERROR,
1246*287e80b3SSadaf Ebrahimi };
1247*287e80b3SSadaf Ebrahimi 
read_event_state(struct tracefs_instance * instance,const char * file,enum event_state * state)1248*287e80b3SSadaf Ebrahimi static int read_event_state(struct tracefs_instance *instance, const char *file,
1249*287e80b3SSadaf Ebrahimi 			    enum event_state *state)
1250*287e80b3SSadaf Ebrahimi {
1251*287e80b3SSadaf Ebrahimi 	char *val;
1252*287e80b3SSadaf Ebrahimi 	int ret = 0;
1253*287e80b3SSadaf Ebrahimi 
1254*287e80b3SSadaf Ebrahimi 	if (*state == STATE_ERROR)
1255*287e80b3SSadaf Ebrahimi 		return -1;
1256*287e80b3SSadaf Ebrahimi 
1257*287e80b3SSadaf Ebrahimi 	val = tracefs_instance_file_read(instance, file, NULL);
1258*287e80b3SSadaf Ebrahimi 	if (!val)
1259*287e80b3SSadaf Ebrahimi 		return -1;
1260*287e80b3SSadaf Ebrahimi 
1261*287e80b3SSadaf Ebrahimi 	switch (val[0]) {
1262*287e80b3SSadaf Ebrahimi 	case '0':
1263*287e80b3SSadaf Ebrahimi 		switch (*state) {
1264*287e80b3SSadaf Ebrahimi 		case STATE_INIT:
1265*287e80b3SSadaf Ebrahimi 			*state = STATE_DISABLED;
1266*287e80b3SSadaf Ebrahimi 			break;
1267*287e80b3SSadaf Ebrahimi 		case STATE_ENABLED:
1268*287e80b3SSadaf Ebrahimi 			*state = STATE_MIXED;
1269*287e80b3SSadaf Ebrahimi 			break;
1270*287e80b3SSadaf Ebrahimi 		default:
1271*287e80b3SSadaf Ebrahimi 			break;
1272*287e80b3SSadaf Ebrahimi 		}
1273*287e80b3SSadaf Ebrahimi 		break;
1274*287e80b3SSadaf Ebrahimi 	case '1':
1275*287e80b3SSadaf Ebrahimi 		switch (*state) {
1276*287e80b3SSadaf Ebrahimi 		case STATE_INIT:
1277*287e80b3SSadaf Ebrahimi 			*state = STATE_ENABLED;
1278*287e80b3SSadaf Ebrahimi 			break;
1279*287e80b3SSadaf Ebrahimi 		case STATE_DISABLED:
1280*287e80b3SSadaf Ebrahimi 			*state = STATE_MIXED;
1281*287e80b3SSadaf Ebrahimi 			break;
1282*287e80b3SSadaf Ebrahimi 		default:
1283*287e80b3SSadaf Ebrahimi 			break;
1284*287e80b3SSadaf Ebrahimi 		}
1285*287e80b3SSadaf Ebrahimi 		break;
1286*287e80b3SSadaf Ebrahimi 	case 'X':
1287*287e80b3SSadaf Ebrahimi 		*state = STATE_MIXED;
1288*287e80b3SSadaf Ebrahimi 		break;
1289*287e80b3SSadaf Ebrahimi 	default:
1290*287e80b3SSadaf Ebrahimi 		*state = TRACEFS_ERROR;
1291*287e80b3SSadaf Ebrahimi 		ret = -1;
1292*287e80b3SSadaf Ebrahimi 		break;
1293*287e80b3SSadaf Ebrahimi 	}
1294*287e80b3SSadaf Ebrahimi 	free(val);
1295*287e80b3SSadaf Ebrahimi 
1296*287e80b3SSadaf Ebrahimi 	return ret;
1297*287e80b3SSadaf Ebrahimi }
1298*287e80b3SSadaf Ebrahimi 
enable_disable_event(struct tracefs_instance * instance,const char * system,const char * event,bool enable,enum event_state * state)1299*287e80b3SSadaf Ebrahimi static int enable_disable_event(struct tracefs_instance *instance,
1300*287e80b3SSadaf Ebrahimi 				const char *system, const char *event,
1301*287e80b3SSadaf Ebrahimi 				bool enable, enum event_state *state)
1302*287e80b3SSadaf Ebrahimi {
1303*287e80b3SSadaf Ebrahimi 	const char *str = enable ? "1" : "0";
1304*287e80b3SSadaf Ebrahimi 	char *system_event;
1305*287e80b3SSadaf Ebrahimi 	int ret;
1306*287e80b3SSadaf Ebrahimi 
1307*287e80b3SSadaf Ebrahimi 	ret = asprintf(&system_event, "events/%s/%s/enable", system, event);
1308*287e80b3SSadaf Ebrahimi 	if (ret < 0)
1309*287e80b3SSadaf Ebrahimi 		return ret;
1310*287e80b3SSadaf Ebrahimi 
1311*287e80b3SSadaf Ebrahimi 	if (state)
1312*287e80b3SSadaf Ebrahimi 		ret = read_event_state(instance, system_event, state);
1313*287e80b3SSadaf Ebrahimi 	else
1314*287e80b3SSadaf Ebrahimi 		ret = tracefs_instance_file_write(instance, system_event, str);
1315*287e80b3SSadaf Ebrahimi 	free(system_event);
1316*287e80b3SSadaf Ebrahimi 
1317*287e80b3SSadaf Ebrahimi 	return ret;
1318*287e80b3SSadaf Ebrahimi }
1319*287e80b3SSadaf Ebrahimi 
enable_disable_system(struct tracefs_instance * instance,const char * system,bool enable,enum event_state * state)1320*287e80b3SSadaf Ebrahimi static int enable_disable_system(struct tracefs_instance *instance,
1321*287e80b3SSadaf Ebrahimi 				 const char *system, bool enable,
1322*287e80b3SSadaf Ebrahimi 				 enum event_state *state)
1323*287e80b3SSadaf Ebrahimi {
1324*287e80b3SSadaf Ebrahimi 	const char *str = enable ? "1" : "0";
1325*287e80b3SSadaf Ebrahimi 	char *system_path;
1326*287e80b3SSadaf Ebrahimi 	int ret;
1327*287e80b3SSadaf Ebrahimi 
1328*287e80b3SSadaf Ebrahimi 	ret = asprintf(&system_path, "events/%s/enable", system);
1329*287e80b3SSadaf Ebrahimi 	if (ret < 0)
1330*287e80b3SSadaf Ebrahimi 		return ret;
1331*287e80b3SSadaf Ebrahimi 
1332*287e80b3SSadaf Ebrahimi 	if (state)
1333*287e80b3SSadaf Ebrahimi 		ret = read_event_state(instance, system_path, state);
1334*287e80b3SSadaf Ebrahimi 	else
1335*287e80b3SSadaf Ebrahimi 		ret = tracefs_instance_file_write(instance, system_path, str);
1336*287e80b3SSadaf Ebrahimi 	free(system_path);
1337*287e80b3SSadaf Ebrahimi 
1338*287e80b3SSadaf Ebrahimi 	return ret;
1339*287e80b3SSadaf Ebrahimi }
1340*287e80b3SSadaf Ebrahimi 
enable_disable_all(struct tracefs_instance * instance,bool enable)1341*287e80b3SSadaf Ebrahimi static int enable_disable_all(struct tracefs_instance *instance,
1342*287e80b3SSadaf Ebrahimi 			      bool enable)
1343*287e80b3SSadaf Ebrahimi {
1344*287e80b3SSadaf Ebrahimi 	const char *str = enable ? "1" : "0";
1345*287e80b3SSadaf Ebrahimi 	int ret;
1346*287e80b3SSadaf Ebrahimi 
1347*287e80b3SSadaf Ebrahimi 	ret = tracefs_instance_file_write(instance, "events/enable", str);
1348*287e80b3SSadaf Ebrahimi 	return ret < 0 ? ret : 0;
1349*287e80b3SSadaf Ebrahimi }
1350*287e80b3SSadaf Ebrahimi 
make_regex(regex_t * re,const char * match)1351*287e80b3SSadaf Ebrahimi static int make_regex(regex_t *re, const char *match)
1352*287e80b3SSadaf Ebrahimi {
1353*287e80b3SSadaf Ebrahimi 	int len = strlen(match);
1354*287e80b3SSadaf Ebrahimi 	char str[len + 3];
1355*287e80b3SSadaf Ebrahimi 	char *p = &str[0];
1356*287e80b3SSadaf Ebrahimi 
1357*287e80b3SSadaf Ebrahimi 	if (!len || match[0] != '^')
1358*287e80b3SSadaf Ebrahimi 		*(p++) = '^';
1359*287e80b3SSadaf Ebrahimi 
1360*287e80b3SSadaf Ebrahimi 	strcpy(p, match);
1361*287e80b3SSadaf Ebrahimi 	p += len;
1362*287e80b3SSadaf Ebrahimi 
1363*287e80b3SSadaf Ebrahimi 	if (!len || match[len-1] != '$')
1364*287e80b3SSadaf Ebrahimi 		*(p++) = '$';
1365*287e80b3SSadaf Ebrahimi 
1366*287e80b3SSadaf Ebrahimi 	*p = '\0';
1367*287e80b3SSadaf Ebrahimi 
1368*287e80b3SSadaf Ebrahimi 	return regcomp(re, str, REG_ICASE|REG_NOSUB);
1369*287e80b3SSadaf Ebrahimi }
1370*287e80b3SSadaf Ebrahimi 
event_enable_disable(struct tracefs_instance * instance,const char * system,const char * event,bool enable,enum event_state * state)1371*287e80b3SSadaf Ebrahimi static int event_enable_disable(struct tracefs_instance *instance,
1372*287e80b3SSadaf Ebrahimi 				const char *system, const char *event,
1373*287e80b3SSadaf Ebrahimi 				bool enable, enum event_state *state)
1374*287e80b3SSadaf Ebrahimi {
1375*287e80b3SSadaf Ebrahimi 	regex_t system_re, event_re;
1376*287e80b3SSadaf Ebrahimi 	char **systems;
1377*287e80b3SSadaf Ebrahimi 	char **events = NULL;
1378*287e80b3SSadaf Ebrahimi 	int ret = -1;
1379*287e80b3SSadaf Ebrahimi 	int s, e;
1380*287e80b3SSadaf Ebrahimi 
1381*287e80b3SSadaf Ebrahimi 	/* Handle all events first */
1382*287e80b3SSadaf Ebrahimi 	if (!system && !event)
1383*287e80b3SSadaf Ebrahimi 		return enable_disable_all(instance, enable);
1384*287e80b3SSadaf Ebrahimi 
1385*287e80b3SSadaf Ebrahimi 	systems = tracefs_event_systems(NULL);
1386*287e80b3SSadaf Ebrahimi 	if (!systems)
1387*287e80b3SSadaf Ebrahimi 		goto out_free;
1388*287e80b3SSadaf Ebrahimi 
1389*287e80b3SSadaf Ebrahimi 	if (system) {
1390*287e80b3SSadaf Ebrahimi 		ret = make_regex(&system_re, system);
1391*287e80b3SSadaf Ebrahimi 		if (ret < 0)
1392*287e80b3SSadaf Ebrahimi 			goto out_free;
1393*287e80b3SSadaf Ebrahimi 	}
1394*287e80b3SSadaf Ebrahimi 	if (event) {
1395*287e80b3SSadaf Ebrahimi 		ret = make_regex(&event_re, event);
1396*287e80b3SSadaf Ebrahimi 		if (ret < 0) {
1397*287e80b3SSadaf Ebrahimi 			if (system)
1398*287e80b3SSadaf Ebrahimi 				regfree(&system_re);
1399*287e80b3SSadaf Ebrahimi 			goto out_free;
1400*287e80b3SSadaf Ebrahimi 		}
1401*287e80b3SSadaf Ebrahimi 	}
1402*287e80b3SSadaf Ebrahimi 
1403*287e80b3SSadaf Ebrahimi 	ret = -1;
1404*287e80b3SSadaf Ebrahimi 	for (s = 0; systems[s]; s++) {
1405*287e80b3SSadaf Ebrahimi 		if (system && !match(systems[s], &system_re))
1406*287e80b3SSadaf Ebrahimi 			continue;
1407*287e80b3SSadaf Ebrahimi 
1408*287e80b3SSadaf Ebrahimi 		/* Check for the short cut first */
1409*287e80b3SSadaf Ebrahimi 		if (!event) {
1410*287e80b3SSadaf Ebrahimi 			ret = enable_disable_system(instance, systems[s], enable, state);
1411*287e80b3SSadaf Ebrahimi 			if (ret < 0)
1412*287e80b3SSadaf Ebrahimi 				break;
1413*287e80b3SSadaf Ebrahimi 			ret = 0;
1414*287e80b3SSadaf Ebrahimi 			continue;
1415*287e80b3SSadaf Ebrahimi 		}
1416*287e80b3SSadaf Ebrahimi 
1417*287e80b3SSadaf Ebrahimi 		events = tracefs_system_events(NULL, systems[s]);
1418*287e80b3SSadaf Ebrahimi 		if (!events)
1419*287e80b3SSadaf Ebrahimi 			continue; /* Error? */
1420*287e80b3SSadaf Ebrahimi 
1421*287e80b3SSadaf Ebrahimi 		for (e = 0; events[e]; e++) {
1422*287e80b3SSadaf Ebrahimi 			if (!match(events[e], &event_re))
1423*287e80b3SSadaf Ebrahimi 				continue;
1424*287e80b3SSadaf Ebrahimi 			ret = enable_disable_event(instance, systems[s],
1425*287e80b3SSadaf Ebrahimi 						   events[e], enable, state);
1426*287e80b3SSadaf Ebrahimi 			if (ret < 0)
1427*287e80b3SSadaf Ebrahimi 				break;
1428*287e80b3SSadaf Ebrahimi 			ret = 0;
1429*287e80b3SSadaf Ebrahimi 		}
1430*287e80b3SSadaf Ebrahimi 		tracefs_list_free(events);
1431*287e80b3SSadaf Ebrahimi 		events = NULL;
1432*287e80b3SSadaf Ebrahimi 	}
1433*287e80b3SSadaf Ebrahimi 	if (system)
1434*287e80b3SSadaf Ebrahimi 		regfree(&system_re);
1435*287e80b3SSadaf Ebrahimi 	if (event)
1436*287e80b3SSadaf Ebrahimi 		regfree(&event_re);
1437*287e80b3SSadaf Ebrahimi 
1438*287e80b3SSadaf Ebrahimi  out_free:
1439*287e80b3SSadaf Ebrahimi 	tracefs_list_free(systems);
1440*287e80b3SSadaf Ebrahimi 	tracefs_list_free(events);
1441*287e80b3SSadaf Ebrahimi 	return ret;
1442*287e80b3SSadaf Ebrahimi }
1443*287e80b3SSadaf Ebrahimi 
1444*287e80b3SSadaf Ebrahimi /**
1445*287e80b3SSadaf Ebrahimi  * tracefs_event_enable - enable specified events
1446*287e80b3SSadaf Ebrahimi  * @instance: ftrace instance, can be NULL for the top instance
1447*287e80b3SSadaf Ebrahimi  * @system: A regex of a system (NULL to match all systems)
1448*287e80b3SSadaf Ebrahimi  * @event: A regex of the event in the system (NULL to match all events)
1449*287e80b3SSadaf Ebrahimi  *
1450*287e80b3SSadaf Ebrahimi  * This will enable events that match the @system and @event.
1451*287e80b3SSadaf Ebrahimi  * If both @system and @event are NULL, then it will enable all events.
1452*287e80b3SSadaf Ebrahimi  * If @system is NULL, it will look at all systems for matching events
1453*287e80b3SSadaf Ebrahimi  * to @event.
1454*287e80b3SSadaf Ebrahimi  * If @event is NULL, then it will enable all events in the systems
1455*287e80b3SSadaf Ebrahimi  * that match @system.
1456*287e80b3SSadaf Ebrahimi  *
1457*287e80b3SSadaf Ebrahimi  * Returns 0 on success, and -1 if it encountered an error,
1458*287e80b3SSadaf Ebrahimi  * or if no events matched. If no events matched, then -1 is set
1459*287e80b3SSadaf Ebrahimi  * but errno will not be.
1460*287e80b3SSadaf Ebrahimi  */
tracefs_event_enable(struct tracefs_instance * instance,const char * system,const char * event)1461*287e80b3SSadaf Ebrahimi int tracefs_event_enable(struct tracefs_instance *instance,
1462*287e80b3SSadaf Ebrahimi 			 const char *system, const char *event)
1463*287e80b3SSadaf Ebrahimi {
1464*287e80b3SSadaf Ebrahimi 	return event_enable_disable(instance, system, event, true, NULL);
1465*287e80b3SSadaf Ebrahimi }
1466*287e80b3SSadaf Ebrahimi 
tracefs_event_disable(struct tracefs_instance * instance,const char * system,const char * event)1467*287e80b3SSadaf Ebrahimi int tracefs_event_disable(struct tracefs_instance *instance,
1468*287e80b3SSadaf Ebrahimi 			  const char *system, const char *event)
1469*287e80b3SSadaf Ebrahimi {
1470*287e80b3SSadaf Ebrahimi 	return event_enable_disable(instance, system, event, false, NULL);
1471*287e80b3SSadaf Ebrahimi }
1472*287e80b3SSadaf Ebrahimi 
1473*287e80b3SSadaf Ebrahimi /**
1474*287e80b3SSadaf Ebrahimi  * tracefs_event_is_enabled - return if the event is enabled or not
1475*287e80b3SSadaf Ebrahimi  * @instance: ftrace instance, can be NULL for the top instance
1476*287e80b3SSadaf Ebrahimi  * @system: The name of the system to check
1477*287e80b3SSadaf Ebrahimi  * @event: The name of the event to check
1478*287e80b3SSadaf Ebrahimi  *
1479*287e80b3SSadaf Ebrahimi  * Checks is an event or multiple events are enabled.
1480*287e80b3SSadaf Ebrahimi  *
1481*287e80b3SSadaf Ebrahimi  * If @system is NULL, then it will check all the systems where @event is
1482*287e80b3SSadaf Ebrahimi  * a match.
1483*287e80b3SSadaf Ebrahimi  *
1484*287e80b3SSadaf Ebrahimi  * If @event is NULL, then it will check all events where @system is a match.
1485*287e80b3SSadaf Ebrahimi  *
1486*287e80b3SSadaf Ebrahimi  * If both @system and @event are NULL, then it will check all events
1487*287e80b3SSadaf Ebrahimi  *
1488*287e80b3SSadaf Ebrahimi  * Returns TRACEFS_ALL_ENABLED if all matching are enabled.
1489*287e80b3SSadaf Ebrahimi  * Returns TRACEFS_SOME_ENABLED if some are enabled and some are not
1490*287e80b3SSadaf Ebrahimi  * Returns TRACEFS_ALL_DISABLED if none of the events are enabled.
1491*287e80b3SSadaf Ebrahimi  * Returns TRACEFS_ERROR if there is an error reading the events.
1492*287e80b3SSadaf Ebrahimi  */
1493*287e80b3SSadaf Ebrahimi enum tracefs_enable_state
tracefs_event_is_enabled(struct tracefs_instance * instance,const char * system,const char * event)1494*287e80b3SSadaf Ebrahimi tracefs_event_is_enabled(struct tracefs_instance *instance,
1495*287e80b3SSadaf Ebrahimi 			 const char *system, const char *event)
1496*287e80b3SSadaf Ebrahimi {
1497*287e80b3SSadaf Ebrahimi 	enum event_state state = STATE_INIT;
1498*287e80b3SSadaf Ebrahimi 	int ret;
1499*287e80b3SSadaf Ebrahimi 
1500*287e80b3SSadaf Ebrahimi 	ret = event_enable_disable(instance, system, event, false, &state);
1501*287e80b3SSadaf Ebrahimi 
1502*287e80b3SSadaf Ebrahimi 	if (ret < 0)
1503*287e80b3SSadaf Ebrahimi 		return TRACEFS_ERROR;
1504*287e80b3SSadaf Ebrahimi 
1505*287e80b3SSadaf Ebrahimi 	switch (state) {
1506*287e80b3SSadaf Ebrahimi 	case STATE_ENABLED:
1507*287e80b3SSadaf Ebrahimi 		return TRACEFS_ALL_ENABLED;
1508*287e80b3SSadaf Ebrahimi 	case STATE_DISABLED:
1509*287e80b3SSadaf Ebrahimi 		return TRACEFS_ALL_DISABLED;
1510*287e80b3SSadaf Ebrahimi 	case STATE_MIXED:
1511*287e80b3SSadaf Ebrahimi 		return TRACEFS_SOME_ENABLED;
1512*287e80b3SSadaf Ebrahimi 	default:
1513*287e80b3SSadaf Ebrahimi 		return TRACEFS_ERROR;
1514*287e80b3SSadaf Ebrahimi 	}
1515*287e80b3SSadaf Ebrahimi }
1516