Archive for the 'Trucos' Category

VirtualBox y Windows 10

viernes, junio 2nd, 2017

Por circunstancias de la vida he tenido que usar Windows 10 en una máquina virtual sobre Linux, así que, por comodidad, decidí usar VirtualBox. Mi sorpresa fue descubrir lo terriblemente lento que iba. Por algún motivo se pasaba todo el rato accediendo al disco duro, y eso enlentecía el sistema hasta límites exasperantes.

Afortunadamente, rebuscando, encontré la solución:

  • Pulsar “Windows”+R, para ejecutar una aplicación, y lanzar “services.msc”
  • Buscar “Windows Search” y “Superfetch”.
  • En cada uno, ir a Propiedades, detenerlo, y desactivarlo.
  • Profit!

Más Gentoo para MipsEL

domingo, diciembre 25th, 2016

Estoy actualizando la distribución de Gentoo para webtv y, como no podía ser de otra manera, hay problemillas. El último ha sido con busybox. Para poder compilarla hay que añadir, además de las opciones que indico en Generando Gentoo para WebTV, hay que añadir las siguientes:

busybox_config_option n NANDWRITE
busybox_config_option n NANDDUMP
busybox_config_option n FLASH_ERASEALL
busybox_config_option n FLASHCP
busybox_config_option n BLKDISCARD

Por otro lado, la variable USE debe contener:

USE="${ARCH} -pam -fortran -sanitize -X -iptables -hardened -seccomp -ipv6 -systemd -mdev internal-glib -caps -gtk -qt -t -boehm-gc -nls -filecaps"

Preparando Gentoo de nuevo

lunes, diciembre 19th, 2016

Estoy preparando una nueva versión de Transmission para el WebTV, y como perdí el sistema Gentoo que había construido hace tiempo he tenido que volver a generarlo, siguiendo mis propias notas.

Sin embargo esta vez me apareció un problema extra una vez finalizado todo. Para empezar, Python siguió dando problemas, así que compilé la versión 3.4 de manera cruzada y dejé para compilar en nativo la versión 3.5. Pero una vez compilado todo, y tras entrar con systemd-nspawn, me encuentro con que varios comandos, entre ellos el importantísimo emerge, devuelven un error rarísimo:

mipsel-unknown-linux-gnu / # env-update
Traceback (most recent call last):
  File "/usr/lib/python-exec/python3.4/env-update", line 31, in 
    import portage
ImportError: No module named 'portage'

Tras muchas pruebas, descubrí que el problema era que, como el sistema gentoo nativo era de 64 bits, metió muchas bibliotecas en /usr/lib64, directorio que el sistema Mipsel no encontraba porque es de 32 bits.

La solución fue tan sencilla como copiar recursivamente /usr/lib64 a /usr/lib.

Usando DBus desde lenguaje C y JavaScript

viernes, diciembre 11th, 2015

Trabajar con DBus desde Python o Vala es muy sencillo: esconden la complejidad del protocolo de manera que uno tiene la ilusión de estar haciendo una llamada local. Sin embargo, históricamente, trabajar con DBus desde C ha sido considerado un peñazo de dimensiones colosales. Sin embargo, desde la llegada de la biblioteca GDBus, que integra DBus dentro de GIO la cosa se ha simplificado bastante, sobre todo en aquellos casos en los que simplemente queremos llamar de manera síncrona a un método remoto.

Debido a algunos cambios que estuve haciendo en Panther Launcher, necesité poder hacer precisamente eso: llamar a un método remoto mediante DBus desde C, para implementarlo dentro del applet para Gnome Flashback. Dado que no encontré documentación sencilla para este detalle concreto (esto es, sin usar entre medias un bucle de eventos), voy a comentar como lo hice, por si le es útil a alguien más.

Lo primero que necesitamos para poder llamar a un método remoto mediante DBus es la interfaz correspondiente donde se define dicho método. Esta interfaz se puede obtener de manera muy sencilla mediante dbus-send y las capacidades de introspección de DBus:

dbus-send --session --type=method_call --print-reply --dest=com.rastersoft.panther.remotecontrol /com/rastersoft/panther/remotecontrol org.freedesktop.DBus.Introspectable.Introspect

En este ejemplo obtenemos las interfaces disponibles en el objeto  /com/rastersoft/panther/remotecontrol, del servicio  com.rastersoft.panther.remotecontrol. El resultado es éste:

freedesktop.DBus.Introspectable.Introspect
method return time=1449871353.404951 sender=:1.1222 -> destination=:1.1246 serial=104 reply_serial=2
 string "<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
 "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<!-- GDBus 2.46.2 -->
