En esta ocasión vamos a hablar de como aplicar parches o comúnmente llamado en ingles Patch, que tan usado es por ejemplo para actualizar el kernel.
Comencemos por el concepto:
Cita wikipedia:
Ahora vamos a aclarar que el patching se pueden aplicar a 2 tipos de cosas:
* Al código fuente del programa
* Al archivo binario (ya compilado)
Por ahora vamos a concentrarnos en el primer tipo.
Parcheando un código fuente
Supongamos que entramos a una web de algún proyecto open source, el código fuente de la aplicación que se esta creando en el proyecto esta disponible desde allí, nos ponemos a revisar el código y vemos algo como esto:
#include <stdio.h>
main() {
int *pnt;
int i, a[3]={1,2,3};for(dato=0; i<3; i++) {
pnt = &a[dato];
printf(«Puntero = %d\n», pnt);
}return 0;
}
Obviamente no es un programa real ni parte de ningún otro, solo un ejemplo que escribí que va a servir para demostrar el uso de los parches.
Ohh, ahí hay un error en una linea, si se compila de esa forma el programa no va a funcionar como debe.
printf(«Puntero = %d\n», pnt);
En esa parte, hay un error en el acceso del contenido del puntero, falta el «*«.
Un error mínimo que no va a dar ninguna clase de problemas en la compilación pero que haría que el programa fuera inútil, sabiendo esto ¿que podríamos hacer?.
Pues una opción seria aplicarle un parche que corrija el error.
¿Como hacerlo?
En GNU/Linux disponemos de dos herramientas que hacen el trabajo extremadamente fácil.
* diff
* patch
Lo primero seria guardar el código fuente, como es un ejemplo, que tenga de nombre programa1.c , ahí tendríamos el programa tal cual esta con el error incluido, ahora creo otro archivo con el mismo código pero cambiado la linea del error por esta:
printf(«Puntero = %d\n», *pnt);
De hecho ese seria el único cambio (en este caso agregar el «*«), el código reparado lo guardamos como programa2.c
Ahora viene la magia, diff es un programa que compara 2 archivos y muestra las diferencias de este, en este caso eso es justo lo que necesitamos.
La sintaxis:
$> diff programa1.c programa2.c > parche.patch
Analizando la linea notamos que compara los dos programas y las diferencias las escribe en un nuevo archivo parche.patch.
Ya tenemos el parche, ahora solo falta aplicarlo, esto lo vamos a hacer con otra aplicación de los sistema Lunix que se llama patch.
Lo que hace este es que toma las diferencias de 2 programas (el parche.patch) y esta diferencia la aplica al archivo original.
La sintaxis:
$> patch -p1 -i parche.patch programa1.c
Analizando:
El -p1 se puede omitir en este caso, se usa más que nada para cuando hay parches en directorios diferentes, y sirve para omitir los slash y la ruta superior.
El -i viene de input y lee el archivo parche.patch
Si todo salio bien el sistema arroja este mensaje:
patching file programa1.c
Y si no hay errores el programa ya debería estar parchado.
Ahora podemos enviarle el parche para que sea aplicado al resto de los usuarios que lo precisen.
Parcheando un archivo binario
Ahora vamos al segundo caso, que pasa si el código fuente del proyecto ya fue compilado (aun con el error) y también ya fue distribuido.
Primero seria sustituir el archivo de la descarga de la web por el correcto, pero.. ¿y los usuarios? , cuando son programas muy grandes no se les puede decir que desinstalen todo y vuelvan a bajar el programa y después volver a instalarlo, en este caso es mejor aplicarle un parche que solucione el error.
¿Como generar el parche?, pues fácil, usando las mismas herramientas que cuando parcheamos el código fuente.
Como anteriormente teníamos el código fuente original (con el error) programa1.c y el código reparado programa2.c, vamos a compilar los 2 código para generar 2 binarios.
$> gcc programa1.c -o programa1
$> gcc programa2.c -o programa2
Ahora vamos a compararlos de esta manera y a generar el nuevo parche:
$> diff -a –binary programa1 programa2 > parchebin.patch
Revisando el comando, diff tenemos:
El -a indica que va a tratar los archivos como texto y va a comparar linea por linea.
El –binary que va a ser una comparación binaria y el parche va a ser de la misma forma.
El programa1 y programa2 son los archivos ya compilados.
parchebin.patch el archivo a usar resultante de la comparación para parchear.
Con eso ya tenemos todo listo, ¿como lo aplicamos?.
Pues bastante parecido al ejemplo anterior y siempre usando patch.
La sintaxis del comando en este caso resulta bastante simple:
$> patch –binary programa1 parchebin.patch
El –binary que el parche se va aplicar de forma binaria y programa1 es el fichero al cual le vamos a aplicar el parche. Todos los archivos deben estar en el mismo directorio.
Si tenemos éxito en estos 2 pasos tendríamos en resultado siguiente:
patching file programa1
En caso de que quisiéramos facilitarle aun más el trabajo al usuario y evitar que se ponga a ejecutar comandos podríamos hacer todo automáticamente con un pequeño script en bash.