Proc file system reflects the current state of Linux kernel.
The current state of kernel could represent various information like the processes running on it, the hardware information, the network information etc. So this system is designed in a way that all this information can easily be accessed by the user level processes.
We also say that a proc file system is a pseudo file system. This is because, the files in this file system are loaded with information when these files are accessed and that the reason why the files in this file system usually exhibit a size zero.
Do a ls /proc on your system and you’ll notice something similar to the following:
$ ls /proc 1 15 1681 1719 35 60 713 878 cgroups filesystems kpageflags pagetypeinfo sysrq-trigger ....
So we see that this file systems contains files as well as directories. The names of files or directories are either alphabetical or numeric. The numeric file or directory names are mostly corresponding to the processes running on the system and the number represents the process ID of the process. So its very easy to know the kernel level information about any process by using its process ID and opening the corresponding file.
In this article we will build upon our knowledge of Loadable Kernel Modules (LKM) and will discuss how these proc files are created, read and written to.
Refer to our earlier article about Linux proc file system to understand the various files that are located under /proc.
Creating Proc files
In the article on Linux kernel modules, we discussed how to create, load and unload LKMs. That was the basic concept for adding more functionality to the linux kernel at run time. Proc files work on the same principle. Each proc file is created, loaded and unloaded in form of an LKM.
In the following code, we try to create a proc file and define its read and write capabilities.
#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_LEN 4096 int read_info( char *page, char **start, off_t off,int count, int *eof, void *data ); ssize_t write_info( struct file *filp, const char __user *buff,unsigned long len, void *data ); static struct proc_dir_entry *proc_entry; static char *info; static int write_index; static int read_index; int init_module( void ) { int ret = 0; info = (char *)vmalloc( MAX_LEN ); memset( info, 0, MAX_LEN ); proc_entry = create_proc_entry( "procEntry123", 0644, NULL ); if (proc_entry == NULL) { ret = -1; vfree(info); printk(KERN_INFO "procEntry123 could not be created\n"); } else { write_index = 0; read_index = 0; proc_entry->read_proc = read_info; proc_entry->write_proc = write_info; printk(KERN_INFO "procEntry123 created.\n"); } return ret; } void cleanup_module( void ) { remove_proc_entry("procEntry123", proc_entry); printk(KERN_INFO "procEntry123 unloaded.\n"); vfree(info); } ssize_t write_info( struct file *filp, const char __user *buff, unsigned long len, void *data ) { int capacity = (MAX_LEN-write_index)+1; if (len > capacity) { printk(KERN_INFO "No space to write in procEntry123!\n"); return -1; } if (copy_from_user( &info[write_index], buff, len )) { return -2; } write_index += len; info[write_index-1] = 0; return len; } int read_info( char *page, char **start, off_t off, int count, int *eof, void *data ) { int len; if (off > 0) { *eof = 1; return 0; } if (read_index >= write_index) read_index = 0; len = sprintf(page, "%s\n", &info[read_index]); read_index += len; return len; }
In the code above :
- In the init_module function we used the ‘create_proc_entry’ function to create a proc file named ‘procEntry123′
- The file is created with suitable privileges as described by the second argument to the create_proc_entry function.
- Two functions read_info and write_info are used when the proc file is read and written.
- The address of these two functions is assigned to members of proc_dir_entry structure.
- The above step was done in order for the code to know which function to call when the proc file is read and written.
- In the write_info function, if there is capacity to write in the buffer, the function copy_from_user is used to copy the string from user space to the kernel module allocated memory buffer.
- In the function read_info, the information present in buffer is send back to the user space.
The Makefile for the above code looks like :
$ cat Makefile 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
Now, when the code above is compiled, we see :
$ make sudo make -C /lib/modules/2.6.32-21-generic/build M=/home/himanshu modules make: Entering directory `/usr/src/linux-headers-2.6.32-21-generic' CC [M] /home/himanshu/proc.o /home/himanshu/proc.c: In function ‘init_module’: /home/himanshu/proc.c:33: warning: assignment from incompatible pointer type Building modules, stage 2. MODPOST 1 modules LD [M] /home/himanshu/proc.ko make: Leaving directory `/usr/src/linux-headers-2.6.32-21-generic'
Once the code is compiled successfully, the module is inserted and loaded by the following command :
$ sudo insmod proc.ko
And after inserting if we see the proc directory, we find an entry ‘procEntry123′
$ ls /proc/procEntry123 /proc/procEntry123
Now, if we try to write and read from it :
$ echo "TGS" > /proc/procEntry123 $ cat /proc/procEntry123 TGS
So we see that that we are able to read and write the proc file. In the same way all the standard proc files are implemented.
Get the Linux Sysadmin Course Now!
{ 6 comments… read them below or add one }
wow, this is really interesting. Keep going.
Thanks!! I have used the /proc filesystem to dump information but this article shows with a simple example how to set it up. Really good and concise explanation.
I tried and it looks like it was only able to to dump up to1024 byte.
Hi Himanshu,
Thanks for the nice tutorial! I get a permission denied error on trying to write into the proc file. Neither sudo nor 0664 mode while creating the proc entry help.
-rw-rw-r– 1 root root 0 Apr 29 18:10 procEntry123
sudo echo “hi” > procEntry123
bash: procEntry123: Permission denied
Minor Typo: In write_info(), shouldn’t it be “int capacity = (MAX_LEN-write_index);”
Removing the module does not remove the proc file system entry like it should.
In clean_module() change:
remove_proc_entry(“procEntry123″, proc_entry);
to:
remove_proc_entry(“procEntry123″, NULL);
I can create proc file.what I want is to learn graphic card info using proc read function.How can I do this? I do not mean to learn that info in terminal( by writing lspci vs).do you know the path of which file stores the graphic card info in /proc directory?