<node>
 <interface name="org.freedesktop.DBus.Properties">
   <method name="Get">
     <arg type="s" name="interface_name" direction="in"/>
     <arg type="s" name="property_name" direction="in"/>
     <arg type="v" name="value" direction="out"/>
   </method>
   <method name="GetAll">
     <arg type="s" name="interface_name" direction="in"/>
     <arg type="a{sv}" name="properties" direction="out"/>
   </method>
   <method name="Set">
     <arg type="s" name="interface_name" direction="in"/>
     <arg type="s" name="property_name" direction="in"/>
     <arg type="v" name="value" direction="in"/>
   </method>
   <signal name="PropertiesChanged">
     <arg type="s" name="interface_name"/>
     <arg type="a{sv}" name="changed_properties"/>
     <arg type="as" name="invalidated_properties"/>
   </signal>
 </interface>
 <interface name="org.freedesktop.DBus.Introspectable">
   <method name="Introspect">
     <arg type="s" name="xml_data" direction="out"/>
   </method>
 </interface>
 <interface name="org.freedesktop.DBus.Peer">
   <method name="Ping"/>
   <method name="GetMachineId">
     <arg type="s" name="machine_uuid" direction="out"/>
   </method>
 </interface>
 <interface name="com.rastersoft.panther.remotecontrol">
   <method name="DoPing">
     <arg type="i" name="v" direction="in"/>
     <arg type="i" name="result" direction="out"/>
   </method>
   <method name="DoShow">
   </method>
 </interface>
</node>

Vemos que aparecen varias interfaces, dentro de cada una varios métodos, y dentro de cada método puede haber cero o más parámetros, y cero o más valores devueltos. Para nuestros propósitos no vamos a necesitar todo, sino sólo la interfaz com.rastersoft.panther.remotecontrol, así que eliminaremos el resto de entradas (y las líneas superiores descriptivas, sólo queremos el XML), y nos quedará esto:

<node>
 <interface name="com.rastersoft.panther.remotecontrol">
   <method name="DoPing">
     <arg type="i" name="v" direction="in"/>
     <arg type="i" name="result" direction="out"/>
   </method>
   <method name="DoShow">
   </method>
 </interface>
</node>

Este fichero XML es el que describe las llamadas que vamos a implementar.

Si queremos llamar a alguno de estos métodos desde JavaScript (por ejemplo, para hacer una llamada desde una extensión de Gnome Shell), sólo necesitaremos hacer lo siguiente:

const Gio = imports.gi.Gio;

const MyIface = '<node>\
 <interface name="com.rastersoft.panther.remotecontrol">\
  <method name="DoShow" />\
  <method name="DoPing" >\
   <arg name="n" direction="in" type="i"/>\
   <arg name="response" direction="out" type="i"/>\
  </method>\
 </interface>\
</node>';

const MyProxy = Gio.DBusProxy.makeProxyWrapper(MyIface);

let instance = new MyProxy(Gio.DBus.session, 'com.rastersoft.panther.remotecontrol','/com/rastersoft/panther/remotecontrol');
instance.DoShowSync();
instance.DoPingSync(0);

Primero importamos Gio para tener acceso a GDBus. Después insertamos el XML con la interfaz en una variable, y creamos un Proxy DBus con ella. Finalmente, cada vez que queramos acceder a un objeto (en este caso /com/rastersoft/panther/remotecontrol) de un servicio DBus (en este caso com.rastersoft.panther.remotecontrol), sólo tenemos que crear una instancia del proxy anterior, el cual nos permitirá llamar a los métodos definidos en la interfaz.

Cabe recalcar que aquí estoy llamando a los métodos con su nombre terminado en Sync. Eso significa que la llamada será bloqueante, y no retornará hasta que se reciba la respuesta del otro extremo. Es posible hacer llamadas asíncronas, pero no lo he investigado y no voy a entrar ahí.

Hasta aquí JavaScript, que es la parte más sencilla. Ahora llega el turno de como hacer esto mismo desde C.

GDbus tiene un generador de código que nos simplifica el trabajo. Para usarlo basta con grabar en un fichero el XML anterior (por ejemplo, remotecontrol.xml) y llamar a gdbus-codegen para que construya el código necesario para poder llamar a dichos métodos:

gdbus-codegen --c-generate-object-manager --generate-c-code dbus remotecontrol.xml

Este comando creará dos ficheros: dbus.c y dbus.h (se utiliza el nombre indicado en –generate-c-code) a partir del fichero remotecontrol.xml. Existen algunos parámetros extra, como –c-namespace, que permite especificar un prefijo para todas las funciones que se generen, y así evitar choques de nombres.

En dichos ficheros tendremos un montón de código ya escrito, y es precisamente este código el que nos simplifica el proceso, pues no tendremos que escribirlo nosotros. Una vez que lo tenemos, sólo hemos de llamarlo así:

#include "dbus.h"

GError *error = NULL;

ComRastersoftPantherRemotecontrol *proxy;

proxy = com_rastersoft_panther_remotecontrol_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
                                                  G_DBUS_PROXY_FLAGS_NONE,
                                                  "com.rastersoft.panther.remotecontrol",
                                                  "/com/rastersoft/panther/remotecontrol",
                                                  NULL, /* GCancellable */
                                                  &error);
