exec()
→ system()함수는 OS가 명령 문자열을 보고 프로그램을 실행하는 함수인데 보안이 허술해 악의적인 사용자가 명령 문자열을 악의적으로 조작이 가능했고, 그리하여 나온 것이 exec()계열 함수다.
- exec()는 현재 실행중인 프로세스를 종료하고 해당 프로세스를 대체하여 실행한다.
- unistd.h에 선언되어 있다. exec() 계열 함수를 호출하면 새 프로세스(외부 프로그램이)가 실행되고 해당 프로세스는 종료된다.
- exec() 함수들은 -1을 반환하며, errno 변수를 설정하여 발생한 오류를 알려준다. 오류는 프로그램 파일이 없는 경우, 실행 권한이 없는 경우, 메모리 부족 등의 이유로 발생할 수 있다.
- exec() 함수는 프로세스 간의 통신이나 프로그램 실행 중 동적으로 다른 프로그램을 호출해야 하는 경우 유용.
- exec()는 프로세스의 메모리 영역과 리소스를 새로운 프로그램으로 덮어씌우기 때문에, 호출 이후에는 이전의 코드와 실행 상태는 모두 사라짐.
exec는 2가지로 나뉜다
- 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;
}
- 부모 프로세스에서 execve() 함수를 사용하여 “/bin/ls” 프로그램을 실행하고 실행할 프로그램 “ls”와 “-l”을 명령행 인수로 전달
- "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
[42_pipex] 함수2. dup, dup2, execve, access, unlink 자세한 설명
'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 |