diff options
Diffstat (limited to 'tools/bpf/bpftool/tracelog.c')
| -rw-r--r-- | tools/bpf/bpftool/tracelog.c | 157 | 
1 files changed, 157 insertions, 0 deletions
diff --git a/tools/bpf/bpftool/tracelog.c b/tools/bpf/bpftool/tracelog.c new file mode 100644 index 000000000000..1fa8e513f590 --- /dev/null +++ b/tools/bpf/bpftool/tracelog.c @@ -0,0 +1,157 @@ +// 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 find_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)) +		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]; +	bool found_trace_pipe; +	size_t buff_len = 0; + +	if (json_output) +		jsonw_start_array(json_wtr); + +	found_trace_pipe = find_tracefs_pipe(trace_pipe); +	if (!found_trace_pipe) { +		p_err("could not find trace pipe, tracefs not mounted?"); +		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; +}  | 