if (proxy != NULL) {
    error = NULL;
    retval = com_rastersoft_panther_remotecontrol_call_do_show_sync(proxy,NULL,&error);

    ...

    error = NULL;
    gint value;
    retval = com_rastersoft_panther_remotecontrol_call_do_ping_sync(proxy,0,&value,NULL,&error);
}

Tras incluir el fichero dbus.h para disponer de las llamadas, lo primero que hacemos es crear un puntero de tipo GError para recibir las excepciones que se produzcan.

A continuación creamos de manera síncrona un proxy de la interfaz concreta que queremos utilizar. Vemos que lo estamos haciendo para el bus de sesión, para el objeto /com/rastersoft/panther/remotecontrol del servicio com.rastersoft.panther.remotecontrol. Es fundamental que el puntero GError esté inicializado a NULL, pues de no hacerlo la llamada fallará.

Y una vez que tenemos dicho proxy ya podemos llamar a los métodos remotos. Vemos que cada llamada está formada por el nombre de la interfaz, más _call_, más el nombre del método, y en este caso, como la llamada queremos que se bloquee hasta que llegue la respuesta, termina en _sync. El primer parámetro es el proxy, y los dos últimos un puntero a la función para cancelar la llamada (que ponemos a NULL para no complicarnos la vida) y un puntero a GError, que también debe estar inicializado a NULL antes de llamar a la función.

Entre medias se introducen, en el mismo orden en que están definidos en el XML, los parámetros de entrada (que se pasan por valor) y punteros para los parámetros de salida.

Para compilarlo hay que utilizar pkg-config gio-2.0 gio-unix-2.0 para que se añadan las cabeceras y bibliotecas necesarias.

Y ya está, con esto podemos por fin llamar de manera sencilla un método DBus desde lenguaje C.

Peleandome con Python 3.4

jueves, julio 30th, 2015

Dado que quiero tener soporte para gnutls, tuve que cambiar el USE de mi distribución a:

USE="${ARCH} -pam -fortran -sanitize -iptables -static -systemd -mdev gnutls internal-glib -caps -filecaps -X -gtk -qt -tk"

Las siete últimas adiciones fueron para no añadir nada de entorno gráfico (pues no tiene sentido en el WebTV) y para asegurar de que las nuevas bibliotecas necesarias para incluir gnutls se puedan compilar. Hubo varios problemillas, pero uno a uno los fui resolviendo.

Por desgracia, el último escollo estaba en python. Cuando compilé el sistema la versión estable era la 3.3, pero ahora ya salió la 3.4. El problema es que se negaba a compilar, dando un error raro:

Python build finished successfully!
The necessary bits to build these optional modules were not found:
    _tkinter
To find the necessary bits, look in setup.py in detect_modules() for the module's name.
Failed to build these modules:
    _socket               _ssl

Decía que se había compilado correctamente, pero emerge devolvía un error. Al principio pensaba que el problema estaba en tkinter, el módulo gráfico de python, pero no tenía sentido porque había especificado que no quería ni tk, ni X ni nada relacionado con un entorno gráfico. Entonces, revisando el log, vi que en medio de la compilación había este error:

/tmp/portage/dev-lang/python-3.4.3/work/Python-3.4.3/Modules/socketmodule.o
/tmp/portage/dev-lang/python-3.4.3/work/Python-3.4.3/Modules/socketmodule.c: In function 'makesockaddr':
/tmp/portage/dev-lang/python-3.4.3/work/Python-3.4.3/Modules/socketmodule.c:1175:14: error: dereferencing pointer to incomplete type
         if (a->can_ifindex) {
              ^
/tmp/portage/dev-lang/python-3.4.3/work/Python-3.4.3/Modules/socketmodule.c:1176:32: error: dereferencing pointer to incomplete type
             ifr.ifr_ifindex = a->can_ifindex;
                                ^
/tmp/portage/dev-lang/python-3.4.3/work/Python-3.4.3/Modules/socketmodule.c:1183:38: error: dereferencing pointer to incomplete type
                                     a->can_family);
                                      ^
/tmp/portage/dev-lang/python-3.4.3/work/Python-3.4.3/Modules/socketmodule.c: In function 'getsockaddrlen':
/tmp/portage/dev-lang/python-3.4.3/work/Python-3.4.3/Modules/socketmodule.c:1802:28: error: invalid application of 'sizeof' to incomplete type 'struct sockaddr_can'
         *len_ret = sizeof (struct sockaddr_can);
                            ^
building '_ssl' extension

¿CAN? ¿En el módulo de sockets? Bastante raro. Rebuscando encontré que, efectivamente, desde el núcleo 2.6.25 hay soporte para el bus CAN; sin embargo, mi núcleo (y sus cabeceras) es el 2.6.22. ¿Por qué se empeñaba en incluir soporte? Por otro lado, python 3.3 también trae de serie soporte para bus CAN, pero esa versión sí compilaba bien. ¿Qué estaba pasando?

