MarioDebian, mi devlog

Bitácora de un desarrollador newbie.

Gestión de dispositivos extraíbles en MultiSeat
Hacía tiempo que programar me aburre (según que cosas claro) pero el fin de semana pasado me lo he vuelto a pasar como un niño escribiendo código.
 
Problema:
 
En la Consejería de Educación de la Comunidad de Madrid han empezado a usar un nuevo invento llamado Multiseat (Microsoft lo llama Multipoint) que consiste en unos pequeños aparatos que de una forma lógica vienen a ser un HUB USB que contiene una tarjeta de vídeo, una tarjeta de sonido, y 4 puertos USB, si conectamos varios (pongamos seis) en un equipo automáticamente multiplicamos los puestos disponibles en ese equipo (por USB conectamos un teclado y un ratón a cada Multiseat) (puedes ver algún detalle más en la web de Thinetic Systems)
 
El cómo hicimos andar todo este montaje es otra historia que algún día contaré, pero lo que hoy nos centra es un pequeño problema, y es la gestión de los dispositivos de almacenamiento que se conectan a los puertos USB del Multiseat, para que todos lo entendamos, cuando conectamos una memoria USB se conecta físicamente al servidor (con un HUB USB por el medio) y teníamos que inventar una manera de que sólo pudiera verlo/usarlo el usuario sentado directamente en ese puesto. Ya os adelanto que en Microsoft aún no lo han conseguido (que yo sepa).
 
Solución:
 
En los sistemas basados en Linux durante los últimos años se han venido usando distintas soluciones para el automontaje de discos extraibles (usbmount, HAL, DeviceKit), ahora estamos en la era de UDisk. Es un software que se conecta al gestor de dispositivos del kernel (udev) mediante unas reglas (/lib/udev/rules.d/80-udisks.rules) y crea un bus de sistema (en dbus) donde expone todo lo que encuentra, así las aplicaciones que quieran gestionar un dispositivo sólo tienen que escuchar esos eventos.
 
UDisks permite inhibir el montaje (sigue reconociendo lo que enchufamos pero advierte en dbus que está inhibido y no realiza ninguna acción) por lo que no se montan los dispositivos automáticamente, a este inhibidor se le puede pasar un comando que cuando termine deje de inhibir... un ejemplo de uso práctico es el asistente de instalación gráfico que usa Ubuntu (ubiquity) y que inhibe el montaje de dispositivos (por razones obvias) durante la modificación de particiones y la instalación.
 
Nuestra primera aplicación a desarrollar es un demonio que se conecte al bus del sistema, escuche los dispositivos que se conectan y desconectan, leemos sus propiedades y a partir de ellas adivinamos (por el DEVPATH) en que puesto Multiseat se ha conectado para entonces montarlo con privilegios exclusivos para ese usuario y crearle un icono en el escritorio para que pueda desmontarlo. Este demonio decidí programarlo en python y lo bauticé como multiseat-udisks.py se ejecuta cuando (al arranque) encuentra los puestos MultiSeat (subcarpetas en /dev/usbseat)
 
Ya tenemos solucionado que los dispositivos de almacenamiento se automonten en su sitio y con sus permisos, ahora viene cuando el usuario quiere extraerlo, GNOME crea un icono en el escritorio con nuestro pendrive, realmente no es un archivo y con el inhibidor por el medio no lo va a crear por lo que modifiqué multiseat-udisks.py para que crease un lanzador *.desktop especial con la línea mágica «X-multiseat-desktop=x» siendo x el puesto donde esta montado (subcarpeta de /dev/usbseat ).
 
Para desmontar tenemos dos problemas, primero el usuario no es root y como el dispositivo no está en fstab no le va a dejar desmontarlo, y segundo ese icono del escritorio nos permite abrir el contenido del dispositivo de memoria pero no extraerlo de manera segura (sync && umount) lo primero que se me ocurrió es hacer una extensión para Nautilus (gestor de archivos de GNOME) para que cuando se haga click derecho sobre un archivo *.desktop busque la línea mágica y, si existe, añada una entrada a ese menú derecho del tipo «Desmontar dispositivo extraíble multiseat», cuando se pulse sobre esa opción se llama al proceso de desmontar. Esta extensión (también escrita en Python) la bauticé como nautilus-umount-multiseat.py 
 
