반응형

프로그램을 개발하거나 운영을 하다 보면 debugging 또는 일시적은 오류에 의해서 대량의 로그가 생성되는 경우가 있다.
이들 로그를 확인하기 위해서

$ tail -f 파일명

으로 확인하거나 vi로 직접 열어서 확인하기도 한다.


그러다가 보면 파일이 너무 크게 쌓여 있어서 파일의 내용을 지우고 다시 쌓고 싶은 경우가 있다.

응용 프로그램에서 파일을 open 후에 로그를 생성하고 있는 데도 불구하고 실수로 

$ rm -f 파일명

하여 파일을 삭제하는 경우가 있다.

 

일반적으로 로그 파일은 로그를 찍을 때 마다 파일을 오픈하고 로그를 찍은 후에 close를 하는 것이 아니라 성능 때문에 한번 open한 후에는 프로그램이 끝날 때까지 close하지 않는 경우가 대부분이다. 이처럼 다른 프로세스가 open한 파일을 삭제를 하면 더 이상 파일이 보이지 않는다. 즉, 보이지는 않지만 Disk를 차지하는 현상이 발생한다. 삭제된 파일은 그 파일을 open한 프로세스가 파일을 닫아주거나 그 프로세스가  종료되어야만 Disk에서 사라진다.

이런 경우에는그 프로그램을 종료시키고 다시 재기동해야 한다.

개발자/운영자들 중에서는 실수로 로그 파일을 지우고 로그 파일이 생성안되니까, 삭제된 파일명과 같은 이름으로 파일을 다시 만들어주는 경우가 있다. 그러나 삭제된 파일은 이미 파일명만 같을 뿐 다른 파일이므로 더 이상 로그를 생성하지 않는다. 

 

다른 프로세스에 의해서 열려진 파일을 초기화하는 간단한 방법(파일의 내용을 모두 지우는 방법)은

$ > 파일명 

이다. 즉, 파일을 삭제하지 말고 redirect로 파일의 내용만 지우면 정상적으로 로그를 쌓게 된다.

 

가끔 disk가 full 나서 이를 해결하기 위해 log를 쌓는 디렉토리로 이동하여 

$ rm -f *.log

를 통하여 파일을 일괄로 삭제하여 disk 용량을 확보하려는 경우가 있다.

이 경우에도 마찬가지로 disk의 공간은 확보되지 않는다. 결국은 실행중인 프로그램을 종료 시켜야만 disk의 용량이 확보되므로 주의해야 한다. 만약, 운영 상황이면 장애 상태가 된다. 이 경우에도 지우고 싶은 파일에 대해서 $ > 파일명으로 파일의 크기만 초기화 해야 한다. 

 

이런 실수를 하는 이유는 OS의 파일관리 방법에 대해서 이해가 부족하기 때문이다. 사람은 파일 관리를 파일명(full path)으로 인식하지만, OS는 inode로 관리합니다. inode는 마운트된 disk 단위로 관리되며, 생성된 파일에 대해 순번을 매겨놓은 것이라고 이해하면 됩니다. 사용자가 파일명을 바꾸더라도 inode는 변경되지 않는다. 그러나 파일을 삭제하고 다시 같은 파일명으로 같은 디렉토리에 파일을 만들어도 inode는 달라진다. 즉, 파일을 삭제했다가 다시 똑같은 파일명으로 파일을 만들어도 OS는 이미 같은 파일로 보지않는다는 것이다. 

 

OS는 open된 파일에 대해서는 파일명에는 관심이 없고 오로지 inode로만 관리를 한다. 그래서 파일을 삭제를 하거나 파일을 rename하거나 file을 다른 디렉토리로 move 하더라도 inode가 변경되지 않기 때문에 같은 파일로 인식한다(다른 disk로 이동하면 inode가 변경됨). 즉, 어떤 프로세스가 파일을 open한 상태에서 파일을 열심히 write를 하고 있는데, 사용자가 mv명령어로 다른 디렉토리로 옮기더라도 옮겨진 파일에 계속 write를 한다. open된 파일에 대해서는 원 디렉토리에 새로 파일을 만들어 write를 하지 않는다. 

 

그런데, 어떤 프로세스가 파일을 write하고 있는 데, 파일을 삭제하면 어떻게 될까요? 파일을 write하고 있는 데, 파일을 삭제하면 OS는 inode로 파일을 관리하기 때문에 파일 write를 계속한다. 그러다가 파일 쓰기를 다 하고 파일을 close할 때나 프로세스를 종료할 때에 OS는 inode는 존재하나 그와 매핑되는 파일명이 없어졌으므로 어차피 사람이 파일을 볼 수 없는 상황이 되었기 때문에 파일이 있어도 다시 그 파일을 처리할 방법이 없다는 것을 안다. 그래서 그 때 파일이 삭제된 것을 알고 그 파일이 차지하고 있던 Disk 공간을 사용할 수 있도록 삭제한다. (정확하게는 쓸 수 있는 공간으로 반환) 

 

위와 같은 이유로 인하여 프로그램이 로그를 열심히 쌓고 있는 데, disk 공간을 확보를 하기 위하여 파일을 rm -f *.log로 삭제를 하면 df 명령어로 봐도 storage 확보는 안되고 파일은 보이지 않는 문제가 생기는 것이다. 이를 해결하기 위해서는 파일을 닫아야 하는 데, 파일을 닫기 위한 방법은 프로세스를 종료하는 수 밖에 없는 것이다. 따라서 로그 파일의 내용을 지우기 위해서는 파일을 삭제하는 것이 아니라 파일을 오픈해서 파일의 내용을 truncate하는 것이다. 쉽게 파일을 truncate하는 방법이 바로 위에서 얘기한  > 파일.log로 redirect하는 것이다.

 

 


의도적으로 open된 파일을 삭제하기

 

open된 파일을 의도적으로 삭제하면 좋은 경우도 있다. 특정 파일을 프로그램 내에서 임시 파일의 형태로 읽고 쓰기를 하는 경우에 사용하면 효과적이다.

 

예를들면, 

FILE *fp = NULL;

if((fp = fopen("/tmp/tempcache.dat", "w+")) == NULL) 
{

    ....

}

unlink("/tmp/tempcache.dat");

....

이렇게 open한 파일을 close하지 않은 상태에서 프로그램 내에서 파일을 삭제하면, 프로그램에서 파일을 읽고 쓰기를 하면서 업무처리를 하다가, 비정상 종료 등으로 파일을 삭제를 하지 못하고 종료되어도 파일을 자동으로 삭제하게 된다. 이렇게 임시 파일을 다른 사용자나 프로세스가 보지도 읽지도 못하도록 하면 보안적인 측면을 강화시킬 수 있다. 물론 fork(2)한 child는 읽기 쓰기를 할 수 있으므로 child도 읽지 못하게 하려면 fork(2)후에 child쪽 프로세스에서 fclose(fp)를 하면 된다.

이처럼 의도적으로 파일을 open 후 바로 삭제를 하면 garbage 파일도 생성되지 않고 보안적인 측면도 강화할 수 있는 방법으로 활용할 수 있다.

 

 

반응형

'LINUX > 기초' 카테고리의 다른 글

LINUX real user vs. effective user의 차이점  (2) 2019.10.11
블로그 이미지

자연&사람

행복한 개발자 programmer since 1995.

,