Al final descubrí que el núcleo 2.6.22 tiene algo de soporte del bus CAN, pero parece que no el suficiente, y eso lía a python 3.4.

La solución que encontré fue editar el fichero /usr/include/bits/socket.h, y comentar la línea donde se define AF_CAN:

//#define AF_CAN PF_CAN

Y con eso, por fin, pude compilar absolutamente todo, listo para empezar a preparar el sistema que va a llevar definitivamente.

No puede caber aqui

miércoles, julio 29th, 2015

Llevo un par de días incapaz de actualizar el paquete binutils usando la emulación de mipsel sobre mi PC. Es una cosa misteriosa, pues daba un error al compilar el linker gold. Tras intentar hacerlo a mano, me devolvió como mensaje de error:

(for i in `seq 1 70000`; do 
  echo "int var_$i __attribute__((section("section_$i"))) = $i;"; 
done) > many_sections_define.h.tmp
make: execvp: /bin/sh: Argument list too long

¿Argument list too long? Un error bastante extraño, sin duda. Y más en el propio make. Encima, si eliminaba todo ese código y metía un simple echo, el error persistía. ¿Qué estaba pasando?

Tras probar de todo y rebuscar por todas partes, por fin encontré el problema: qemu define un tamaño máximo para la línea de comandos (MAX_ARG_PAGES) demasiado pequeño para compilar binutils, y por eso casca. Encima, dicho valor se define a piñón en el código fuente, por lo que la única solución consiste en bajarse los fuentes de qemu, modificar el fichero linux-user/qemu.h para aumentar a 64 o más las páginas reservadas para la línea de comandos (yo puse 129), y compilarlo todo con:

./configure --static --target-list=mipsel-linux-user
make

Con esto ya tendremos en mipsel-linux-user/qemu-mipsel el ejecutable estático, el cual podemos copiar dentro de la carpeta de nuestra máquina virtual como usr/bin/qemu-mipsel-static. Y con esto deberíamos ser capaces de compilar cualquier cosa.

(Si, el título es por esta escena 🙂 )

Actualizando la Gentoo del WebTV desde el PC

lunes, julio 27th, 2015

Siguiendo con lo que hice el otro día, ahora quería empezar a instalar cosas en el sistema Gentoo del WebTV. Por desgracia la cosa no es tan sencilla porque enseguida pide actualizar algunos paquetes, lo cual tarda mucho tiempo al hacer la compilación en el propio dispositivo. Y por si fuera poco, con alguno necesita tanta memoria que, directamente, casca a la mitad de la compilación.

Afortunadamente hay una forma de hacer todo esto directamente en un PC, pero haciendo creer al sistema Gentoo que está corriendo de forma nativa en un sistema Mipsel. Para ello sólo necesitamos QEMU.

Para empezar necesitamos el binario /usr/bin/qemu-mipsel-static, así que buscamos en qué paquete está disponible y lo instalamos en nuestro sistema. En el caso de Debian, el paquete es qemu-user-static. Este binario nos permite ejecutar binarios de la arquitectura deseada, pero (y esto es lo interesante) encaminando las llamadas al núcleo directamente al de la máquina física, con lo que no necesitamos compilar otro núcleo.

Ahora descomprimimos el fichero entorno_gentoo_mipsel.tar.bz2 en un directorio (por ejemplo, en /tmp), y descomprimimos en lugar adecuado (en nuestro ejemplo, en /tmp/bg_apps/usr) también el fichero de portage, tras bajarlo. Por último, copiamos /usr/bin/qemu-mipsel-static dentro de nuestro sistema mipsel (en nuestro caso, en /tmp/bg_apps/usr/bin/). Con esto hemos terminado los preparativos.

Ahora lanzamos nuestra sesión mediante:

sudo systemd-nspawn -u 1000 -D /tmp/bg_apps /bin/bash

De esta manera lanzamos nuestra sesión como usuario 1000 (que es el que usa el WebTV cuando se arranca una sesión en segundo plano). Además, gracias a que copiamos el binario de qemu, los binarios de mipsel se ejecutarán directamente, sin ningún problema, como si fuesen nativos de nuestro sistema (por increíble que parezca).

Una vez hecho esto ya podemos actualizar el sistema y demás, sin temor a quedarnos sin memoria y a mucha más velocidad. Pero echad un vistazo también a esta entrada posterior: http://blog.rastersoft.com/?p=1645.

Generando Gentoo para el WebTV

domingo, julio 19th, 2015

Nota: actualizado el parche para BusyBox.

Estos días estoy bastante liado con el trabajo-que-paga-las-facturas, pero por suerte he podido sacar un rato para cacharrear. Me he puesto con el WebTV (que tengo bastante abandonado desde que me compré la Raspberry Pi) y he decidido intentar meter un sistema “decente”. ¿A qué me refiero? Pues a que, por defecto, la máxima versión de Debian que puede correr es wheezy, que ya es old-stable. La estable actual (jessie) necesita un núcleo más reciente, y se niega a trabajar con el que trae el WebTV (2.6.22).

