runtime/procfs.c - systemtap
Global variables defined
Functions defined
Macros defined
Source code
#ifndef _STP_PROCFS_C_
#define _STP_PROCFS_C_
#if (!defined(STAPCONF_PATH_LOOKUP) && !defined(STAPCONF_KERN_PATH_PARENT) \
&& !defined(STAPCONF_VFS_PATH_LOOKUP) && !defined(STAPCONF_KERN_PATH))
#error "Either path_lookup(), kern_path_parent(), vfs_path_lookup(), or kern_path() must be exported by the kernel."
#endif
#ifdef STAPCONF_KERN_PATH
#include <linux/namei.h>
#endif
#ifdef STAPCONF_VFS_PATH_LOOKUP
#include <linux/mount.h>
#include <linux/pid_namespace.h>
#endif
#include "proc_fs_compatibility.h"
#include "uidgid_compatibility.h"
#if defined(STAPCONF_PATH_LOOKUP) && !defined(STAPCONF_KERN_PATH_PARENT)
#define kern_path_parent(name, nameidata) \
path_lookup(name, LOOKUP_PARENT, nameidata)
#endif
#ifndef STAPCONF_PDE_DATA
#define _STP_ALLOW_PROCFS_PATH_SUBDIRS
#endif
#ifndef STP_MAX_PROCFS_FILES
#define STP_MAX_PROCFS_FILES 16
#endif
static int _stp_num_pde = 0;
static struct proc_dir_entry *_stp_pde[STP_MAX_PROCFS_FILES];
static struct proc_dir_entry *_stp_proc_root = NULL;
static void _stp_close_procfs(void);
static void _stp_rmdir_proc_module(void)
{
if (!_stp_lock_transport_dir()) {
errk("Unable to remove '/proc/systemap/%s':"
" can't lock transport directory.\n",
THIS_MODULE->name);
return;
}
if (_stp_proc_root) {
proc_remove(_stp_proc_root);
_stp_proc_root = NULL;
}
_stp_unlock_transport_dir();
}
static int _stp_mkdir_proc_module(void)
{
int found = 0;
static char proc_root_name[STP_MODULE_NAME_LEN + sizeof("systemtap/")];
#if defined(STAPCONF_PATH_LOOKUP) || defined(STAPCONF_KERN_PATH_PARENT)
struct nameidata nd;
#else struct path path;
#if defined(STAPCONF_VFS_PATH_LOOKUP)
struct vfsmount *mnt;
#endif
int rc;
#endif
if (_stp_proc_root != NULL)
return 0;
if (!_stp_lock_transport_dir()) {
errk("Unable to create '/proc/systemap/%s':"
" can't lock transport directory.\n",
THIS_MODULE->name);
return -EINVAL;
}
#if defined(STAPCONF_PATH_LOOKUP) || defined(STAPCONF_KERN_PATH_PARENT)
if (! kern_path_parent("/proc/systemtap/foo", &nd)) {
found = 1;
#ifdef STAPCONF_NAMEIDATA_CLEANUP
path_put(&nd.path);
#else path_release(&nd);
#endif }
#elif defined(STAPCONF_KERN_PATH)
rc = kern_path("/proc/systemtap", 0, &path);
if (rc == 0) {
found = 1;
path_put (&path);
}
#else if (! init_pid_ns.proc_mnt) {
errk("Unable to create '/proc/systemap':"
" '/proc' doesn't exist.\n");
goto done;
}
mnt = init_pid_ns.proc_mnt;
rc = vfs_path_lookup(mnt->mnt_root, mnt, "systemtap", 0, &path);
if (rc == 0) {
found = 1;
path_put (&path);
}
#endif
if (!found) {
struct proc_dir_entry *de;
de = proc_mkdir ("systemtap", NULL);
if (de == NULL) {
errk("Unable to create '/proc/systemap':"
" proc_mkdir failed.\n");
goto done;
}
}
strlcpy(proc_root_name, "systemtap/", sizeof(proc_root_name));
strlcat(proc_root_name, THIS_MODULE->name, sizeof(proc_root_name));
_stp_proc_root = proc_mkdir(proc_root_name, NULL);
#ifdef STAPCONF_PROCFS_OWNER
if (_stp_proc_root != NULL)
_stp_proc_root->owner = THIS_MODULE;
#endif
if (_stp_proc_root == NULL)
errk("Unable to create '/proc/systemap/%s':"
" proc_mkdir failed.\n", THIS_MODULE->name);
done:
_stp_unlock_transport_dir();
return (_stp_proc_root) ? 0 : -EINVAL;
}
#ifdef _STP_ALLOW_PROCFS_PATH_SUBDIRS
static struct proc_dir_entry *_stp_procfs_lookup(const char *dir, struct proc_dir_entry *parent)
{
int i;
for (i = 0; i <_stp_num_pde; i++) {
struct proc_dir_entry *pde = _stp_pde[i];
if (pde->parent == parent && !strcmp(dir, pde->name))
return pde;
}
return NULL;
}
#endif
static int _stp_create_procfs(const char *path, int num,
const struct file_operations *fops, int perm,
void *data)
{
const char *p; char *next;
struct proc_dir_entry *last_dir, *de;
if (num >= STP_MAX_PROCFS_FILES) {
_stp_error("Requested file number %d is larger than max (%d)\n",
num, STP_MAX_PROCFS_FILES);
return -1;
}
last_dir = _stp_proc_root;
if (strlen(path) == 0)
p = "command";
else
p = path;
#ifdef _STP_ALLOW_PROCFS_PATH_SUBDIRS
while ((next = strchr(p, '/'))) {
if (_stp_num_pde == STP_MAX_PROCFS_FILES)
goto too_many;
*next = 0;
de = _stp_procfs_lookup(p, last_dir);
if (de == NULL) {
last_dir = proc_mkdir(p, last_dir);
if (!last_dir) {
_stp_error("Could not create directory \"%s\"\n", p);
goto err;
}
_stp_pde[_stp_num_pde++] = last_dir;
#ifdef STAPCONF_PROCFS_OWNER
last_dir->owner = THIS_MODULE;
#endif
proc_set_user(last_dir, KUIDT_INIT(_stp_uid),
KGIDT_INIT(_stp_gid));
}
else {
last_dir = de;
}
p = next + 1;
}
#else if (strchr(p, '/') != NULL) {
_stp_error("Could not create path \"%s\","
" contains subdirectories\n", p);
goto err;
}
#endif
if (_stp_num_pde == STP_MAX_PROCFS_FILES)
goto too_many;
de = proc_create_data(p, perm, last_dir, fops, data);
if (de == NULL) {
_stp_error("Could not create file \"%s\" in path \"%s\"\n",
p, path);
goto err;
}
#ifdef STAPCONF_PROCFS_OWNER
de->owner = THIS_MODULE;
#endif
proc_set_user(de, KUIDT_INIT(_stp_uid), KGIDT_INIT(_stp_gid));
_stp_pde[_stp_num_pde++] = de;
return 0;
too_many:
_stp_error("Attempted to open too many procfs files. Maximum is %d\n",
STP_MAX_PROCFS_FILES);
err:
_stp_close_procfs();
return -1;
}
static void _stp_close_procfs(void)
{
int i;
for (i = _stp_num_pde-1; i >= 0; i--) {
struct proc_dir_entry *pde = _stp_pde[i];
proc_remove(pde);
}
_stp_num_pde = 0;
}
#endif