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