PFG – Control remoto de la Raspberry PI mediante CGI
CGI es una tecnología que permite a un cliente solicitar datos de un programa ejecutado en un servidor web. Nos va a ser útil al permitirnos ejecutar programas alojados en la Raspberry Pi desde un navegador e incluso desde un terminal Android.
Para ello, en primer lugar instalamos Apache en la Raspberry Pi
> pacman -S apache
y hacemos que su demonio se ejecute automáticamente al iniciar el equipo
> systemctl enable httpd
Configuración de Apache
Vamos a repasar las líneas más significativas del fichero de configuración por defecto de Apache, localizado en /etc/httpd/conf/httpd.conf
ServerRoot "/etc/httpd" #Los ficheros de configuración se almacenan en este directorio. Listen 80 #El servidor escuchará las peticiones que reciba por el puerto 80. Todo correcto. LoadModule cgi_module modules/mod_cgi.so #Es muy importante descomentar esta línea. En caso contrario los script CGI que escribamos no se podrán ejecutar. User http Group http # El usuario que atenderá y resolverá las peticiones que reciba Apache. Nos afectará más adelante. <Directory /> AllowOverride none Require all denied </Directory> # Todas las peticiones recibidas se deniegan por defecto, excepto para los casos definidos a continuación. DocumentRoot "/srv/http" <Directory "/srv/http"> Options Indexes FollowSymLinks AllowOverride None Require all granted </Directory> # Fijamos el directorio principal a la carpeta /srv/http, lo cual significa que cuando nos dirijamos a http://domain.com/index.html estaremos abriendo el archivo index.html ubicado en esa carpeta. Además se le indica a Apache que atienda las peticiones que lleguen a esa ruta. ScriptAlias /cgi-bin/ "/srv/http/cgi-bin/" #Esta línea establece un alias a la carpeta donde almacenaremos los scripts en CGI y les da permisos de ejecución, necesarios para funcionar. <Directory "/srv/http/cgi-bin"> Options None AllowOverride None Require all granted </Directory> # De nuevo, damos la orden de atender las peticiones llegadas a este directorio.
Es importante que los archivos CGI que queramos que se ejecuten tengan permisos de ejecución para el usuario http, y además la ruta en la que se encuentre también tenga permisos de ejecución. En mi caso ha sido necesario darle permisos al directorio raíz /, en caso contrario al ejecutar un script recibía un error 403 forbidden.
A continuación realizamos la prueba escribiendo un pequeño script CGI en C que muestre un texto en el navegador.
#include <stdio.h> int main() { printf("Content-Type: text/html\n\n"); printf("Hello world"); return 0; }
Lo compilamos con gcc, le damos permisos de ejecución y vemos el resultado
Funciona correctamente, por lo que podemos pasar al siguiente nivel.
Adaptando nuestro programa i2c.c para ser ejecutado como script CGI
Para que nuestro programa se ejecute correctamente sin dar errores es necesario añadir los headers necesarios para que sea interpretado como html y los printf que realizamos aparezcan en pantalla. Además, se le ha añadido un título de página y se han adaptado los saltos de línea a html. El programa queda así:
#include <stdio.h> #include <stdlib.h> // exit #include <fcntl.h> // open modo O_RDWR #include <linux/i2c-dev.h> #define ADDRESS 0x04 int main() { int file; unsigned char cmd[16]; int enviado = 1; char buff[1]; int recibido; printf("Content-Type: text/html\n\n"); printf("<html>"); printf("<head><title>Test</title></head"); printf("<body>"); printf("I2C: Conectando...<br/>"); if ((file = open("/dev/i2c-0", O_RDWR)) < 0) { printf("I2C: error de acceso"); exit(1); } printf("I2C: Accediendo al dispositivo<br/>"); if (ioctl(file, I2C_SLAVE, ADDRESS) < 0) { printf("I2C: error al acceder al esclavo en 0x%x", ADDRESS); exit(1); } printf("Enviado %d<br/>", enviado); cmd[0] = enviado; if (write(file, cmd, 1) == 1) { usleep(10000); if (read(file, buff, 1) == 1) { recibido = (int) buff[0]; printf("Recibido %d<br/>", recibido); } } printf("I2C: Terminando..."); printf("</html>"); close(file); return (EXIT_SUCCESS); }
Compilamos con gcc:
> gcc i2c.c -o i2c.cgi
Sin embargo, al ejecutarlo obtenemos el siguiente error:
Nuestro programa no puede escribir sobre el dispositivo /dev/i2c-0, y es debido a que el script lo ejecuta el usuario http cuando realizamos la petición, y no tiene privilegios sobre ese dispositivo. Vamos a solucionarlo creando un grupo llamado i2c, añadiendo a dicho grupo los usuarios root y http, y dando permisos de lectura y escritura del fichero /dev/i2c-0 al grupo.
Primero creamos el grupo y añadimos los usuarios:
> groupadd i2c > usermod -a -G i2c http > usermod -a -G i2c root
Modificamos el dueño de la carpeta donde se encuentran los scripts CGI al nuevo grupo:
> chown root:i2c -R /srv/http/cgi-bin/
Y por último modificamos los permisos del dispositivo. Estos permisos los controla el programa udev, y para hacerlos persistentes debemos añadir una nueva regla al programa, creando el fichero /lib/udev/rules.d/60-i2c-tools.rules con el contenido:
KERNEL=="i2c-0", GROUP="i2c", MODE="0660"
Ejecutando ahora:
El LED integrado en la placa Arduino Mega se enciende y apaga correctamente.
Recent Comments