2014-02-10 2 views
0

여기 상황이 있습니다. 로깅 기능을 수행하는 코드를 디버깅하고 있습니다. 사용자가 로그인하면 로그 파일은 .part 형식으로 생성됩니다. 이 파일은 호스트에 로컬로 저장됩니다. 왜 그 이름이 .part인지 나는 모른다. 사용자가 세션을 끝내면 로그 파일의 이름은 .username으로 만 바뀝니다. 로컬 로그 파일 옆에이 코드는이 서버가 로깅 파일도 저장하는 서버에도 연결됩니다. 문제는 로깅이 계속 실행 중이지만 호스트가 갑자기 재부팅 될 때입니다. 재부팅은 root 명령이나 강제 재부팅 또는 하드웨어 오류 일 수 있습니다. 이로 인해 로깅 파일이 .part로 유지되고 서버도 함께 유지됩니다.프로세스가 여전히 실행 중일 때 재부팅을 처리하는 방법

그래서, 내 질문은 : 프로세스가 사망하거나 재부팅시 종료되기 전에

는 어떻게이 파일의 이름을 변경하기 위해?

내가 처리해야하는 신호는 무엇입니까?

이것이 경쟁 조건과 관련 될 수 있다고 생각합니다. 재부팅을 지연시킬 수있는 방법이 있습니까?

내 접근 방식은

은 SIGPWR은, SIGSTOP, SIGTERM, SIGQUIT

때 프로세스 시작의 이름을 변경 할 수있는 bash는 스크립트를 작성 처리하기 위해 노력했다.

int main(int argc, char **argv) 
{ 
    int ch; 
    int NoFork = 0; 
    struct event_config *evconfig; 
    struct event *signal_event_int; 
    struct event *signal_event_quit; 
    struct event *signal_event_term; 
    struct event *signal_event_hup; 
    struct event *signal_event_chld; 
    struct event *signal_event_pwr; 
    struct event *signal_event_stop; 

    syspath_init_from_argv0(argv[0]); 

    load_config(); /* load config first, the command line parameters will override */ 
    event_set_log_callback(my_event_log_cb); 

    evconfig = event_config_new(); 
    if (event_config_require_features(evconfig, EV_FEATURE_FDS)!=0) { 
      log_error("event_config_require_features_failed"); 
    } 
    while (!done) { 
      /* ignore HUP first, just in case someone send us a HUP 
       when we are reloading config, that will create a condition 
       that makes us exit, with HangUp */ 
      sig_catch(SIGHUP,SIG_IGN); 
      base = event_base_new_with_config(evconfig); 

      local_listener = create_local_listener(base); 

      if (!local_listener) { 
        log_error("Could not create a local listener!"); 
        return 1; 
      } 
      http_listener = create_http_listener(); 
      if (!http_listener) { 
        log_error("Could not create a remote listener!"); 
        return 1; 
      } 
      evhttp_set_cb(http_listener, "/mrexec", http_mrexec_cb, NULL); 
      if (options.accept_remote) { 
        evhttp_set_cb(http_listener, "/rlog", http_rlog_cb, NULL); 
      } 
      if (pidfile_create(ACTSLOGD_PIDFILE)==-1) { 
        log_error("pidfile_create:failed:%d:%s", errno, strerror(errno)); 
      } 
      LIST_INIT(&clientlist); 
      if (options.log_remote) { 
        start_log_remote(); 
      } 

      signal_event_int = evsignal_new(base, SIGINT, exit_cb, (void *)base); 
      event_add(signal_event_int, NULL); 
      signal_event_quit = evsignal_new(base, SIGQUIT, exit_cb, (void *)base); 
      event_add(signal_event_quit, NULL); 
      signal_event_term = evsignal_new(base, SIGTERM, exit_cb, (void *)base); 
      event_add(signal_event_term, NULL); 
      signal_event_hup = evsignal_new(base, SIGHUP, reload_config_cb, (void *)base); 
      event_add(signal_event_hup, NULL); 
      signal_event_chld = evsignal_new(base, SIGCHLD, sigchld_cb, (void *)base); 
      event_add(signal_event_chld, NULL); 
      signal_event_pwr = evsignal_new(base, SIGPWR, power_off_cb, (void *)base); 
      event_add(signal_event_pwr, NULL); 
      signal_event_stop = evsignal_new(base, SIGSTOP, power_off_cb, (void *)base); 
      event_add(signal_event_chld, NULL); 

      actslog_event_start(AGENT_ACTSLOGD); 
      actslog_event_start(AGENT_ESCALATED); 
      event_base_dispatch(base); 
      printf("finished dispatch\n"); 

      evconnlistener_free(local_listener); 

      evhttp_free(http_listener); 
      http_listener = NULL; 

      event_free(signal_event_int); 
      event_free(signal_event_quit); 
      event_free(signal_event_term); 
      event_free(signal_event_hup); 
      event_free(signal_event_pwr); 
      event_free(signal_event_stop); 

      if (options.log_remote) { 
        end_log_remote(); 
      } 
      event_base_free(base); 
      if (!done) { 
        load_config(); 
      } 
      while (clientlist.lh_first != NULL) { 
        struct bufferevent *bev = clientlist.lh_first->bev; 
        bufferevent_free(bev); 
        LIST_REMOVE(clientlist.lh_first, clients); 
      } 
    } 
    if (rlog) { 
      rlog_close(rlog); 
    } 
    unlink(PATH_ACTSLOG); 
    pidfile_cleanup(ACTSLOGD_PIDFILE); 

    return 0; 
} 

