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