IT

“argv [0] = name-of-executable”이 허용되는 표준입니까 아니면 일반적인 규칙입니까?

lottoking 2020. 9. 5. 10:11
반응형

“argv [0] = name-of-executable”이 허용되는 표준입니까 아니면 일반적인 규칙입니까?


main()C 또는 C ++ 응용 프로그램에서 인수를받을 때 argv[0]항상 실행 파일의 이름이 검증됩니까? 아니면 이것이 일반적인 관례 일 뿐이며 100 % 진실이라고 보장되지 않는 보장입니까?


추측 (교육을받은 추측 작업 포함)은 재미를 추측하는 작업 표준 문서로 이동해야합니다. 예를 들어 ISO C11은 다음과 같이 (내 강조).

의 값 argc이 0 크면로 많고은 프로그램 이름 argv[0] 나타냅니다 . argv[0][0]호스트 환경에서 프로그램 이름을 사용할 수없는 경우 널 문자가됩니다.

따라서 해당 이름을 사용할 수있는 경우 에만 프로그램 이름 입니다. 그것은 그리고 프로그램 이름을 "나타내고" , 프로그램 이름 일 반드시 필요 없습니다 . 그 앞의 섹션은 다음과 가변적이다.

값의 argc이 0보다 크면 포함를 argv[0]통한 배열 구성원 argv[argc-1]은 프로그램 시작 전에 호스트 Environmental &에서 구현 정의 값을 제공하는 문자열에, 대한 포인터를 포함합니다.

이는 C99에서 변경되지 않는 현상, 조차도 표준에 의해 지시되지 않습니다 . 이는 전적으로 구현에 달려 있습니다.

Environmental &이 경우 호스트 수단은 프로그램 이름이 비어있을 수 없는 호스트 Environmental &이 경우를 제공하고, 아무것도 하지 "무엇은"어떻게 든 프로그램 이름을 나타내는 제공을 제공합니다 . 더 가학적인 순간에 스와힐리어로 번역하고 대체 암호를 통해 실행 한 다음 역 바이트 순서로 저장하는 것을 고려할 것입니다 :-).

그러나 구현 정의 ISO 표준에서 특정 의미를 갖습니다. 구현시 작동 방식을 문서화해야합니다. 따라서 호출 제품군에 argv[0]원하는 것을 수있는 UNIX조차도이를 exec문서화해야합니다 (그리고 수행합니다).


에서 *nix와 타입 시스템 exec*()호출, argv[0]에 어떤 발신자 풋 될 것에 argv0자리 exec*()전화.

쉘은 대부분의 프로그램 이름이라는 규칙을 사용하고 대부분의 다른 프로그램은 일반적으로 일반적으로 argv[0]프로그램 이름입니다.

그러나 악성 Unix 프로그램은 원하는 것을 호출 exec()하고 argv[0]수 있으므로 C 표준이 말하는 것과 상관없이 시간을 100 % 믿을 수 없습니다.


C ++ 표준, 섹션 3.6.1에 따르면 :

argv [0]은 프로그램을 호출하는 데 사용되는 이름을 장르 NTMBS의 초기 문자에 대한 포인터 또는 ""입니다.

따라서 최소한의 표준에 의해 보장되지 않습니다.


이 페이지 는 다음을 설명합니다.

argv [0] 요소는 일반적으로 프로그램의 이름을 포함하지만, 이것은 의존 할 대상입니다. 어쨌든 프로그램이 자신의 이름을 알지 못하는 것은 드문 일입니다!

그러나 다른 페이지는 항상 실행 파일의 이름이라는 사실을 백업하는 것처럼 보입니다. 이것은 다음과 같이 사실.

argv [0]이 프로그램 자체의 경로와 이름임을 알 수 있습니다. 이를 통해 프로그램은 자신에 대한 정보를 사용할 수 있습니다. 또한 프로그램 인수 배열에 하나를 더 추가 할 때 명령 줄 인수를 추가 할 때 발생하는 오류는 argv [1]을 원할 때 argv [0]을 가져옵니다.


ISO-IEC 9899는 다음과 같이 사실.

5.1.2.2.1 프로그램 시작

의 값 이 0 보다 크면로 많음은 프로그램 이름을 나타냅니다. 호스트 환경에서 프로그램 이름을 사용할 수없는 경우 널 문자가됩니다. 의 값 이 1 보다 크면을 통해 가밍 프로그램 변수나타냅니다 .argcargv[0]argv[0][0]argcargv[1]argv[argc-1]

