130da46b5SQuentin Monnet // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 230da46b5SQuentin Monnet /* Copyright (c) 2015-2017 Daniel Borkmann */ 330da46b5SQuentin Monnet /* Copyright (c) 2018 Netronome Systems, Inc. */ 430da46b5SQuentin Monnet 530da46b5SQuentin Monnet #include <errno.h> 630da46b5SQuentin Monnet #include <limits.h> 730da46b5SQuentin Monnet #include <signal.h> 830da46b5SQuentin Monnet #include <stdio.h> 930da46b5SQuentin Monnet #include <string.h> 1030da46b5SQuentin Monnet #include <unistd.h> 1130da46b5SQuentin Monnet #include <linux/magic.h> 1230da46b5SQuentin Monnet #include <sys/fcntl.h> 1330da46b5SQuentin Monnet #include <sys/vfs.h> 1430da46b5SQuentin Monnet 1530da46b5SQuentin Monnet #include "main.h" 1630da46b5SQuentin Monnet 1730da46b5SQuentin Monnet #ifndef TRACEFS_MAGIC 1830da46b5SQuentin Monnet # define TRACEFS_MAGIC 0x74726163 1930da46b5SQuentin Monnet #endif 2030da46b5SQuentin Monnet 2130da46b5SQuentin Monnet #define _textify(x) #x 2230da46b5SQuentin Monnet #define textify(x) _textify(x) 2330da46b5SQuentin Monnet 2430da46b5SQuentin Monnet FILE *trace_pipe_fd; 2530da46b5SQuentin Monnet char *buff; 2630da46b5SQuentin Monnet 2730da46b5SQuentin Monnet static int validate_tracefs_mnt(const char *mnt, unsigned long magic) 2830da46b5SQuentin Monnet { 2930da46b5SQuentin Monnet struct statfs st_fs; 3030da46b5SQuentin Monnet 3130da46b5SQuentin Monnet if (statfs(mnt, &st_fs) < 0) 3230da46b5SQuentin Monnet return -ENOENT; 3330da46b5SQuentin Monnet if ((unsigned long)st_fs.f_type != magic) 3430da46b5SQuentin Monnet return -ENOENT; 3530da46b5SQuentin Monnet 3630da46b5SQuentin Monnet return 0; 3730da46b5SQuentin Monnet } 3830da46b5SQuentin Monnet 3930da46b5SQuentin Monnet static bool 4030da46b5SQuentin Monnet find_tracefs_mnt_single(unsigned long magic, char *mnt, const char *mntpt) 4130da46b5SQuentin Monnet { 4230da46b5SQuentin Monnet size_t src_len; 4330da46b5SQuentin Monnet 4430da46b5SQuentin Monnet if (validate_tracefs_mnt(mntpt, magic)) 4530da46b5SQuentin Monnet return false; 4630da46b5SQuentin Monnet 4730da46b5SQuentin Monnet src_len = strlen(mntpt); 4830da46b5SQuentin Monnet if (src_len + 1 >= PATH_MAX) { 4930da46b5SQuentin Monnet p_err("tracefs mount point name too long"); 5030da46b5SQuentin Monnet return false; 5130da46b5SQuentin Monnet } 5230da46b5SQuentin Monnet 5330da46b5SQuentin Monnet strcpy(mnt, mntpt); 5430da46b5SQuentin Monnet return true; 5530da46b5SQuentin Monnet } 5630da46b5SQuentin Monnet 5730da46b5SQuentin Monnet static bool find_tracefs_pipe(char *mnt) 5830da46b5SQuentin Monnet { 5930da46b5SQuentin Monnet static const char * const known_mnts[] = { 6030da46b5SQuentin Monnet "/sys/kernel/debug/tracing", 6130da46b5SQuentin Monnet "/sys/kernel/tracing", 6230da46b5SQuentin Monnet "/tracing", 6330da46b5SQuentin Monnet "/trace", 6430da46b5SQuentin Monnet }; 6530da46b5SQuentin Monnet const char *pipe_name = "/trace_pipe"; 6630da46b5SQuentin Monnet const char *fstype = "tracefs"; 6730da46b5SQuentin Monnet char type[100], format[32]; 6830da46b5SQuentin Monnet const char * const *ptr; 6930da46b5SQuentin Monnet bool found = false; 7030da46b5SQuentin Monnet FILE *fp; 7130da46b5SQuentin Monnet 7230da46b5SQuentin Monnet for (ptr = known_mnts; ptr < known_mnts + ARRAY_SIZE(known_mnts); ptr++) 7330da46b5SQuentin Monnet if (find_tracefs_mnt_single(TRACEFS_MAGIC, mnt, *ptr)) 7430da46b5SQuentin Monnet goto exit_found; 7530da46b5SQuentin Monnet 7630da46b5SQuentin Monnet fp = fopen("/proc/mounts", "r"); 7730da46b5SQuentin Monnet if (!fp) 7830da46b5SQuentin Monnet return false; 7930da46b5SQuentin Monnet 8030da46b5SQuentin Monnet /* Allow room for NULL terminating byte and pipe file name */ 8130da46b5SQuentin Monnet snprintf(format, sizeof(format), "%%*s %%%zds %%99s %%*s %%*d %%*d\\n", 8230da46b5SQuentin Monnet PATH_MAX - strlen(pipe_name) - 1); 8330da46b5SQuentin Monnet while (fscanf(fp, format, mnt, type) == 2) 8430da46b5SQuentin Monnet if (strcmp(type, fstype) == 0) { 8530da46b5SQuentin Monnet found = true; 8630da46b5SQuentin Monnet break; 8730da46b5SQuentin Monnet } 8830da46b5SQuentin Monnet fclose(fp); 8930da46b5SQuentin Monnet 9030da46b5SQuentin Monnet /* The string from fscanf() might be truncated, check mnt is valid */ 9130da46b5SQuentin Monnet if (!found || validate_tracefs_mnt(mnt, TRACEFS_MAGIC)) 9230da46b5SQuentin Monnet return false; 9330da46b5SQuentin Monnet 9430da46b5SQuentin Monnet exit_found: 9530da46b5SQuentin Monnet strcat(mnt, pipe_name); 9630da46b5SQuentin Monnet return true; 9730da46b5SQuentin Monnet } 9830da46b5SQuentin Monnet 9930da46b5SQuentin Monnet static void exit_tracelog(int signum) 10030da46b5SQuentin Monnet { 10130da46b5SQuentin Monnet fclose(trace_pipe_fd); 10230da46b5SQuentin Monnet free(buff); 10330da46b5SQuentin Monnet 10430da46b5SQuentin Monnet if (json_output) { 10530da46b5SQuentin Monnet jsonw_end_array(json_wtr); 10630da46b5SQuentin Monnet jsonw_destroy(&json_wtr); 10730da46b5SQuentin Monnet } 10830da46b5SQuentin Monnet 10930da46b5SQuentin Monnet exit(0); 11030da46b5SQuentin Monnet } 11130da46b5SQuentin Monnet 11230da46b5SQuentin Monnet int do_tracelog(int argc, char **argv) 11330da46b5SQuentin Monnet { 11430da46b5SQuentin Monnet const struct sigaction act = { 11530da46b5SQuentin Monnet .sa_handler = exit_tracelog 11630da46b5SQuentin Monnet }; 11730da46b5SQuentin Monnet char trace_pipe[PATH_MAX]; 11830da46b5SQuentin Monnet bool found_trace_pipe; 11930da46b5SQuentin Monnet size_t buff_len = 0; 12030da46b5SQuentin Monnet 12130da46b5SQuentin Monnet if (json_output) 12230da46b5SQuentin Monnet jsonw_start_array(json_wtr); 12330da46b5SQuentin Monnet 12430da46b5SQuentin Monnet found_trace_pipe = find_tracefs_pipe(trace_pipe); 12530da46b5SQuentin Monnet if (!found_trace_pipe) { 12630da46b5SQuentin Monnet p_err("could not find trace pipe, tracefs not mounted?"); 12730da46b5SQuentin Monnet return -1; 12830da46b5SQuentin Monnet } 12930da46b5SQuentin Monnet 13030da46b5SQuentin Monnet trace_pipe_fd = fopen(trace_pipe, "r"); 13130da46b5SQuentin Monnet if (!trace_pipe_fd) { 13230da46b5SQuentin Monnet p_err("could not open trace pipe: %s", strerror(errno)); 13330da46b5SQuentin Monnet return -1; 13430da46b5SQuentin Monnet } 13530da46b5SQuentin Monnet 13630da46b5SQuentin Monnet sigaction(SIGHUP, &act, NULL); 13730da46b5SQuentin Monnet sigaction(SIGINT, &act, NULL); 13830da46b5SQuentin Monnet sigaction(SIGTERM, &act, NULL); 13930da46b5SQuentin Monnet while (1) { 14030da46b5SQuentin Monnet ssize_t ret; 14130da46b5SQuentin Monnet 14230da46b5SQuentin Monnet ret = getline(&buff, &buff_len, trace_pipe_fd); 14330da46b5SQuentin Monnet if (ret <= 0) { 14430da46b5SQuentin Monnet p_err("failed to read content from trace pipe: %s", 14530da46b5SQuentin Monnet strerror(errno)); 14630da46b5SQuentin Monnet break; 14730da46b5SQuentin Monnet } 14830da46b5SQuentin Monnet if (json_output) 14930da46b5SQuentin Monnet jsonw_string(json_wtr, buff); 15030da46b5SQuentin Monnet else 15130da46b5SQuentin Monnet printf("%s", buff); 15230da46b5SQuentin Monnet } 15330da46b5SQuentin Monnet 15430da46b5SQuentin Monnet fclose(trace_pipe_fd); 15530da46b5SQuentin Monnet free(buff); 15630da46b5SQuentin Monnet return -1; 15730da46b5SQuentin Monnet } 158