[리눅스] system함수 사용 방법과 구현(fork, exec, waitpid)
fork, exec에 대한 상세 내용과 더 많은 정보와 예제를 담은 리눅스 교재를 배포했습니다. 아래의 페이지에서 리눅스 교재를 받아가세요.
https://reakwon.tistory.com/233
system함수
system함수는 유닉스 운영체제에는 모두 지원합니다. system함수는 입력받은 command의 문자열을 실제로 실행시켜주는 함수입니다.
system함수를 사용하기 위해서는 stdlib.h 헤더파일을 include 해야합니다.
#include <stdlib.h>
system함수의 원형은 아래와 같습니다.
int system(const char *command);
사용하는 방법은 매우 간단합니다. command에 실행할 명령어를 전달해주기만 하면 됩니다. 아래의 사용 예를 보시면 금방 사용하실수 있을겁니다.
사용예)
//system_test.c
#include <stdlib.h>
#include <stdio.h>
int main(){
char *command="ls -al";
int ret;
ret = system(command);
printf("system함수 종료 :%d\n",WEXITSTATUS(ret));
}
# gcc system_test.c
# ./a.out
합계 208
drwxr-xr-x 19 ubuntu ubuntu 4096 4월 11 17:22 .
drwxr-xr-x 6 root root 4096 4월 1 15:38 ..
-rw------- 1 ubuntu ubuntu 378 4월 11 17:17 .Xauthority
-rw------- 1 ubuntu ubuntu 5496 4월 11 12:42 .bash_history
-rw-r--r-- 1 ubuntu ubuntu 220 2월 22 2021 .bash_logout
...
system 함수 호출 완료 ret:0
system함수의 내부
system함수에 NULL을 전달하게 되면 적절한 명령처리기가 존재한다면 0을 돌려줍니다. 그 외에는 상황에 따라 다릅니다. system함수를 내부적으로 들여다보면 fork, exec, waitpid로 이루어진 함수입니다. 이 세개의 함수에 대해서 모르신다면 아래의 포스팅을 참고하시기 바랍니다.
- fork()
https://reakwon.tistory.com/45
- exec()
https://reakwon.tistory.com/207?category=300674
- waitpid
https://reakwon.tistory.com/99
system함수의 반환 값
1. fork 호출이 실패했거나 waitpid가 EINTR외의 오류를 돌려주면 system함수는 errno를 EINTR오류로 설정하고 -1를 반환합니다.
2. exec함수가 실패했다면 이런 경우에는 shell을 실행할수 없다는 뜻이며, exit(127)과 동일합니다.
3. 그 외의 경우에는 waitpid에 지정된 셸의 종지 상태가 return됩니다.
아래의 코드는 system함수를 흉내낸 코드입니다.
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
int system(const char *cmd){
pid_t pid;
int status;
if(cmd == NULL) return 1; //UNIX에는 명령 처리기가 존재
if((pid = fork()) < 0){
status = -1; //프로세스 생성 에러
}else if(pid == 0){ //자식 프로세스
execl("/bin/sh","sh","-c",cmd,(char*)0);
_exit(127); //위 2번읜 case
}else{ //부모 프로세스 : 자식이 끝날때까지 기다림
while(waitpid(pid, &status, 0) < 0){
if(errno != EINTR){ //위 1번의 case
status = -1;
break;
}
}
}
return status;
}
int main(){
int ret;
ret = system("ls -al");
printf("system함수 종료 :%d\n",WEXITSTATUS(ret));
}
이러한 구현사항때문에 내부적으로 fork()로 자식 프로세스를 수행하고 자식 프로세스는 exec함수를 호출하는데요. 부모 프로세스는 waitpid로 자식 프로세스를 기다리기 때문에 system다음 줄의 printf가 실행될수 있는 것이죠.
종지 상태 확인
WEXITSTATUS로 실제 exit()이나 return값을 확인할수 있습니다. 아래는 main에서 바로 return 18로 빠져 나오는 한 프로그램입니다. 혹은 exit(18)을 해도 똑같습니다.
//program.c
int main(){
//exit(18);
return 18;
}
# gcc program.c -o program
# ls program
program
program이라는 실행파일이 생겨납니다. 이제 이 실행파일을 실행시키기 위해 system함수를 사용해보겠습니다.
//system_test.c
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(){
int ret;
ret = system("./program");
printf("system함수 종료 :%d\n",WEXITSTATUS(ret));
}
# gcc system_test.c
# ./a.out
system함수 종료 :18
우리가 return했던 값을 확인할 수 있죠? 단순 ret값을 출력하는게 아닌 매크로를 통해서 종지상태를 확인해야한다는 점을 기억하세요.
이상으로 system에 관한 포스팅을 마치도록 하겠습니다.