이 내가 exit_cb 기능의 모든 신호를 처리하기 위해 테스트 한 신호 처리기

static void exit_cb(evutil_socket_t sig, short events, void *user_data) 
{ 
    struct event_base *base = user_data; 
    struct timeval delay = { 2, 0 }; 

    actslog_event_stop(AGENT_ACTSLOGD); 
    actslog_event_stop(AGENT_ESCALATED); 

    done = 1; //when this is 1, there is a function that will connect to the server to tell that the logging is stopped. 

    /* need to give some delay for us to send out the stop message to Logger */ 

    event_base_loopexit(base, &delay); 
} 

static void power_off_cb(evutil_socket_t sig, short events, void *user_data) 
{ 
    struct event_base *base = user_data; 
    struct timeval delay = { 5, 0 }; 
    char logfile_partial[MAXPATHLEN]; 
    char logfile_complete[MAXPATHLEN]; 
    char id[1024]; 

    done =1;  

    event_base_loopexit(base,&delay); 

    snprintf(logfile_partial, //the logfile_partial will be the one with .part file 
    sizeof(logfile_partial), 
    "%s/SHELL.%s.part", logpath2, id); 

    snprintf(logfile_complete, //the logfile_complete will be the complete without .part 
    sizeof(logfile_complete), 
    "%s/SHELL.%s", logpath2, id); 

    if (rename(logfile_partial, logfile_complete)!=0) { 
      if (errno==ENOENT) { 
        int tmp; 
        log_error("mastershell [%s] log is incomplete", logfile_complete); 
        tmp = creat(logfile_complete, LOG_FILE_MODE); 
        if (tmp==-1) { 
          log_error("creat:%s:failed:%d:%s!!\n", logfile_complete, errno, strerror(errno)); 
        } else { 
        close(tmp); 
        } 
      } else { 
      log_error("rename:%s:%s:failed:%d:%s!!\n", logfile_partial, logfile_complete, errno, strerror(errno)); 
      } 
    } 

    if (rlog) { 
      rlog_close(rlog); 
    } 
    unlink(PATH_ACTSLOG); 
    pidfile_cleanup(ACTSLOGD_PIDFILE); 
} 

은 다음과 같습니다

다음은 주요 코드입니다. 또한 power_off_cb 내의 모든 신호가 기능합니다. 둘 중 누구도 일하지 않습니다. 나는 CentOS와 우분투에서 테스트했다. 로깅 프로세스는 시작 프로세스입니다. 모든 의견이나 제안은 정말 감사드립니다.

답변

1

여기 상황이 있습니다. 로깅 기능을 수행하는 코드를 디버깅하고 있습니다. 사용자가 로그인하면 로그 파일은 .part 형식으로 생성됩니다. 이 파일은 호스트에 로컬로 저장됩니다. 왜 이름이 인지 .part. 사용자가 세션을 끝내면 로그 파일은 .username으로 만 이름이 바뀝니다. 로컬 로그 파일 옆에이 코드는 또한이 서버가 로깅 파일을 저장할 서버에 연결된 입니다. 문제는 로깅이 여전히 실행 중이지만 호스트 이 갑자기 재부팅 될 때입니다. 재부팅은 루트의 명령으로 인해 발생할 수 있습니다.

루트의 명령으로 인해 발생하는 경우 /etc/init.d/에서 스크립트를 작성하여 처리 할 수 ​​있습니다.

또는 강제 재부팅 또는 하드웨어 오류 일 수 있습니다. 이로 인해 로깅 파일 은 .part로 유지되고 서버도 따라옵니다.

미래는 예측할 수없고 OS도 예측할 수 없습니다.전원 또는 하드웨어 장애로 인한 재부팅이있을 경우이를 예측할 방법이 없습니다.

+0

강제 재부팅이 발생한다고 가정하면 시스템을 재부팅하는 데 여전히 시간이 걸립니다. 그 시간 동안 어쨌든 로깅 프로세스가 세션이 끝났음을 알리기 위해 서버에 신호를 보낼 수 있습니까? –

+0

@MohdFikrie : 아니요, 불가능합니다. 강제로 재부팅하면 모든 프로세스가 강제 종료됩니다. –

+0

@MohdFikrie "재부팅 -f"로 "재부팅 강제 실행"을 호출하면 스크립트를 실행하거나 특별한 신호를 보내지 않고 시스템을 즉시 종료합니다. 확인 : [http://unix.stackexchange.com/questions/64280/what-is-the-difference-between-reboot-init-6-and-shutdown-r-now]. 정상적인 재부팅에서 shutdown은 SIGTERM 다음에 SIGKILL을 발행합니다. SIGTERM을 잡을 수는 있지만 처리하는데 충분한 시간은 없습니다. 알았어. – Fernando

관련 문제