42Seoul/pipex

execve()

재윤 2023. 9. 13. 01:28
반응형

exec()

→ system()함수는 OS가 명령 문자열을 보고 프로그램을 실행하는 함수인데 보안이 허술해 악의적인 사용자가 명령 문자열을 악의적으로 조작이 가능했고, 그리하여 나온 것이 exec()계열 함수다.

  • exec()는 현재 실행중인 프로세스를 종료하고 해당 프로세스를 대체하여 실행한다.
  • unistd.h에 선언되어 있다. exec() 계열 함수를 호출하면 새 프로세스(외부 프로그램이)가 실행되고 해당 프로세스는 종료된다.
  • exec() 함수들은 -1을 반환하며, errno 변수를 설정하여 발생한 오류를 알려준다. 오류는 프로그램 파일이 없는 경우, 실행 권한이 없는 경우, 메모리 부족 등의 이유로 발생할 수 있다.
  • exec() 함수는 프로세스 간의 통신이나 프로그램 실행 중 동적으로 다른 프로그램을 호출해야 하는 경우 유용.
  • exec()는 프로세스의 메모리 영역과 리소스를 새로운 프로그램으로 덮어씌우기 때문에, 호출 이후에는 이전의 코드와 실행 상태는 모두 사라짐.

exec는 2가지로 나뉜다

  1. execv 계열
  • e
    • 환경 변수에 대한 포인터 배열이 새 프로세스 이미지에 명시적으로 전달됨.
  • l
    • 명령줄 인수가 함수에 개별적으로(목록) 전달됨.
  • p
    • PATH 환경 변수를 사용하여 실행항 파일로 인수에 이름이 지정된 파일을 찾는다.
  • v
    • 명령줄 인수는 포인터의 배열(벡터)로 함수에 전달된다.

execl, execlp, execv 및 execvp를 호출하면 현재 환경 변수를 가지고 새 프로세스를 시작한다.

exec 계열함수은 system call 함수

나머지는 execve에 wrapping을 한 함수

읽다가 운영체제를 공부하지 못한 분들은 system call과 wrapping을 보고 이거 뭐지?라는 생각을 할 것이다.

→ 시스템 콜??

  • 운영 체제 커널에 있는 기능을 호출하는 인터페이스임.
  • 사용자 프로그램은 시스템 콜을 통해 운영 체제의 기능을 활용할 수 있다.
  • 프로그램이 하드웨어 리소스에 접근하거나 운영 체제 서비스를 이용하기 위해 필요하다.
  • 시스템 콜은 커널 모드에서 실행되며, 사용자 프로그램은 유저 모드에서 실행된다.
  • 사용자 프로그램이 시스템 콜을 호출하면, 프로그램의 실행은 유저 모드에서 커널 모드로 전환되어 운영체제의 해당 기능을 수행한다.
    • 다른 프로그램을 실행하고 자신은 종료한다. execle() 이나 execve()처럼 exec 함수 중 e로 끝나는 함수는 환경변수를 지정할 수 있음.

이 말만 보면 무슨 개소린지 싶을 것이다. 한 번 쉽게 보쟈

우리가 c언어에서 막 코딩을 한다 생각해보자 그러면 조건문, 반복문 등을 사용해서 코딩을 할 텐데 파일을 읽어오거나 파일에 무엇을 쓰기를 하거나 등 뭔가 컴퓨터 하드웨어에 접근해서 하는 것들을 할 수도 있는데 이 접근하는 것 자체가 시스템 콜이라는 것이다. 그 중 쉬운 예는 read, write 등이 있다.

좀 더 유치원생한테 설명하듯이 해보면 우리 컴퓨터는 하드웨어, 메모리 등을 운영체제의 커널이라는 친구가 관리를 하게 되는데 아무나 막 접근을 할 수 있으면 안된다. 우리 사용자도 마찬가지이다. 그러면 접근을 하기 위해서는 우리는 커널한테 허락을 받아야한다.

근데 우리가 코딩할 때 허락 받으려고 어떤 행위를 하지는 않는다 그것을 해주는 친구가 시스템 콜이라고 보면 된다.

ex) 내가 read 함수를 사용 → 시스템 콜 → 커널

 

좀 더 공부하고 싶은 사람은 system call에 대해 찾아보면 좋겠다!

→ Wrapping?

  • 프로그래밍에서 기존 함수나 기능을 감싸서 추가적인 기능을 더하거나 수정하는 과정
  • 사용자가 원래의 시스템 콜을 호출할 때, 추가적인 작업을 수행하기 위해 시스템 콜을 감싸는 (wrapper)함수를 작성하는 것을 의미

쉽게 말해서 exec() 함수는 execve가 틀인데 이 틀을 통해서 다른 친구들을 만들었다고 생각하면 됨. → excel, execvp … 전부


환경변수의 사용 이유?

환경변수라는 것부터 보자

→ 프로세스가 컴퓨터에서 동작하는 방식에 영향을 미치는, 동적인 값들의 모임

