Archivo para la categoría ‘Informática’

Actualizar Ubuntu LTS a la siguiente versión en modo consola

Cuando tenemos un servidor corriendo Ubuntu y queremos actualizarlo a la siguiente versión, hay que utilizar el comando:

user@server:~:$ sudo do-release-upgrade

Este comando está en el paquete update-manager-core fácilmente instalable mediante el comando apt-get.

Pero ¿qué pasa cuando estamos en una versión LTS de Ubuntu? Por defecto no nos actualizará ya que sólo actualizará entre versiones LTS. Simplemente dirá “No new release found”.

Para solucionarlo hay que editar el archivo /etc/update-manager/release-upgrades y cambiar la línea que pone Prompt=lts por una que ponga Prompt=normal. Con esto indicaremos al actualizador que busque y actualice a nuevas versiones aunque la versión actual sea LTS y la siguiente no lo sea.

Esta funcionalidad se puede “simular” usando el parámetro -d del comando do-release-upgrade indicando que se quiere actualizar a versiones de desarrollo, con lo que el actualizador tendrá en cuenta todas las versiones, independientemente de si son LTS o no.

Como última nota por seguridad, hay que tener en cuenta que una actualización de este tipo es recomendable hacerla con un terminal in situ ya que, en caso de hacerla a través de ssh, en caso de fallo es muy difícil recuperar el sistema (vamos, eso dice la ayuda, que yo no he llegado a probarlo).

Y es ahora cuando me pongo a hacerlo… ;)

Widgetsoid

De las mejores aplicaciones que he probado últimamente para Android en mi HTC Magic: Widgetsoid.

Capturas de pantalla de Widgetsoid

Esta aplicación sirve para crear widgets del mismo estilo que el gestor de energía de Android 2.x (el widget con los botones para activar el Wifi, el Bluetooth, el GPS, la sincronización y el brillo) pero con un botón para (casi) cualquier acción posible dentro de la configuración de Android.

Además cuenta con varios estilos personalizados para hacerlo lo más parecido al tema que estés usando en cada momento pudiendo elegir tanto el color de fondo, el color de los iconos o el color de la barra que indica si el elemento está activado o no.

Lo mejor, a parte de la gran cantidad de configuración que tiene, es que es gratuita, aunque también existe una versión donate que cuesta 1 €.

Lo peor es que la interfaz no es muy amigable (la gente se empeña en crear su propia interfaz cuando el sistema ya trae la suya; y a veces no es la mejor opción).

Pero el problema más grave que he detectado es que consume muchísima batería. Al menos en estas versiones en mi Magic se pasa de durar la batería día y medio (uso normal) a durar ¡medio día! Además, aunque elimines todos los widgets, queda el servicio de Widgetsoid en ejecución. Espero que solucionen pronto esto porque es una aplicación muy interesante.

Y para que no lo pierda, mi configuración es:

  • En el widget principal: Wifi, Bluetooth, GPS, temporizador de pantalla y brillo.
  • En el secundario: sincronización, sincronizar ahora, activar/desactivar 2G/3G y activar/desactivar acceso a Internet (datos).

Pero, por supuesto, todo esto se puede configurar hasta llegar al extremo ;) .

Lazarus, el clon de Delphi para FreePascal

IDE de Lazarus

En el inicio de la carrera, uno de los lenguajes que usábamos era Pascal1 porque era un lenguaje muy bueno para aprender por su sintaxis y no tan complicado como el C con los punteros (aunque también los tiene).

Después, con el ansia de hacer cosas más «profesionales» descubrí Delphi allá por la versión 3, para tener ya aplicaciones con interfaz gráfica escritas en Pascal avanzado (orientado a objetos y demás).

Es en esta época que mezcla el estudio de la carrera con la programación en Delphi en la que soy más productivo: hice infinidad de aplicaciones, principalmente para aprender a programar (por mi cuenta, todo hay que decirlo) aunque alguna sí que se salvó y usaba uso habitualmente.

Luego, con esto de la salida del estudio para integrarse en el mundo laboral, dejé de lado el Delphi para centrarme en… bueno, en lo que tocara en ese momento.

Pero ahora me he encontrado con que tengo que volver a hacer una aplicación, con interfaz gráfica (un editor de JSON principalmente aunque algo especial) y tiene que funcionar tanto en Windows como en Linux. En su momento probé Java pero necesitaba dos librerías que había que distribuir con el *.jar, así que le volví a dar una oportunidad al Pascal, aunque esta vez de la mano de Lazarus y FreePascal.

