这是情况。我正在调试代码来执行日志记录功能。当用户登录时,将使用.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;
}
这是信号处理程序
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);
}
我已经测试过处理exit_cb函数中的所有信号。此外,power_off_cb内的所有信号都起作用。他们俩都没有工作。我在CentOS和Ubuntu上测试过。日志记录过程是一个新兴的过程。任何评论或建议都非常感谢。
答案 0 :(得分:1)
以下是这种情况。我正在调试代码来执行日志记录功能。 当用户登录时,将使用.part格式创建日志文件。 此文件在本地内部保存。我不知道为什么这个名字 作为一部分。当用户完成会话时,日志文件将是 仅重命名为.username。除了本地日志文件,此代码也是 连接到服务器,此服务器也将保存日志记录 文件。问题是日志记录仍在运行,但主机 突然重启。重启可能是由root
命令引起的
如果它是由root命令引起的,你可以在/etc/init.d /中创建一个脚本来处理它。
,或者a 强制重启,或者可能是硬件故障。这会导致记录文件 保留为.part,服务器也随之而来。
您无法预测未来,也无法预测操作系统。如果由电源或硬件故障引起重启,则无法预测它。