Capítulo 5. Ejemplo

Para compilar este módulo utiliza:

gcc -I/usr/src/linux-2.4/include -Wall -DMODULE -D__KERNEL__ -DLINUX -c ejemplo_procfs.c


/*
 * ejemplo_procfs.c: un ejemplo de la interface proc
 *
 * Copyright (C) 2001, Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
 *
 * Este archivo acompaña la guía de procfs en el código del 
 * núcleo Linux. Su uso principal es demostrar los conceptos y
 * funciones descritas en la guía.
 *
 * Este software ha sido desarrollado mientras se trabajaba en
 * el LART computing board (http://www.lart.tudelft.nl/), que
 * está patrocinado por los proyectos Mobile Multi-media 
 * Communications (http://www.mmc.tudelft.nl/) y Ubiquitous 
 * Communications (http://www.ubicom.tudelft.nl/).
 *
 * El autor puede ser encontrado en:
 *
 *  Erik Mouw
 *  Information and Communication Theory Group
 *  Faculty of Information Technology and Systems
 *  Delft University of Technology
 *  P.O. Box 5031
 *  2600 GA Delft
 *  The Netherlands
 *
 *
 * Este programa es software libre; puedes redistribuirlo
 * y/o modificarlo bajo los términos de la GNU General
 * Public License tal como ha sido publicada por la Free 
 * Software Foundation; por la versión 2 de la Licencia, 
 * o (a tu elección) cualquier versión posterior.
 *
 * Este programa es distribuido con la esperanza de que 
 * sea útil, pero SIN NINGUNA GARANTÍA; sin incluso la 
 * implicada de COMERCIABILIDAD o ADECUACCION PARA UN 
 * PROPOSITO PARTICULAR. Para más detalles refiérase a la 
 * GNU General Public License.
 *
 * Deberías de haber recibido una copia de la GNU General 
 * Public License con este programa; si no es así, escribe a
 * Free Software Foundation, Inc., 59 Temple Place,
 * Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <asm/uaccess.h>


#define MODULE_VERSION "1.0"
#define MODULE_NAME "ejemplo_procfs"

#define FOOBAR_LEN 8

struct fb_data_t {
        char name[FOOBAR_LEN + 1];
        char value[FOOBAR_LEN + 1];
};


static struct proc_dir_entry *example_dir, *foo_file,
        *bar_file, *jiffies_file, *tty_device, *symlink;


struct fb_data_t foo_data, bar_data;


static int proc_read_jiffies(char *page, char **start,
                             off_t off, int count,
                             int *eof, void *data)
{
        int len;

        MOD_INC_USE_COUNT;
        
        len = sprintf(page, "jiffies = %ld\n",
                      jiffies);

        MOD_DEC_USE_COUNT;

        return len;
}


static int proc_read_foobar(char *page, char **start,
                            off_t off, int count, 
                            int *eof, void *data)
{
        int len;
        struct fb_data_t *fb_data = (struct fb_data_t *)data;

        MOD_INC_USE_COUNT;
        
        len = sprintf(page, "%s = '%s'\n", 
                      fb_data->name, fb_data->value);

        MOD_DEC_USE_COUNT;

        return len;
}


static int proc_write_foobar(struct file *file,
                             const char *buffer,
                             unsigned long count, 
                             void *data)
{
        int len;
        struct fb_data_t *fb_data = (struct fb_data_t *)data;

        MOD_INC_USE_COUNT;

        if(count > FOOBAR_LEN)
                len = FOOBAR_LEN;
        else
                len = count;

        if(copy_from_user(fb_data->value, buffer, len)) {
                MOD_DEC_USE_COUNT;
                return -EFAULT;
        }

        fb_data->value[len] = '\0';

        MOD_DEC_USE_COUNT;

        return len;
}


static int __init init_procfs_example(void)
{
        int rv = 0;

        /* crea directorio */
        example_dir = proc_mkdir(MODULE_NAME, NULL);
        if(example_dir == NULL) {
                rv = -ENOMEM;
                goto out;
        }
        
        example_dir->owner = THIS_MODULE;
        
        /* crea jiffies usando la función conveniente */
        jiffies_file = create_proc_read_entry("jiffies", 
                                              0444, example_dir, 
                                              proc_read_jiffies,
                                              NULL);
        if(jiffies_file == NULL) {
                rv  = -ENOMEM;
                goto no_jiffies;
        }

        jiffies_file->owner = THIS_MODULE;

        /* crea los archivos foo y bar usando las mismas
         * funciones de retrollamada
         */
        foo_file = create_proc_entry("foo", 0644, example_dir);
        if(foo_file == NULL) {
                rv = -ENOMEM;
                goto no_foo;
        }

        strcpy(foo_data.name, "foo");
        strcpy(foo_data.value, "foo");
        foo_file->data = &foo_data;
        foo_file->read_proc = proc_read_foobar;
        foo_file->write_proc = proc_write_foobar;
        foo_file->owner = THIS_MODULE;
                
        bar_file = create_proc_entry("bar", 0644, example_dir);
        if(bar_file == NULL) {
                rv = -ENOMEM;
                goto no_bar;
        }

        strcpy(bar_data.name, "bar");
        strcpy(bar_data.value, "bar");
        bar_file->data = &bar_data;
        bar_file->read_proc = proc_read_foobar;
        bar_file->write_proc = proc_write_foobar;
        bar_file->owner = THIS_MODULE;
                
        /* crea dispositivo tty */
        tty_device = proc_mknod("tty", S_IFCHR | 0666,
                                example_dir, MKDEV(5, 0));
        if(tty_device == NULL) {
                rv = -ENOMEM;
                goto no_tty;
        }
        
        tty_device->owner = THIS_MODULE;

        /* crea enlace simbólico */
        symlink = proc_symlink("tambien_jiffies", example_dir, 
                               "jiffies");
        if(symlink == NULL) {
                rv = -ENOMEM;
                goto no_symlink;
        }

        symlink->owner = THIS_MODULE;

        /* todo está OK */
        printk(KERN_INFO "%s %s inicializado\n",
               MODULE_NAME, MODULE_VERSION);
        return 0;

no_symlink:
        remove_proc_entry("tty", example_dir);
no_tty:
        remove_proc_entry("bar", example_dir);
no_bar:
        remove_proc_entry("foo", example_dir);
no_foo:
        remove_proc_entry("jiffies", example_dir);
no_jiffies:                           
        remove_proc_entry(MODULE_NAME, NULL);
out:
        return rv;
}


static void __exit cleanup_procfs_example(void)
{
        remove_proc_entry("tambien_jiffies", example_dir);
        remove_proc_entry("tty", example_dir);
        remove_proc_entry("bar", example_dir);
        remove_proc_entry("foo", example_dir);
        remove_proc_entry("jiffies", example_dir);
        remove_proc_entry(MODULE_NAME, NULL);

        printk(KERN_INFO "%s %s borrado\n",
               MODULE_NAME, MODULE_VERSION);
}


module_init(init_procfs_example);
module_exit(cleanup_procfs_example);

MODULE_AUTHOR("Erik Mouw");
MODULE_DESCRIPTION("ejemplos procfs");

EXPORT_NO_SYMBOLS;