실행 파일에 여러 개의 심볼릭 링크가 있는 경우 래퍼 스크립트를 사용하여 호출을 기록하는 방법

실행 파일에 여러 개의 심볼릭 링크가 있는 경우 래퍼 스크립트를 사용하여 호출을 기록하는 방법

간단히 말해서, 일부 시스템 동작을 추적하기 위해 특정 실행 파일이 호출되는 방식을 추적하고 싶습니다. 실행 파일이 있다고 가정해 보겠습니다.

/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에서는 발견되지 않음)을 사용하여 실행 중인 명령을 지정할 수 있습니다.mkshyashargv[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;
}

관련 정보