Para el problema de los privilegios tuve que programar la tercera ficha de este puzle, una pequeña aplicación en C (instalada con bit SUID) y que eleva privilegios a root para llamar al comando de desmontaje umount.multiseat.c. Muchas aplicaciones de montar y desmontar (instaladas en /sbin) van con el BIT SUID por lo que me parece una manera bastante estandar de hacerlo y más teniendo en cuenta que los usuarios que usan MultiSeat pueden estar en un LDAP.
 
Cuando la extensión de Nautilus detecta que el icono es de un dispositivo conectado a un Multiseat, llama a esta aplicación que eleva los privilegios a root (mediante setuid(0) ) y llama a multiseat-udisks.py con 2 argumentos, el primero es el dispositivo montado (ejemplo: /dev/sdc1 ) y el segundo que se genera dentro del programa C es el UID (identificador numérico del usuario que quiere desmontarlo). El script multiseat-udisks hace una serie de comprobaciones para que los parámetros sean correctos y que el usuario pueda desmontar ese dispositivo (que el punto de montaje le pertenezca) lo desmonta y limpia tanto la carpeta donde se ha montado como el icono del escritorio.
 
El sistema lo hemos probado en varias instalaciones y funciona a la perfección, más tarde convertí el código en paquete *.deb y a instalar en los centros...
 
El motivo por el que me he vuelto a divertir programando es que nadie había hecho algo del estilo y la documentación que podía buscar por internet solo se centraba en el uso de cada herramienta o API por separado por lo que el desarrollo ha sido desde cero hasta algo terminado y funcionando.
 
Siento el tostón técnico pero a algunos nos gusta contar nuestras frikadas Tongue out




Compilando rsync en Android

Hace muy pocos días que he aterrizado en el mundo de android pero creo que voy avanzando poco a poco. Voy a publicar una minireceta de como compilar utilidades linux (sencillas) nativamente en Android. Antes de empezar sería bueno recordar que los binarios de Android se compilan para arquitectura ARM por lo que o usamos un emulador (tipo qemu) o un toolchain. Yo he usado el toolchain para compilar nativamente, con el emulador deberíamos compilar en estático y el binario ocupará bastante más. Vamos por pasos:

1.- Descargar el git de android, viene muy bien explicado aquí. Yo lo he descargado en mi $HOME/toolchain.

mkdir ~/toolchain
cd toolchain
wget http://android.git.kernel.org/repo
chmod +x repo
./repo init -u git://android.git.kernel.org/platform/manifest.git
./repo sync

2.- Hora de tomarse algo, descarga la friolera de 2.1 GiB, seguimos, hay que compilar la parte base (librerías)

make BUILD_TINY_ANDROID=true

3.- Tarda otro buen ratillo, ahora compilamos la parte oprofile (lo he compilado aquí porque así tenía a mano los includes de popt.h que son los únicos que he necesitado), cargamos el entorno de ayuda y compilamos el directorio actual y subdirectorios con "mm":

cd external/oprofile
. ../../build/envsetup.sh
mm 

4.- Ahora descargamos las fuentes de rsync (pueden valer las de Debian)

dget -u http://ftp.uk.debian.org/debian/pool/main/r/rsync/rsync_3.0.6-1.dsc
cd rsync-3.0.6

5.- La parte que más me ha costado ha sido entender los Makefile de Android que se llaman Android.mk. Este es mi Android.mk para rsync:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
flist.c\
rsync.c\
generator.c\
receiver.c\
cleanup.c\
sender.c\
exclude.c\
util.c\
main.c\
checksum.c\
match.c\
syscall.c\
log.c\
backup.c\
options.c\
io.c\
compat.c\
hlink.c\
token.c\
uidlist.c\
socket.c\
hashtable.c\
fileio.c\
batch.c\
clientname.c\
chmod.c\
acls.c\
xattrs.c\
progress.c\
pipe.c\
params.c\
loadparm.c\
clientserver.c\
access.c\
connection.c\
authenticate.c\
lib/wildmatch.c\
lib/compat.c\
lib/snprintf.c\
lib/mdfour.c\
lib/md5.c\
lib/permstring.c\
lib/pool_alloc.c\
lib/sysacls.c\
lib/sysxattrs.c\
zlib/deflate.c\
zlib/inffast.c\
zlib/inflate.c\
zlib/inftrees.c\
zlib/trees.c\
zlib/zutil.c\
zlib/adler32.c\
zlib/compress.c\
zlib/crc32.c
LOCAL_SRC_FILES += netbsd_getpass.c
LOCAL_STATIC_LIBRARIES := \
libpopt
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/.. \
$(LOCAL_PATH)/../libdb \
$(LOCAL_PATH)/../libutil \
$(LOCAL_PATH)/../libop \
$(LOCAL_PATH)/../libabi
LOCAL_MODULE := rsync
include $(BUILD_EXECUTABLE)

