mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
166 lines
3.5 KiB
166 lines
3.5 KiB
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) |
|
/* Copyright (c) 2015-2017 Daniel Borkmann */ |
|
/* Copyright (c) 2018 Netronome Systems, Inc. */ |
|
|
|
#include <errno.h> |
|
#include <limits.h> |
|
#include <signal.h> |
|
#include <stdio.h> |
|
#include <string.h> |
|
#include <unistd.h> |
|
#include <linux/magic.h> |
|
#include <sys/fcntl.h> |
|
#include <sys/vfs.h> |
|
|
|
#include "main.h" |
|
|
|
#ifndef TRACEFS_MAGIC |
|
# define TRACEFS_MAGIC 0x74726163 |
|
#endif |
|
|
|
#define _textify(x) #x |
|
#define textify(x) _textify(x) |
|
|
|
FILE *trace_pipe_fd; |
|
char *buff; |
|
|
|
static int validate_tracefs_mnt(const char *mnt, unsigned long magic) |
|
{ |
|
struct statfs st_fs; |
|
|
|
if (statfs(mnt, &st_fs) < 0) |
|
return -ENOENT; |
|
if ((unsigned long)st_fs.f_type != magic) |
|
return -ENOENT; |
|
|
|
return 0; |
|
} |
|
|
|
static bool |
|
find_tracefs_mnt_single(unsigned long magic, char *mnt, const char *mntpt) |
|
{ |
|
size_t src_len; |
|
|
|
if (validate_tracefs_mnt(mntpt, magic)) |
|
return false; |
|
|
|
src_len = strlen(mntpt); |
|
if (src_len + 1 >= PATH_MAX) { |
|
p_err("tracefs mount point name too long"); |
|
return false; |
|
} |
|
|
|
strcpy(mnt, mntpt); |
|
return true; |
|
} |
|
|
|
static bool get_tracefs_pipe(char *mnt) |
|
{ |
|
static const char * const known_mnts[] = { |
|
"/sys/kernel/debug/tracing", |
|
"/sys/kernel/tracing", |
|
"/tracing", |
|
"/trace", |
|
}; |
|
const char *pipe_name = "/trace_pipe"; |
|
const char *fstype = "tracefs"; |
|
char type[100], format[32]; |
|
const char * const *ptr; |
|
bool found = false; |
|
FILE *fp; |
|
|
|
for (ptr = known_mnts; ptr < known_mnts + ARRAY_SIZE(known_mnts); ptr++) |
|
if (find_tracefs_mnt_single(TRACEFS_MAGIC, mnt, *ptr)) |
|
goto exit_found; |
|
|
|
fp = fopen("/proc/mounts", "r"); |
|
if (!fp) |
|
return false; |
|
|
|
/* Allow room for NULL terminating byte and pipe file name */ |
|
snprintf(format, sizeof(format), "%%*s %%%zds %%99s %%*s %%*d %%*d\\n", |
|
PATH_MAX - strlen(pipe_name) - 1); |
|
while (fscanf(fp, format, mnt, type) == 2) |
|
if (strcmp(type, fstype) == 0) { |
|
found = true; |
|
break; |
|
} |
|
fclose(fp); |
|
|
|
/* The string from fscanf() might be truncated, check mnt is valid */ |
|
if (found && validate_tracefs_mnt(mnt, TRACEFS_MAGIC)) |
|
goto exit_found; |
|
|
|
if (block_mount) |
|
return false; |
|
|
|
p_info("could not find tracefs, attempting to mount it now"); |
|
/* Most of the time, tracefs is automatically mounted by debugfs at |
|
* /sys/kernel/debug/tracing when we try to access it. If we could not |
|
* find it, it is likely that debugfs is not mounted. Let's give one |
|
* attempt at mounting just tracefs at /sys/kernel/tracing. |
|
*/ |
|
strcpy(mnt, known_mnts[1]); |
|
if (mount_tracefs(mnt)) |
|
return false; |
|
|
|
exit_found: |
|
strcat(mnt, pipe_name); |
|
return true; |
|
} |
|
|
|
static void exit_tracelog(int signum) |
|
{ |
|
fclose(trace_pipe_fd); |
|
free(buff); |
|
|
|
if (json_output) { |
|
jsonw_end_array(json_wtr); |
|
jsonw_destroy(&json_wtr); |
|
} |
|
|
|
exit(0); |
|
} |
|
|
|
int do_tracelog(int argc, char **argv) |
|
{ |
|
const struct sigaction act = { |
|
.sa_handler = exit_tracelog |
|
}; |
|
char trace_pipe[PATH_MAX]; |
|
size_t buff_len = 0; |
|
|
|
if (json_output) |
|
jsonw_start_array(json_wtr); |
|
|
|
if (!get_tracefs_pipe(trace_pipe)) |
|
return -1; |
|
|
|
trace_pipe_fd = fopen(trace_pipe, "r"); |
|
if (!trace_pipe_fd) { |
|
p_err("could not open trace pipe: %s", strerror(errno)); |
|
return -1; |
|
} |
|
|
|
sigaction(SIGHUP, &act, NULL); |
|
sigaction(SIGINT, &act, NULL); |
|
sigaction(SIGTERM, &act, NULL); |
|
while (1) { |
|
ssize_t ret; |
|
|
|
ret = getline(&buff, &buff_len, trace_pipe_fd); |
|
if (ret <= 0) { |
|
p_err("failed to read content from trace pipe: %s", |
|
strerror(errno)); |
|
break; |
|
} |
|
if (json_output) |
|
jsonw_string(json_wtr, buff); |
|
else |
|
printf("%s", buff); |
|
} |
|
|
|
fclose(trace_pipe_fd); |
|
free(buff); |
|
return -1; |
|
}
|
|
|