title:Create procfs entry keywords:kernel,linux,threads # Create procfs entry Lets extend hello world driver. ## Starting point __Makefile__ ```Makefile obj-m += procfs_entry.o KDIR ?= /lib/modules/$(shell uname -r)/build all: make -C $(KDIR) M=$(PWD) modules clean: make -C $(KDIR) M=$(PWD) clean ``` __procfs_entry.c__ ```c #include /* Needed by all modules */ #include int procfs_entry_init( void ) { printk(KERN_DEBUG "Hello Procfs!\n"); return 0; } void procfs_entry_exit( void ) { printk(KERN_DEBUG "Exit Procfs!\n"); } module_init( procfs_entry_init ); module_exit( procfs_entry_exit ); MODULE_LICENSE("GPL"); ``` ## Adding procfs directory Create proc directory with ```c dir = proc_mkdir(DIR_NAME, PARENT_DIR); ``` under the directory create file that will contain data ```c proc_create("file", MODE, PARENT_DIR, PROC_FOPS) ``` Lets create /proc/secret/file. And define basic read/write operations. That at this stage will do nothing. ```c #include static struct proc_dir_entry *procdir, *procfile; static int secret_open(struct inode *inode, struct file *file) { return 0; } static int secret_release(struct inode *inode, struct file *file) { return 0; } static ssize_t secret_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) { return 0; } static ssize_t secret_write(struct file *file, const char *buffer, size_t length, loff_t *offset) { return 0; } static struct proc_ops procfs_ops = { .proc_open = secret_open, .proc_read = secret_read, .proc_write = secret_write, .proc_release = secret_release }; int procfs_entry_init( void ) { ... procdir = proc_mkdir("secret", NULL); if (procdir == NULL) { pr_err("Cant create secret directory\n"); return -1; } procfile = proc_create("file", 0644, procdir, &procfs_ops); if (procfile == NULL) { pr_err("Cant create file under the secret\n"); return -1; } ... } void procfs_entry_exit( void ) { ... //remove entries after unloading module proc_remove(procdir); proc_remove(procfile); ... } ``` Now module can be run and there is one file under the /proc/secret Next step add data to read from file entry/ Update the file operation functions, so its possible to read some data from /proc/secret/file ```c char file_data[256] = "This is data\n"; static int read_once=1; static int secret_open(struct inode *inode, struct file *file) { return 0; } static int secret_release(struct inode *inode, struct file *file) { return 0; } static ssize_t secret_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) { int len=0; if (read_once) { read_once=0; } else { read_once=1; return 0; } len = strlen(file_data); if (copy_to_user(buffer, &file_data, len)) { pr_err("secreate_read: Error\n"); } return len; } static ssize_t secret_write(struct file *file, const char *buffer, size_t length, loff_t *offset) { return 0; } ``` Now some data is exposed if module is loaded and run command ```sh cat /proc/secret/file ``` output will be ```sh This is data ``` ## List of procfs functions used | Function name | Note | |---|---| | proc_mkdir | Create procfs directory | | proc_create | Create procfs file | | proc_remove | Remove procfs entry | ## Final result __procfs_entry.c__ ```c #include /* Needed by all modules */ #include #include static struct proc_dir_entry *procdir, *procfile; char file_data[256] = "This is data\n"; static int read_once=1; static int secret_open(struct inode *inode, struct file *file) { return 0; } static int secret_release(struct inode *inode, struct file *file) { return 0; } static ssize_t secret_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) { int len=0; if (read_once) { read_once=0; } else { read_once=1; return 0; } len = strlen(file_data); if (copy_to_user(buffer, &file_data, len)) { pr_err("secreate_read: Error\n"); } return len; } static ssize_t secret_write(struct file *file, const char *buffer, size_t length, loff_t *offset) { return 0; } static struct proc_ops procfs_ops = { .proc_open = secret_open, .proc_read = secret_read, .proc_write = secret_write, .proc_release = secret_release }; int procfs_entry_init( void ) { printk(KERN_DEBUG "Hello Procfs!\n"); procdir = proc_mkdir("secret", NULL); if (procdir == NULL) { pr_err("Cant create secret directory\n"); return -1; } procfile = proc_create("file", 0644, procdir, &procfs_ops); if (procfile == NULL) { pr_err("Cant create file under the secret\n"); return -1; } return 0; } void procfs_entry_exit( void ) { printk(KERN_DEBUG "Exit Procfs!\n"); proc_remove(procdir); proc_remove(procfile); } module_init( procfs_entry_init ); module_exit( procfs_entry_exit ); MODULE_LICENSE("GPL") ``` ## Links https://elixir.bootlin.com/linux/v6.1.21/source/include/linux/proc_fs.h