2010-08-20 2 views
18

그것은 다음과 같이 진행됩니다리눅스의 파일 기술자 3은 무엇이 특별한가요? 나는 리눅스와 맥 OS X에서 일 것 서버 응용 프로그램에서 일하고 있어요

  • 기본 응용 프로그램 컨트롤러 과정의
  • 포크에게
  • 전화 lock_down 시작() 컨트롤러 과정에서
  • 결국 컨트롤러가 더 많은 작업을 분기 유지하는 작업자 프로세스를 생성, 포크 다시 기본 응용 프로그램
  • 다음 컨트롤러 프로세스를 종료 어 프로세스들.

나는 여러 가지 방법으로 로그 할 수있다. syslog 또는 파일)하지만 지금은 syslog에 대해 숙고하고 있습니다. "재미있는"것은 아래에 #ifdef 섹션을 포함하지 않으면 컨트롤러 프로세스에서 syslog 출력이 보이지 않는다는 것입니다.

아래의 ifdef'ed 섹션이 있거나없는 Mac OS X 및 Linux에서 작업자 프로세스 로그를 완벽하게 처리합니다. 컨트롤러는 또한 # ifdef'ed 섹션없이 Mac OS X에서 완벽하게 기록하지만, 컨트롤러 프로세스에서 syslog (또는 그 문제에 대한 로그 파일)로 출력을 보려면 ifdef가 필요합니다.

그래서, 왜 그런가요?

static int 
lock_down(void) 
{ 
    struct rlimit rl; 
    unsigned int n; 
    int fd0; 
    int fd1; 
    int fd2; 

    // Reset file mode mask 
    umask(0); 

    // change the working directory 
    if ((chdir("/")) < 0) 
     return EXIT_FAILURE; 

    // close any and all open file descriptors 
    if (getrlimit(RLIMIT_NOFILE, &rl)) 
     return EXIT_FAILURE; 
    if (RLIM_INFINITY == rl.rlim_max) 
     rl.rlim_max = 1024; 

    for (n = 0; n < rl.rlim_max; n++) { 
#ifdef __linux__   
     if (3 == n) // deep magic... 
      continue; 
#endif 
     if (close(n) && (EBADF != errno)) 
      return EXIT_FAILURE; 
    } 

    // attach file descriptors 0, 1 and 2 to /dev/null 
    fd0 = open("/dev/null", O_RDWR); 
    fd1 = dup2(fd0, 1); 
    fd2 = dup2(fd0, 2); 
    if (0 != fd0) 
     return EXIT_FAILURE; 

    return EXIT_SUCCESS; 
} 

camh는 가까웠지만 closelog()를 사용하여 트릭을 한 아이디어는 명예가 jilles로가는 아이디어였습니다. 뭔가 다른, syslogs 발 아래에서 파일 설명자를 닫는 것 외에는 계속해야합니다. 단지 루프 전에) 나는 closelog에 대한 호출을 추가 한 코드가 작동 (만들려면 :

closelog(); 
for (n = 0; n < rl.rlim_max; n++) { 
    if (close(n) && (EBADF != errno)) 
     return EXIT_FAILURE; 
} 

내 말은, 매뉴얼 페이지의 그대로 이해에 의존했다 :

openlog의 사용 ()는 선택 사항입니다. 필요하면 syslog()에 의해 자동으로 호출됩니다 ...

필자는 syslog가 파일 디스크립터가 닫혀 있는지 감지 할 것이라고 해석했습니다. 분명히 그렇지 않았습니다. 디스크립터가 닫혔다는 것을 syslog에 알리기 위해서는 리눅스에서 명시적인 closelog()가 필요했다.

아직도 나에게 난처한 점은 closelog()를 사용하지 않으면 첫 번째 forked 프로세스 (컨트롤러)가 로그 파일을 열고 사용하지 못하게된다는 것입니다. 다음의 fork 된 프로세스는 문제없이 syslog 또는 로그 파일을 사용할 수 있습니다. 어쩌면 첫 번째 분기 된 프로세스가 파일 설명자가 사용 가능하다는 신뢰할 수없는 "아이디어"를 갖는 파일 시스템에 캐싱 효과가있을 수 있습니다. 다음 forked 프로세스 세트는이 영향을받지 않을만큼 충분히 지연됩니까?

+3

+1 :'deep magic ... ':-) 리눅스 커널을 가지고있을 때 누가 해리포터를 필요로 하는가? –

