blob: 326b455958984a9866cd1338c37cea11d1aa9caf [file] [log] [blame]
// SPDX-License-Identifier: LGPL-2.1
/*
* Copyright (C) 2008, 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
*
* Updates:
* Copyright (C) 2019, VMware, Tzvetomir Stoyanov <tz.stoyanov@gmail.com>
*
*/
#include <stdlib.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <linux/limits.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "tracefs.h"
#include "tracefs-local.h"
#define TRACEFS_PATH "/sys/kernel/tracing"
#define DEBUGFS_PATH "/sys/kernel/debug"
#define _STR(x) #x
#define STR(x) _STR(x)
void __attribute__((weak)) warning(const char *fmt, ...)
{
}
static int mount_tracefs(void)
{
struct stat st;
int ret;
/* make sure debugfs exists */
ret = stat(TRACEFS_PATH, &st);
if (ret < 0)
return -1;
ret = mount("nodev", TRACEFS_PATH,
"tracefs", 0, NULL);
return ret;
}
static int mount_debugfs(void)
{
struct stat st;
int ret;
/* make sure debugfs exists */
ret = stat(DEBUGFS_PATH, &st);
if (ret < 0)
return -1;
ret = mount("nodev", DEBUGFS_PATH,
"debugfs", 0, NULL);
return ret;
}
/**
* tracefs_find_tracing_dir - Find tracing directory
*
* Returns string containing the full path to the system's tracing directory.
* The string must be freed by free()
*/
char *tracefs_find_tracing_dir(void)
{
char *debug_str = NULL;
char fspath[PATH_MAX+1];
char *tracing_dir;
char type[100];
int use_debug = 0;
FILE *fp;
fp = fopen("/proc/mounts", "r");
if (!fp) {
warning("Can't open /proc/mounts for read");
return NULL;
}
while (fscanf(fp, "%*s %"
STR(PATH_MAX)
"s %99s %*s %*d %*d\n",
fspath, type) == 2) {
if (strcmp(type, "tracefs") == 0)
break;
if (!debug_str && strcmp(type, "debugfs") == 0) {
debug_str = strdup(fspath);
if (!debug_str) {
fclose(fp);
return NULL;
}
}
}
fclose(fp);
if (strcmp(type, "tracefs") != 0) {
if (mount_tracefs() < 0) {
if (debug_str) {
strncpy(fspath, debug_str, PATH_MAX);
fspath[PATH_MAX] = 0;
} else {
if (mount_debugfs() < 0) {
warning("debugfs not mounted, please mount");
free(debug_str);
return NULL;
}
strcpy(fspath, DEBUGFS_PATH);
}
use_debug = 1;
} else
strcpy(fspath, TRACEFS_PATH);
}
free(debug_str);
if (use_debug) {
int ret;
ret = asprintf(&tracing_dir, "%s/tracing", fspath);
if (ret < 0)
return NULL;
} else {
tracing_dir = strdup(fspath);
if (!tracing_dir)
return NULL;
}
return tracing_dir;
}
/**
* tracefs_get_tracing_dir - Get tracing directory
*
* Returns string containing the full path to the system's tracing directory.
* The returned string must *not* be freed.
*/
const char *tracefs_get_tracing_dir(void)
{
static const char *tracing_dir;
if (tracing_dir)
return tracing_dir;
tracing_dir = tracefs_find_tracing_dir();
return tracing_dir;
}
/**
* tracefs_get_tracing_file - Get tracing file
* @name: tracing file name
*
* Returns string containing the full path to a tracing file in
* the system's tracing directory.
*
* Must use tracefs_put_tracing_file() to free the returned string.
*/
char *tracefs_get_tracing_file(const char *name)
{
static const char *tracing;
char *file;
int ret;
if (!name)
return NULL;
if (!tracing) {
tracing = tracefs_find_tracing_dir();
if (!tracing)
return NULL;
}
ret = asprintf(&file, "%s/%s", tracing, name);
if (ret < 0)
return NULL;
return file;
}
/**
* tracefs_put_tracing_file - Free tracing file or directory name
*
* Frees tracing file or directory, returned by
* tracefs_get_tracing_file() or tracefs_get_tracing_dir() APIs
*/
void tracefs_put_tracing_file(char *name)
{
free(name);
}
__hidden int str_read_file(const char *file, char **buffer)
{
char stbuf[BUFSIZ];
char *buf = NULL;
int size = 0;
char *nbuf;
int fd;
int r;
fd = open(file, O_RDONLY);
if (fd < 0) {
warning("File %s not found", file);
return -1;
}
do {
r = read(fd, stbuf, BUFSIZ);
if (r <= 0)
continue;
nbuf = realloc(buf, size+r+1);
if (!nbuf) {
warning("Failed to allocate file buffer");
size = -1;
break;
}
buf = nbuf;
memcpy(buf+size, stbuf, r);
size += r;
} while (r > 0);
close(fd);
if (r == 0 && size > 0) {
buf[size] = '\0';
*buffer = buf;
} else
free(buf);
return size;
}