Me pregunto cómo se pueden actualizar aplicaciones asesinas como Thunderbird o Firefox a través del administrador de paquetes del sistema mientras aún se están ejecutando. ¿Qué sucede con el código antiguo mientras se actualizan? ¿Qué debo hacer cuando quiero escribir un programa que se actualice mientras se está ejecutando?
files
upgrade
executable
ubuplex
fuente
fuente
Respuestas:
Reemplazar archivos en general
Primero, hay varias estrategias para reemplazar un archivo:
Abra el archivo existente para escribir, trúnquelo a 0 de longitud y escriba el nuevo contenido. (Una variante menos común es abrir el archivo existente, sobrescribir el contenido antiguo con el nuevo contenido, truncar el archivo a la nueva longitud si es más corto). En términos de shell:
Elimine el archivo antiguo y cree un nuevo archivo con el mismo nombre. En términos de shell:
Escriba en un nuevo archivo con un nombre temporal, luego mueva el nuevo archivo al nombre existente. El movimiento elimina el archivo antiguo. En términos de shell:
No enumeraré todas las diferencias entre las estrategias, solo mencionaré algunas que son importantes aquí. Con la estrategia 1, si algún proceso está usando el archivo actualmente, el proceso ve el nuevo contenido a medida que se actualiza. Esto puede causar cierta confusión si el proceso espera que el contenido del archivo permanezca igual. Tenga en cuenta que esto solo se trata de procesos que tienen el archivo abierto (como se ve en
lsof
o dentro ; las aplicaciones interactivas que tienen un documento abierto (por ejemplo, abrir un archivo en un editor) generalmente no mantienen el archivo abierto, cargan el contenido del archivo durante el Operación "abrir documento" y reemplazan el archivo (usando una de las estrategias anteriores) durante la operación "guardar documento"./proc/PID/fd/
Con las estrategias 2 y 3, si algún proceso tiene el archivo
somefile
abierto, el archivo antiguo permanece abierto durante la actualización de contenido. Con la estrategia 2, el paso de eliminar el archivo de hecho solo elimina la entrada del archivo en el directorio. El archivo en sí solo se elimina cuando no tiene una entrada de directorio que lo lleve (en los sistemas de archivos Unix típicos, puede haber más de una entrada de directorio para el mismo archivo ) y ningún proceso lo tiene abierto. Aquí hay una manera de observar esto: el archivo solo se elimina cuando se cierra elsleep
proceso (rm
solo elimina su entrada de directorio).Con la estrategia 3, el paso de mover el nuevo archivo al nombre existente elimina la entrada del directorio que conduce al contenido anterior y crea una entrada de directorio que conduce al nuevo contenido. Esto se realiza en una operación atómica, por lo que esta estrategia tiene una gran ventaja: si un proceso abre el archivo en cualquier momento, verá el contenido antiguo o el nuevo contenido; no hay riesgo de obtener contenido mixto o el archivo no existente.
Sustitución de ejecutables
Si prueba la estrategia 1 con un ejecutable en ejecución en Linux, obtendrá un error.
Un "archivo de texto" significa un archivo que contiene código ejecutable por razones históricas oscuras . Linux, como muchas otras variantes de Unix, se niega a sobrescribir el código de un programa en ejecución; Algunas variantes de Unix permiten esto, lo que lleva a bloqueos a menos que el nuevo código fuera una muy buena modificación del antiguo código.
En Linux, puede sobrescribir el código de una biblioteca cargada dinámicamente. Es probable que conduzca a un bloqueo del programa que lo está usando. (Es posible que no pueda observar esto
sleep
porque carga todo el código de biblioteca que necesita cuando se inicia. Pruebe un programa más complejo que haga algo útil después de dormir, comoperl -e 'sleep 9; print lc $ARGV[0]'
).Si un intérprete ejecuta un script, el intérprete abre el archivo de script de manera normal, por lo que no hay protección contra la sobrescritura del script. Algunos intérpretes leen y analizan el guión completo antes de comenzar a ejecutar la primera línea, otros leen el guión según sea necesario. Consulte ¿Qué sucede si edita un script durante la ejecución? y ¿Cómo trata Linux los scripts de shell? para más detalles.
Las estrategias 2 y 3 también son seguras para los ejecutables: aunque ejecutar ejecutables (y bibliotecas cargadas dinámicamente) no son archivos abiertos en el sentido de tener un descriptor de archivo, se comportan de una manera muy similar. Mientras algún programa ejecute el código, el archivo permanece en el disco incluso sin una entrada de directorio.
Actualizar una aplicación
La mayoría de los administradores de paquetes usan la estrategia 3 para reemplazar archivos, debido a la gran ventaja mencionada anteriormente: en cualquier momento, abrir el archivo conduce a una versión válida del mismo.
Donde las actualizaciones de la aplicación pueden romperse es que si bien la actualización de un archivo es atómica, la actualización de la aplicación en su conjunto no lo es si la aplicación consta de múltiples archivos (programa, bibliotecas, datos, ...). Considere la siguiente secuencia de eventos:
En el paso 3, la instancia en ejecución de la versión anterior de la aplicación está abriendo un archivo de datos de la nueva versión. Si esto funciona o no depende de la aplicación, de qué archivo es y cuánto se ha modificado el archivo.
Después de una actualización, notará que el antiguo programa aún se está ejecutando. Si desea ejecutar la nueva versión, deberá salir del programa anterior y ejecutar la nueva versión. Los administradores de paquetes generalmente matan y reinician los demonios en una actualización, pero dejan en paz las aplicaciones del usuario final.
Algunos demonios tienen procedimientos especiales para manejar las actualizaciones sin tener que matar al demonio y esperar a que la nueva instancia se reinicie (lo que causa una interrupción del servicio). Esto es necesario en el caso de init , que no se puede matar; Los sistemas init proporcionan una manera de solicitar que la instancia en ejecución llame
execve
para reemplazarse con la nueva versión.fuente
unlink
, como cubrimos más adelante. Tal vez "reemplaza el nombre existente", pero eso sigue siendo algo confuso.La actualización se puede ejecutar mientras se ejecuta el programa, pero el programa en ejecución que ve es en realidad la versión anterior. El viejo binario permanece en el disco hasta que cierre el programa.
Explicación: en sistemas Linux, un archivo es solo un inodo, que puede tener varios enlaces. P.ej. lo
/bin/bash
que ves es solo un enlace ainode 3932163
mi sistema. Puede encontrar a qué inodo hace algo el enlace emitiéndolols --inode /path
en el enlace. Un archivo (inodo) solo se elimina si hay cero enlaces apuntando a él y ningún programa lo está utilizando. Cuando el administrador de paquetes se actualiza, por ejemplo./usr/bin/firefox
, primero se desenlaza (elimina el enlace duro/usr/bin/firefox
), luego crea un nuevo archivo llamado/usr/bin/firefox
que es un enlace duro a un inodo diferente (el que contiene la nuevafirefox
versión). El antiguo inodo ahora está marcado como libre y se puede reutilizar para almacenar nuevos datos, pero permanece en el disco (los inodos solo se crean cuando construye su sistema de archivos y nunca se eliminan). En el próximo comienzo defirefox
, se usará el nuevo.Si desea escribir un programa que se "actualice" mientras se ejecuta, la única solución posible que se me ocurre es verificar periódicamente la marca de tiempo de su propio archivo binario, y si es más reciente que la hora de inicio del programa, vuelva a cargarla.
fuente
apt
trabajo de actualización de Debian ? Puedo actualizar cualquier programa en ejecución sin problemas, incluidoIceweasel
(Firefox
).dpkg
) no sobrescribe los archivos. En su lugar, los desvincula y coloca uno nuevo con el mismo nombre. Consulte la pregunta y la respuesta a las que me vinculé para obtener una explicación.ln
(enlaces duros). Puede eliminar nombres conrm
(desvincular). En realidad, no puede eliminar directamente un archivo, solo eliminar sus nombres. Cuando un archivo no tiene nombres y, además, no está abierto, el núcleo lo eliminará. Un programa en ejecución tiene abierto el archivo, por lo que incluso después de eliminar todos los nombres, el archivo sigue existiendo.Me pregunto cómo se pueden actualizar aplicaciones asesinas como Thunderbird o Firefox a través del administrador de paquetes del sistema mientras aún se están ejecutando. Bueno, puedo decirte que esto realmente no funciona bien ... He tenido un ataque de Firefox sobre mí horriblemente si lo dejo abierto mientras se ejecutaba una actualización del paquete. A veces tenía que matarlo con fuerza y reiniciarlo, porque estaba tan roto que ni siquiera podía cerrarlo correctamente.
¿Qué sucede con el código antiguo mientras se actualizan? Normalmente en Linux, un programa se carga en la memoria, por lo que el ejecutable en el disco no se necesita ni se utiliza mientras el programa se está ejecutando. De hecho, incluso puede eliminar el ejecutable y el programa no debería importarle ... Sin embargo, algunos programas pueden necesitar el ejecutable, y ciertos sistemas operativos (como Windows) bloquearán el archivo ejecutable, evitando la eliminación o incluso renombrar / mover, mientras que el El programa se está ejecutando. Firefox se rompe, porque en realidad es bastante complejo y utiliza un montón de archivos de datos que le indican cómo construir su GUI (interfaz de usuario). Durante la actualización de un paquete, estos archivos se sobrescriben (actualizan), por lo que cuando un ejecutable anterior de Firefox (en la memoria) intenta usar los nuevos archivos GUI, pueden suceder cosas extrañas ...
¿Qué debo hacer cuando quiero escribir un programa que se actualice mientras se está ejecutando? Ya hay muchas respuestas a su pregunta. Mira esto: /programming/232347/how-should-i-implement-an-auto-updater Por cierto, las preguntas sobre programación son mejores en StackOverflow.
fuente