open() 함수의 플래그 중 O_CLOEXEC를 이해해봅니다.
리눅스의 open() 함수의 플래그에서 이해하기 힘들었던 O_CLOEXEC
플래그를 이해해 보겠습니다.
일단, 아래의 명령어를 통해 open()
함수의 Manual에서 O_CLOEXEC
에 대한 설명을 읽어봅시다.
$ man 2 open
새로운 파일 디스크립터가 생성될 때, close-on-exec
플래그를 설정해주는 역할을 한다고 합니다. 그렇다면 close-on-exec
플래그가 무엇인지 알아야겠습니다.
기본적으로 리눅스 프로그램은, exec
로 프로세스를 생성할 때 열어놓은 파일 디스크립터를 모두 물려줍니다. 하지만 close-on-exec
플래그가 설정되어 있으면, exec
계열 함수로 새로운 프로세스를 생성할 때 파일 디스크립터를 그 프로세스에게 물려주지 않습니다.
직접 확인해봅시다. 일단 간단한 확인을 위해 네임드 파이프 하나를 만들어줍시다.
mkfifo aaa
그리고 이 aaa
라는 파이프를 열 프로그램을 2개 작성합니다. 하나는 aaa
를 open
하는 과정에서 O_CLOEXEC
를 세워 놓고, 하나는 세우지 않은 채로 작성합니다.
「cloexec.c」
#include <stdio.h>
#include <fcntl.h>
int main(void){
open("aaa", O_RDWR | O_CLOEXEC);
execl("YOUR_PATH/wr_to_pipe", "./wr_to_pipe", 0);
}
「n_cloexec.c」
#include <stdio.h>
#include <fcntl.h>
int main(void){
open("aaa", O_RDWR);
execl("YOUR_PATH/wr_to_pipe", "./wr_to_pipe", 0);
}
그리고, exec
에 의해 실행되어 상속받은 파일 디스크립터에 write를 수행할 프로그램을 작성합니다.
「main.c」
#include <stdio.h>
int main(void){
write(3, "TEST", 5); // Write to File descriptor 3
perror("write");
}
파일 디스크립터는 3번부터 열리기 때문에, 만약에 부모 프로세스로부터 파일 디스크립터를 상속받았다면 3번 디스크립터에 write를 수행할 수 있을 겁니다.
하지만 부모 프로세스가 3번 디스크립터에 파일을 open하는 과정에서 O_CLOEXEC
플래그를 올려 놓았다면, exec
에 의해 실행되어도 3번 디스크립터를 물려받지 못해 write를 수행할 수 없을 겁니다. write가 성공적으로 수행되었는지 perror()
함수를 통해 확인해 봅시다.
세 개의 파일을 모두 컴파일한 후, cloexec
와 n_cloexec
를 실행합니다.
O_CLOEXEC를 올렸던 프로그램이 wr_to_pipe를 실행하면, 파일 디스크립터를 인식하지 못하고 write에 실패하는 것을 볼 수 있습니다.