¿Y por qué FreePascal/Lazarus? Pues porque me ha sorprendido muy gratamente que el código fuente se compila y ejecuta sin ningún cambio en Windows y Linux (obviamente son ejecutables distintos pero un sólo código fuente). No hay que preocuparse en ningún momento de directivas de compilación, de hacer diferente código para diferentes sistemas operativos y basta con distribuir un sólo ejecutable.

Además, la interfaz gráfica es totalmente coherente con la interfaz general del sistema sin ningún cambio en el código. Si estás en Linux tienes los temas de Linux y si estás en Windows tienes los temas de Windows. Incluso con los efectos de Windows 7.

Cierto es que hay lenguajes más “modernos” como Python, pero digamos que Python y yo no somos muy amigos. Y pongo “modernos” entre comillas porque en realidad no importa la modernidad del lenguaje: C es de 1972, C++ de 1980 y Cobol (el lenguaje que usan muchísimos sistemas bancarios) es de 1960.

En definitiva, si queréis desarrollar rápido una aplicación y habéis hecho vuestros pinitos en Pascal/Delphi hace sus años, Lazarus es una buena opción. Eso sí, no le pidáis peras al olmo porque esto es para lo que es: desarrollo rápido pero casi sin planificación y con un código un poco spaghetti (es lo que tiene el desarrollo dirigido a eventos). Y tened en cuenta también que esta experiencia no os servirá para mucho más. Aún así a mi me está resolviendo la papeleta de una forma muy… elegante ;) .

Nota: Considero que Pascal es un lenguaje de programación excelente para aprender a programar porque abstrae mucho más que C y similares de los entresijos de la arquitectura del ordenador centrando la atención en los algoritmos y en las estructuras de datos. Y lo mismo pienso de la programación orientada a objetos: no se debería ver hasta tener una buena base de programación estructura y, ni mucho menos, iniciarse en la programación usando POO. Y parece que esto último no soy el único que lo piensa.

Lanzar excepciones de forma polimórfica en C++

Otro de mis ladrillos sobre C++. Esta vez sobre lanzamiento de excepciones polimórficas en C++ sobre Linux. Vamos al lío:

Para ponernos en antecedentes, digamos que tenemos una aplicación multihilo escrita en C++ en Linux. Cuando en uno de los hilos se produce una excepción, esta debe ser atrapada (try { ... } catch(...) { ... }) dentro del propio hilo. En caso de que no se haga así, la excepción se propaga al hilo principal (main()) sin posibilidad de atraparla, con lo que la aplicación finaliza.

Para resumir este punto: las excepciones no se propagan entre diferentes hilos de ejecución por lo que hay que atraparlas y procesarlas dentro del propio hilo.

Pero ¿qué pasa cuando queremos que una excepción sí se propague a otros hilos? Es decir, que un error que se produce en un hilo se notifique a otro hilo para que tome medidas. Por ejemplo, tenemos un hilo que gestiona las comunicaciones y otro que gestiona la interfaz. Cuando se produce un error de comunicación es la interfaz la que tiene que notificar al usuario de dicho error.

Soluciones existen varias. Una de ellas es enviar un mensaje con la excepción que se produce al hilo que la procesa aunque hay que tener en cuenta que debe haber una arquitectura de paso de mensajes entre hilos previa.

Por ejemplo, en pseudocódigo, el hilo de comunicaciones:

void
hilo_comunicaciones() {
while(mensaje = cola_mensajes.getMensaje()) {
try {
enviar_mensaje(mensaje);
mensaje = recibir_respuesta();
} catch(Exception& e) {
notificar_interfaz(e);
}
}
}

Y ahora el hilo de proceso de las notificaciones en la interfaz:

void
hilo_proceso_notificaciones_error_comunicaciones(Exception& e) {
try {
throw e;
} catch(ComunicationException& e) {
// procesar excepciones relativas a la conexión
} catch(TimeOutException& e) {
// procesar excepciones relativas al fallo de la conexión por tiempo
} catch(ProtocolException& e) {
// procesar excepciones por errores de protocolo
} catch(…) {
// procesar excepciones generales
}
}

