別のプロセスでディレクトリを変更できないのはなぜですか?

別のプロセスでディレクトリを変更できないのはなぜですか?

現在の作業ディレクトリを変更するプロセスを作成できないのはなぜですか?良いCD注文はどこにありますか?

答え1

あなたが求めるものを考えてみてください。シェルがあり、シェルのcwdを変更する外部プログラムを作成しようとしています。これはまだ意味がありますか?私には、シェルが文字列を受け入れていくつかの子プロセス(自然に親プロセスシェルのcwdを継承する)を生成するプログラムにすぎないことをよく理解していないようです。

私はptraceを使ってシェルプロセスにコマンドを注入することでこれを達成できると思います。 「子wd」に対して異なる設定を維持する独自のシェルを作成できます(主な変更は、子をフォークした後にchdir()を覚えておく必要があることです)。任意のプロセスのcwdを強制的に変更できるカーネルモジュールを作成できますが、これは役に立つよりも多くの問題を台無しにすると予想されます。

このようなことが適切であれば、(適切な権限で) "ln -fs /somewhere /proc/$pid/cwd"を実行できます。 rootで試してみると、straceは「ln:cwd /:ディレクトリを上書きできません」というメッセージを表示します。ターゲットがすでに存在することを確認して表示するようです。この場合、シンボリックリンク()が失敗するようです。したがって、シンボリックリンクコマンドは最初に既存のリンクを削除する必要があり、カーネルはそれを許可しないと思います。

答え2

プロセスは、コンピュータですべての操作を実行する基本単位です。仮想メモリとその内容、CPU レジスタの状態と命令ポインタ(コードが実行される場所を指すポインタ)、オペレーティングシステムレベルで開いているファイルと作業ディレクトリなどをカプセル化します。これは、プログラムロジックが正しく機能するために外部イベントによって変更される必要がある実行中のプロセスです。

プログラムの実行中にCPUレジスタまたはコマンドポインタが変更されると、非常に予期しないことが発生します。同様に、プログラム内で開かれたファイルを変更すると、HTTPサーバーが突然間違ったファイルを提供するように切り替えたり、不明な構成ファイルを読み取ったりすることがあります。相対パスを使用している場合、プロセスの作業ディレクトリを変更すると誤ったファイルが見つかります。または削除してください。rm -rf somedir実行が突然別のディレクトリに移動した場合は、何が起こるのかを想像してください。間違った場所からファイルが削除され始めます。

したがって、プロセス自体の協力なしにこれを可能にするのは良い考えではありません。自分の作業ディレクトリを変更するプログラムを作成することはできますが、シェルに対して他のプログラムでこれを行うようにすることは良い考えではありません。これは、シェルが組み込みコマンドを使用して独自に実行できるため、必要ではなく、カスタマイズが必要な場合はシェル機能を使用して実行できます。外部プログラムを使用して変更するディレクトリを選択すると同時に、cd実際の変更を実行するためにシェル独自のプログラムを使用できます。たとえば、次のことを考えてみてくださいcdfoo() { cd -- "$(get_foo_dir "$1")"; }

答え3

子プロセスでは現在の作業ディレクトリを変更できません。理由は次のとおりです。君は実はかなり上手く出来る

これclone(2)プロセスを作成し、などのレガシーインターフェイスを実装するために使用されるfork(2)Linuxシステムコールには、子プロセスにルートディレクトリをCLONE_FS共有させるために使用できるフラグがあります。現在の作業ディレクトリumaskとその親:

#define _GNU_SOURCE
#include <sched.h>
#include <unistd.h>
#include <syscall.h>
#include <sys/wait.h>
#include <err.h>

int main(void){
        pid_t cpid = syscall(SYS_clone, CLONE_FS, (void*)0);
        if(cpid == -1) err(1, "SYS_clone");
        if(cpid == 0){
                /* the child, change the cwd and exit */
                execl("/bin/sh", "sh", "-c", "cd /etc", (void*)0);
                err(1, "execl /bin/sh");
        }else{
                /* the parent, wait for the child, then print the cwd */
                waitpid(-1, 0, __WALL);
                execl("/bin/sh", "sh", "-c", "pwd", (void*)0);
                err(1, "execl /bin/sh");
        }
}

Bourneシェル(bashが実装されています)は別のプロセスをフォークし、外部コマンドを実行するときにそのフラグを使用しないため、これはシェルでは機能しません。しかし、シェルは多くのとんでもない制限を持つ古い作成です。また、語彙のスコープ、システムインターフェイスへの直接アクセス、正気、既存の構文、およびその他の多くの機能もサポートしていません。

45歳のおもちゃの言語の無能をシステム全体に推論してはいけません。システム全体が大幅に発展したからです。


cd「不可能」が外部コマンド(そして現在のディレクトリの必要性!)であるという事実は、自然で当然のことではなく、Unixの進歩的な進歩とPDP-7システムの限界に関連しています。で初めて実行されました。

~から「Dennis Ritchie - Unixの時間共有システムの進化」:

現在のファイルシステムと非常に似ていますが、PDP-7ファイルシステムは1つの点で大きく異なります。パス名がなく、システムの各ファイル名パラメーターは、現在のファイルシステムとは異なり、単純な名前(「/」なし)です。礼拝の規則。

...

マルチプロセスというアイデアは、実際には受け入れやすいが、意図しない結果をもたらします。最も記憶に残るものの1つは、新しいシステムが登場し、確実に動作した直後に明らかになりました。喜んで走っていたときにchdir(現在のディレクトリ変更)コマンドが動作を停止したことがわかりました。多くのコードを読んでフォークを追加すると、chdir呼び出しがどのように中断されるのか心配していました。ついに真実が明らかになった。 chdirは以前のシステムでは一般的なコマンドでした。端末に接続されている(唯一の)プロセスの現在のディレクトリを調整します。新しいシステムでは、chdirコマンドはそれを実行するために作成されたプロセスの現在のディレクトリを正しく変更しますが、プロセスは親シェルに影響を与えずにすぐに終了します。


コメントから:

通常のシェル(外部から提供された任意のコマンドを実行するプログラム)は使用できません。CLONE_FSこれは、すべての子プロセスが現在のディレクトリを制御するために競合するためです。

これはエラーです。それは「もはやバスドライバーがいないので配管工を許可することはできません」のようです。シェルは、次の場合にのみこれを実行できます。場合によっては。子には既に標準のファイル記述子があります(子でstdinを非ブロックにすると、親でも非ブロックになります)。現在の名前空間(子にディレクトリをマウントすると親にもマウントされます)に「戦い」があります。システムとCLONE_*すべてのさまざまな部分は、異なるシステムインターフェイスを介して共有または分割できます。 「作業ディレクトリ」は実行環境の一部にすぎず、互換性の問題であり、必須ではありません(すべての最新システムでは、他のディレクトリへの相対パスを開くことができます。すべて参照openat(2)などlinkat(2))。

これは、子プロセスが実行できない自然法則ではありません。変化しかし、完全に可能でなければなりません。移動するまたは削除する(すでにそうだから)。 50年前のデフォルト値はまさに標準ではありません。たとえば、私はコマンドをクリアする方法でawk実行するよりも、シェルの作業ディレクトリを変更する方法でコマンドを実行またはフィルタリングする方がデフォルトのシェルを持っていると思います。jqまたはファイル(現在の場合)。

関連情報