As we have already discussed the procfile system in my previous article. Here we will learn about how to create a procfile which can be read and written to. Since, proc files act as an interface between user space and kernel space, so creating, reading and writing a proc file will not be simple programming. Programming with proc files involves kernel level programming in form of loadable kernel modules. Example As I have already discussed how to program LKMs, so I will not repeat it here. Lets start with creating Proc files : The function used for creating proc files is 'create_proc_entry'. It takes 3 arguments- name of proc file, permissions to the file, a location in the /proc filesystem in which the file is to reside and returns a pointer to structure 'struct proc_dir_entry'. The return pointer ctan be used to configure other aspects of the proc file, such as the function to call when a read is performed on the file. The structure 'proc_dir_entry' is as follows : Code: struct proc_dir_entry { const char *name; // virtual file name mode_t mode; // mode permissions uid_t uid; // File's user id gid_t gid; // File's group id struct inode_operations *proc_iops; // Inode operations functions struct file_operations *proc_fops; // File operations functions struct proc_dir_entry *parent; // Parent directory ... read_proc_t *read_proc; // /proc read function write_proc_t *write_proc; // /proc write function void *data; // Pointer to private data atomic_t count; // use count ... }; To remove a file from /proc, use the 'remove_proc_entry' function. We have declared/defined two functions 'my_read' and 'my_write' that get called when proc file is read and written to respectively. Since the data is coming from user space in case of 'my_write' function, so we cannot directly use the pointer to the data passed by the user space. To solve the above problem we use the function 'copy_from_user' Similarly 'copy_to_user' is used in case of a read for proc file is issued. Enough of theory, lets look at a real example : Code: #include <linux/module.h> #include <linux/kernel.h> #include <linux/proc_fs.h> #include <linux/string.h> #include <linux/vmalloc.h> #include <asm/uaccess.h> #define MAX_LENGTH PAGE_SIZE static struct proc_dir_entry *proc_entry; static char *info; // Space for my_proc_entry strings static int write_index; // Index to write static int read_index; // Index to read int my_read( char *page, char **start, off_t off, int count, int *eof, void *data ); ssize_t my_write( struct file *filp, const char __user *buff, unsigned long len, void *data ); int init_my_module( void ) { int ret = 0; info = (char *)vmalloc( MAX_LENGTH ); if (!info) { ret = -ENOMEM; } else { memset( info, 0, MAX_LENGTH ); proc_entry = create_proc_entry( "my_proc_entry", 0644, NULL ); if (proc_entry == NULL) { ret = -ENOMEM; vfree(info); printk(KERN_INFO "my_proc_entry: Couldn't create proc entry\n"); } else { write_index = 0; read_index = 0; proc_entry->read_proc = my_read; proc_entry->write_proc = my_write; printk(KERN_INFO "my_proc_entry: Module loaded.\n"); } } return ret; } void cleanup_my_module( void ) { remove_proc_entry("my_proc_entry", proc_entry); vfree(info); printk(KERN_INFO "my_proc_entry: Module unloaded.\n"); } ssize_t my_write( struct file *filp, const char __user *buff, unsigned long len, void *data ) { int space_available = (MAX_LENGTH-write_index)+1; if (len > space_available) { printk(KERN_INFO "my_proc_entry: space full!\n"); return -ENOSPC; } if (copy_from_user( &info[write_index], buff, len )) { return -EFAULT; } write_index += len; info[write_index-1] = 0; return len; } int my_read( char *page, char **start, off_t off, int count, int *eof, void *data ) { int len; if (off > 0) { *eof = 1; return 0; } /* Wrap-around */ if (read_index >= write_index) read_index = 0; len = sprintf(page, "%s\n", &info[read_index]); read_index += len; return len; } module_init( init_my_module ); module_exit( cleanup_my_module ); Makefile for the above LKM : Code: obj-m += proc.o all: sudo make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: sudo make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean Compilation and insertion of module: Code: practice # make sudo make -C /lib/modules/2.6.32-21-generic/build M=/home/himanshu/practice modules make: Entering directory `/usr/src/linux-headers-2.6.32-21-generic' CC [M] /home/himanshu/practice/proc.o /home/himanshu/practice/proc.c: In function ‘init_my_module’: /home/himanshu/practice/proc.c:49: warning: assignment from incompatible pointer type Building modules, stage 2. MODPOST 1 modules LD [M] /home/himanshu/practice/proc.ko make: Leaving directory `/usr/src/linux-headers-2.6.32-21-generic' practice # insmod ./proc.ko Now, when we see our proc file system, we will find an entry for my_proc_entry. To play around, run the following command : Code: $ echo "hello world" > /proc/my_proc_entry now, try to view the contents of the proc file 'my_proc_entry'. You will see that the string 'hello world' will be displayed. Conclusion To conclude, programming with proc files is extremely useful where-in there is a requirement to expose dynamic kerenl information to the user space and take parameters as input from user space and change the kernel configuration dynamically. Stay tuned for more!!!!!