En muchos ejemplos previos, tuvimos que codificar algo en el módulo del núcleo, tal como el nombre del fichero para los ficheros /proc o el número mayor del dispositivo para el dispositivo para que pudiéramos hacer ioctls en él. Esto va en contra de la filosofía de Unix, y Linux, que es escribir un programa flexible que el usuario pueda configurar.
La forma de decirle a un programa, o a un módulo del núcleo, algo que necesitan antes de empezar a trabajar es mediante los parámetros de la línea de órdenes. En el caso de los módulos del núcleo, no disponemos de argc y argv; en cambio tenemos algo mejor. Podemos definir variables globales en el módulo del núcleo e insmod las rellenará por nosotros.
En este módulo del núcleo definimos dos de ellas: str1 y str2. Todo lo que necesitas hacer es compilar el módulo del núcleo y entonces ejecutar insmod str1=xxx str2=yyy. Cuando se llama a init_module, str1 apuntará a la cadena de caracteres `xxx' y str2 a la cadena de caracteres `yyy'.
En la versión 2.0 no hay comprobación de tipos de estos argumentos6.1. Si el primer carácter de str1 o str2 es un dígito, el núcleo rellenará la variable con el valor del entero, en vez de con un puntero a la cadena de caracteres. En una situación de la vida real tienes que verificar esto.
En cambio, en la versión 2.2 usas la macro MACRO_PARM para decir a insmod lo que esperas como parámetros, su nombre y su tipo. Esto resuelve el problema de los tipos y permite a los módulos del núcleo recibir cadenas de caracteres que empiezan con un dígito, por ejemplo.
/* param.c * * Recibe en linea de comandos los parámetros en la instalación del módulo */ /* Copyright (C) 1998-99 by Ori Pomerantz */ /* Los ficheros de cabeceras necesarios */ /* Estándar en los módulos del núcleo */ #include <linux/kernel.h> /* Estamos haciendo trabajo del núcleo */ #include <linux/module.h> /* Específicamente, un módulo */ /* Distribuido con CONFIG_MODVERSIONS */ #if CONFIG_MODVERSIONS==1 #define MODVERSIONS #include <linux/modversions.h> #endif #include <stdio.h> /* Necesito NULL */ /* En 2.2.3 /usr/include/linux/version.h se incluye * una macro para esto, pero 2.0.35 no lo hace - por lo * tanto lo añado aquí si es necesario */ #ifndef KERNEL_VERSION #define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c)) #endif /* Emmanuel Papirakis: * * Los nombres de parámetros son ahora (2.2) * manejados en una macro. * El núcleo no resuelve los nombres de los * símbolos como parecía que tenía que hacer. * * Para pasar parámetros a un módulo, tienes que usar una macro * definida en include/linux/modules.h (linea 176). * La macro coge dos parámetros. El nombre del parámetro y * su tipo. El tipo es una letra entre comillas. * Por ejemplo, "i" debería de ser un entero y "s" debería * de ser una cadena de caracteres. */ char *str1, *str2; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) MODULE_PARM(str1, "s"); MODULE_PARM(str2, "s"); #endif /* Inicializa el módulo - muestra los parámetros */ int init_module() { if (str1 == NULL || str2 == NULL) { printk("La próxima vez, haz insmod param str1=<algo>"); printk("str2=<algo>\n"); } else printk("Cadenas de caracteres:%s y %s\n", str1, str2); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) printk("Si intentas hacer insmod a este módulo dos veces,"); printk("(sin borrar antes (rmmod)\n"); printk("al primero), quizás obtengas el mensaje"); printk("de error:\n"); printk("'el símbolo para el parámetro str1 no ha sido encontrado'.\n"); #endif return 0; } /* Limpieza */ void cleanup_module() { }