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