≡ Menu

How to Create Linux Proc Files in C Program using LKM

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.

Add your comment

If you enjoyed this article, you might also like..

  1. 50 Linux Sysadmin Tutorials
  2. 50 Most Frequently Used Linux Commands (With Examples)
  3. Top 25 Best Linux Performance Monitoring and Debugging Tools
  4. Mommy, I found it! – 15 Practical Linux Find Command Examples
  5. Linux 101 Hacks 2nd Edition eBook Linux 101 Hacks Book

Bash 101 Hacks Book Sed and Awk 101 Hacks Book Nagios Core 3 Book Vim 101 Hacks Book

Comments on this entry are closed.

  • bartek April 25, 2012, 2:32 pm

    wow, this is really interesting. Keep going.

  • bob April 26, 2012, 2:41 pm

    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.

  • Anonymous April 27, 2012, 2:15 pm

    I tried and it looks like it was only able to to dump up to1024 byte.

  • Anant April 29, 2012, 6:46 am

    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);”

  • Michael Glass November 15, 2012, 3:20 pm

    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);

  • specta December 6, 2013, 12:36 am

    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?

  • Anon June 25, 2014, 6:48 pm

    This method is deprecated. To bad it’s the most widely documented method.

  • shashibhushan February 3, 2015, 11:36 am

    very nice…thanks