El problema del proceso de procesado de excepciones en la interfaz es que al relanzar la excepción que se recibe como parámetro (throw e;) esta no es la excepción recibida en el hilo de comunicaciones, es decir, no hay polimorfismo por lo que siempre se procesa como una excepción general en lugar de la correspondiente.

La opción de usar typeid(e).name() en la excepción para procesar su tipo no es viable porque es demasiado costosa (el operador typeid es bastante costoso) y porque el nombre de la excepción no es estándar, esto es, en GNU C++ (g++) el nombre está “retorcido”, mangled en inglés.

La opción recomendable es añadir a la excepción base de tu aplicación, teniendo en cuenta que para tu aplicación has desarrollado una jerarquía de excepciones acorde con su funcionalidad, un método virtual que implementen las excepciones derivadas donde, simplemente, se lancen a sí mismas.

Un código de ejemplo sería el siguiente:

// Excepción base de la jerarquía de excepciones de mi aplicación
class Exception : public runtime_error {
public:
Exception(const string msg) : runtime_error(msg) {}
virtual void raise() { throw *this; }
};

// Excepción que se lanza cuando hay un error de acceso denegado
class AccessDeniedException : public Exception {
public:
AccessDeniedException(const string msg) : Exception(msg) {}
virtual void raise() { throw *this; }

};

// Resto de excepciones derivadas conforme a los
// errores que se quieren notificar

Con esta forma de declarar las excepciones, el código de gestión de las notificaciones de error en la interfaz quedaría:

void
hilo_proceso_notificaciones_error_comunicaciones(Exception& e) {
try {
e.raise();
} catch(ComunicationException& e) {
// procesar excepciones relativas a la conexión
} catch(TimeOutException& e) {
// procesar excepciones relativas al fallo de la conexión por tiempo
} catch(ProtocolException& e) {
// procesar excepciones por errores de protocolo
} catch(…) {
// procesar excepciones generales
}
}

Con lo que funcionaría sin ningún problema ya que la excepción se lanza de forma polimórfica al usar un método virtual en la clase base que implementan todas las clases derivadas.

Para hacer una prueba se puede descargar un archivo con un programa de ejemplo (1,4 KB). Para compilarlo basta con ejecutar el comando g++ -o test exception-test.cpp.

Y por ir un poco más allá, se podría pensar que para implementar todas las excepciones que usa una aplicación habría que escribir bastante código, además, la mayoría sería repetido; lo único que cambiaría sería el nombre de la excepción y del constructor, el resto es todo igual.

Bueno, pues para eso están las macros de C: se puede crear una macro a la que se le pase como parámetro el nombre de tu nueva excepción y que ella genere todo el código restante. Pero no olvidéis que las macros son malignas en 4 formas diferentes.

Consumo excesivo de memoria de nm-applet en Ubuntu

¿Es normal que el nm-applet, la aplicación que gestiona las conexiones a redes en Ubuntu (el applet del NetworkManager), consuma más de 500 MB de memoria RAM después de tener el sistema arrancado menos de un día?

Consumo de memoria de nm-applet

Después de buscar un rato, una de las razones que se dan es que, debido a las actualizaciones en lugar de a una reinstalación limpia del sistema operativo, puede que queden archivos de configuración incorrectos que dan lugar a este consumo excesivo de memoria.

Y después de seguir buscando… no aparece nada más excepto que este problema se da en bastante usuarios.

Una forma de mitigarlo es matar el proceso nm-applet en el administrador de procesos y, posteriormente, iniciarlo como root presionando Alt+F2 y ejecutando gksu nm-applet --sm-disable.

Así que, de momento, no hay resolución. Habrá que estar atento para que el proceso no se desboque y podamos seguir trabajando sin reiniciar.

El mandamiento «Donut»

Y el señor dijo a los hombres:

“Aquel que actualice el repositorio rompiendo la compilación deberá pagar una penitencia en donuts”.

Esa es la ley.

Lo vi en MundoGeek y lo pongo porque me ha gustado… y porque hoy lo he hecho. He roto la compilación :oops: . Por cierto, la he roto en la revisión 1666 ;) .

Además tienen ustedes una imagen con esta “ley” y con una foto. Eso sí, en inglés.

Actualización: También hay una versión personalizada en español ;) .

Solucionar la espera infinita a la acción del usuario en GRUB2 cuando la máquina no se apaga correctamente

