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/tracing", 61 "/sys/kernel/debug/tracing", 62 }; 63 const char *pipe_name = "/trace_pipe"; 64 const char *fstype = "tracefs"; 65 char type[100], format[32]; 66 const char * const *ptr; 67 bool found = false; 68 FILE *fp; 69 70 for (ptr = known_mnts; ptr < known_mnts + ARRAY_SIZE(known_mnts); ptr++) 71 if (find_tracefs_mnt_single(TRACEFS_MAGIC, mnt, *ptr)) 72 goto exit_found; 73 74 fp = fopen("/proc/mounts", "r"); 75 if (!fp) 76 return false; 77 78 /* Allow room for NULL terminating byte and pipe file name */ 79 snprintf(format, sizeof(format), "%%*s %%%zus %%99s %%*s %%*d %%*d\\n", 80 PATH_MAX - strlen(pipe_name) - 1); 81 while (fscanf(fp, format, mnt, type) == 2) 82 if (strcmp(type, fstype) == 0) { 83 found = true; 84 break; 85 } 86 fclose(fp); 87 88 /* The string from fscanf() might be truncated, check mnt is valid */ 89 if (found && validate_tracefs_mnt(mnt, TRACEFS_MAGIC)) 90 goto exit_found; 91 92 if (block_mount) 93 return false; 94 95 p_info("could not find tracefs, attempting to mount it now"); 96 strcpy(mnt, known_mnts[0]); 97 if (mount_tracefs(mnt)) 98 return false; 99 100 exit_found: 101 strcat(mnt, pipe_name); 102 return true; 103 } 104 105 static void exit_tracelog(int signum) 106 { 107 fclose(trace_pipe_fd); 108 free(buff); 109 110 if (json_output) { 111 jsonw_end_array(json_wtr); 112 jsonw_destroy(&json_wtr); 113 } 114 115 exit(0); 116 } 117 118 int do_tracelog(int argc, char **argv) 119 { 120 const struct sigaction act = { 121 .sa_handler = exit_tracelog 122 }; 123 char trace_pipe[PATH_MAX]; 124 size_t buff_len = 0; 125 126 if (json_output) 127 jsonw_start_array(json_wtr); 128 129 if (!get_tracefs_pipe(trace_pipe)) 130 return -1; 131 132 trace_pipe_fd = fopen(trace_pipe, "r"); 133 if (!trace_pipe_fd) { 134 p_err("could not open trace pipe: %s", strerror(errno)); 135 return -1; 136 } 137 138 sigaction(SIGHUP, &act, NULL); 139 sigaction(SIGINT, &act, NULL); 140 sigaction(SIGTERM, &act, NULL); 141 while (1) { 142 ssize_t ret; 143 144 ret = getline(&buff, &buff_len, trace_pipe_fd); 145 if (ret <= 0) { 146 p_err("failed to read content from trace pipe: %s", 147 strerror(errno)); 148 break; 149 } 150 if (json_output) 151 jsonw_string(json_wtr, buff); 152 else 153 printf("%s", buff); 154 } 155 156 fclose(trace_pipe_fd); 157 free(buff); 158 return -1; 159 } 160