web-dev-qa-db-ja.com

オンザフライで出力をリダイレクトします-Linuxでは不可能に見えますが、なぜですか?

私はウェブ検索を試しましたが、Linuxリダイレクト出力をその場で検索しても答えが見つかりませんでした。私が理解している限り、stdoutと言う出力はファイル記述子1を使用して機能します。

$ ls -l /proc/pid/fd/1
lrwx------ 1 user1 user1 64 Sep 27 13:37 1 -> /dev/pts/1

procファイルシステムで機能するUnixコマンドがあります。 lsここでは、teeはファイルに書き込み、catは読み取りが可能です。なぜ例えばLinuxでは、ユーザーがbashln -sを介してこれらのリンクを手動で変更できるように実装されていませんでしたか? (私がしようとしたときにエラー"No such file or directory"が発生しました)。実装するのは難しいですか?どのユーティリティがprocで動作するかをどのように決定しましたか-そのユーティリティのプログラマーによって?

2
Marisha

どのユーティリティがprocで動作するかをどのように決定しましたか-そのユーティリティのプログラマーによって?

いいえ、procfsの開発者は、カーネル情報をファイルシステムの形式でエクスポートする仮想ファイルシステムであり、通常のPOSIXシステムコールで操作できます。

lslnは、常に同じシステムコールを実行するだけです。nixすべてがファイルです。それがポイントであり、lsofpsなどの特別なツールを必要とせずに_ls -l_で_/proc/PID_を使用できる理由です。