나는 또한 사용했다 :

#if defined(_WIN32)
  static size_t getExecutablePathName(char* pathName, size_t pathNameCapacity)
  {
    return GetModuleFileNameA(NULL, pathName, (DWORD)pathNameCapacity);
  }
#elif defined(__linux__) /* elif of: #if defined(_WIN32) */
  #include <unistd.h>
  static size_t getExecutablePathName(char* pathName, size_t pathNameCapacity)
  {
    size_t pathNameSize = readlink("/proc/self/exe", pathName, pathNameCapacity - 1);
    pathName[pathNameSize] = '\0';
    return pathNameSize;
  }
#elif defined(__APPLE__) /* elif of: #elif defined(__linux__) */
  #include <mach-o/dyld.h>
  static size_t getExecutablePathName(char* pathName, size_t pathNameCapacity)
  {
    uint32_t pathNameSize = 0;

    _NSGetExecutablePath(NULL, &pathNameSize);

    if (pathNameSize > pathNameCapacity)
      pathNameSize = pathNameCapacity;

    if (!_NSGetExecutablePath(pathName, &pathNameSize))
    {
      char real[PATH_MAX];

      if (realpath(pathName, real) != NULL)
      {
        pathNameSize = strlen(real);
        strncpy(pathName, real, pathNameSize);
      }

      return pathNameSize;
    }

    return 0;
  }
#else /* else of: #elif defined(__APPLE__) */
  #error provide your own implementation
#endif /* end of: #if defined(_WIN32) */

그런 다음 디렉토리를 구문 분석하여 경로에서 실행 파일 이름을 추출해야합니다.


argv[0] !=실행 가능한 이름 을을 응용 프로그램

  • 많은 쉘이 확인하여 로그인 쉘인지 판별합니다 argv[0][0] == '-'. 로그인 셸은 다른 속성을 가지고 있고 특히 /etc/profile.

    일반적으로 init 자체이거나 getty선행을 추가합니다 -. https://unix.stackexchange.com/questions/299408/how-to-login-automatically-without-typing-the-root-username-or-password를 참조하십시오. -인-빌드 / 300152 # 300152

  • 다중 호출 바이너리, 아마도 가장 주목할만한 것은 Busybox 입니다. 이 심볼릭 링크 여러 이름은 예 /bin/sh/bin/ls단일 exebutable에 /bin/busybox에서 사용하는 도구를 인식 argv[0].

    이를 통해 여러 도구를 나타내는 하나의 작은 정적으로 연결된 실행 파일을 가질 수 있으며 기본적으로 모든 Linux 환경에서 작동합니다.

참조 : https://unix.stackexchange.com/questions/315812/why-does-argv-include-the-program-name/315817

실행 가능한 POSIX execve예에서 argv[0] !=실행 파일 이름

다른 사람들은 언급 exec했지만 여기에 실행 가능한 예가 있습니다.

ac

#define _XOPEN_SOURCE 700
#include <unistd.h>

int main(void) {
    char *argv[] = {"yada yada", NULL};
    char *envp[] = {NULL};
    execve("b.out", argv, envp);
}

기원전

#include <stdio.h>

int main(int argc, char **argv) {
    puts(argv[0]);
}

그때:

gcc a.c -o a.out
gcc b.c -o b.out
./a.out

제공 :

yada yada

예, 다음과 argv[0]같을 수도 있습니다.

Ubuntu 16.10에서 테스트되었습니다.


거의 보편적 인 관습인지 표준인지는 잘 모르겠지만 어느 쪽이든 따라야합니다. 나는 그것이 유닉스와 유닉스 계열 시스템 밖에서 악용되는 것을 본 적이 없다. 유닉스 환경에서, 특히 예전에는 프로그램이 호출되는 이름에 따라 상당히 다른 동작을 할 수 있습니다.

편집 됨 : 다른 게시물에서 누군가가 특정 표준에서 나온 것으로 식별 한 것을 동시에 다른 게시물에서 볼 수 있지만,이 협약이 표준보다 오래 전부터 있다고 확신합니다.


Workbench로 Amiga 프로그램을 시작하면 argv [0]이 설정되지 않고 CLI로만 설정됩니다.

참고 URL : https://stackoverflow.com/questions/2050961/is-argv0-name-of-executable-an-accepted-standard-or-just-a-common-conventi

반응형