티스토리 뷰

C | C++

프로그램 실행

야라바 2018. 8. 4. 14:54
728x90

☞ system, execv, execl, execve, execle, execvp, execlp

<stdlib.h>
<unistd.h>

int system(const char *command);
int execv(const char *filename, char *const argv[]);
int execl(const char *filename, const char *arg0, ...);
int execve(const char *filename, char *const argv[], char *const env[]);
int execle(const char *filename, const char *arg0, ..., char *const env[]);
int execvp(const char *filename, char *const argv[]);
int execlp(const char *filename, const char *arg0, ...);

실행중인 프로그램에서 다른 프로그램을 실행시키는 방법들 입니다. 가장 간단한 방법은 system() 함수를 사용하는 것으로 자세한 컨트롤은 할 수 없지만 쉘 또는 콘솔에서 명령을 수행하는 것처럼 명령행 문자열을 인수로 넘기면 쉘을 통해서 지정한 명령을 수행합니다. command를 통해서 수행을 지시한 명령이 끝날때까지 system() 함수는 리턴하지 않습니다.



☞ 예제1

void csql_invoke_system (const char *command)
{
    bool error_found = false;	/* TRUE if error found */

    if (system (command) == 127)
    {
        error_found = true;
        csql_Error_code = CSQL_ERR_OS_ERROR;
    }

    if (error_found)
    {
        nonscr_display_error (csql_Scratch_text, SCRATCH_TEXT_LEN);
    }
}

위의 예제는 큐브리드 DBMS의 코드 일부로 사용자가 프로그램 수행중에 시스템 명령을 수행하고 싶을때 system()함수를 통해서 사용자가 입력한 명령을 수행시켜주는 과정입니다. 실행중인 프로세스에서 다른 프로그램을 실행시키는 과정을 살펴보면 그 시작은 fork()를 통해서 자식 프로세스를 생성하는 것으로 시작합니다. fork()는 기존 프로세스와 동일한 복사본을 새롭게 만들고 새로운 프로세스 ID를 부여합니다. 이 시점부터 부모 프로세스와 자식 프로세스는 각각 독립적으로 동시 수행됩니다. 자식 프로세스가 종료되면 부모 프로세스로 시그널을 전송하는 것으로 그 생애를 마감합니다. 부모 프로세스가 자식 프로세스의 실행이 종료 될 때 까지 실행을 잠시 멈추고 싶다면 wait() 또는 waitpid()를 호출하면 됩니다. system() 함수는 이런 과정을 단순화 시켜 준 것입니다.



☞ 예제2

static pgpid_t start_postmaster(void)
{
    char		cmd[MAXPGPATH];

#ifndef WIN32
    pgpid_t		pm_pid;

    /* Flush stdio channels just before fork, to avoid double-output problems */
    fflush(stdout);
    fflush(stderr);

    pm_pid = fork();
    if (pm_pid < 0)
    {
        /* fork failed */
        write_stderr(_("%s: could not start server: %s\n"),
            progname, strerror(errno));
        exit(1);
    }
    if (pm_pid > 0)
    {
        /* fork succeeded, in parent */
        return pm_pid;
    }

    /* fork succeeded, in child */

    if (log_file != NULL)
        snprintf(cmd, MAXPGPATH, "exec \"%s\" %s%s < \"%s\" >> \"%s\" 2>&1",
        exec_path, pgdata_opt, post_opts,
        DEVNULL, log_file);
    else
        snprintf(cmd, MAXPGPATH, "exec \"%s\" %s%s < \"%s\" 2>&1",
        exec_path, pgdata_opt, post_opts, DEVNULL);

    (void) execl("/bin/sh", "/bin/sh", "-c", cmd, (char *) NULL);

    /* exec failed */
    write_stderr(_("%s: could not start server: %s\n"),
        progname, strerror(errno));
    exit(1);

    return 0;					/* keep dumb compilers quiet */
#else							/* WIN32 */
    PROCESS_INFORMATION pi;

    if (log_file != NULL)
        snprintf(cmd, MAXPGPATH, "CMD /C \"\"%s\" %s%s < \"%s\" >> \"%s\" 2>&1\"",
        exec_path, pgdata_opt, post_opts, DEVNULL, log_file);
    else
        snprintf(cmd, MAXPGPATH, "CMD /C \"\"%s\" %s%s < \"%s\" 2>&1\"",
        exec_path, pgdata_opt, post_opts, DEVNULL);

    if (!CreateRestrictedProcess(cmd, &pi, false))
    {
        write_stderr(_("%s: could not start server: error code %lu\n"),
            progname, (unsigned long) GetLastError());
        exit(1);
    }
    /* Don't close command process handle here; caller must do so */
    postmasterProcess = pi.hProcess;
    CloseHandle(pi.hThread);
    return pi.dwProcessId;		/* Shell's PID, not postmaster's! */
#endif							/* WIN32 */
}

위의 예제는 PostgreSQL DBMS 코드의 일부로 fork()로 자식 프로세스를 생성하는 과정을 참조해 볼 수 있습니다. fork() 함수를 호출한 다음에 부모 프로세스는 0보다 큰 값을 리턴 받으므로 함수를 빠져 나가고 실제 작업을 수행할 자식 프로세스에서는 execl()을 통해서 외부 명령을 수행하고 있습니다. 주의할 점은 윈도우 운영체제에서는 exec*()함수들 대신에 별도의 API를 사용하고 있으므로 필요에 따라 적절하게 활용할 필요가 있습니다. exec*() 함수들은 프로그램 아규먼트를 어떻게 전달할 것인지만 다를뿐 fork()로 생성된 자식 프로세스 이미지로 filename으로 지정한 파일을 실행시키는 것은 동일합니다.

  • execv : main() 함수가 아규먼트로 받는 argv[] 형태로 인수가 담긴 문자열 배열 하나를 전달합니다. 배열 맨 끝에는 널 스트링이 꼭 있어야 합니다.
  • execl : arg0, arg1, ....처럼 개별적인 인수로 아규먼트를 전달하고 싶을때 사용. 맨 마지막 인수는 널 스트링이어야 합니다.
  • execve : execv()유사하나 환경변수를 argv[]와 같은 형태로 env[]를 전달할 수 있습니다.
  • execle : execl()유사하나 환경변수를 argv[]와 같은 형태로 env[]를 전달할 수 있습니다.
  • execvp : execv()유사하나 filename으로 지정한 파일을 PATH 환경변수에 정의 되어 있는 경로에서 찾습니다.
  • execlp : execl()유사하나 filename으로 지정한 파일을 PATH 환경변수에 정의 되어 있는 경로에서 찾습니다.






728x90

'C | C++' 카테고리의 다른 글

벡터 클래스(std::vector) 정리  (0) 2024.01.22
프로세스 생성과 관리  (0) 2018.08.04
프로그램 종료  (0) 2018.08.04
환경 변수 다루기  (0) 2018.08.04
프로그램 아규먼트와 옵션 처리  (0) 2018.08.04