Backup con manzana a las finas unidades externas

Hace unos años, Apple presentó Time Machine, un programa de copia de seguridad que, por fin, hacía no sólo sencillo, sino también divertido, hacer backups regulares de tus datos.

Pronto surgieron varios clones para Linux, tales como Flyback, Time Vault, o el cómodo Dejá Dup, pero ninguno me convencía, así que decidí hacer yo uno propio. Y ya puestos, decidí hacerlo lo más parecido posible al Time Machine original.

El resultado es Cronopete, un clon de Time Machine para Linux. El nombre lo tomé de El anacronópete, una novela de viajes en el tiempo escrita por Enrique Gaspar y Rimbaud ocho años antes de la célebre La máquina del tiempo, de H.G. Wells.

Al igual que el programa original, Cronopete hace una copia completa del disco cada hora, y conserva todas las copias que pueda para poder volver atrás si es necesario y recuperar un documento en cualquier momento de su historia.

Cada copia del árbol de directorios se conserva en una carpeta propia, cuyo nombre es la fecha y hora en que se realizó. También, al igual que el original, copia realmente sólo los archivos que han cambiado, y se limita a hacer un enlace a la copia anterior para aquellos archivos que no han cambiado, lo que permite acelerar el proceso y consumir muchísimo menos disco.

También para ahorrar espacio, las copias se guardan en una progresión exponencial: para las últimas 24 horas se guarda una por cada hora; para el último mes, una copia diaria; y después, una copia semanal hasta que se llena el disco.

También he copiado al milímetro la interfaz. Al lanzar Cronopete, éste aparece de esta manera en la barra de notificaciones, exactamente igual que Time Machine:

Icono principal de Cronopete

Y esta es la interfaz principal:

Interfaz de cronopete

Todavía no tiene la interfaz para restaurar los ficheros de manera «bonita», por lo que para hacerlo hay que ir al disco externo y copiarlos «a mano», aunque dado que los archivos están guardados «tal cual», sin ningún tipo de empaquetado ni compresión, esto no supone ninguna dificultad. Sin embargo, ya estoy investigando la biblioteca clutter para implementarla también.

Las primeras pruebas de Cronopete las había escrito en C, con la intención de usar Python para la interfaz, pero no lo acababa de ver porque necesitaba mucha fiabilidad para un programa de este tipo, así que al final decidí probar Vala. Y, como comenté en su momento, me enamoré: la gestión automática de memoria como en Python es una delicia, y encima tengo el rendimiento y el bajo consumo de recursos de C, además de azúcar sintáctico como para abastecer una pastelería durante un año.

Enlace directo a la página de descargas: Cronopete.

DBus en Vala

Actualizado Estoy trabajando en un nuevo proyecto, escrito íntegramente en Vala, y la verdad es que cuantas más cosas aprendo sobre él, más me gusta.

Lo último que descubrí fue como trabajar con DBus en Vala, y resulta que es extremadamente sencillo y elegante, aunque tuve que investigar bastante hasta encontrar como hacer algunas cosas, pues los ejemplos que vienen en la página tratan de como trabajar con un servidor hecho por uno mismo, cuando yo necesitaba acceder a un servicio del sistema.

Así pues, y sin más dilación, veamos como se puede usar DBus para obtener una lista de los discos duros conectados por USB al ordenador, y como formatearlos.

Lo primero que vemos es que toda esa información la gestiona el demonio UDisk, el cual exporta una serie de funciones y objetos a través de DBus para que cualquier programa pueda acceder a ellos. Si echamos un vistazo a la documentación de la API, vemos que se exporta el método EnumerateDevices, el cual nos devuelve un array de objetos.

¿Y como accedemos a este método del objeto UDisk desde Vala? Pues con este código:

[DBus (name = "org.freedesktop.UDisks")]
interface UDisk_if : GLib.Object {
    public abstract ObjectPath[] EnumerateDevices() throws IOError;
}

UDisk_if udisk = Bus.get_proxy_sync<UDisk_if> (BusType.SYSTEM, "org.freedesktop.UDisks","/org/freedesktop/UDisks");
var retval = udisk.EnumerateDevices();

Aquí vemos que primero definimos una interfaz con todos los métodos a los que vamos a querer acceder (en este caso sólo uno), sacando de la documentación los parámetros y demás, y le añadimos antes una cabecera con el nombre del objeto. Luego, creamos un proxy síncrono, conectándonos a través del bus del sistema (BusType.SYSTEM), al servidor UDisk (org.freedesktop.UDisks) y pedimos acceso al objeto deseado (/org/freedesktop/UDisks). Finalmente, llamamos al método deseado, almacenando el resultado en una nueva variable.