환경변수 확인 법

export

다른 분의 아주 좋은 설명

  • 환경변수라는 이름만 놓고 보더라도 일종의 변수라는 것을 알 수 있음. os에서 자식프로세스들을 생성할 때 참조하는 변수들이라고 생각하면 아주 좋다
  • 우리가 컴퓨터로 띄우는 모든 작업창 조금 더 엄밀히 얘기해서 프로세스들은 전부 OS라는 프로그램에 의해 실행되는 자식 프로세스들이다.
  • 이때 OS입장에서 해당 프로세스를 실행시키기위해 참조하는 변수가 바로 이 환경변수이다.
  • 환경변수 중에서 일반이 유저를 포함해서 컴퓨터를 쓴다면 자주 마주칠법한 변수가 하나 있는데 그 변수가 PATH라는 이름의 변수이다.
  • PATH 변수는 운영체제가 어떤 프로세스를 실행시킬 때, 그 경로를 찾는데 이용된다.
  • 명령프롬프트 상에서(윈도우 기준) 환경변수 설정은 set을 통해 조작할 수 있으며, 현재 등록된 모든 환경변수들의 이름과 값들을 확인 가능.

그럼 환경변수를 왜 사용할까

  • 환경변수는 바로가기처럼 미리 지정해 놓은 루트로 바로 간다.
  • 환경변수를 정하지 않고 모두 쓴 다음에 파일을 실행.

예시를 보자

mac → goinfre에 test.sh를 만듦

~로 돌아가서 이것을 실행시키려면 요렇게 해야함

이 경로를 환경변수에 추가해주자

export test=goinfre/test.sh

추가 된 거 확인하고

$test해주면 됨 

만약 permission denied이 친구가 나오면 환경변수를 가져와서 실행시킬 수 있는 권
한이 없어서 그럼 권한 바꿔줘야함.

환경변수 정리

→ 우리가 명령어를 인수로 줄텐데 그 친구들을 실행시키기 위해 환경변수에 있는 친구들 각각 하나씩 검사해서 이 명령어를 실행시킬 수 있는지 확인해야함

export

환경변수의 path를 확인해보면 “:” 기준으로 나뉠텐데 예를 통해 알아보자

PATH=/usr/local/bin:usr/bin

명령어가 만약 /usr/local/bin에 없으면 /usr/bin으로 간다는 말임.

그러면 우리는 이제 알 수 있다.

환경변수를 각각 다 들고와서 인자값으로 넣어준 명령어들을 환경변수에 붙여서 되는지 확인을 해야함.

이 말이 이해가 안 된다면 밑에 예제를 보자


exec의 함수들을 각각 예제를 통해 살펴보자

1. execl()

  • 이 함수는 단일 명령행 인수를 받는 경우에 사용됨.
  • /bin/ls -l 명령어를 실행하는 경우.
#include <stdio.h>
#include <unistd.h>

int main() {
    printf("부모 프로세스 시작\\n");

    // execl() 함수를 사용하여 "/bin/ls" 명령어 실행
    execl("/bin/ls", "ls", "-l", NULL);

    // execl() 함수가 성공적으로 실행되면 아래의 코드는 실행되지 않음
    printf("부모 프로세스 종료\\n");

    return 0;
}

결과

2. execv()

  • 명령행 인수를 배열로 받는 경우에 사용됨.
  • /bin/ls -l 명령어를 실행하는 경우.

→ 부모 프로세스에서 execv 함수를 사용하여 "ls -l" 명령어를 실행하는 예제.

  • 처음에는 "부모 프로세스 시작"이라는 출력을 확인. 그런 다음 execv() 함수를 사용하여 "/bin/ls" 프로그램을 실행하고, "ls"와 "-l"을 명령행 인수로 전달. 실행 결과로 현재 디렉토리의 파일 및 폴더 목록이 출력.
  • 부모 프로세스 종료라는 것은 나오지 않음 execv 성공적으로 실행되면 아래의 코드는 실행되지 않는다!
#include <stdio.h>
#include <unistd.h>

int main() {
    printf("부모 프로세스 시작\\n");

    // execv() 함수를 사용하여 "ls" 명령어를 실행
    char *args[] = {"ls", "-l", NULL};
    execv("/bin/ls", args);

    // execv() 함수가 성공적으로 실행되면 아래의 코드는 실행되지 않음
    printf("부모 프로세스 종료\\n");

    return 0;
}

결과

3. execle()

  • 함수는 환경 변수를 포함하여 단일 명령행 인수를 받는 경우에 사용됨.
  • /bin/ls -l 명령어를 실행하고 환경 변수 "HOME=/home/user"를 전달하는 경우.
#include <stdio.h>
#include <unistd.h>