Hace tiempo que comenté el problema de que GRUB2 se quedaba esperando la respuesta del usuario al hibernar Ubuntu.

Pues ese problema se produce en más ocasiones y, una de ellas, es que cuando el sistema operativo no se apaga correctamente, es decir, no se apaga con reboot o poweroff sino que hay un fallo en el sistema operativo o hay un fallo de corriente, al reiniciar de nuevo, a GRUB2 le da por esperar hasta que el usuario seleccione una de las entradas de su lista de sistemas operativos.

Eso no está nada mal cuando es un ordenador de escritorio, así puede saber que ha ocurrido un error y entrar en el modo seguro para solucionarlo. El problema viene cuando el sistema operativo se está ejecutando en un servidor que no tiene ni pantalla ni teclado. Te puedes tirar un día intentando conectar por ssh probando diferentes IP y diferentes cables hasta que, por fin, te decides ir a la sala donde está y poner un monitor y un teclado para ver, con entre sorpresa y cabreo, que llevas una jornada intentando conectar con GRUB porque está esperando a que algún usuario compasivo presione Enter.

Este es un error de GRUB, no es que haya una configuración rara por ahí, así está programado en sus scripts. Existe una variable de este cargador de arranque que se llama recordfail que es la que se fija cuando se apaga correctamente y que es la que hace esperar cuando hay un error.

