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