간단히 말해서, 일부 시스템 동작을 추적하기 위해 특정 실행 파일이 호출되는 방식을 추적하고 싶습니다. 실행 파일이 있다고 가정해 보겠습니다.
/usr/bin/do_stuff
실제로 심볼릭 링크를 통해 다양한 이름으로 호출됩니다.
/usr/bin/make_tea -> /usr/bin/do_stuff
/usr/bin/make_coffee -> /usr/bin/do_stuff
등. 분명히 do_stuff
수신한 첫 번째 인수는 취할 실제 조치를 결정하는 데 사용되며 나머지 인수는 그에 따라 처리됩니다.
이루어진 호출 /usr/bin/do_stuff
(및 전체 매개변수 목록)을 기록하고 싶습니다. 심볼릭 링크가 없다면 단순히 이동하여 do_stuff
스크립트 do_stuff_real
를 작성 하면 됩니다.
#!/bin/sh
echo "$0 $@" >> logfile
/usr/bin/do_stuff_real "$@"
그러나 내가 아는 한 호출된 이름을 확인하는데 작동하지 않습니다. 동일한 목표를 달성하면서도 do_stuff
올바른 "실행 파일에서 사용하는 이름"을 전달하는 스크립트를 어떻게 작성할 수 있습니까?
기록을 위해 다음 질문에 대답하지 않으려면 다음을 수행하십시오.
- 나는 C에서 (execve를 사용하여) 그것을 할 수 있다는 것을 알고 있지만, 이 경우 쉘 스크립트를 사용할 수 있다면 훨씬 쉬울 것입니다.
do_stuff
단순히 로깅 프로그램으로 대체할 수는 없습니다 .
답변1
busybox
대부분의 일반적인 UNIX 유틸리티를 단일 실행 파일로 제공하는 와 같은 유틸리티에서 이를 자주 볼 수 있습니다. 이 유틸리티의 동작은 호출되거나 busybox
전달되는 acpid
항목 에 따라 달라집니다 zcat
.
argv[0]
일반적으로 매개변수를 보고 무엇을 해야 할지 결정합니다 main()
. 단순한 비교가 되어서는 안 됩니다. 왜냐하면 argv[0]
비슷한 일이 있을 수도 있고 sleep
, 그럴 수도 있고 /bin/sleep
, 같은 일을 하기로 결정해야 하기 때문입니다. 즉, 이 경로는 상황을 더욱 복잡하게 만듭니다.
따라서 작업자가 올바르게 수행하면 로깅 래퍼가 와 같은 것에서 실행될 수 있습니다 /bin/realstuff/make_tea
. 작업자가 기본 이름만 보면 argv[0]
올바른 함수를 실행해야 합니다.
#!/bin/sh -
myexec=/tmp/MYEXEC$$
mybase=`basename -- "$0"`
echo "$0 $@" >> logfile
mkdir "$myexec" || exit
ln -fs /usr/bin/real/do_stuff "$myexec/$mybase" || exit
"$myexec/$mybase" "$@"
ret=$?
rm -rf "$myexec"
exit "$ret"
위의 예에서 argv[0]
다음과 같이 읽어야 합니다 /tmp/MYEXEC4321/make_tea
(4321이 실행 중인 PID인 경우 /bin/sh
). 이는 basename make_tea
동작을 트리거해야 합니다.
argv[0]
래퍼 없이 상황을 정확하게 복제하고 싶다면 더 어려운 문제에 직면하게 될 것입니다. 절대 파일 경로가 /
.로 시작하기 때문에 새 경로를 만들 수 없습니다. /bin/sleep
(이 없으면 chroot
거기에 가고 싶지 않을 것 같습니다.) 알다시피, 이를 수행하기 위해 몇 가지 맛을 사용할 수 있지만 exec()
쉘로 포장되지는 않습니다.
별칭을 사용하여 로거에 액세스한 다음 스크립트 래퍼 대신 기본 프로그램을 시작하는 것을 고려해 보셨나요? 제한된 이벤트 집합만 캡처하지만 아마도 해당 이벤트에만 관심이 있을 수 있습니다.
답변2
exec -a
( bash
, ksh93
, , zsh
에는 있지만 아직 POSIX에서는 발견되지 않음)을 사용하여 실행 중인 명령을 지정할 수 있습니다.mksh
yash
argv[0]
#! /bin/bash -
printf '%s\n' "$0 $*" >> /some/log
exec -a "$0" /usr/bin/do_stuff_real "$@"
이는$0
아니요주문 argv[0]
이 접수되었습니다. 이는 에 전달되고 execve()
에 인수로 전달되는 스크립트의 경로이지만 bash
이는 귀하의 목적에 충분할 수 있습니다.
예를 들어 if는 다음 make_tea
과 같이 호출됩니다.
execv("/usr/bin/make_tea", ["make_tea", "--sugar=2"])
이름으로 명령을 호출할 때( 에서 실행 파일 찾기 $PATH
) 셸이 일반적으로 수행하는 것처럼 래퍼는 다음을 수행합니다.
execv("/usr/bin/do_stuff_real", ["/usr/bin/make_tea", "--sugar=2"])
그건 아니야:
execv("/usr/bin/do_stuff_real", ["make_tea", "--sugar=2"])
do_stuff_real
그러나 그것이 차를 위한 것임을 아는 것만으로도 충분합니다 .
다음과 같이 호출되는 경우 do_stuff
:
execv("/usr/bin/do_stuff", ["/usr/bin/make_tea", "--sugar=2"])
왜냐하면 이것은 다음과 같이 번역될 것이기 때문입니다:
execv("/usr/bin/do_stuff_real", ["/usr/bin/do_stuff", "--sugar=2"])
이는 정상적인 작업 중에는 발생하지 않지만 래퍼가 유사한 작업을 수행한다는 점에 유의하세요.
대부분의 시스템에서는 argv[0]
인터프리터가 실행되면(여기) 스크립트에 전달된 내용이 손실됩니다(/bin/bash
대부분의 시스템에서 통역사의 경로는 argv[0]
she-bang 라인에 제공된 경로입니다.) 따라서 쉘 스크립트는 이에 대해 아무것도 할 수 없습니다.
를 전달하려면 argv[0]
실행 파일을 컴파일해야 합니다. 그것은 다음과 같습니다:
#include <stdio.h>
int main(int argc, char *argv[], char *envp[])
{
/* add logging */
execve("/usr/bin/do_stuff_real", argv, envp);
perror("execve");
return 127;
}