El archivo netbsd_getpass.c lo he tomado de ~/toolchain/external/dropbear/netbsd_getpass.c ya que Android no debe tener la rutina getpass(), sólo se usa si la rutina getpassf() de rsync nativa falla.

6.- A compilar toca, sólo hay que ejecutar "mm" dentro del directorio rsync-3.0.6 y si todo va bien veremos al final:

target Executable: rsync (out/target/product/generic/obj/EXECUTABLES/rsync_intermediates/LINKED/rsync)
target Non-prelinked: rsync (out/target/product/generic/symbols/system/bin/rsync)
target Strip: rsync (out/target/product/generic/obj/EXECUTABLES/rsync_intermediates/rsync)
Install: out/target/product/generic/system/bin/rsync
make: se sale del directorio `/home/mario/toolchain'

7.- Para copiarlo al móvil (conectar el cable USB y activar el modo depuración USB en las preferencias)Necesitamos el SDK de Android.

cd ~/sdk/tools
sudo ./adb kill-server
sudo ./adb remount
sudo ./adb push ~/toolchain/out/target/product/generic/system/bin/rsync /system/bin
sudo ./adb shell chmod 755 /system/bin

Ya podemos abrir el terminal desde android (o desde adb shell) y ejecutar rsync para ver si se copio bien.

Se me ocurren miles de cosas sencillas (GScript + rsync) para tener las fotos publicadas en un blog, hacer copias de seguridad remotas (incrementales) o incluso usarlo para descargar contenido pudiendo perder la conexión temporalmente.

Rizando el rizo, estaría guapo hacer un pequeño frontend con las opciones más usadas y llamarlo desde una aplicación APK.

Como próximo objectivo compilar alguna otra cosa que hecho en falta (¿git? etc...)





Qué pequeño es el mundo.

Uno (que humildemente aún se cree desarrollador newbie) programa cuatro líneas (para más "inri", aprendiedo a programar mientras tecleaba) y de casualidad va viendo pedacitos de su código en otros proyectos...

 

¿En esto consiste el Software Libre no? Cool

Este Makefile [baifox] se parece mucho a éste [tcosphpmonitor].

Pero ya la prueba irrefutable: debian/postrm [baifox] debian/postrm[tcosphpmonitor]

 





Squid 3.0 con soporte a X_FORWARDED_FOR

Cuando se mezcla Dansguardian con Squid en un proxy transparente existen ciertos inconvenientes que es bueno conocer.

  1. Dansguardian escucha las peticiones de la red interna en el puerto 8080, con iptables redirigimos todo el tráfico de salida a este puerto.
  2. Dansguardian pasa su petición a Squid por localhost al puerto 3128.
  3. Squid hace la petición y dansguardian la procesa.

Esto tiene un inconveniente y es que todas reglas acl o delay_pool en squid dejan de trabajar ya que todo el tráfico usa como IP cliente 127.0.0.1.

Existe un parche relativamente antiguo llamado follow_xff (pensado para versiones 2.x) que he reescrito en parte para que Squid3 use la cabecera X_FORWARDED_FOR. El parche se guarda en debian/patches en formato dpatch. Me falta el detalle de que no muestre un mensaje de no reconocer las nuevas reglas, porque funcionar sí lo hace.

Parece que en Debian (#523943) estaba activado, pero solo era un modificador de debian/rules, no había ni rastro de código y también parece que se ha añadido a Squid a partir de la versión 3.1.0.1.

He preparado un repositorio GIT de squid para compilarlo en Debian lenny con el parche y un simple «git-buildpackage».





Marketing bluetooth por proximidad: python-thinblue

ThinBlue es una aplicación desarrollada en python que envía archivos mediante el protocolo OBEX a dispositivos móviles (teléfonos por ejemplo).

Desde Thinetic Systems (empresa en la que trabajo) hemos liberado una primera versión (funcional, aunque beta) de esta aplicación bajo la licencia GPL2.

De momento tenemos un repositorio GIT con el código y en breve publicaremos paquetes *.deb para las versiones más usadas de Debian y Ubuntu.

Tienes más información en la noticia de nuestra web: ThinBlue, aplicación bluetooth para marketing por proximidad.

Una de las cosas más chulas ha sido desarrollar el panel de administración con el framework web: web.py , de hecho sin contar javascript, html o css son apenas 300 líneas.

A disfrutarla Wink





Mi regalo de reyes, nuevo interfaz de TcosDevicesNG

Hacer que algo simple y poco práctico:

 

 

Pase a ser algo como esto:

 

 

A falta de pulir un poco como se coloca el texto en la columna central creo que el tema ha mejorado bastante...

Disponible desde ya en el SVN.

Tengo que reconocer que me he inspirado gráficamente en Ejecter, aunque sólo en el aspecto, esto es una ventana gtk.Window() en modo popup y con detección de posición cada vez que aparece, de hecho el cambio para hacer que esto funcione sobre tcos-devices-ng.py es una sóla línea, y una nueva clase con los mismos métodos que la vieja.

Felices reyes y sed buenos Laughing




Hace un año: Nueva versión MaX 3.1

Análisis gráfico del arranque de TCOS

Supongo que muchos conocereis el paquete bootchart, que reemplazando a init guarda un registro del arranque del equipo para luego generar unas gráficas bastante chulas.

Pues bien, hasta ahora bootchart sólo trabajaba (que yo sepa) desde el mismo proceso init de la partición de nuestro linux y no había manera de lanzarlo desde el INITRAMFS... con un poco de «hacking» y mucho borrar código que no necesitaba he hecho un tcos-bootchartd para analizar el arranque de TCOS.

La víctima es un terminal ligero eTC3800 y este es el gráfico (pulsar para ver más grande):

Al tiempo total (47 segundos) hay que restar 2 segundos metidos a propósito para que se vean los últimos procesos antes de parar bootchartd.

Conclusiones:

  • La descarga del squashfs es lo que más tiempo tarda (14 segundos) Embarassed
  • Gracias a bootchart he quitado un par de «sleep» que sobraban Tongue out
  • Gracias a bootchart he visto que el sistema de registro de dipositivos que se inyecta en udev (tcos-udev.sh) perdía mucho tiempo cuando aún no es útil por lo que se activa casi al final. Surprised
  • «ldconfig» tarda casi 2 segundos... quizás se pueda mejorar ejecutándolo cuando se genera la imagen con «chroot ldconfig»
  • El arranque tiene picos de 100% CPU sostenidos con udev y Xorg (algo relativamente lógico)
Hace un tiempo el arranque no bajaba de 1 minuto, tener un arranque usable (el terminal muestra GDM antes de los 44) ha sido todo un logro y gracias a bootchart podré saber donde se pierde ese tiempo tan precioso.

Luego lo subo al SVN por si alguien quiere probarlo.



¿Qué es Thinetic Systems?

 

Thinetic Systems





¿Cómo borrar de forma segura un disco duro?
Hoy después de escribir unos datos importantes en un disco duro que me han prestado, tenía que borralo para que el dueño no pudiese acceder a mi privacidad.

Así que con el borrador magnético de alta tecnología marca ACME, creo que no ha quedado ni rastro.




II Jornadas de Software Libre y Comunicaciones de Fuerteventura (gnumax'07)
Desde hace unos días se ha abierto el plazo para presentación de ponencias y comunicaciones para las II Jornadas de Software Libre y Comunicaciones de Fuerteventura que tendrán lugar el 13 y 14 de abril en esa paradisiaca isla de las Canarias.



Aún recuerdo las I Jornadas [1] [2] [3] a las que tuve el honor de ser invitado y en donde conocí mucha gente que han pasado a ser muy buenos amigos.

Corren rumores, y no debería decir mucho más, que este año el cartel de las ponencias superará las de las anteriores y que los que asistan sin duda no se arrepentirán.

Voy preparando mi pequeño resumen para ver si este año volvemos por allí... ¿de que voy a hablar? pues yo creo que está claro, ¿o no?



Hace un año: Cambiando el mundo

1 2 3 4 5 6  Siguiente»