実行中のプロセスを取得する前に失敗したプロセスモニターをデバッグしようとしています。私はこれが不思議なLinux動作のために起こったと確信しています。実行中のプロセスは/opt/my/path/directoryname/daemonnameですが、奇妙な理由でディレクトリ名の周りに/の代わりにスペースが表示されます。多くのデーモンが同じディレクトリで実行されており、正しいパスで表示されます。各サーバーの特定のデーモンだけです。
ps -ef
このデーモンについては、以下を表示します。
/opt/my/path directoryname daemonname --arg1 VALUE1 --arg-two VALUE.TWO --arg-three ARG.UMENT.THREE.ERR --worker daemonname --pid-role daemonname
デーモンはPerlスクリプトによって開始されます。他のスクリプトと比較すると、ディレクトリパスは他のすべてのスクリプトとまったく同じ環境変数を使用して提供されるように見えますが、これらの他のスクリプトは正しいパスを生成します。たとえば、/opt/my/path/directoryname/daemonname
関連するperl行は次のようになりますexec => catfile( $settings->config("/directories/executables"), $daemon_name ),
。 config( "/directories/executables") が正しい値です。/opt/my/path/directoryname
スペースを含むディレクトリ名に関するすべての質問のために、この問題を検索するのは悪夢でした。これはそうではありません。すべてのパスにスペースを含めないでください。 psはスラッシュスペースを含むmkdirコマンドを表示します。私が見つけることができる最も近い場所でしたが、答えはありませんでした。
ベストアンサー1
返されるフィールドの1つは、ps -f
プロセス(またはその祖先の1つ)によって実行された最後のコマンドに渡された引数のリストです。通過できますps -o args
。
プロセスがファイルを実行すると、これはexecve()
システムコールを介して行われます。
execve("/path/to/executable", [arg0, arg1..., 0], [env1, env2... 0])
arg0
通常、これは実行可能ファイルの名前です。シェルが解釈されるとき:
cmd arg
コマンドラインでは、次のように呼び出しますexecve("/path/to/cmd", ["cmd", "arg", 0], ...)
。
/path/to/cmd arg
それは電話するexecve("/path/to/cmd", ["/path/to/cmd", "arg", 0], ...)
。
これらの文字列(cmd
、、arg
)はプロセススタックの一番下にあり、NULで区切られています。この過程でargv[0]
、argv[1]
... を指すものです。
Linuxでは、ゾーンはサイトからのインポートに/proc/<pid>/cmdline
さらされます。ps
args
技術的には、ps
文字列のリストをスペースで連結して印刷し、最終フィールドがコマンドのargs
実行に使用されるシェルコマンドラインのように見えます。
ここにps
表示される場合:
/opt/my/path directoryname daemonname --arg1...
これらのスペースは、これらの文字列の実際のスペース、別々の文字列、またはNULで置き換えられた文字列のスペースを表すことができます。
手順を使用する場合標準strtok()
機能あるいは、sargv[0]
に分割するのと似たように/
実行されている実行可能ファイルのベース名またはパスの他のディレクトリコンポーネントを見つけることもできます。
たとえば、次のように生成する場合:
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
strtok(argv[0], "/");
while (strtok(NULL, "/"));
pause();
}
コンパイルして実行します。
$ cc a.c
$ "$PWD/a.out" &
[1] 67758
$ ps -fp "$!"
UID PID PPID C STIME TTY TIME CMD
chazelas 67758 60043 0 19:19 pts/4 00:00:00 /home chazelas a.out
/
sが空白に置き換えられていることがわかります。
実際にはNULに置き換えられており、次のように確認できます。
$ sed -n l "/proc/$!/cmdline"
/home\000chazelas\000a.out\000$
ただし、ps
これらのNULを見て、それらをスペースで連結された3つの異なるパラメータの区切り文字として解釈します。
後でコメントでも指摘したように、dirname()
/
引数で s を 0 に置き換える別の標準関数です。
$ cat b.c
#include <libgen.h>
#include <unistd.h>
int main(int argc, char *argv[]) {dirname(dirname(argv[0])); pause();}
$ cc b.c
$ "$PWD/a.out" &
[1] 42128
$ ps -fp "$!"
UID PID PPID C STIME TTY TIME CMD
chazelas 42128 39744 0 20:18 pts/6 00:00:00 /home chazelas a.out
もしそうなら、これが正しい解釈であると仮定すると、そうではありません。奇妙なLinuxの動作これは、起動後にアプリケーション自体argv[0]
を変更するだけです(/
おそらくいくつかのパスコンポーネントを抽出するためにsをNULに置き換えることによって)。
Linuxでプロセスが現在実行されている実行可能ファイルを確認するためのより信頼性の高い方法は、たとえばユーティリティまたは組み込みの次のいずれかを使用してreadlink()
実行することです。/proc/<pid>/exe
realpath
readlink
stat
zsh
$ zmodload zsh/stat
$ stat +link /proc/$!/exe
/home/chazelas/a.out
$ readlink "/proc/$!/exe"
/home/chazelas/a.out
$ realpath "/proc/$!/exe"
/home/chazelas/a.out
Linuxのprocpsの実装ps
はこれをps -o exe
。
/proc/<pid>/cmdline
プロセスが表示される内容を変更できるため、コマンドに渡される引数を決定する明確な方法はありません。
ただし、監査ログにはこの情報を含めることができます。