/* SPDX-License-Identifier: (BSD-2-Clause OR GPL-2.0-or-later) * (C) 2019-2021 AVM GmbH * * vim:set noexpandtab shiftwidth=8 softtabstop=8 fileencoding=utf-8: * * Simple handling of linux kernel proc fs trees */ #ifndef SHAREDLIBS_CPROCFS_H #define SHAREDLIBS_CPROCFS_H #ifdef CONFIG_PROC_FS #include #include #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0) /* The wrappers are public for anyone who needs to use the procfs API directly (like * cprocfs internally). So just include cprocfs.h and use either cprocfs or the * new-style procfs kernel API (even on old kernels). * * See mainline commits: * commit 97a32539b956 proc: convert everything to "struct proc_ops" * commit d56c0d45f0e2 proc: decouple proc from VFS with "struct proc_ops" * * proc_ops replaces file_operations and must be passed to proc_* interfaces. * * Conversion rule (see commit 97a32539b956): * llseek => proc_lseek * unlocked_ioctl => proc_ioctl * * => proc_* * owner => delete assignment */ #ifndef CPROCFS_NO_PROC_OPS /* Define if you don't want CPROCFS_NO_PROC_OPS, e.g. if the proc_read * definition conflicts with members in unrelated types. */ struct proc_ops { #define proc_open _proc_fops.open #define proc_read _proc_fops.read #define proc_write _proc_fops.write #define proc_lseek _proc_fops.llseek #define proc_ioctl _proc_fops.unlocked_ioctl #define proc_release _proc_fops.release struct file_operations _proc_fops; }; #define proc_create_data(name, mode, proc_dir, proc_ops, data) \ proc_create_data(name, mode, proc_dir, &(proc_ops)->_proc_fops, data) #define proc_create(name, mode, proc_dir, proc_ops) \ proc_create(name, mode, proc_dir, &(proc_ops)->_proc_fops) #endif /* CPROCFS_NO_PROC_OPS */ #endif /* --------------------------------------------------------------------- */ typedef int (*cprocfs_walk_cb_t)(void *, const char *, ...) __attribute__((format(printf, 2, 3))); struct cprocfs_file; struct cprocfs_dir { struct cprocfs_dir *next; const char *name; bool is_root; struct cprocfs_dir *parent; /* NULL if is_root or not attached */ struct proc_dir_entry *proc_dir; struct cprocfs_file *cfiles; struct cprocfs_dir *cdirs; }; struct cprocfs_file { struct cprocfs_file *next; struct cprocfs_dir *cdir; const char *name; struct proc_dir_entry *procfs_file; void (*showfunc)(void *userdata, cprocfs_walk_cb_t cb, void *arg); void (*control)(void *userdata, int argc, char *argv[]); void *userdata; }; /* --------------------------------------------------------------------- */ /** * cprocfs_create_root_dir: set root proc_dir_entry of a cprocfs_root. * * @param name name of directory * */ struct cprocfs_dir *cprocfs_create_root_dir(const char *name); /** * cprocfs_destroy: remove all files and directories under 'root' * * @param root tree to destroy (NOT NULL). * */ void cprocfs_destroy(struct cprocfs_dir *root); /* --------------------------------------------------------------------- */ /** * cprocfs_add_dir: add a directory to a directory. * * @param cdir parent directory (NOT NULL). * * @returns cprocfs_dir or NULL (kmalloc() failed). */ struct cprocfs_dir *cprocfs_add_dir(struct cprocfs_dir *cdir, const char *name); /** * cprocfs_delete_dir: remove a directory tree * * @param cdir directory to remove (NOT NULL). */ void cprocfs_delete_dir(struct cprocfs_dir *cdir); /** * cprocfs_register_file: add a readonly file * * @param cdir directory NOT NULL * @param name name of file * @param userdata used as first argument for 'showfunc' * @param showfunc 'read' function. * * @retval 0 file registered * @retval -1 kmalloc failed */ int cprocfs_register_file(struct cprocfs_dir *cdir, const char *name, void (*showfunc)(void *userdata, cprocfs_walk_cb_t cb, void *arg), void *userdata); /** * cprocfs_register_control: add a readwrite file * * @param cdir directory NOT NULL * @param name name of file * @param showfunc 'read' function. * @param control 'write' function. * @param userdata used as first argument for 'showfunc' and 'control' * * @retval 0 file registered * @retval -1 kmalloc failed */ int cprocfs_register_control(struct cprocfs_dir *cdir, const char *name, void (*showfunc)(void *userdata, cprocfs_walk_cb_t cb, void *arg), void (*control)(void *userdata, int argc, char *argv[]), void *userdata); /* --------------------------------------------------------------------- */ /** * cprocfs_create_detached_dir: create a cprocfs_dir without parent * * can be attached with cprocfs_attach_dir(). * * @param name name of directory * * @returns cprocfs_dir or NULL */ struct cprocfs_dir *cprocfs_create_detached_dir(const char *name); /** * cprocfs_attach_dir: add a directory to a directory. * * @param parent directory where 'child' will be attached (NOT NULL). * @param child directory to add to 'parent' (NOT NULL). */ void cprocfs_attach_dir(struct cprocfs_dir *parent, struct cprocfs_dir *child); /** * cprocfs_rename_dir: rename a detached directory. * * @param cdir directory to rename (NOT NULL). * * @retval 0 directory renamed * @retval -1 directory already detached */ int cprocfs_rename_dir(struct cprocfs_dir *cdir, const char *name); /** * cprocfs_walk: walk over directory tree and output information * * @param cdir directory to start (NOT NULL). * @param cb function (if NULL output will be done via printk) * @param arg arg to function * * @returns number of objects visited */ unsigned int cprocfs_walk(struct cprocfs_dir *cdir, cprocfs_walk_cb_t cb, void *arg); /* --------------------------------------------------------------------- */ #endif /* CONFIG_PROCFS */ #endif /* SHAREDLIBS_CPROCFS_H */