Go4Expert

Go4Expert (http://www.go4expert.com/)
-   Linux (http://www.go4expert.com/articles/linux/)
-   -   Programming with Linux proc files (http://www.go4expert.com/articles/programming-linux-proc-files-t26815/)

poornaMoksha 29Sep2011 23:45

Programming with Linux proc files
 
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!!!!!


All times are GMT +5.5. The time now is 16:07.