Para intentar aplicar un parche para solucionarlo hay que editar dos archivos. El primero es el archivo /etc/default/grub. En ese archivo hay que comentar (con una almohadilla como primer carácter de la línea: #) la línea que contiene el texto GRUB_HIDDEN_TIMEOUT="0". Además, si estás en un servidor, también se pueden quitar los parámetros por defecto del kernel, quiet splash, para que salga la información de inicio en lugar de la agradable imagen de inicio del sistema.

El segundo archivo que hay que modificar es el archivo /etc/grub.d/00_header. Hay que modificar la función make_timeout() (a partir de la línea 238, más o menos) comentando (también con una almohadilla como primer carácter de la línea: #) la línea que pone set timeout=-1 y añadiendo, justo debajo, la línea set timeout=15, donde 15 es el número de segundos que esperará GRUB a iniciar en caso de error (en caso de que recordfail esté a 1). Y digo comentar en vez de sustituir la línea para que, en caso de que no funcione, se pueda volver sin problemas a la versión anterior de este archivo.

Con estos cambios conseguiremos que aunque el equipo no se apague correctamente, sí se inicie correctamente cuando vuelva la luz (o cuando se inicie de nuevo). Y, en caso de que el fallo sea de hardware o de software, no os preocupéis que el propio Linux ya indicará información sobre el error.

Clases en C++ con constructores con parámetros variables (variadic functions)

Tanto C como C++ tienen la característica, mediante macros, de crear funciones con un número indefinido de argumentos. Esto es lo que se conoce como variadic functions.

Un ejemplo de una función en C con argumentos variables sería el siguiente:

#include <stdarg.h>

int
variadic_function(int arg_count,...) {
va_list arg_list;
va_start(arg_list,arg_count);
int i, sum;
for(i = 0; i < arg_count; i++) {
sum += va_arg(arg_list,int); // acciones con el argumento
}
return sum;
}

Para declarar una función que tenga un número indefinido de argumentos es necesario incluir los puntos suspensivos (…) como argumento, pero al menos debe tener uno que no sea indefinido, esto es, primero un argumento y, posteriormente, los puntos suspensivos. Esto es así porque en la función va_start() hay que pasarle, como segundo argumento, el nombre del último argumento conocido de la función. Si no tuviese al menos un argumento conocido no se podría pasar este argumento a la función va_start().

También se pueden crear métodos (funciones dentro de clases) que tengan la lista de argumentos variable, incluidos los constructores de las clases, de la forma:

class MyClass {
public:
MyClass(...);
};

Y dirán ustedes ¿y aquí por qué no se pone al menos un argumento como nos acabas de indicar?

Y yo voy a responder con otra pregunta: ¿qué es lo que te enseñan el primer día de curso de programación orientada a objetos sobre los métodos de una clase? Que los métodos no estáticos de una clase tienen un argumento implícito que es un puntero a la instancia de dicha clase. El famoso puntero this en lenguajes como C++, Java, D y alguno que otro más.

Y como este argumento es el primero del método, se puede pasar sin problemas como segundo argumento de la función va_start() para indicar que es el último definido de la lista. La implementación sería, más o menos, así:

#include <cstdarg>

using namespace std;

#include "MyClass.hpp"

MyClass::MyClass(...) {
int size = X; // el tamaño lo tenemos que tener especificado de alguna forma
int sum = 0;
va_list arg_list;
va_start(arg_list,this);
for(int i = 0; i < size; i++) {
sum += va_arg(arg_list,int);
}
va_end(arg_list);
}

Esto de los argumentos indefinidos en C y C++ es una de las chapuzas que hay para tener esta funcionalidad ya que, en su mayoría, se hace con macros (aunque están implementadas de forma interna al compilador).

Hasta que no tengamos el estándar C++0x (el nuevo estándar de C++ que supongo que ya quedará poco para que salga definitivamente) no tendremos esta característica incluida en el lenguaje. Incluso se ha ampliado a parámetros variables en las plantillas (variadic templates), con lo que podremos tener tuplas de n elementos de distinto tipo. Pero, de momento, nos conformaremos ;) .

Desarrollar librerías en linux usando otras librerías (y sus curiosos efectos)

Después del pequeño tostón del otro día donde se comentaba la ruta de las librerías en Linux, hoy toca comentar el gran tostón de cómo se desarrollan librerías que usen otras librerías y varios efectos durante el enlazado. Si no estáis muy interesados en el desarrollo de librerías en Linux no sigáis leyendo porque quizás me odiéis. Y si sí desarrolláis librerías… bueno, quizás tampoco deberíais seguir… quedáis avisados.

Lo primero, una descripción rápida de como programar una libraría en Linux:

Creas el archivo de código fuente, por ejemplo mylib.cpp, para luego compilarlo con la opción del compilador de generar código independiente de la posición (PIC):

$ g++ -Wall -fPIC -c mylib.cpp

Luego enlazas todos los archivos objeto resultantes (*.o) en el binario de la librería indicándole al linker, además, el nombre de la librería (soname):

$ g++ -shared -Wl,soname,libmylib.so.0 -o libmylib.so.0.1 *.o

Una vez hecho esto se puede instalar la librería en algún directorio como /usr/local/lib u /opt/lib, aunque no es necesario para hacer estas pruebas.

Para usar la librería, basta con crear un programa, por ejemplo myprog.cpp, y enlazar esta librería en él. Eso sí, no os olvidéis de indicarle al compilador dónde están los archivos de cabecera (con la opción -I) y de exportar la variable LD_LIBRARY_PATH indicando el directorio de vuestra librería (como vimos el otro día):

$ g++ -I/path/to/mylib/include -o myprog -lmylib myprog.cpp

Una vez tenemos la librería y nuestro programa que la usa vamos con los curiosos efectos:

En el caso de que nuestra librería use otra librería de forma interna, a la hora de compilar es necesario indicarle donde están los archivos de cabecera de la librería a usar (opción -I) pero no es necesario indicarle, a la hora de enlazar, la librería con la que enlazar:

$ g++ -Wall -fPIC -I/path/to/otherlib/include -c mylib.cpp
$ g++ -shared -Wl,soname,libmylib.so.0 -lotherlib -o libmylib.so.0.1 *.o

A la hora de compilar nuestro programa con nuestra librería enlazada de la forma anterior, es necesario que enlacemos nuestro programa a la otra librería, sino ni siquiera enlazará porque no se pueden resolver los símbolos de otherlib que usa mylib. Por ello nuestro programa se compilaría:

$ g++ -o myprog -lmylib -lotherlib myprog.cpp

En caso de enlazar mylib con otherlib (usando la opción -lotherlib antes comentada), no sería necesario enlazar myprog con otherlib. Resumiendo este tostón incomprensible: hay que enlazar nuestro programa con todas las librerías que use y todas las que usen éstas y no lo estén ya en las mismas, aunque siempre es mejor enlazar cada cosa con lo que utiliza.

Un ejemplo:

  • Compilo mylib sin enlazar con otherlib:
    • Compilo myprog enlazando a mylib: error porque no enlaza con otherlib.
    • Compilo myprog enlazando a mylib y otherlib: todo correcto.
  • Compilo mylib enlazando con otherlib:
    • Compilo myprog enlazando a mylib: todo correcto porque, aunque hace uso de otherlib, esta ya está enlazada en mylib.
    • Compilo myprog enlazando a mylib y otherlib: todo correcto aunque innecesario porque otherlib ya está enlazada con mylib.

Buf… bueno, yo lo entiendo porque me ha pasado y he investigado un rato para resolverlo, pero visto aquí, así, sin anestesia… pues cuesta. Pero bueno, aquí queda por si en un futuro se me olvida. Y para quién le sea útil, por supuesto.

Ruta para las librerías en desarrollo en Linux

Cuando estás desarrollado alguna librería en Linux, es probable que durante este desarrollo no tengas la librería instalada en los directorios por defecto del sistema (que son /lib, /usr/lib y /usr/local/lib) por lo que cuando vayas a probar el programa que hace uso de esa librería se produzca el siguiente error:

diego@box:~/projects/my_lib/test:$ ./test
test: error while loading shared libraries: libsxxx.so: cannot open shared object file: No such file or directory
diego@box:~/projects/my_lib/test:$

Para solucionarlo basta que con insertes en la variable de entorno LD_LIBRARY_PATH el directorio donde está esta librería:

diego@box:~/projects/my_lib/test:$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../lib

Suponiendo que la librería está en ../lib.

Con esto ya se ejecutará tu programa de prueba sin problemas, aunque hay que tener en cuenta que cuando salgas de ese terminal esta variable va a volver a su valor original (que suele ser la cadena vacía).

Una vez que instales tu librería en alguna ruta del sistema (generalmente las librerías propias irán en /usr/local/lib) debes ejecutar el comando ldconfig para que se actualice la caché de librerías y todos los programas que la usen la encuentren sin problemas.

Windows en procesadores ARM

¿Recuerdan ustedes que comenté que mi previsión era que los procesadores ARM conquistasen el escritorio y que, probablemente, no sería Windows el sistema operativo que los controlase? Pues parece que Microsoft no quiere perder esa parte del pastel (como es lógico) y ya planea portar sus Windows a esta arquitectura.

Dicen que Windows NT es (o era) bastante portable y que lleva años funcionando en procesadores ARM dentro de los laborarios de Microsoft, pero ¿cuánto de Windows NT tiene Windows 7?

Además, espero que sea rápido porque Android ya está muy metido en harina, sobre todo en tablets que, a mi entender, son el futuro cercano de las comunicaciones móviles junto con los teléfonos “inteligentes” o smartphones.

Estaremos atentos a los movimientos en el patio.

Script con Zenity para mostrar un dialogo de descarga mediante wget

Mediante el script mostrado a continuación, desarrollado en BASH, se pueden descargar archivos de Internet con el comando wget y mostrando una interfaz gráfica con una barra de progreso mediante Zenity. La ventana mostrada se cierra cuando alcanza el 100%.

#!/bin/bash

function download() {
rand="$RANDOM `date`"
pipe="/tmp/pipe.`echo ‘$rand’ | md5sum | tr -d ‘ -’`"
mkfifo $pipe
wget -c $1 2>&1 | while read data; do
if [ "`echo $data | grep '^Longitud:'`" ]; then
total_size=`echo $data | grep "^Longitud:" | sed ‘s/.*\((.*)\).*/\1/’ | tr -d ‘()’`
fi
if [ "`echo $data | grep '[0-9]*%’ `" ];then
percent=`echo $data | grep -o "[0-9]*%" | tr -d ‘%’`
current=`echo $data | grep "[0-9]*%" | sed ‘s/\([0-9BKMG.]\+\).*/\1/’ `
speed=`echo $data | grep "[0-9]*%" | sed ‘s/.*\(% [0-9BKMG.]\+\).*/\1/’ | tr -d ‘ %’`
remain=`echo $data | grep -o "[0-9A-Za-z]*$" `
echo $percent
echo "#Descargando «$1»…\n\nDatos descargados\t\t: $current de $total_size ($percent%)\nVelocidad de descarga\t: $speed/s\nTiempo estimado\t\t: $remain"
fi
done > $pipe &

wget_info=`ps ax | grep "wget.*$1" | awk ‘{print $1"|"$2}’`
wget_pid=`echo $wget_info | cut -d’|’ -f1 `

zenity --progress --auto-close --window-icon "/usr/share/icons/hicolor/48×48/status/aptdaemon-download.png" --text="Conectando a «$1»…\n\n\n" --width="350" --title="Descargando «`basename $1`»…" < $pipe
if [ "`ps -A |grep "$wget_pid"`" ]; then
kill $wget_pid
fi
rm -f $pipe
}

if [ $1 ]; then
download "$1"
else
dllink=$(zenity --entry --text "Indique el enlace a descargar:" --width="350" --entry-text "" --title="Descargar archivo de URL")
if [ $dllink ]; then
download "$dllink"
fi
fi

Para hacerlo funcionar basta guardar el código anterior en un archivo de texto (por ejemplo zdownload) para luego darle los permisos de ejecución (chmod 755 zdownload). Cuando se ejecute este programa sin parámetros, mostrará una ventana para introducir la URL de descarga. Una vez hecho esto, se ejecutará la aplicación mostrando una ventana como esta:

Progreso de Zenity

El script original lo vi en Ubuntu Life aunque yo lo he retocado un poco para que reconozca que el comando wget está en español.

ARM a por el escritorio

Que ARM de el salto a ordenadores de escritorio es cuestión de tiempo. Ya lo comentaba Diego Calleja, pero cuanto más tiempo pasa más claro está.

Porque resulta ARM está preparando un procesador destinado no sólo a teléfonos móviles, sino también a ordenadores portátiles. Y eso es asaltar el escritorio.

Pero no sólo eso, además está preparando otro procesador ¡para servidores! Sí, habéis oído bien: un ARM en servidores. Y puede que las características no sean muy halagüeñas (1,6 GHz de velocidad) pero hay que tener en cuenta que sólo consumirá 10 W.

Ahora mismo Intel tiene que estar un poco nervioso por lo que se avecina. Pero no creo que estén parados. Puede que intenten sacar un nuevo procesador que consuma poco y tenga el mismo rendimiento que los ARM, incluso puede que lo consigan, pero recordemos que su handicap principal es la arquitectura x86 (que es CISC y tiene más de 25 años) con su amplísimo juego de instrucciones, no la tecnología de fabricación. ARM tiene una arquitectura RISC muchísmo más sencilla con un juego de instrucciones más simple y con un mayor número de registros. Esto, a priori, hace que sea mucho más escalable que la de Intel que creo que ya ha dado bastante de sí.

Pero aún sí, este no es el punto más fuerte del tema. El punto más fuerte es saber cual será el sistema operativo que se llevará el gato al agua de los ordenadores personales con esta nueva arquitectura. Porque Windows domina en x86, pero creo que no hay port para ARM. Y Linux sí que está portado a esta arquitectura y con muy buenos resultados. De hecho Android, MeeGo y WebOS son Linux y todos funcionan perfectamente en sus correspondientes teléfonos cuya arquitectura es ARM y sería muy fácil llevarlos al ordenador de escritorio.

Digamos que gracias a este cambio (que es una suposición, no se vayan ustedes a pensar que soy adivino) todos los sistemas operativos parten desde el mismo punto: Windows gracias a su solera —aunque no tenga port para ARM— y Linux porque sí funciona en ARM pero no está tan difundido.

¿Conseguiremos ver esto en un plazo razonable? ¿Conseguirá triunfar el software libre entre el gran público? Eso espero…

Ahora vamos con los deseos: existe “el otro” sistema operativo, esto es, Haiku, el clon de mi querido y desaparecido BeOS. Si se ponen las pilas y emplean su tiempo en una implementación para ARM (en lugar de hacerla para los Amiga M68k, que también, pero ahora no) quizás consigan salir con unas ventajas y capacidades cercanas a las de los dos sistemas operativos principales y quizás lograrían entrar en el juego. Pero ya digo, sólo quizás, aunque me gustaría.

NetworkManager no se lleva bien con las interfaces virtuales

Vamos, no es que no se lleve ni bien ni mal, directamente no se lleva. NetworkManager, el gestor de conexiones de redes en Linux, no soporta interfaces virtuales de red como, por ejemplo, eth0:1.

Para centrarnos un poco pero sin profundizar, una interfaz virtual es una interfaz ficticia asociada a una interfaz real, esto es, simular dos tarjetas de red teniendo sólo una. También se llaman “alias”.

¿Y esto para que sirve? Pues para acceder, por ejemplo, a dos redes diferentes desde el mismo equipo. Por ejemplo, la IP real de nuestro equipo es 192.168.1.42 con máscara de subred 255.255.255.0 y queremos acceder a un equipo cuya IP es 192.168.2.100 con máscara de subred 255.255.255.0. Como están en distinta red no se puede acceder directamente, a no ser que creemos una interfaz virtual o alias de red.

Para ello basta con configurar en el archivo /etc/network/interfaces la nueva interfaz. Suponiendo que nuestra interfaz principal se llame eth0, el archivo de configuración quedaría así (además de lo que hubiese antes):

auto eth0:1
iface eth0:1 inet static
address 192.168.2.42
netmask 255.255.255.0
network 192.1638.2.0
broadcast 192.168.2.255

En caso de que nuestra interfaz tuviese un nombre diferente, por ejemplo ra0, el nombre de la interfaz virtual debería ser ra0:1 (o cualquier otro número entero detrás de los dos puntos).

Una vez hecha la configuración, la nueva interfaz virtual se activa mediante el comando:

diego@box:~:$ sudo ifup eth0:1

Pero, como reza el título de esta entrada y como ya iba siendo hora de contarlo, si usas Ubuntu con NetworkManager, en el próximo reinicio de la máquina la interfaz virtual no se activará porque NetworkManager no soporta interfaces virtuales.

Pero como (casi) siempre, en Linux hay solución. Para ello hay que hacer uso de la ejecución de los scripts que usa NetworkManager. Estos scripts se encuentran en el directorio /etc/NetworkManager/dispatcher.d. Ahí hay que crear un archivo —al que llamaré updownaliases— con el siguiente contenido (cambiando el nombre de la interfaz según corresponda):

#!/bin/bash

iface="$1"
shift

action="$1"
shift

if [ "$iface" == "eth0" ]; then
case "$action" in
up)
/sbin/ifup eth0:1
;;
down)
/sbin/ifdown eth0:1
;;
*)
echo "updownaliases: Invalid action for $iface: $action" 1>&2
exit 1
;;
esac
fi

