Programming with Linux proc files

Discussion in 'Linux' started by poornaMoksha, Sep 29, 2011.

  1. poornaMoksha

    poornaMoksha New Member

    Joined:
    Jan 29, 2011
    Messages:
    150
    Likes Received:
    33
    Trophy Points:
    0
    Occupation:
    Software developer
    Location:
    India
    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 :
    1. 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'.
    2. 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.
    3. 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
      
          ...
      
      };
    4. To remove a file from /proc, use the 'remove_proc_entry' function.
    5. We have declared/defined two functions 'my_read' and 'my_write' that get called when proc file is read and written to respectively.
    6. 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.
    7. To solve the above problem we use the function 'copy_from_user'
    8. 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!!!!!
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice