1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 /* Copyright (c) 2015-2017 Daniel Borkmann */ 3 /* Copyright (c) 2018 Netronome Systems, Inc. */ 4 5 #include <errno.h> 6 #include <limits.h> 7 #include <signal.h> 8 #include <stdio.h> 9 #include <string.h> 10 #include <unistd.h> 11 #include <linux/magic.h> 12 #include <fcntl.h> 13 #include <sys/vfs.h> 14 15 #include "main.h" 16 17 #ifndef TRACEFS_MAGIC 18 # define TRACEFS_MAGIC 0x74726163 19 #endif 20 21 #define _textify(x) #x 22 #define textify(x) _textify(x) 23 24 FILE *trace_pipe_fd; 25 char *buff; 26 27 static int validate_tracefs_mnt(const char *mnt, unsigned long magic) 28 { 29 struct statfs st_fs; 30 31 if (statfs(mnt, &st_fs) < 0) 32 return -ENOENT; 33 if ((unsigned long)st_fs.f_type != magic) 34 return -ENOENT; 35 36 return 0; 37 } 38 39 static bool 40 find_tracefs_mnt_single(unsigned long magic, char *mnt, const char *mntpt) 41 { 42 size_t src_len; 43 44 if (validate_tracefs_mnt(mntpt, magic)) 45 return false; 46 47 src_len = strlen(mntpt); 48 if (src_len + 1 >= PATH_MAX) { 49 p_err("tracefs mount point name too long"); 50 return false; 51 } 52 53 strcpy(mnt, mntpt); 54 return true; 55 } 56 57 static bool get_tracefs_pipe(char *mnt) 58 { 59 static const char * const known_mnts[] = { 60 "/sys/kernel/debug/tracing", 61 "/sys/kernel/tracing", 62 "/tracing", 63 "/trace", 64 }; 65 const char *pipe_name = "/trace_pipe"; 66 const char *fstype = "tracefs"; 67 char type[100], format[32]; 68 const char * const *ptr; 69 bool found = false; 70 FILE *fp; 71 72 for (ptr = known_mnts; ptr < known_mnts + ARRAY_SIZE(known_mnts); ptr++) 73 if (find_tracefs_mnt_single(TRACEFS_MAGIC, mnt, *ptr)) 74 goto exit_found; 75 76 fp = fopen("/proc/mounts", "r"); 77 if (!fp) 78 return false; 79 80 /* Allow room for NULL terminating byte and pipe file name */ 81 snprintf(format, sizeof(format), "%%*s %%%zds %%99s %%*s %%*d %%*d\\n", 82 PATH_MAX - strlen(pipe_name) - 1); 83 while (fscanf(fp, format, mnt, type) == 2) 84 if (strcmp(type, fstype) == 0) { 85 found = true; 86 break; 87 } 88 fclose(fp); 89 90 /* The string from fscanf() might be truncated, check mnt is valid */ 91 if (found && validate_tracefs_mnt(mnt, TRACEFS_MAGIC)) 92 goto exit_found; 93 94 if (block_mount) 95 return false; 96 97 p_info("could not find tracefs, attempting to mount it now"); 98 /* Most of the time, tracefs is automatically mounted by debugfs at 99 * /sys/kernel/debug/tracing when we try to access it. If we could not 100 * find it, it is likely that debugfs is not mounted. Let's give one 101 * attempt at mounting just tracefs at /sys/kernel/tracing. 102 */ 103 strcpy(mnt, known_mnts[1]); 104 if (mount_tracefs(mnt)) 105 return false; 106 107 exit_found: 108 strcat(mnt, pipe_name); 109 return true; 110 } 111 112 static void exit_tracelog(int signum) 113 { 114 fclose(trace_pipe_fd); 115 free(buff); 116 117 if (json_output) { 118 jsonw_end_array(json_wtr); 119 jsonw_destroy(&json_wtr); 120 } 121 122 exit(0); 123 } 124 125 int do_tracelog(int argc, char **argv) 126 { 127 const struct sigaction act = { 128 .sa_handler = exit_tracelog 129 }; 130 char trace_pipe[PATH_MAX]; 131 size_t buff_len = 0; 132 133 if (json_output) 134 jsonw_start_array(json_wtr); 135 136 if (!get_tracefs_pipe(trace_pipe)) 137 return -1; 138 139 trace_pipe_fd = fopen(trace_pipe, "r"); 140 if (!trace_pipe_fd) { 141 p_err("could not open trace pipe: %s", strerror(errno)); 142 return -1; 143 } 144 145 sigaction(SIGHUP, &act, NULL); 146 sigaction(SIGINT, &act, NULL); 147 sigaction(SIGTERM, &act, NULL); 148 while (1) { 149 ssize_t ret; 150 151 ret = getline(&buff, &buff_len, trace_pipe_fd); 152 if (ret <= 0) { 153 p_err("failed to read content from trace pipe: %s", 154 strerror(errno)); 155 break; 156 } 157 if (json_output) 158 jsonw_string(json_wtr, buff); 159 else 160 printf("%s", buff); 161 } 162 163 fclose(trace_pipe_fd); 164 free(buff); 165 return -1; 166 } 167