sábado, 21 de marzo de 2009

El targetfs de un sistema embedded

Un sistema embedded es un sistema informático de bajo coste, y de propósito general, que corre sobre una plataforma hardware con recursos generalmente escasos. El hecho de que los recursos hardware escaseen en el sistema embedded, plantea problemas nuevos al ingeniero de software generalmente acostumbrado a trabajar con un ordenador de sobremesa. Imagina por un momento que tuvieras que instalar una distribución de Linux de las tipicas (Ubuntu, Fedora, Suse, etc.) en un disco duro de solo 4MB. Una distribucion Debian tipica minima (excluyendo el kernel) ocupa unos 40MB, demasiado para nuestro sistema embedded. Necesitas una alternativa bastante mas ligera.

El objetivo de este post es generar un targetfs para el sistema embedded que tenga disponibles todas las aplicaciones del user-space necesarias para manejar tu dispositivo embedded (target). Para ello usaremos la herramienta busybox.



Su manual (man) lo define como "The Swiss Army Knife of Embedded Linux", algo asi como "la navaja suiza de los Linux embedded". Busybox es un único binario que combina pequeñas versiones de los distintos comandos basicos de un sistema Linux. En terminologia busybox, cada comando basico es un "applet". La lista de los 107 applets incluidos no tiene desperdicio:

addgroup, adduser, adjtimex, ar, arping, ash, awk, basename, bunzip2,
busybox, bzcat, cal, cat, chgrp, chmod, chown, chroot, chvt, clear, cmp,
cp, cpio, crond, crontab, cut, date, dc, dd, deallocvt, delgroup, deluser,
devfsd, df, dirname, dmesg, dos2unix, dpkg, dpkg-deb, du, dumpkmap,
dumpleases, echo, egrep, env, expr, false, fbset, fdflush, fdformat, fdisk,
fgrep, find, fold, free, freeramdisk, fsck.minix, ftpget, ftpput, getopt,
getty, grep, gunzip, gzip, halt, hdparm, head, hexdump, hostid, hostname,
httpd, hush, hwclock, id, ifconfig, ifdown, ifup, inetd, init, insmod,
install, ip, ipaddr, ipcalc, iplink, iproute, iptunnel, kill, killall,
klogd, lash, last, length, linuxrc, ln, loadfont, loadkmap, logger, login,
logname, logread, losetup, ls, lsmod, makedevs, md5sum, mesg, mkdir,
mkfifo, mkfs.minix, mknod, mkswap, mktemp, modprobe, more, mount, msh, mt,
mv, nameif, nc, netstat, nslookup, od, openvt, passwd, patch, pidof, ping,
ping6, pipe_progress, pivot_root, poweroff, printf, ps, pwd, rdate,
readlink, realpath, reboot, renice, reset, rm, rmdir, rmmod, route, rpm,
rpm2cpio, run-parts, rx, sed, seq, setkeycodes, sha1sum, sleep, sort,
start-stop-daemon, strings, stty, su, sulogin, swapoff, swapon, sync,
sysctl, syslogd, tail, tar, tee, telnet, telnetd, test, tftp, time, top,
touch, tr, traceroute, true, tty, udhcpc, udhcpd, umount, uname,
uncompress, uniq, unix2dos, unzip, uptime, usleep, uudecode, uuencode,
vconfig, vi, vlock, watch, watchdog, wc, wget, which, who, whoami, xargs,
yes, zcat

Busybox funciona usando argv[0] para determinar el applet que debe invocar. Al renombrar el binario de busybox con el nombre de un applet determinado, se ejecuta dicho applet. Sin embargo esto no es practico. El truco que usa busybox es tener un único binario llamado "busybox" y tener un enlace (link) simbólico distinto por cada applet apuntando al binario de busybox. Asi por ejemplo:
$ ls -l /bin
-rwxr-xr-x 1 0 0 272800 busybox
lrwxrwxrwx 1 0 0 12 sh -> busybox
lrwxrwxrwx 1 0 0 12 cp -> busybox
lrwxrwxrwx 1 0 0 12 ls -> busybox

Para crear los enlaces simbólicos, se usa el comando ln:
$ ln -fs busybox sh
$ ln -fs busybox cp
$ ln -fs busybox ls

Así por ejemplo, para ejecutar un listado largo usando el applet ls, hacemos:
$ /bin/ls -l

donde /bin/ls es en realidad un link apuntando al binario busybox.

Para compilar busybox, hay que descargar los fuentes, preferiblemente del sitio oficial http://www.busybox.net/downloads/. Para obtener los fuentes de la versión 1.9.0 y extraer su contenido, hacemos esto:
$ cd /usr/src
$ wget http://www.busybox.net/downloads/busybox-1.9.0.tar.gz
$ tar xvfz busybox-1.9.0.tar.gz

Durante el proceso de configuración de la compilación de busybox, el usuario decide los applets que integra el binario resultante una vez compilado. Para ello, busybox emplea un método similar al de la compilación del kernel de Linux (.config), pudiendo usar varias opciones:
$ make allnoconfig
$ make oldconfig
$ make menuconfig

Para realizar la compilación, basta con ejecutar el comando make, igual que se hace con el kernel de Linux, y el binario resultante aparece en la raiz de los fuentes:
$ make

Despues de un buen rato esperando, tendras compilado tu busybox.

Retomando el objetivo inicial de este post, nos interesa generar un targetfs para el dispositivo embedded. Para ello crea una partición de 4MB en un fichero de tu disco duro (por ejemplo targetfs4M.img) y crear un sistema de ficheros en su interior (por ejemplo, formatealo con EXT2).
$ dd if=/dev/zero of=targetfs4M.img bs=1M count=8
$ mkfs.ext2 -F targetfs4M.img

Despues monta la partición de 4MB recien creada (targetfs4M.img) en el sistema de ficheros de tu ordenador de sobremesa, por ejemplo en el directorio /media/removable.
$ mount -o loop targetfs4M.img /media/removable

Por ultimo instala el binario de busybox en el targetfs de tu sistema embedded:
$ make install CONFIG_PREFIX=/media/removable

La instalación copia el binario del busybox en /media/removable (en la partición de 4MB montada en ese directorio) y crea en su interior todos los enlaces simbólicos a los applets configurados y compilados dentro del directorio de compilación.

Con esto ya tienes un targetfs básico para tu sistema embedded. No estará completo porque deberás añadir la aplicación que deba correr tu sistema embedded, pero ya dispones de un buen punto de partida para empezar a jugar con tu sistema. Ah! Y no olvides hacer un sync y desmontar /media/removable antes de hacer nada mas con esa partición!

Visitas:

Seguidores