프로세스 ps 명령이 디렉토리 주위에 슬래시 대신 공백을 표시하는 이유는 무엇입니까?

프로세스 ps 명령이 디렉토리 주위에 슬래시 대신 공백을 표시하는 이유는 무엇입니까?

실행 중인 프로세스를 검색하는 실패한 이전 프로세스 모니터를 디버깅하려고 합니다. 나는 이것이 신비한 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

반환되는 필드 중 하나는 ps -f프로세스(또는 해당 조상 중 하나)가 실행한 마지막 명령에 전달된 인수 목록입니다. 통과할 수 있습니다 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노출 됩니다 .psargs

기술적으로는 ps해당 문자열 목록을 공백으로 연결하여 인쇄하여 최종 필드가 args명령을 실행하는 데 사용되는 셸 명령줄처럼 보이도록 합니다.

여기에 ps표시되는 경우:

/opt/my/path directoryname daemonname --arg1...

이러한 공백은 이러한 문자열의 실제 공백, 별도의 문자열 또는 NUL로 대체된 문자열의 공백을 나타낼 수 있습니다.

절차가 사용되는 경우표준 strtok()기능또는 s argv[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>/exerealpathreadlinkstatzsh

$ 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프로세스가 표시되는 내용을 수정할 수 있으므로 명령에 전달되는 인수를 결정하는 확실한 방법은 없습니다 .

그러나 감사 로그에는 이 정보가 포함될 수 있습니다.

관련 정보