Ante esto decidí probar con Gentoo, a ver si conseguía compilarlo todo. A continuación indicaré como lo hice.

NOTA: para los que no quieran leerse este tocho, en mi web está disponible este entorno Gentoo completo para WebTV, ya compilado y listo para usar.

Para empezar, me bajé la stage 3 de Gentoo para X86_64, bajé también la última lista de paquetes de portage, y descomprimí ésta última en /usr de la stage 3. Con ello ya pude lanzar un contenedor de gentoo con

sudo systemd-nspawn -D /directorio/con/la/stage3 /bin/bash

Aquí toca primero preparar el sistema para hacer crossdev. Esto se puede repasar en una entrada anterior: Emergiendo.

Una vez dentro intenté hacer un crossdev para compilar una gentoo para mipsel usando

crossdev --kernel 2.6.22 -t mipsel -v

Por desgracia fallaba: se empeñaba en utilizar las cabeceras de la versión 2.4.36. ¿Qué pasaba? Pues que aunque en los repositorios de Gentoo sí existen las cabeceras del kernel 2.6.22, éstas no están disponibles en la lista de ebuilds de portage.

Ante esto empecé a buscar y probar, y finalmente con la ayuda de la gente de IRC del canal #Gentoo-kernel conseguí el ebuild de las cabeceras para la versión 2.6.22-r2. Sin embargo tuve que grabarlo en /usr/portage/sys-kernel/linux-headers con el nombre linux-headers-2.6.22-r3, pues la R3 es la versión disponible en el repositorio.

Tras ello actualicé el fichero Manifest para que encontrase el nuevo ebuild con

ebuild /usr/portage/sys-kernel/linux-headers/linux-headers-2.6.22-r3.ebuild manifest

Probé de nuevo a generar el crossdev pero seguía intentando usar la versión 2.4.36… porque la versión 2.6.22-r3 es posterior a la 2.6.22 a secas. Cambiando el parámetro en crossdev solucionó el problema.

crossdev --kernel 2.6.22-r3 -t mipsel -v

Por desgracia, ahora me encontraba con otro: ocurría un error durante la instalación de las cabeceras:

HOSTCC  scripts/unifdef
scripts/unifdef.c:209:25: error: conflicting types for 'getline'
 static Linetype         getline(void);
                         ^
