ThunderbirdやFirefoxなどのキラーアプリがシステムパッケージマネージャを介して実行時にどのように更新されるかを知りたいです。古いコードが更新されたらどうなりますか?実行時に自分で更新されるプログラムa.outを作成するにはどうすればよいですか?
答え1
一般的な代替ファイル
まず、ファイルを置き換えるためのいくつかの戦略があります。
開いている既存の書き込みファイルはゼロ長に切り捨てられ、新しいコンテンツが記録されます。 (あまり一般的なバリエーションは、既存のファイルを開き、古い内容を新しい内容で上書きし、ファイルが短い場合は新しい長さに切り捨てることです)。
echo 'new content' >somefile
削除する古いファイルを削除し、同じ名前の新しいファイルを作成します。シェル用語で:
rm somefile echo 'new content' >somefile
一時名で新しいファイルを作成し、移動する新しいファイルを既存の名前に変更します。移動すると、古いファイルが削除されます。シェル用語で:
echo 'new content' >somefile.new mv somefile.new somefile
私はこれらの戦略の間のすべての違いをリストしているわけではなく、いくつかの重要なことだけを言及します。ポリシー1を使用すると、プロセスが現在ファイルを使用している場合、そのプロセスは更新時に新しいコンテンツを表示します。プロセスがファイルの内容を変更しないことを期待している場合、これは多少の混乱を招く可能性があります。これは、ファイル(またはlsof
に表示されるファイルなど)を開くプロセスにのみ関連します。ドキュメントを開くインタラクティブアプリケーション(エディタでファイルを開く)は通常、ファイルを開いたままにせずに「ドキュメントを開く」操作中に実行します。 「文書の保存」操作中のファイルの置き換え(上記の戦略のいずれかを使用)。/proc/PID/fd/
ポリシー2と3を使用すると、プロセスでファイルが開いている場合は、somefile
コンテンツのアップグレード中に古いファイルが開いたままになります。ストラテジー 2 では、ファイル削除フェーズでは、実際にはディレクトリ内のファイルエントリのみが削除されます。ファイル自体は、そのファイルを指すディレクトリエントリがない場合にのみ削除されます(通常のUnixファイルシステムでは、同じファイルの複数のディレクトリエントリ)そして開いているプロセスはありません。これを観察する方法は次のとおりです。sleep
プロセスが終了したときにのみファイルが削除されます(rm
そのディレクトリエントリのみが削除されます)。
echo 'old content' >somefile
sleep 9999999 <somefile &
df .
rm somefile
df .
cat /proc/$!/fd/0
kill $!
df .
戦略3の場合、新しいファイルを既存の名前に移動する手順では、既存のコンテンツに関連付けられているディレクトリエントリを削除し、新しいコンテンツにリンクするディレクトリエントリを作成します。これは1つの原子操作で行われるため、この戦略には1つの主な利点があります。プロセスがいつでもファイルを開くと、古いコンテンツまたは新しいコンテンツが表示されます。混在したコンテンツを取得したり、ファイルが存在しないリスクはありません。既存の。
実行ファイルの置き換え
実行中の実行可能ファイルを使用してLinuxで戦略1を試みると、エラーが発生します。
cp /bin/sleep .
./sleep 999999 &
echo oops >|sleep
bash: sleep: Text file busy
「テキストファイル」とは、実行可能コードを含むファイルを意味します。未知の歴史的理由から。他の多くのUnixの亜種と同様に、Linuxは実行中のプログラムのコードの上書きを拒否します。一部のUNIXバリアントではこれを許可するため、新しいコードが古いコードを根本的に変更しない限り、競合が発生します。
Linuxでは、ライブラリを動的にロードするコードをオーバーライドできます。これを使用するプログラムがクラッシュする可能性があります。 (sleep
起動時に必要なすべてのライブラリコードをロードするため、これを観察することはできません。たとえば、スリープ後に便利なタスクを実行するより複雑なプログラムを試してみてください。perl -e 'sleep 9; print lc $ARGV[0]'
)
インタプリタがスクリプトを実行している場合、インタプリタはスクリプトファイルを正常に開くため、スクリプトが上書きされるのを防ぐ方法はありません。一部の通訳者は、最初の行の実行を開始する前にスクリプト全体を読み取り、解析し、他の通訳者は必要に応じてスクリプトを読み取ります。バラより実行中にスクリプトを編集するとどうなりますか?そしてLinuxはシェルスクリプトをどのように処理しますか?詳細については。
戦略2と3は実行可能ファイルにも安全です。実行中の実行可能ファイル(および動的にロードされたライブラリ)は、ファイル記述子があるという点で開かれたファイルではありませんが、非常に似た方法で動作します。プログラムがコードを実行している間は、ディレクトリエントリがなくてもファイルはディスクに残ります。
アップグレード申請
ほとんどのパッケージマネージャは、上記の主な利点を持つファイル交換戦略3を使用しています。つまり、どの時点でも開いているファイルの有効なバージョンを取得できるということです。
アプリケーションのアップグレード時に問題が発生する可能性があります。 1つのファイルをアップグレードすることはアトミックですが、アプリケーションが複数のファイル(プログラム、ライブラリ、データなど)で構成されている場合、アプリケーション全体をアップグレードすることはアトミックではありません。次の一連のイベントを考えてみましょう。
- アプリケーションインスタンスが起動しました。
- アプリケーションがアップグレードされました。
- 実行中のインスタンスアプリケーションはデータファイルの1つを開きます。
ステップ3では、実行中の以前のバージョンのアプリケーションインスタンスが新しいバージョンのデータファイルを開きます。これが機能するかどうかは、アプリケーション、ファイルの種類、ファイルの変更の程度によって異なります。
アップグレード後も既存のプログラムが実行され続けていることがわかります。新しいバージョンを実行するには、古いプログラムを終了して新しいバージョンを実行する必要があります。パッケージマネージャは通常、アップグレード時にデーモンをシャットダウンして再起動しますが、エンドユーザーアプリケーションは影響を受けません。
一部のデーモンには、デーモンを終了して新しいインスタンスが再起動されるのを待たずに(サービスが中断される可能性がある)、アップグレードを処理する特別な手順があります。これは、次の状況で必要です。内部に、終了できません。初期化システムは、実行中のインスタンス呼び出しを要求する方法を提供します。execve
新しいバージョンに置き換えられます。
答え2
アップグレードはプログラムの実行中に実行できますが、プログラムの実行中に表示される内容は実際には以前のバージョンです。以前のバイナリはプログラムを閉じるまでディスクに残ります。
説明する:Linuxシステムでは、ファイルは単なるinodeであり、複数のリンクを持つことができます。例えば。あなたが見るのは/bin/bash
私のシステムのリンクだけです。リンクに対してコマンドを実行して、リンクが接続されinode 3932163
ている inode を確認できます。ls --inode /path
ファイル(インデックスノード)は、そのファイルを指すリンクがなく、どのプログラムでも使用されていない場合にのみ削除されます。たとえば、パッケージマネージャがアップグレードされている場合。/usr/bin/firefox
最初にリンクを解除(ハードリンクを削除)してから、別のinode(inodeの新しいバージョンを含む)へのハードリンクである対応するファイルと呼ばれる/usr/bin/firefox
新しいファイルを作成します。古いinodeは現在利用可能とマークされ、新しいデータを保存するために再利用できるようになりましたが、ディスクに残ります(inodeはファイルシステムの構築時にのみ作成され、削除されません)。次回の起動時に新しいものが使用されます。/usr/bin/firefox
firefox
firefox
実行時に独自に「アップグレード」されるプログラムを作成したい場合は、私が考えることができる唯一の解決策は、独自のバイナリのタイムスタンプを定期的にチェックし、プログラムの開始時刻より新しい場合はそれ自体を再ロードすることです。
答え3
ThunderbirdやFirefoxなどのキラーアプリをシステムパッケージマネージャで実行時にどのように更新できるか疑問に思います。 まあ、これはうまくいきません...パッケージアップデートの実行中にFirefoxを開いたままにすると、非常に深刻な欠陥が発生します。時には強制的にシャットダウンして再起動する必要があります。破損しすぎて正常に終了できないからです。
古いコードが更新されたらどうなりますか? 通常、Linuxではプログラムがメモリにロードされるため、プログラムの実行中にディスク上の実行可能ファイルは必要または使用されません。実際には実行可能ファイルを削除することもできますが、プログラムは気にする必要はありません...しかし、一部のプログラムでは実行可能ファイルが必要な場合があり、一部のオペレーティングシステム(Windowsなど)は実行可能ファイルをロックして削除や名前変更を防ぎます。 /プログラムの実行中に移動します。 Firefoxは実際には非常に複雑で、多くのデータファイルを使用してGUI(ユーザーインターフェイス)を構築する方法を知っているため、競合が発生します。パッケージの更新中にこれらのファイルは上書き(更新)されるため、古いFirefox実行可能ファイル(メモリ内)が新しいGUIファイルを使用しようとすると、奇妙なことが発生する可能性があります。
実行時に自分で更新されるプログラムa.outを作成するにはどうすればよいですか? あなたの質問に対する答えはすでにたくさんあります。これを見てください: https://stackoverflow.com/questions/232347/how-should-i-implement-an-auto-updater ちなみに、プログラミングに関する質問はStackOverflowで最もよく質問されます。