162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 262306a36Sopenharmony_ci/* Copyright (c) 2015-2017 Daniel Borkmann */ 362306a36Sopenharmony_ci/* Copyright (c) 2018 Netronome Systems, Inc. */ 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <errno.h> 662306a36Sopenharmony_ci#include <limits.h> 762306a36Sopenharmony_ci#include <signal.h> 862306a36Sopenharmony_ci#include <stdio.h> 962306a36Sopenharmony_ci#include <string.h> 1062306a36Sopenharmony_ci#include <unistd.h> 1162306a36Sopenharmony_ci#include <linux/magic.h> 1262306a36Sopenharmony_ci#include <fcntl.h> 1362306a36Sopenharmony_ci#include <sys/vfs.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "main.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#ifndef TRACEFS_MAGIC 1862306a36Sopenharmony_ci# define TRACEFS_MAGIC 0x74726163 1962306a36Sopenharmony_ci#endif 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define _textify(x) #x 2262306a36Sopenharmony_ci#define textify(x) _textify(x) 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ciFILE *trace_pipe_fd; 2562306a36Sopenharmony_cichar *buff; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic int validate_tracefs_mnt(const char *mnt, unsigned long magic) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci struct statfs st_fs; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci if (statfs(mnt, &st_fs) < 0) 3262306a36Sopenharmony_ci return -ENOENT; 3362306a36Sopenharmony_ci if ((unsigned long)st_fs.f_type != magic) 3462306a36Sopenharmony_ci return -ENOENT; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci return 0; 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic bool 4062306a36Sopenharmony_cifind_tracefs_mnt_single(unsigned long magic, char *mnt, const char *mntpt) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci size_t src_len; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci if (validate_tracefs_mnt(mntpt, magic)) 4562306a36Sopenharmony_ci return false; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci src_len = strlen(mntpt); 4862306a36Sopenharmony_ci if (src_len + 1 >= PATH_MAX) { 4962306a36Sopenharmony_ci p_err("tracefs mount point name too long"); 5062306a36Sopenharmony_ci return false; 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci strcpy(mnt, mntpt); 5462306a36Sopenharmony_ci return true; 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic bool get_tracefs_pipe(char *mnt) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci static const char * const known_mnts[] = { 6062306a36Sopenharmony_ci "/sys/kernel/debug/tracing", 6162306a36Sopenharmony_ci "/sys/kernel/tracing", 6262306a36Sopenharmony_ci "/tracing", 6362306a36Sopenharmony_ci "/trace", 6462306a36Sopenharmony_ci }; 6562306a36Sopenharmony_ci const char *pipe_name = "/trace_pipe"; 6662306a36Sopenharmony_ci const char *fstype = "tracefs"; 6762306a36Sopenharmony_ci char type[100], format[32]; 6862306a36Sopenharmony_ci const char * const *ptr; 6962306a36Sopenharmony_ci bool found = false; 7062306a36Sopenharmony_ci FILE *fp; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci for (ptr = known_mnts; ptr < known_mnts + ARRAY_SIZE(known_mnts); ptr++) 7362306a36Sopenharmony_ci if (find_tracefs_mnt_single(TRACEFS_MAGIC, mnt, *ptr)) 7462306a36Sopenharmony_ci goto exit_found; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci fp = fopen("/proc/mounts", "r"); 7762306a36Sopenharmony_ci if (!fp) 7862306a36Sopenharmony_ci return false; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci /* Allow room for NULL terminating byte and pipe file name */ 8162306a36Sopenharmony_ci snprintf(format, sizeof(format), "%%*s %%%zds %%99s %%*s %%*d %%*d\\n", 8262306a36Sopenharmony_ci PATH_MAX - strlen(pipe_name) - 1); 8362306a36Sopenharmony_ci while (fscanf(fp, format, mnt, type) == 2) 8462306a36Sopenharmony_ci if (strcmp(type, fstype) == 0) { 8562306a36Sopenharmony_ci found = true; 8662306a36Sopenharmony_ci break; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci fclose(fp); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci /* The string from fscanf() might be truncated, check mnt is valid */ 9162306a36Sopenharmony_ci if (found && validate_tracefs_mnt(mnt, TRACEFS_MAGIC)) 9262306a36Sopenharmony_ci goto exit_found; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci if (block_mount) 9562306a36Sopenharmony_ci return false; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci p_info("could not find tracefs, attempting to mount it now"); 9862306a36Sopenharmony_ci /* Most of the time, tracefs is automatically mounted by debugfs at 9962306a36Sopenharmony_ci * /sys/kernel/debug/tracing when we try to access it. If we could not 10062306a36Sopenharmony_ci * find it, it is likely that debugfs is not mounted. Let's give one 10162306a36Sopenharmony_ci * attempt at mounting just tracefs at /sys/kernel/tracing. 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_ci strcpy(mnt, known_mnts[1]); 10462306a36Sopenharmony_ci if (mount_tracefs(mnt)) 10562306a36Sopenharmony_ci return false; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ciexit_found: 10862306a36Sopenharmony_ci strcat(mnt, pipe_name); 10962306a36Sopenharmony_ci return true; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic void exit_tracelog(int signum) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci fclose(trace_pipe_fd); 11562306a36Sopenharmony_ci free(buff); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci if (json_output) { 11862306a36Sopenharmony_ci jsonw_end_array(json_wtr); 11962306a36Sopenharmony_ci jsonw_destroy(&json_wtr); 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci exit(0); 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ciint do_tracelog(int argc, char **argv) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci const struct sigaction act = { 12862306a36Sopenharmony_ci .sa_handler = exit_tracelog 12962306a36Sopenharmony_ci }; 13062306a36Sopenharmony_ci char trace_pipe[PATH_MAX]; 13162306a36Sopenharmony_ci size_t buff_len = 0; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if (json_output) 13462306a36Sopenharmony_ci jsonw_start_array(json_wtr); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci if (!get_tracefs_pipe(trace_pipe)) 13762306a36Sopenharmony_ci return -1; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci trace_pipe_fd = fopen(trace_pipe, "r"); 14062306a36Sopenharmony_ci if (!trace_pipe_fd) { 14162306a36Sopenharmony_ci p_err("could not open trace pipe: %s", strerror(errno)); 14262306a36Sopenharmony_ci return -1; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci sigaction(SIGHUP, &act, NULL); 14662306a36Sopenharmony_ci sigaction(SIGINT, &act, NULL); 14762306a36Sopenharmony_ci sigaction(SIGTERM, &act, NULL); 14862306a36Sopenharmony_ci while (1) { 14962306a36Sopenharmony_ci ssize_t ret; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci ret = getline(&buff, &buff_len, trace_pipe_fd); 15262306a36Sopenharmony_ci if (ret <= 0) { 15362306a36Sopenharmony_ci p_err("failed to read content from trace pipe: %s", 15462306a36Sopenharmony_ci strerror(errno)); 15562306a36Sopenharmony_ci break; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci if (json_output) 15862306a36Sopenharmony_ci jsonw_string(json_wtr, buff); 15962306a36Sopenharmony_ci else 16062306a36Sopenharmony_ci printf("%s", buff); 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci fclose(trace_pipe_fd); 16462306a36Sopenharmony_ci free(buff); 16562306a36Sopenharmony_ci return -1; 16662306a36Sopenharmony_ci} 167