Es importante recalcar que cualquier método que se defina puede emitir, siempre, una excepción de tipo IOError, por lo que siempre se debe añadir al final de la definición la coletilla throws IOError. De no hacerlo se producirá un error de compilación. También comentar que dado que esta función sólo devuelve un parámetro, la he escrito en formato resultado metodo(parametros); sin embargo, también es perfectamente válida la sintaxis void metodo (parametros,…, out resultado). Esta segunda forma es obligatoria cuando un método devuelve más de un resultado. Con esa sintaxis, la interfaz tendría esta forma:

[DBus (name = "org.freedesktop.UDisks")]
interface UDisk_if : GLib.Object {
    public abstract void EnumerateDevices(out ObjectPath[] path) throws IOError;
}

En retval tenemos ahora un array de objetos ObjectPath, cada uno de tipo Device, representando una unidad extraíble. ¿Y ahora, qué? Pues ahora vamos a imprimir el punto de montaje de cada uno de ellos. Si miramos la documentación del objeto Device, vemos que dicha información se almacena como una propiedad, así que definimos nuestra interfaz así:

[DBus (name = "org.freedesktop.UDisks.Device")]
interface Device_if : GLib.Object {
    public abstract string IdLabel { owned get; }
    public abstract string[] DeviceMountPaths { owned get; }

    public abstract void FilesystemUnmount(string[] options) throws IOError;
    public abstract void FilesystemCreate(string type, string[] options) throws IOError;
    public abstract void PartitionModify (string type, string label, string[] options) throws IOError;
    public abstract void FilesystemMount(string type, string[] options, out string mount_path) throws IOError;
}

Ponemos { owned get; } en lugar de {owned get; set; } porque los campos son de sólo lectura. También he añadido los cuatro métodos necesarios para poder formatear una partición, aunque en el ejemplo no los voy a utilizar.

Ahora llega el momento del código que accede a los datos, que es éste:

Device_if device2;
foreach (ObjectPath o in retval) {
    device2 = Bus.get_proxy_sync<Device_if> (BusType.SYSTEM, "org.freedesktop.UDisks",o);
    GLib.stdout.printf("Disco %s montado en:n",device2.IdLabel);
    foreach (string s in device2.DeviceMountPaths) {
        GLib.stdout.printf("    %sn",s);
    }
}

Así, primero recorremos la lista de objetos que obtuvimos con la anterior llamada (en retval), y creamos un proxy síncrono para cada uno de ellos, contra el servidor de UDisk (él es quien nos dio la lista de objetos, por lo que estos tienen que estar en él). Luego imprimimos la etiqueta simplemente leyendo la propiedad del objeto, y por último imprimimos todos los puntos de montaje (una misma partición puede estar montada en varios sitios a la vez).

Actualización: Uno de los problemas que tuve fue que la llamada a FilesystemCreate (que formatea la unidad especificada) tarda varios segundos en ejecutarse, lo que hacía que la GUI se quedase colgada. La primera solución que encontré fue ejecutarla en un thread aparte, y usar espera activa para detectar cuando terminó, pero era muy poco elegante. La solución definitiva consiste en realizar llamadas asíncronas a DBus, explicadas en el tutorial de Vala. La idea consiste en añadir la palabra reservada async en la definición de la función en la clase, con lo que la llamada a DBus será no-bloqueante, y definir un callback anónimo.

[DBus (name = "org.freedesktop.UDisks.Device")]
interface Device_if : GLib.Object {
  [...]
  public abstract async void FilesystemCreate(string type, string[] options) throws IOError;
  [...]
}

  // Llamamos a la función, añadiéndo como último parámetro
  // una función anónima que se ejecutará al terminar la
  // ejecución
  device2.FilesystemCreate.begin(format,options, (obj,res) => {
    try {
      // La llamada a .end recoge los valores devueltos (de haberlos)
      // y dispara cualquier excepción que se haya producido
      device2.FilesystemCreate.end(res);
      return;
    } catch (IOError e) {
      // Captura de excepciones (en este caso, fallo durante el formateo)
    }
  });

Una vez que hemos hecho la llamada, podemos volver al bucle principal de GTK o llamar a la función run() de un cuadro de diálogo, y éste seguirá funcionando en paralelo a la ejecución de nuestra llamada a DBus.

Vuelve Devede

Hace hoy justo un año que lancé la última versión de Devede, así que he decidido que ya era hora de sacar una revisión con los cambios que hice en estos meses. No han sido muchos, pero sí muy necesarios, a la vista de las peticiones en la lista de correos. Además, llevaban una temporada esperando en el repositorio GIT de Devede, así que ya tocaba.

