Je me demande comment des applications tueuses telles que Thunderbird ou Firefox peuvent être mises à jour via le gestionnaire de paquets du système alors qu'elles sont toujours en cours d'exécution. Que se passe-t-il avec l'ancien code pendant sa mise à jour? Que dois-je faire lorsque je veux écrire un programme a.out qui se met à jour pendant son exécution?
files
upgrade
executable
ubuplex
la source
la source
Réponses:
Remplacement de fichiers en général
Tout d'abord, il existe plusieurs stratégies pour remplacer un fichier:
Ouvrez le fichier existant pour l'écriture, tronquez-le à la longueur 0 et écrivez le nouveau contenu. (Une variante moins courante consiste à ouvrir le fichier existant, à remplacer l'ancien contenu par le nouveau contenu, à tronquer le fichier à la nouvelle longueur s'il est plus court.) En termes de shell:
Supprimez l'ancien fichier et créez un nouveau fichier du même nom. En termes de coquille:
Écrivez dans un nouveau fichier sous un nom temporaire, puis déplacez le nouveau fichier vers le nom existant. Le déplacement supprime l'ancien fichier. En termes de coquille:
Je ne vais pas énumérer toutes les différences entre les stratégies, je vais juste en mentionner quelques-unes qui sont importantes ici. Avec la stratégie 1, si un processus utilise actuellement le fichier, le processus voit le nouveau contenu lors de sa mise à jour. Cela peut entraîner une certaine confusion si le processus s'attend à ce que le contenu du fichier reste le même. Notez que cela concerne uniquement les processus qui ont le fichier ouvert (comme visible dans
lsof
ou dans ; les applications interactives qui ont un document ouvert (par exemple, ouvrir un fichier dans un éditeur) ne gardent généralement pas le fichier ouvert, elles chargent le contenu du fichier pendant la "Ouvrir le document" et ils remplacent le fichier (en utilisant l'une des stratégies ci-dessus) pendant l'opération "enregistrer le document"./proc/PID/fd/
Avec les stratégies 2 et 3, si un processus a le fichier
somefile
ouvert, l'ancien fichier reste ouvert pendant la mise à niveau du contenu. Avec la stratégie 2, l'étape de suppression du fichier ne supprime en fait que l'entrée du fichier dans le répertoire. Le fichier lui-même n'est supprimé que s'il ne contient aucune entrée de répertoire (sur les systèmes de fichiers Unix typiques, il peut y avoir plusieurs entrées de répertoire pour le même fichier ) et qu'aucun processus ne l'a ouvert. Voici un moyen d'observer cela - le fichier n'est supprimé que lorsque lesleep
processus est tué (rm
supprime uniquement son entrée de répertoire).Avec la stratégie 3, l'étape de déplacement du nouveau fichier vers le nom existant supprime l'entrée de répertoire menant à l'ancien contenu et crée une entrée de répertoire menant au nouveau contenu. Cela se fait en une seule opération atomique, donc cette stratégie a un avantage majeur: si un processus ouvre le fichier à tout moment, il verra l'ancien contenu ou le nouveau contenu - il n'y a aucun risque d'obtenir du contenu mixte ou du fichier non existant.
Remplacement des exécutables
Si vous essayez la stratégie 1 avec un exécutable en cours d'exécution sur Linux, vous obtiendrez une erreur.
Un «fichier texte» signifie un fichier contenant du code exécutable pour des raisons historiques obscures . Linux, comme beaucoup d'autres variantes d'Unix, refuse d'écraser le code d'un programme en cours d'exécution; quelques variantes Unix le permettent, entraînant des plantages à moins que le nouveau code ne soit une modification très bien pensée de l'ancien code.
Sous Linux, vous pouvez remplacer le code d'une bibliothèque chargée dynamiquement. Il est susceptible d'entraîner une panne du programme qui l'utilise. (Vous ne pourrez peut-être pas observer cela avec
sleep
car il charge tout le code de bibliothèque dont il a besoin au démarrage. Essayez un programme plus complexe qui fait quelque chose d'utile après avoir dormi, commeperl -e 'sleep 9; print lc $ARGV[0]'
.)Si un interpréteur exécute un script, le fichier de script est ouvert de manière ordinaire par l'interpréteur, il n'y a donc aucune protection contre l'écrasement du script. Certains interprètes lisent et analysent l'intégralité du script avant de commencer à exécuter la première ligne, d'autres lisent le script si nécessaire. Voir Que se passe-t-il si vous modifiez un script pendant l'exécution? et comment Linux traite-t-il les scripts shell? pour plus de détails.
Les stratégies 2 et 3 sont également sans danger pour les exécutables: bien que l'exécution d'exécutables (et de bibliothèques chargées dynamiquement) ne soit pas des fichiers ouverts dans le sens d'avoir un descripteur de fichier, ils se comportent de manière très similaire. Tant qu'un programme exécute le code, le fichier reste sur le disque même sans entrée de répertoire.
Mettre à niveau une application
La plupart des gestionnaires de packages utilisent la stratégie 3 pour remplacer les fichiers, en raison de l'avantage majeur mentionné ci-dessus - à tout moment, l'ouverture du fichier conduit à une version valide de celui-ci.
Là où les mises à niveau d'application peuvent se briser, c'est que si la mise à niveau d'un fichier est atomique, la mise à niveau de l'application dans son ensemble ne l'est pas si l'application se compose de plusieurs fichiers (programme, bibliothèques, données,…). Considérez la séquence d'événements suivante:
À l'étape 3, l'instance en cours d'exécution de l'ancienne version de l'application ouvre un fichier de données à partir de la nouvelle version. Que cela fonctionne ou non dépend de l'application, de quel fichier il s'agit et de la quantité de fichier modifié.
Après une mise à niveau, vous remarquerez que l'ancien programme est toujours en cours d'exécution. Si vous souhaitez exécuter la nouvelle version, vous devrez quitter l'ancien programme et exécuter la nouvelle version. Les gestionnaires de packages tuent et redémarrent généralement les démons lors d'une mise à niveau, mais laissent les applications des utilisateurs finaux tranquilles.
Quelques démons ont des procédures spéciales pour gérer les mises à niveau sans avoir à tuer le démon et à attendre que la nouvelle instance redémarre (ce qui provoque une interruption de service). Cela est nécessaire dans le cas d' init , qui ne peut pas être tué; Les systèmes init fournissent un moyen de demander à l'appel d'instance en cours
execve
de se remplacer par la nouvelle version.la source
unlink
, comme vous le verrez plus tard. Peut-être que "remplace le nom existant", mais cela reste quelque peu déroutant.La mise à niveau peut être exécutée pendant l'exécution du programme, mais le programme en cours d'exécution que vous voyez est en fait l'ancienne version de celui-ci. L'ancien binaire reste sur le disque jusqu'à ce que vous fermiez le programme.
Explication: sur les systèmes Linux, un fichier est juste un inode, qui peut avoir plusieurs liens vers celui-ci. Par exemple. le que
/bin/bash
vous voyez est juste un lien versinode 3932163
mon système. Vous pouvez trouver quel inode fait quelque chose de lien vers en émettantls --inode /path
sur le lien. Un fichier (inode) n'est supprimé que s'il n'y a aucun lien pointant vers lui et n'est utilisé par aucun programme. Lorsque le gestionnaire de paquets met à niveau par exemple./usr/bin/firefox
, il délie d'abord (supprime le lien dur/usr/bin/firefox
), puis crée un nouveau fichier appelé/usr/bin/firefox
qui est un lien dur vers un autre inode (celui qui contient la nouvellefirefox
version). L'ancien inode est désormais marqué comme libre et peut être réutilisé pour stocker de nouvelles données mais reste sur le disque (les inodes ne sont créés que lorsque vous construisez votre système de fichiers et ne sont jamais supprimés). Au prochain démarrage defirefox
, le nouveau sera utilisé.Si vous voulez écrire un programme qui se "met à jour" pendant son exécution, la seule solution possible à laquelle je peux penser est de vérifier périodiquement l'horodatage de son propre fichier binaire, et s'il est plus récent que l'heure de démarrage du programme, puis rechargez-vous.
la source
apt
travail de mise à niveau de Debian ? Je peux mettre à niveau n'importe quel programme en cours d'exécution sans problème, y comprisIceweasel
(Firefox
).dpkg
) n'écrase pas les fichiers. Il les dissocie à la place et en place un nouveau sous le même nom. Voir la question et la réponse à laquelle j'ai lié pour une explication.ln
(liens durs). Vous pouvez supprimer des noms avecrm
(dissocier). Vous ne pouvez pas réellement supprimer directement un fichier, supprimez uniquement ses noms. Lorsqu'un fichier n'a pas de nom et n'est en outre pas ouvert, le noyau le supprimera. Un programme en cours d'exécution a le fichier à partir duquel il est ouvert, donc même après avoir supprimé tous les noms, le fichier est toujours là.Je me demande comment des applications tueuses telles que Thunderbird ou Firefox peuvent être mises à jour via le gestionnaire de paquets du système alors qu'elles sont toujours en cours d'exécution? Eh bien, je peux vous dire que cela ne fonctionne pas vraiment bien ... J'ai eu Firefox se briser sur moi assez horriblement si je le laissais ouvert alors qu'une mise à jour du paquet était en cours d'exécution. Je devais parfois le tuer avec force et le redémarrer, car il était tellement cassé que je ne pouvais même pas le fermer correctement.
Que se passe-t-il avec l'ancien code pendant sa mise à jour? Normalement, sous Linux, un programme est chargé en mémoire, de sorte que l'exécutable sur le disque n'est pas nécessaire ou utilisé pendant l'exécution du programme. En fait, vous pouvez même supprimer l'exécutable et le programme ne devrait pas s'en soucier ... Cependant, certains programmes peuvent avoir besoin de l'exécutable, et certains systèmes d'exploitation (comme Windows) verrouillent le fichier exécutable, empêchant la suppression ou même renommer / déplacer, tandis que le programme est en cours d'exécution. Firefox tombe en panne, car il est en fait assez complexe et utilise un tas de fichiers de données qui lui indiquent comment construire son interface graphique (interface utilisateur). Lors d'une mise à jour de package, ces fichiers sont écrasés (mis à jour), donc lorsqu'un ancien exécutable Firefox (en mémoire) essaie d'utiliser les nouveaux fichiers GUI, des choses étranges peuvent se produire ...
Que dois-je faire lorsque je veux écrire un programme a.out qui se met à jour pendant son exécution? Il y a déjà beaucoup de réponses à votre question. Vérifiez ceci: /programming/232347/how-should-i-implement-an-auto-updater Soit dit en passant, les questions sur la programmation sont mieux sur StackOverflow.
la source