+0

그래서 그 시점에서 fd 3에 무엇이 있습니까? – Gilles

+0

@ David. 커널과 관련이 없습니다. fd 0, 1 및 2조차도 커널에 특별하지 않습니다. – camh

답변

6

syslog (3)는 syslogd의 소켓 열기에 대한 파일 설명자를 유지할 수 있습니다. 발 밑에서 이것을 닫으면 문제가 생길 수 있습니다. closelog (3) 호출이 도움이 될 수 있습니다.

13

파일 디스크립터 3의 특별한면은 일반적으로 새로운 파일 디스크립터를 할당하는 시스템 호출에서 반환 된 첫 번째 파일 디스크립터이며, 0, 1 및 2가 보통 stdin, stdout 및 stderr .

이것은 당신이 전화 한 모든 라이브러리 함수는 기능을 수행하기 위해 자신의 내부 목적을위한 파일 기술자를 할당하는 경우, 그것은 FD를 얻을 것을 의미합니다 3. openlog (3) 라이브러리 호출이 필요합니다

/dev/log을 열어 syslog 데몬과 통신하십시오. 이후에 모든 파일 디스크립터를 닫으면 syslog 라이브러리 함수를 처리 할 수있는 방법으로 기록되지 않은 경우 syslog 라이브러리 함수가 손상 될 수 있습니다.

1

Syslog는 시작할 때 지정된 설명자에 바인딩됩니다. 대부분의 시간 설명자 3. 당신이 그것을 닫으면 로그가 없습니다.

syslog-ng -d -v 

씬 뒷이야기에 대한 자세한 정보를 제공합니다.

출력은 다음과 같이 같아야합니다 :

binding fd 3, inetaddr: 0.0.0.0, port: 514 
io.c: Preparing fd 3 for reading 
io.c: Preparing fd 4 for reading 
binding fd 5, unixaddr: /dev/log 
io.c: listening on fd 5 
+0

이것은 syslog-ng 디버깅에 유용하지만 다른 프로그램에서는 아무 것도하지 않습니다. syslog-ng의 fd3은 다른 프로세스에서 fd9에 쉽게 연결될 수 있습니다. –

+1

사실이지만 코드를 실행 한 후 syslog가 지정된 파일 설명자를 사용하여 통신한다는 점이 분명하지 않은 것처럼 보였습니다. – jdehaan

8

리눅스에이 만들어지고있는 실제 시스템 호출을 추적하는 strace을 사용하는 것입니다 디버깅하는 방법; syslog에 파일 디스크립터를 사용하면 분명해진다.

$ cat syslog_test.c 
#include <stdio.h> 
#include <syslog.h> 

int main(void) 
{ 
    openlog("test", LOG_PID, LOG_LOCAL0); 
    syslog(LOG_ERR, "waaaaaah"); 
    closelog(); 
    return 0; 
} 
$ gcc -W -Wall -o syslog_test syslog_test.c 
$ strace ./syslog_test 
... 
socket(PF_FILE, SOCK_DGRAM, 0)   = 3 
fcntl64(3, F_SETFD, FD_CLOEXEC)   = 0 
connect(3, {sa_family=AF_FILE, path="/dev/log"}, 16) = 0 
send(3, "<131>Aug 21 00:47:52 test[24264]"..., 42, MSG_NOSIGNAL) = 42 
close(3)        = 0 
exit_group(0)       = ? 
Process 24264 detached 
관련 문제