Los cambios, básicamente, se resumen en:

  • Corregido un bug en MKISOFS: en algunas versiones, utiliza una coma en lugar de un punto como separador decimal, lo que confundía a Devede. Ahora admite ambos símbolos.
  • Define la variable VIDEO_FORMAT: este cambio es necesario para las últimas versiones de SPUMUX, que exigen que el tipo de vídeo que se utiliza esté definido en dicha variable, y no sólo en el fichero XML.
  • Añadido workaround para las versiones recientes de Mencoder, mediante el uso de AC3_FIX: las últimas versiones de Mencoder tienen un fallo en la codificación AC3, por lo que es necesario activar esta opción.

Además, se ha creado una ventana de configuración (en Editar -> Configuracion) con parámetros más o menos «fijos», como donde meter los ficheros temporales y demás. De esta forma está todo más organizado.

Ahora, mi objetivo más inmediato es reemplazar Mencoder por FFmeg, para evitar de una vez por todas los cada vez mayores problemas que da este software.

Lanzado EasyWall

Acabo de lanzar un nuevo programa, llamado, en un alarde de originalidad, EasyWall. Como su propio nombre indica, se trata de un firewall que intenta ser lo más sencillo de usar posible. Para ello trae «de fábrica» varias plantillas para multitud de programas, con sus puertos predefinidos. La idea es que si instalas un programa (el aMule, por ejemplo), sólo tienes que ir a EasyWall y activar la casilla «aMule»; y listo.

Por supuesto, si simplemente fuese ésto no sería muy útil, porque muchos programas permiten cambiar sus puertos, además de que si mostramos todos los programas posibles, sería una lista interminable. Por eso, EasyWall incorpora una serie de capacidades extra:

  • Oculta las plantillas de programas que no están instalados. Para ello se puede definir una lista de ficheros en las plantillas, que hacen que si no existe ninguno de ellos, considera que dicho programa no está instalado y no muestra esa opción.
  • Permite definir qué puertos de una plantilla son modificables y cuales no. Así, si un programa tiene un puerto que siempre es fijo, y otro que es definible por el usuario, EasyWall permitirá modificar el segundo pero no el primero.
  • Permite definir un puerto en base a otro. Así, por ejemplo, en aMule, hay tres puertos configurables por el usuario, pero el tercero siempre es el primero más tres. EasyWall automatiza este tipo de casos, con lo que el usuario sólo tiene que configurar los dos puertos base, y el tercero se configurará automáticamente en base a los valores anteriores.
  • Permite automatizar también la carga de módulos para funcionalidades extra, como por ejemplo módulos necesarios para SMB/Samba, etc.
  • En caso de que no exista plantilla para algún programa concreto, el usuario puede definir sus propios rangos de puertos, para abrir y cerrar aquellos que necesite.

Las plantillas se definen con sencillos ficheros XML, por lo que es muy fácil añadir nuevos programas. Además, aunque el programa en en modo gráfico, incluye un par de funcionalidades en modo texto para permitir refrescar el firewall si se añaden o eliminan programas al sistema.

Por último, la funcionalidad se ha dividido en dos ficheros: easywall_core.py y easywall_gtk.py. El primero tiene toda la parte de bajo nivel, y el segundo es el front-end en GTK. Esta división se ha hecho así con vistas a que quien lo desee, pueda hacer fácilmente un front-end en Qt para KDE. Para ello sólo tiene que incluir el módulo easywall_core.py y utilizar sus clases y métodos para refrescar el firewall, añadir puertos, etc.

¡A disfrutarlo!

Instalando Eclipse Indigo en Ubuntu (u otro Linux)

Actualizado Ha salido la versión 3.7 (Indigo) del famoso IDE Eclipse. Por desgracia, todavía no está disponible como fichero .deb para Ubuntu, así que vamos a instalarlo «a mano».

Lo primero, desinstalar cualquier versión anterior de Eclipse.

A continuación, bajarse la versión correspondiente (32 o 64 bits) desde la página de descargas de Eclipse. Yo he instalado la edición Classic. Lo descomprimimos (como root, obviamente) en /opt/eclipse.

Instalamos la máquina virtual de Java, si es que todavía no la tenemos: sudo apt-get install openjdk-6-jre

Creamos un fichero eclipse.desktop en /usr/share/applications o en ~/.local/share/applications con el siguiente contenido:

[Desktop Entry]
X-MultipleArgs=false
Type=Application
Name=Eclipse
GenericName=Eclipse IDE
TryExec=/opt/eclipse/eclipse
Exec=/opt/eclipse/eclipse
Categories=Development;
Icon=/opt/eclipse/icon.xpm

¡Y listo! Ya tenemos Eclipse Indigo en nuestro sistema y en nuestro menú de aplicaciones.

Nos vemos en las calles

Mañana es la manifestación del 19J en contra del Pacto del Euro, la cual entronca directamente con la original del 15M. Para los que quieran ir, pueden buscar donde va a ser la de su ciudad en una de las muchas páginas que publican la información, como por ejemplo la de spanishrevolution. En Vigo será a las 18:00 horas desde la Plaza de España, aunque la gente de la acampada saldrá a las 17:30 desde la Plaza del Rey para unirse a esa hora con el resto.

El 19J toma la calle

Por último, una nota publicada en N-1 con una recomendación de protocolo de actuación en caso de violencia por parte de manifestantes. Es sólo una sugerencia, pero personalmente me parece perfecto.

Repositorio GIT para Devede

Hace unos días subí el código de Devede a un repositorio en GitHUB para hacer accesibles de manera más rápida las correcciones que voy haciendo ante los bugs que reporta la gente. En estos momentos ya hay varias correcciones, alguna de ellas bastante importante pues permite utilizar Devede con las últimas versiones de Mencoder (que necesitan usar el modificador AC3_FIXED en lugar de AC3 a secas para que funcione el sonido), así como con las últimas versiones de DVDAuthor (necesitan que se defina una variable de entorno con el tipo de vídeo por defecto -PAL o NTSC-).

También empiezan a llegar parches para el código, que iré añadiendo progresivamente.

Ahora quiero añadir algún sistema para facilitar la traducción. Me han recomendado Pootle, pero no tengo muy claro que pueda añadir ahí un proyecto cualquiera. Se aceptan sugerencias.

FBZX 2.5.0

La nueva versión de FBZX ya está en la calle con dos opciones pedidas por un usuario. Para empezar, ahora se pueden meter POKEs, lo que nos dará esas maravillosas vidas infinitas que tanto necesitamos. Por otro lado, ahora podemos emular una televisión en blanco y negro, para los nostálgicos pobretones que no nos podíamos permitir una tele en color para el speecy. Por último, y de rebote, le añadí soporte para cargar y hacer snapshots de la pantalla en formato SCR.

Nueva version de FBZX

Tras un aviso del autor de Gelide, he procedido a corregir un pequeño bug en los parámetros de línea de comandos de FBZX. Simplemente ocurría que, al activar la opción de double scan, sólo se podía desactivar desde el menú interno, quedándose activa incluso al salir y volver a entrar, además de no hacer caso al parámetro -ds. Ahora ya responde a él, y además incorpora el parámetro -ss para forzar el desactivar el double scan.

Ya esta aqui TTOS

¿Y qué es TTOS? Pues el proyecto en el que llevo embarcado desde hace siete meses. Se trata de un gestor de ventanas por composición para el navegador TomTom, que permite dotarlo de una serie de capacidades al estilo de Android o del iPhone.

La idea surgió el verano pasado, cuando, volviendo de vacaciones, tuve que hacer casi todo el viaje de vuelta en silencio porque me había olvidado los CDs de música, en la radio sólo se pillaba Radio Clásica y Radio María (nada que ver con la hierba), y casi no tenía batería en el móvil para reproducir mis MP3 desde él. Fue entonces cuando recordé que tenía un viejo TomTom que no utilizaba para casi nada, y dado que éste tiene un Linux embebido, se me ocurrió que podría hacer un pequeño reproductor de MP3 para él. Pero ya existía: TomPlayer.

Entonces me dije ¿por qué no intentar mejorarlo? Y entonces empecé a investigar sobre Android, pero era demasiado pesado para él. Así que decidí intentar hacer una versión ligera, con lo mínimo para poder hacer los efectos de scroll y demás que se ven en los móviles de hoy en día.

El resultado es TTOS, un pequeño entorno que permite desarrollar y ejecutar pequeñas aplicaciones sobre TomTom. El API es muy sencillo, y permite hacer mucho con pocas líneas.

En estos momentos TTOS trae una calculadora, un reloj calendario, un terminal, una aplicación de ejemplo y un reproductor de MP3/Vorbis, pero, cuando tenga algo más de tiempo, me estoy planteando portar Navit, un navegador libre que utiliza los mapas de OpenStreetMap.

Como muestra, una pequeña animación que muestra como es TTOS: