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 <sys/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 find_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 return false; 93 94 exit_found: 95 strcat(mnt, pipe_name); 96 return true; 97 } 98 99 static void exit_tracelog(int signum) 100 { 101 fclose(trace_pipe_fd); 102 free(buff); 103 104 if (json_output) { 105 jsonw_end_array(json_wtr); 106 jsonw_destroy(&json_wtr); 107 } 108 109 exit(0); 110 } 111 112 int do_tracelog(int argc, char **argv) 113 { 114 const struct sigaction act = { 115 .sa_handler = exit_tracelog 116 }; 117 char trace_pipe[PATH_MAX]; 118 bool found_trace_pipe; 119 size_t buff_len = 0; 120 121 if (json_output) 122 jsonw_start_array(json_wtr); 123 124 found_trace_pipe = find_tracefs_pipe(trace_pipe); 125 if (!found_trace_pipe) { 126 p_err("could not find trace pipe, tracefs not mounted?"); 127 return -1; 128 } 129 130 trace_pipe_fd = fopen(trace_pipe, "r"); 131 if (!trace_pipe_fd) { 132 p_err("could not open trace pipe: %s", strerror(errno)); 133 return -1; 134 } 135 136 sigaction(SIGHUP, &act, NULL); 137 sigaction(SIGINT, &act, NULL); 138 sigaction(SIGTERM, &act, NULL); 139 while (1) { 140 ssize_t ret; 141 142 ret = getline(&buff, &buff_len, trace_pipe_fd); 143 if (ret <= 0) { 144 p_err("failed to read content from trace pipe: %s", 145 strerror(errno)); 146 break; 147 } 148 if (json_output) 149 jsonw_string(json_wtr, buff); 150 else 151 printf("%s", buff); 152 } 153 154 fclose(trace_pipe_fd); 155 free(buff); 156 return -1; 157 } 158