여기 상황이 있습니다. 로깅 기능을 수행하는 코드를 디버깅하고 있습니다. 사용자가 로그인하면 로그 파일은 .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와 우분투에서 테스트했다. 로깅 프로세스는 시작 프로세스입니다. 모든 의견이나 제안은 정말 감사드립니다.
강제 재부팅이 발생한다고 가정하면 시스템을 재부팅하는 데 여전히 시간이 걸립니다. 그 시간 동안 어쨌든 로깅 프로세스가 세션이 끝났음을 알리기 위해 서버에 신호를 보낼 수 있습니까? –
@MohdFikrie : 아니요, 불가능합니다. 강제로 재부팅하면 모든 프로세스가 강제 종료됩니다. –
@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