int main() {
    printf("부모 프로세스 시작\\n");

    // execle() 함수를 사용하여 "/bin/ls" 명령어 실행
    char *envp[] = {"HOME=/home/user", NULL};
    execle("/bin/ls", "ls", "-l", NULL, envp);

    // execle() 함수가 성공적으로 실행되면 아래의 코드는 실행되지 않음
    printf("부모 프로세스 종료\\n");

    return 0;
}

결과

4. execve()

  • 이 함수는 환경 변수와 명령행 인수를 배열로 받는 경우에 사용.
  • 예를 들어, /bin/ls -l 명령어를 실행하고 환경 변수 "HOME=/home/user"와 "PATH=/bin:/usr/bin"를 전달하는 경우.
#include <stdio.h>
#include <unistd.h>

int main() {
    printf("부모 프로세스 시작\\n");

    // 실행할 프로그램의 경로
    char *path = "/bin/ls";

    // 실행할 프로그램에 전달할 명령행 인수
    char *args[] = {"ls", "-l", NULL};

    // 실행할 프로그램에 전달할 환경 변수
    char *envp[] = {"HOME=/home/user", "PATH=/bin:/usr/bin", NULL};

    // execve() 함수를 사용하여 프로그램 실행
    execve(path, args, envp);

    // execve() 함수가 성공적으로 실행되면 아래의 코드는 실행되지 않음
    printf("부모 프로세스 종료\\n");

    return 0;
}
  1. 부모 프로세스에서 execve() 함수를 사용하여 “/bin/ls” 프로그램을 실행하고 실행할 프로그램 “ls”와 “-l”을 명령행 인수로 전달
  2. "HOME=/home/user"와 "PATH=/bin:/usr/bin"이라는 환경 변수들도 전달

결과

  • 부모 프로세스 시작이라는 출력 확인 가능
  • execve()함수를 사용하여 "/bin/ls" 프로그램을 실행하고, "ls"와 "-l"을 명령행 인수로 전달하며, "HOME=/home/user"와 "PATH=/bin:/usr/bin"이라는 환경 변수들도 전달

execve 함수 에러

#include <stdio.h>
#include <unistd.h>

int main() {
    char *argv[] = {"ls", "-l", NULL};
    char *envp[] = {NULL};

    if (execve("/bin/ls", argv, envp) == -1) {
        perror("execve");
        return 1;
    }

    return 0;
}

위의 코드에서 execve 함수를 사용하여 ls 프로그램을 실행

  • argv 배열은 ls 프로그램에 전달할 명령행 인수들을 나타내며, 여기서는 -l 옵션을 사용하여 자세한 파일 목록을 출력하도록 지정. 배열의 마지막 요소는 반드시 NULL로 끝나야 합니다.
  • envp 배열은 프로그램에 전달할 환경 변수들을 나타내는 문자열 배열.
  • execve 함수는 /bin/ls 경로의 실행 파일을 실행. 경로는 실행하려는 프로그램의 위치에 따라 적절하게 수정해야 함.
  • execve 함수가 호출되면 현재 프로세스의 이미지는 ls 프로그램으로 대체됩니다. 따라서 이후의 코드는 실행되지 않는다.
  • 만약 execve 함수 호출이 실패하면 -1을 반환하고, perror 함수를 사용하여 오류 메시지를 출력하고 종료합니다.
  • 위의 예제를 컴파일하고 실행하면, ls 명령어의 출력 결과가 터미널에 표시됨.
  • 주의할 점은 execve 함수를 호출하면 현재 프로세스의 이미지가 완전히 교체되기 때문에, execve 이후의 코드는 실행되지 않는다. 따라서 execve 이후에 필요한 코드가 있다면, 자식 프로세스를 생성하여 execve 를 호출해야 함.

[스카웃 C언어 강좌] 37-3 프로세스 대체 함수 exec

 

[스카웃 C언어 강좌] 37-3 프로세스 대체 함수 exec

[스카웃 C언어 강좌] 37-3 프로세스 대체 함수 exec       머...

blog.naver.com

[42_pipex] 함수2. dup, dup2, execve, access, unlink 자세한 설명

 

[42_pipex] 함수2. dup, dup2, execve, access, unlink 자세한 설명

1.dup, dup2 이 함수는 파일 디스크립터를 복사하는 함수이다. 아마 duplicate이 어원일 것 같다..! #include intdup(int fd); intdup2(int fd, int fd2); dup은 매개변수 fd를 복제하여 반환한다. 성공 시 새 fd, 오류시

sudo-me.tistory.com

1-1 환경변수란? 환경변수와 path

 

1-1 환경변수란? 환경변수와 path

다음은 백과사전 상의 환경변수의 정의다. 환경변수란 프로세스가 컴퓨터에서 동작하는 방식에 영향을 미치...

blog.naver.com

 

반응형

'42Seoul > pipex' 카테고리의 다른 글

pipe(), unlink()  (0) 2023.09.13
access()  (0) 2023.09.13
dup, dup2  (0) 2023.09.13
리다이렉션 <, >, <<, >>  (0) 2023.09.13
프로세스 통신(IPC)  (0) 2023.09.13