In file included from scripts/unifdef.c:70:0:
/usr/include/stdio.h:678:20: note: previous declaration of 'getline' was here
 extern _IO_ssize_t getline (char **__restrict __lineptr,
                    ^
scripts/Makefile.host:118: recipe for target 'scripts/unifdef' failed
make[1]: *** [scripts/unifdef] Error 1
Makefile:927: recipe for target 'headers_install' failed
make: *** [headers_install] Error 2
emake failed

Tocaba buscar más soluciones. Afortunadamente esta era sencilla: bastaba con editar el fichero unifdef.c y sustituir todas las ocurrencias de getline por otra cosa, como por ejemplo get_line. Preparé el siguiente parche para ello:

--- a/scripts/unifdef.c
+++ b/scripts/unifdef.c
@@ -206,7 +206,7 @@ static void             done(void);
 static void             error(const char *);
 static int              findsym(const char *);
 static void             flushline(bool);
-static Linetype         getline(void);
+static Linetype         get_line(void);
 static Linetype         ifeval(const char **);
 static void             ignoreoff(void);
 static void             ignoreon(void);
@@ -512,7 +512,7 @@ process(void)
 
 	for (;;) {
 		linenum++;
-		lineval = getline();
+		lineval = get_line();
 		trans_table[ifstate[depth]][lineval]();
 		debug("process %s -> %s depth %d",
 		    linetype_name[lineval],
@@ -526,7 +526,7 @@ process(void)
  * help from skipcomment().
  */
 static Linetype
-getline(void)
+get_line(void)
 {
 	const char *cp;
 	int cursym;

Y entonces me encontré con el problema de como aplicarlo durante la generación del crossdev. La cosa no era sencilla, porque se empeña en comprobar los valores de sha256, sha512 y whirlpool de todo lo que baje. En teoría se pueden añadir parches manualmente en /etc/portage/patches, pero tras probar de todo no conseguí que funcionase, así que al final fui a la solución cazurra y metí el comando de parcheado directamente en el ebuild. Para ello edité el fichero /usr/portage/sys-kernel/linux-headers/linux-headers-2.6.22-r3.ebuild y lo dejé como sigue:

# Copyright 1999-2007 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: /var/cvsroot/gentoo-x86/sys-kernel/linux-headers/Attic/linux-headers-2.6.22-r2.ebuild,v 1.11 2008/04/12 22:24:36 vapier dead $

ETYPE="headers"
H_SUPPORTEDARCH="alpha amd64 arm cris hppa m68k mips ia64 ppc ppc64 s390 sh sparc x86"
inherit kernel-2
detect_version

echo ${PV}
echo ${PATCH_VER}

PATCH_VER="3"
SRC_URI="mirror://gentoo/gentoo-headers-base-${PV}.tar.bz2"
[[ -n ${PATCH_VER} ]] && SRC_URI="${SRC_URI} mirror://gentoo/gentoo-headers-${PV}-${PATCH_VER}.tar.bz2"

KEYWORDS="-* alpha amd64 arm hppa ia64 m68k mips ppc ppc64 s390 sh sparc x86"

DEPEND="dev-util/unifdef"
RDEPEND=""

S=${WORKDIR}/gentoo-headers-base-${PV}

src_unpack() {
        unpack ${A}
        cd "${S}"
        [[ -n ${PATCH_VER} ]] && EPATCH_SUFFIX="patch" epatch "${WORKDIR}"/${PV}
        patch -p1 < /getline.patch
}

src_install() {
        kernel-2_src_install
        cd "${D}"
        egrep -r '[[:space:]](asm|volatile|inline)[[:space:](]' .
        headers___fix $(find -type f)
}

src_test() {
        make ARCH=$(tc-arch-kernel) headers_check || die
}

Luego copié el texto del parche en el fichero /getline.patch y actualicé de nuevo el manifest. Ahora, siempre que se intente instalar el paquete, se parcheará correctamente.

A intentarlo otra vez… y otra vez falla, esta vez porque la versión 2.20 de glibc necesita, al menos, un kernel 2.6.32. Como el núcleo disponible es el que es, toca probar con una versión anterior. La 2.19r1 fue suficiente:

crossdev --kernel 2.6.22-r3 --l 2.19-r1 -t mipsel -v

Finalmente, con esto ya es capaz de compilar glibc. Ahora vienen las curvas, porque no es capaz de compilar el soporte de Fortran para el GCC, ni las pruebas sanity ni algunas cosas más, así que toca armarse de paciencia e ir probando opciones de USE hasta que todo compile. El resultado final es que hay que usar la siguiente línea (añadí el -X para reducir las dependencias, pues en el WebTV no es necesario):

USE="-fortran -sanitize -X" CFLAGS="-O2 -pipe" crossdev --kernel 2.6.22-r3 --l 2.19-r1 -s4 -t mipsel -v

Inicializamos los wrappers de compilación cruzada…

emerge-wrapper --target mipsel-unknown-linux-gnu --init

Y ya tenemos el sistema de compilación cruzada para MIPSel. Ahora toca configurar el entorno y preparar el sistema. Para ello lo primero es borrar el enlace /usr/mipsel-unknown-linux-gnu/etc/portage/make.profile (que, por defecto, apunta a /usr/portage/profiles/embedded) y sustituirlo por uno que apunte a /usr/portage/profiles/ default/linux/mips/13.0/mipsel.

Una vez hecho esto editamos /usr/mipsel-unknown-linux-gnu/etc/portage/make.conf, y ahí modificamos la línea donde se define el USE para añadir, al menos, -fortran -sanitize -X -iptables. También podemos añadir, opcionalmente, un MAKEOPTS=”-jX” (siendo X el número de núcleos de nuestro procesador más uno), para que la compilación sea más rápida.

También tenemos que editar el fichero /usr/mipsel-unknown-linux-gnu/etc/portage/package.mask, y añadir estas líneas:

>sys-libs/glibc-2.19-r1
>sys-kernel/linux-headers-2.6.22-r3

Con ellas evitamos que instale versiones posteriores de ambos paquetes, que harían que el sistema dejase de funcionar en nuestro WebTV.

Con esto ya podemos intentar generar nuestro sistema base con

emerge-mipsel-unknown-linux-gnu system

Si falla al compilar Busybox, es probable que haya alguna opción que no le gusta. En ese caso hay que editar su fichero .ebuild en /usr/portage/sys-apps/busybox/busybox-X.Y.Z.ebuild, añadir las opciones de configuración que se quieren activar o desactivar, y luego ejecutar ebuild /usr/portage/sys-apps/busybox/busybox-X.Y.Z.ebuild manifest para actualizar el manifest. En mi caso, el problema es que se activan por defecto el soporte de UBIFS y de I2C, cosa que no parece gustarle, así que para eliminarlo tuve que añadir las siguientes líneas en el sitio adecuado del ebuild:

busybox_config_option n I2CGET
busybox_config_option n I2CSET
busybox_config_option n I2CDUMP
busybox_config_option n I2CDETECT
busybox_config_option n UBIATTACH
busybox_config_option n UBIDETACH
busybox_config_option n UBIMKVOL
busybox_config_option n UBIRMVOL
busybox_config_option n UBIRSVOL
busybox_config_option n UBIUPDATEVOL

Con suerte, en un par de días este parche ya estará incluido en los repositorios oficiales.

Otro problema, esta vez más grave, es con Perl: se trata de un paquete al que no le gusta que le hagan compilación cruzada. El resultado es que, simplemente, no podemos instalarlo así. La solución consiste en, de momento, hacer creer al sistema que sí está instalado, e instalarlo manualmente desde el sistema final una vez que ya estamos en el equipo. Para hacer esto basta con editar el fichero /usr/mipsel-unknown-linux-gnu/etc/portage/profile/package.provided y poner, en cada línea, los paquetes que queremos marcar como instalados. Hice lo mismo con los paquetes de UDev, que tampoco los necesito. En mi caso su contenido fue:

dev-lang/perl-5.22
virtual/perl-Data-Dumper-2.158.0
perl-core/File-Temp-0.230.400-r1
virtual/perl-File-Temp-0.230.400-r3
dev-perl/Text-Unidecode-1.230.0
dev-perl/libintl-perl-1.240.0
virtual/perl-File-Spec-3.560.0
dev-perl/Unicode-EastAsianWidth-1.330.0-r1
sys-fs/udev-222
virtual/udev-217
sys-fs/udev-init-scripts-30
virtual/dev-manager-0

Pero, obviamente, depende de la versión de portage y de los paquetes disponibles.

Tras instalar todo esto, si el equipo es de 64 bits nos encontraremos con que nos ha metido varios elementos de python en /usr/lib64, cuando todo debería ir en /usr/lib. Es por esto que debemos mover todos los ficheros del primero al segundo.

Ahora ya podemos copiar el contenido de /usr/mipsel-unknown-linux-gnu/ a un disco duro externo (dentro de una carpeta llamada bg_apps), añadir un fichero init y otro vacío llamado no_base_system, y ya podemos arrancar nuestro sistema Gentoo en el WebTV.

Pero aún no hemos acabado. Para empezar, es necesario hacer el siguiente enlace cada vez que se encienda el equipo:

ln -s /proc/self/fd /dev/fd

para que emerge funcione correctamente. También es recomendable editar el fichero /etc/portage/make.conf y eliminar la opción de compilación -pipe, pues consume más memoria, y en un equipo relativamente limitado como el WebTV nos puede dar problemas con compilaciones muy tochas.

Por otro lado, tenemos que comentar las entradas de Perl que pusimos en el fichero /usr/mipsel-unknown-linux-gnu/etc/portage/profile/package.provided, y procer a instalarlos todos con emerge.

No hay que olvidar que, debido a la gran cantidad de ficheros que tiene el directorio /usr/portage, el arranque de la sesión en segundo plano del WebTV tardará bastante tiempo (en torno a un minuto), pues antes de lanzar la sesión, el sistema revisa todos y cada uno de los ficheros para asegurarse de que no hay “cosas raras”.

Generando paquetes DEB para programas en Python

lunes, febrero 2nd, 2015

Estos últimos meses he estado aprovechando para reescribir Devede. El principal motivo de reescribirlo desde cero ha sido, aparte de aprovechar mejor las distintas características de Python 3 y GTK 3, para darle una arquitectura interna más moderna, flexible y modular. El resultado es que ahora es muchísimo más fácil añadir nuevas características, backends y utilidades, y además puede hacer cosas como convertir en paralelo varios vídeos, aprovechando al máximo las CPUs multinúcleo actuales.

Desde el principio decidí escribir el código en condiciones utilizando el módulo DistUtils para realizar la instalación, y resultó ser un gran acierto porque permite simplificar notablemente la generación de paquetes DEB, algo necesario porque varios usuarios que querían utilizarlo no se aclaraban con GITHUB ni la línea de comandos.

Una vez que ya tenemos listo nuestro script de instalación setup.py, siguiendo las directrices de distutils, basta con instalar en nuestro sistema las utilidades stdeb. En Debian y Ubuntu el paquete se llama python3-stdeb; sin embargo, la versión para Python 3 sólo está disponible en Ubuntu a partir de Vivid (15.04), que en el momento de escribir esta entrada todavía está en fase de desarrollo (en Debian está disponible desde Jessie en adelante, por lo que no hay problema). Los que tengan la ultima revisión estable de Ubuntu (14.10 en el momento de escribir esta entrada) sólo dispondrán de python-stdeb en sus repositorios, que sólo funciona para Python 2 (incluso reescribe el shebang para que apunte a Python 2 en caso de que nuestro código lo tuviese apuntando a Python 3), por lo que tendrán que bajarse a mano el paquete .deb. La opción más directa consiste en buscarlos en Ubuntu Packages.

Una vez instalado hay que añadir el módulo dep_util en el script setup.py, para que reconozca las nuevas opciones. Para ello basta con añadir al principio:

from distutils import dep_util

Una vez hecho esto hay que añadir en el raíz de nuestro proyecto un fichero llamado stdeb.cfg. Este fichero contendrá todos aquellos datos que el generador no puede extraer de los que se pasan en el script setup.py, como por ejemplo las dependencias de nuestro programa. El fichero de Devede-NG contiene lo siguiente:

[DEFAULT]
Depends = python3, python-support, python-urllib3, python-gi, libgtk-3-0, ffmpeg (>= 7:1.2.6) | libav-tools(>= 6:9.16), mplayer, mpv | vlc, dvdauthor, mkisofs | genisoimage, vcdimager, libvorbis0a, libvorbisfile3

El resto de las opciones posibles que se pueden poner se pueden encontrar en la documentación de stdeb. Un detalle importante es que no conseguí que funcionase con el comando XS-Python-Version. Cada vez que lo añadía para forzar que sólo generase paquetes de Python 3, el proceso devolvía un error.

Ahora ya está todo listo, por lo que para generar el paquete basta con ejecutar el siguiente comando:

python3 setup.py --command-packages=stdeb.command bdist_deb

Y ya está; se creará un directorio llamado deb_dist en cuyo interior encontraremos un paquete deb con nombre python3-nombreprograma​_numero​.de​.version​_all.deb.

Por último, comentar varios detalles extra:

  • es fundamental llamarlo con python3; de no hacerlo así, generará un paquete para Python 2 (incluso reescribirá el shebang de los ficheros python para que apunten a Python 2)
  • podemos hacer todos los cambios que queramos en nuestro código y regenerar el paquete directamente siempre que no cambiemos la cadena con la versión en nuestro script setup.py. Si la cambiamos debemos borrar el directorio deb_dist antes de volver a generar el paquete, o el proceso fallará, devolviendo un error.
  • debe tenerse muy en cuenta que, al generar paquetes .deb, el script setup.py se ejecuta dos veces: la primera para copiar al directorio deb_dist sólo los ficheros que realmente conforman nuestro programa y que se tienen que instalar en el sistema (de manera que otros ficheros, como el README o similares, no se incluirán en el paquete), y la segunda vez para configurar y generar el paquete .DEB en sí. En el caso de Devede-NG esto fue importante tenerlo en cuenta porque lo primero que hace el script de instalación es compilar los ficheros de traducciones .po y copiarlos en una carpeta diferente, que es la que luego se instala en el sistema. Pero al ejecutarse por segunda vez dentro de deb_dist, los ficheros .po ya no estaban disponibles porque éstos no se copian en el sistema. Tras hacer unas modificaciones menores fue posible hacer que funcionase perfectamente.

Mapear los botones de un ratón logitech

lunes, octubre 6th, 2014

Desde hace tiempo tengo un ratón Performance MX de Logitech. Estoy muy contento con él desde que lo compré, salvo por el detalle de que usar la rueda como botón central es bastante incómodo, porque es difícil no girarla al pulsarla. Por eso lo primero que hice fue mapear la tecla zoom (que está disponible en el pulgar) como el botón central. Para ello hice este pequeño script bash, que añadí a las aplicaciones al inicio de mi sesión:

#!/bin/bash

xmodmap -e "pointer = 1 13 3 4 5 6 7 8 9 10 11 12 2"

Al principio este script funcionaba perfectamente, hasta que un día, dejó de hacerlo. Lo raro era que si lo ejecutaba a mano desde un terminal, funcionaba perfectamente; sólo fallaba si lo ejecutaba como aplicación al inicio de sesión. Esto me obligaba a ejecutarlo manualmente cada vez que encendía el ordenador, lo que era un peñazo, así que empecé a investigar qué era lo que ocurría, y descubrí que el ratón, como dispositivo de entrada, no es visible por el ordenador hasta que se mueve por primera vez. Eso significa que, cuando se ejecutaba el script al principio de la sesión, como para el ordenador aún no había ningún ratón, no hacía nada; pero cuando lo ejecutaba a mano, como ya lo había movido para lanzar el terminal, éste ya aparecía en la lista de dispositivos, y por eso funcionaba.

La solución final consistió en modificar el script para que, al lanzarse, compruebe regularmente si hay un dispositivo Logitech, y sólo entonces ejecute el comando xmodmap. El script final quedó así:

#!/bin/bash

x=1

while [ $x -ne 0 ]
do
	sleep 1
	xinput --list | grep Logitech
	x=$?
done

xmodmap -e "pointer = 1 13 3 4 5 6 7 8 9 10 11 12 2"

Dado que sabemos que tiene que haber un ratón Logitech (si no, no meteríamos este script), comprobamos una vez por segundo si en la lista de dispositivos de entrada aparece el receptor (esa pausa permite no consumir recursos inútilmente mientras esperamos a que aparezca). En el momento en que se cumpla sabemos que el comando xmodmap va a funcionar, así que lo ejecutamos y salimos del script.


Utilizamos cookies para garantizar que tenga la mejor experiencia en nuestro sitio web.