_/proc/PID/fd/*_ファイルで必要なものを実行できます。プログラムがその構成ファイルを開いている場合、lessでそのファイルを読み取り、emacsまたはvimで編集するか、_gzip < /proc/.../3 > foo.gz_

これはシンボリックリンクをたどるだけで機能すると思います。しかし、実際にはそうではありません。そのファイルのlstatはそれをシンボリックリンクとして報告し、readlinkはリンクターゲットを示します。ただし、そのリンクターゲットは、カーネルによって作成された単なるテキストです。リンクが解除された後もファイル上でまだ開いているFDの場合、/foo/bar (deleted)のようになります。ただし、その_/proc_パスでopen()を使用しても、実際のファイルは開きます。 (ほとんどのシステムコールと同様に、openは内部的にシンボリックリンクに従います。通常のファイルシステム上の通常のシンボリックリンクの場合、リンクターゲットは通常のパス名のように扱われます。)

そのiノードをファイルシステムにリンクする方法はありません(主にセキュリティ上の理由から、_O_TMPFILE_で開かれたFDでlinkat(2)を使用することは可能ですが、決してhadそもそもパス名 https://stackoverflow.com/questions/4171713/relinking-an-anonymous-unlinked-but-open-file


あなたの場合、正しい質問は「どのシステムコールが/ proc/PIDの下にあるものに対して何を行うべきかがどのように決定されたか」です。

AFAIK、_/proc_ファイルのシステムコールはプロセス環境を変更できません。つまりカーネル情報は読み取り専用でエクスポートされます。

プロセスのコンテキスト内で_dup2_のようなシステムコールを行うには、コメントで説明されているような他のハックを使用する必要があります。例えばptrace AP​​Iを使用します。例えばptraceを使用してターゲットプロセス内で処理を行うGDBまたは他のデバッガーを使用する。

4
Peter Cordes

なぜ例えばLinuxユーザーがbashでln -sを使用してこれらのリンクを手動で変更できるように実装されていませんか?

procファイルシステムは内部のカーネル状態を表示するだけだからです。特定のファイルにデータを書き込むことで実際にカーネルの状態に影響を与えることができる場合もありますが、物事を移動できる単一の例は思いつきません。

実装するのは難しいですか?

カーネルはオープンソースであり、一見して自分で決めてください(「難しい」はプログラミングの経験に関連します)。

また、変更しているプロセスがstdoutに何かを書き込んでいる場合にどうなるかを考えます。また、セキュリティへの影響も考慮してください。

ただし、上流カーネルにこのような変更を加える可能性は、おそらく私の見積もりではかなり低いでしょう。

どのユーティリティがprocで動作するかを決定したのですか-そのユーティリティのプログラマーによって?

/procは仮想ファイルシステムであり、仮想ファイルシステムに必要なカーネル機能を実装しています。さまざまなカーネルプログラマが/proc、彼らは通常、プログラミングするのが最も簡単な方法でそれをしようとします。

10
dirkt

Linuxでは、標準の入出力ファイル記述子は、/procファイルシステムではなく、カーネルシステムコールを介して作成されます。

/procに表示されるシンボリックリンクは、データをパイプするために使用される実際の手段ではなく、プロセスがデータにアクセスできるようにするためにカーネルが実行していることのreflectionです。そのため、ln -sを使用してそれらを変更することはできません。

その場で出力をリダイレクトすることについてのあなたの質問のために、私はそれを行うコマンドを知りません。しかし、それは確かに可能です。このようなプログラムを開発する方法の例を次に示します。

  1. まず、catの機能を実装することから始めます。したがって、標準入力を取り、それを標準出力にダンプします。これは非インタラクティブアプリケーションです。
  2. 次に、インタラクティブになるようにプログラムを変更します。簡単な例は、少量の入力を転送し、ユーザーがEnterキーを押すのを待つことです。次に、もう少し入力を転送して繰り返します。この段階で、プログラムは一時停止して決定を下すことができます。これは、出力をその場でリダイレクトできるために重要です。
  3. 最後に、プログラムを変更して、入力と出力を指定するコマンドを実行できるようにします。 APIやNCURSES UIなどのデーモンプロセスである可能性があります。

上記は言うよりも確かに簡単です。たくさんの重要な詳細に目を通しましたが、その場で出力をリダイレクトすることが少なくとも実行可能であることを示すには十分だと思います。

6
Emmanuel Rosa

Stdinなどが指す場所を変更する代わりに、 pseudo-terminal(PTY) を作成し、それを介して入力と出力をリダイレクトすることで、プログラムが何かが変更されたことを認識する必要がなくなります。実際、それだけを行うプログラムがいくつかあります(しばしば ターミナルマルチプレクサ と呼ばれます)。

ご存知のように、tmuxのようなマルチプレクサを使用して、1つの端末のセッションから切断して別の場所に再接続できますが、いつでも標準入力または出力のいずれかをパイプすることもできます。たとえば、tmuxペイン内でシェルを実行していて、コマンドpipe-pane 'cat >>~/test.txt'man page から取得)をtmuxに送信した場合、標準セッションペイン内で何も変更せずに、出力が~/test.txtに追加されるようになりました。

5
ErikF

ここでの誤解の核心は、シンボリックリンクが記述されている間に変更すると、予期したとおりに変更されることです。

そうではありません。実際のファイル(またはデバイスやパイプ)が開かれると、すべてのアクティビティは開いているファイルに関係し、それを指しているシンボリックリンクなどに発生したことはすべて無視されます。実際、これはシンボリックリンクに限定されませんが、実際にはファイルに名前を付ける「ハード」リンクに等しく関係します。unixoidシステムでは、ファイルを実際に移動または削除(!)することもできます(注:上書きしてください! )一部のプロセスが開いており、プロセスはファイルを閉じるまで何も変更されていません。

1
rackandboneman

シンボリックリンクは、実際のファイルを見つけるためのヘルパーにすぎません。実際のファイルは、実際のiノードを見つけるためのヘルパーです。その後、何を開くかは、iノード自体によって決まります。の場合 /dev/pts/1実際に開いているのは、メジャーデバイス番号が136でマイナー1のキャラクターデバイスです。

ファイル名のその時点から、ファイルまたはシンボリックリンクの存在は重要ではありません。削除する前に開いていた場合に限り、削除したファイルにアクセスできます。

1
V13