Ich frage mich, wie Killeranwendungen wie Thunderbird oder Firefox über den Paketmanager des Systems aktualisiert werden können, während sie noch ausgeführt werden. Was passiert mit dem alten Code, während er aktualisiert wird? Was muss ich tun, wenn ich ein Programm a.out schreiben möchte, das sich selbst aktualisiert, während es ausgeführt wird?
files
upgrade
executable
ubuplex
quelle
quelle
Antworten:
Ersetzen von Dateien im Allgemeinen
Erstens gibt es verschiedene Strategien, um eine Datei zu ersetzen:
Öffnen Sie die vorhandene Datei zum Schreiben, kürzen Sie sie auf die Länge 0 und schreiben Sie den neuen Inhalt. (Eine seltenere Variante besteht darin, die vorhandene Datei zu öffnen, den alten Inhalt mit dem neuen Inhalt zu überschreiben und die Datei auf die neue Länge zu kürzen, wenn sie kürzer ist.) In Shell-Begriffen:
Entfernen Sie die alte Datei und erstellen Sie eine neue Datei mit demselben Namen. In Shell-Begriffen:
Schreiben Sie in eine neue Datei unter einem temporären Namen und verschieben Sie die neue Datei an den vorhandenen Namen. Durch das Verschieben wird die alte Datei gelöscht. In Shell-Begriffen:
Ich werde nicht alle Unterschiede zwischen den Strategien auflisten, ich werde nur einige erwähnen, die hier wichtig sind. Wenn in Strategie 1 derzeit ein Prozess die Datei verwendet, wird der neue Inhalt beim Aktualisieren angezeigt. Dies kann zu Verwirrung führen, wenn der Prozess erwartet, dass der Dateiinhalt gleich bleibt. Beachten Sie, dass es sich nur um Prozesse handelt, bei denen die Datei geöffnet ist (wie in
lsof
oder in sichtbar) . Interaktive Anwendungen, bei denen ein Dokument geöffnet ist (z. B. Öffnen einer Datei in einem Editor), lassen die Datei normalerweise nicht geöffnet. Sie laden den Dateiinhalt während der Der Vorgang "Dokument öffnen" und sie ersetzen die Datei (unter Verwendung einer der oben genannten Strategien) während des Vorgangs "Dokument speichern"./proc/PID/fd/
Bei den Strategien 2 und 3
somefile
bleibt die alte Datei während der Inhaltsaktualisierung geöffnet , wenn bei einem Prozess die Datei geöffnet ist. Bei Strategie 2 wird beim Entfernen der Datei tatsächlich nur der Eintrag der Datei im Verzeichnis entfernt. Die Datei selbst wird nur entfernt, wenn kein Verzeichniseintrag zu ihr führt (auf typischen Unix-Dateisystemen kann es mehr als einen Verzeichniseintrag für dieselbe Datei geben ) und kein Prozess hat sie geöffnet. Hier ist eine Möglichkeit, dies zu beobachten: Die Datei wird nur entfernt, wenn dersleep
Prozess beendet wird (rm
nur der Verzeichniseintrag wird entfernt).Bei Strategie 3 wird beim Verschieben der neuen Datei auf den vorhandenen Namen der Verzeichniseintrag entfernt, der zum alten Inhalt führt, und ein Verzeichniseintrag erstellt, der zum neuen Inhalt führt. Dies geschieht in einer atomaren Operation, daher hat diese Strategie einen großen Vorteil: Wenn ein Prozess die Datei zu einem beliebigen Zeitpunkt öffnet, wird entweder der alte Inhalt oder der neue Inhalt angezeigt - es besteht kein Risiko, dass gemischte Inhalte angezeigt werden, oder die Datei nicht bestehender.
Ausführbare Dateien ersetzen
Wenn Sie Strategie 1 mit einer laufenden ausführbaren Datei unter Linux versuchen, wird eine Fehlermeldung angezeigt.
Eine „Textdatei“ ist eine Datei, die aus unklaren historischen Gründen ausführbaren Code enthält . Linux weigert sich, wie viele andere Unix-Varianten, den Code eines laufenden Programms zu überschreiben. Einige Unix-Varianten erlauben dies und führen zu Abstürzen, es sei denn, der neue Code ist eine sehr durchdachte Modifikation des alten Codes.
Unter Linux können Sie den Code einer dynamisch geladenen Bibliothek überschreiben. Es ist wahrscheinlich, dass das Programm, das es verwendet, abstürzt. (Möglicherweise können Sie dies nicht beobachten,
sleep
da der gesamte Bibliothekscode geladen wird, der beim Start benötigt wird. Probieren Sie ein komplexeres Programm aus, das nach dem Schlafengehen etwas Nützliches ausführt, zperl -e 'sleep 9; print lc $ARGV[0]'
. B.. )Wenn ein Interpreter ein Skript ausführt, wird die Skriptdatei auf normale Weise vom Interpreter geöffnet, sodass kein Schutz gegen das Überschreiben des Skripts besteht. Einige Interpreter lesen und analysieren das gesamte Skript, bevor sie mit der Ausführung der ersten Zeile beginnen, andere lesen das Skript nach Bedarf. Siehe Was passiert, wenn Sie ein Skript während der Ausführung bearbeiten? und wie geht Linux mit Shell-Skripten um? für mehr Details.
Die Strategien 2 und 3 sind auch für ausführbare Dateien sicher: Obwohl ausführbare Dateien (und dynamisch geladene Bibliotheken) keine offenen Dateien im Sinne eines Dateideskriptors sind, verhalten sie sich sehr ähnlich. Solange ein Programm den Code ausführt, bleibt die Datei auch ohne Verzeichniseintrag auf der Festplatte.
Aktualisieren einer Anwendung
Die meisten Paketmanager verwenden Strategie 3, um Dateien zu ersetzen, da der oben erwähnte große Vorteil darin besteht, dass das Öffnen der Datei zu jedem Zeitpunkt zu einer gültigen Version führt.
Anwendungs-Upgrades können zu Problemen führen, wenn das Upgrade einer einzelnen Datei nur aus einzelnen Dateien besteht (Programm, Bibliotheken, Daten usw.). Betrachten Sie die folgende Abfolge von Ereignissen:
In Schritt 3 öffnet die ausgeführte Instanz der alten Version der Anwendung eine Datendatei aus der neuen Version. Ob dies funktioniert oder nicht, hängt von der Anwendung ab, um welche Datei es sich handelt und in welchem Umfang die Datei geändert wurde.
Nach einem Upgrade werden Sie feststellen, dass das alte Programm noch ausgeführt wird. Wenn Sie die neue Version ausführen möchten, müssen Sie das alte Programm beenden und die neue Version ausführen. Paketmanager beenden und starten Dämonen normalerweise bei einem Upgrade neu, lassen Endbenutzeranwendungen jedoch in Ruhe.
Einige Daemons haben spezielle Verfahren, um Upgrades durchzuführen, ohne den Daemon beenden und auf den Neustart der neuen Instanz warten zu müssen (was zu einer Dienstunterbrechung führt). Dies ist im Fall von init erforderlich , das nicht getötet werden kann. init-Systeme bieten eine Möglichkeit, den laufenden Instanzaufruf aufzufordern
execve
, sich selbst durch die neue Version zu ersetzen.quelle
unlink
, wie Sie später behandeln. Vielleicht "ersetzt den vorhandenen Namen", aber das ist immer noch etwas verwirrend.Das Upgrade kann ausgeführt werden, während das Programm ausgeführt wird. Das angezeigte Programm ist jedoch die alte Version. Die alte Binärdatei bleibt auf der Festplatte, bis Sie das Programm schließen.
Erläuterung: Auf Linux-Systemen ist eine Datei nur eine Inode, die mehrere Verknüpfungen haben kann. Z.B. Das, was
/bin/bash
Sie sehen, ist nur ein Link zuinode 3932163
meinem System. Sie können herausfinden, zu welchem Inode ein Link führt, indem Siels --inode /path
auf den Link klicken. Eine Datei (Inode) wird nur entfernt, wenn keine Links darauf verweisen, und wird von keinem Programm verwendet. Wenn der Paketmanager ein Upgrade durchführt, z./usr/bin/firefox
wird zuerst die Verknüpfung aufgehoben (die feste Verknüpfung wird entfernt/usr/bin/firefox
) und dann eine neue Datei mit dem Namen erstellt, die eine feste Verknüpfung/usr/bin/firefox
zu einem anderen Inode darstellt (demjenigen, der die neuefirefox
Version enthält ). Der alte Inode ist jetzt als frei markiert und kann zum Speichern neuer Daten wiederverwendet werden, verbleibt jedoch auf der Festplatte (Inodes werden nur erstellt, wenn Sie Ihr Dateisystem erstellen, und werden niemals gelöscht). Beim nächsten Start vonfirefox
wird der neue verwendet.Wenn Sie ein Programm schreiben möchten, das sich während der Ausführung selbst "aktualisiert", ist die einzige mögliche Lösung, die ich mir vorstellen kann, regelmäßig den Zeitstempel der eigenen Binärdatei zu überprüfen. Wenn sie neuer als die Startzeit des Programms ist, laden Sie sich selbst neu.
quelle
apt
Upgrade-Arbeit? Ich kann jedes laufende Programm problemlos aktualisieren, einschließlichIceweasel
(Firefox
).dpkg
) überschreibt keine Dateien. Stattdessen werden die Verknüpfungen aufgehoben und eine neue unter demselben Namen eingefügt. In der Frage & Antwort, die ich verlinkt habe, finden Sie eine Erklärung.ln
(harte Links) hinzufügen . Sie können Namen mitrm
(Unlink) entfernen . Sie können eine Datei nicht direkt löschen, sondern nur ihre Namen entfernen. Wenn eine Datei keine Namen hat und zusätzlich nicht geöffnet ist, wird sie vom Kernel gelöscht. Ein laufendes Programm hat die Datei, von der es ausgeführt wird, geöffnet, sodass die Datei auch nach dem Entfernen aller Namen noch vorhanden ist.Ich frage mich, wie Killeranwendungen wie Thunderbird oder Firefox über den Paketmanager des Systems aktualisiert werden können, während sie noch ausgeführt werden. Nun, ich kann Ihnen sagen, dass dies nicht wirklich gut funktioniert ... Ich hatte eine schreckliche Firefox-Unterbrechung, wenn ich sie offen ließ, während ein Paket-Update lief. Ich musste es manchmal gewaltsam töten und neu starten, weil es so kaputt war, dass ich es nicht einmal richtig schließen konnte.
Was passiert mit dem alten Code, während er aktualisiert wird? Normalerweise wird unter Linux ein Programm in den Speicher geladen, sodass die ausführbare Datei auf der Festplatte nicht benötigt oder verwendet wird, während das Programm ausgeführt wird. Tatsächlich können Sie sogar die ausführbare Datei löschen, und das Programm sollte sich nicht darum kümmern ... Einige Programme benötigen jedoch möglicherweise die ausführbare Datei, und bestimmte Betriebssysteme (wie Windows) sperren die ausführbare Datei und verhindern das Löschen oder sogar das Umbenennen / Verschieben, während die Programm läuft. Firefox bricht ab, weil es eigentlich recht komplex ist und eine Reihe von Datendateien verwendet, die ihm sagen, wie er seine GUI (Benutzeroberfläche) erstellt. Während einer Paketaktualisierung werden diese Dateien überschrieben (aktualisiert). Wenn also eine ältere (im Speicher befindliche) Firefox-Programmdatei versucht, die neuen GUI-Dateien zu verwenden, können seltsame Dinge passieren ...
Was muss ich tun, wenn ich ein Programm a.out schreiben möchte, das sich selbst aktualisiert, während es ausgeführt wird? Es gibt bereits viele Antworten auf Ihre Frage. Überprüfen Sie dies: /programming/232347/how-should-i-implement-an-auto-updater Übrigens sind Fragen zur Programmierung bei StackOverflow besser gestellt.
quelle