Este archivo debe pertenecer a root (los que no pertenecen a root son ignorados) y luego hay que darle los permisos de ejecución mediante el comando:

diego@box:~:$ sudo chmod 755 updownaliases

Para probarlo basta con que desactivéis y activéis la red desde el NetworkManager (botón derecho sobre el icono y hacer clic en el menú «Activar red»). Para comprobar si todo es correcto hay que ejecutar el comando:

diego@box:~:$ ifconfig

Y ahí tienen que salir todas las interfaces, tanto la real (que generalmente es eth0) como la virtual o alias, que, en este caso, es eth0:1.

Con Eclipse mejor Sun JDK que OpenJDK

Una nota rápida: si usas Eclipse en Linux seguramente este esté usando OpenJDK para ejecutarse. OpenJDK es la implementación libre de la plataforma Java y es generalmente el paquete que viene por defecto en la mayoría de las distribuciones, entre ellas en Ubuntu.

Pero de vez en cuando a Eclipse le da por petarse con un SIGSEGV. Vamos, con una violación de segmento de toda la vida. Y esto es porque el OpenJDK tiene algún error.

Para solucionarlo basta con desinstalar el OpenJDK e instalar la versión oficial de Java que está en los repositorios:

diego@box:~:$ sudo apt-get remove openjdk
[...]
diego@box:~:$ sudo apt-get install sun-java6*
[...]
diego@box:~:$

Con estos simples comandos, aunque perdemos la pureza que algunos quieren darle a los sistemas GNU/Linux de que todo el software sea libre, tu Eclipse estará contento y trabajarás mucho mejor. Porque de lo que se trata es de que trabajes bien y a gusto con tu sistema informático. La filosofía la dejamos para otro día.

Parche para el módulo site_map de Drupal

He creado un parche para el módulo site_map de Drupal para poder incluir en el mapa del sitio todos los menús que estén ocultos, porque a veces es necesario que el menú de cada página (que suele estar en un lateral) no tenga tanta profundidad, pero sí debe salir en el mapa del sitio.

Actualmente el parche no está dentro de la rama principal de desarrollo pero, una vez instalado el módulo, se puede aplicar a partir de los archivos *.patch (generados con svn diff) con la herramienta patch.

Es la primera vez que contribuyo a un proyecto libre y, por supuesto, esta entrada es únicamente para engordar mi ego (a veces pasa…), aunque espero que el parche sea incluido y al menos le sirva a alguien a parte de a mi ;) .