135 lines
4.8 KiB
C
135 lines
4.8 KiB
C
|
volatile sig_atomic_t reloadLogSig = 0;
|
||
|
volatile sig_atomic_t terminateSig = 0;
|
||
|
|
||
|
void logsReopen(){ // logrotation can send SIGHUP to notify that log file should be reopened due it's cleaned up
|
||
|
if (freopen("/var/log/loperIRCLogBot.log", "a", stdout) == NULL ){
|
||
|
syslog(LOG_ERR, "Failed to reopen /var/log/loperIRCLogBot.log after SIGHUP notificatuib recieved");
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
setlinebuf(stdout); // line buffer
|
||
|
if (freopen("/var/log/loperIRCLogBot.log", "a", stderr) == NULL ){
|
||
|
syslog(LOG_ERR, "Failed to reopen /var/log/loperIRCLogBot.log after SIGHUP notificatuib recieved");
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
setvbuf(stderr, NULL, _IONBF, 0); // no buffering for srderr
|
||
|
reloadLogSig = 0;
|
||
|
}
|
||
|
|
||
|
void killBySignalRecieved(irc_session_t * session){
|
||
|
if (irc_cmd_quit(session, "interrupted by signal") != 0) // "Return code 0 means the command was sent to the IRC server successfully.
|
||
|
irc_disconnect(session); // This does not mean the operation succeed, and you need to wait for the appropriate
|
||
|
fclose(stdin); // event or for the error code via event_numeric event."(c)docs. :wSo FUCK THIS SHIT. It would be always EOF.
|
||
|
fclose(stdout); // In case servers stuck, we would have to wait AGES before app dies. No thanks.
|
||
|
fclose(stderr);
|
||
|
if (remove(DEF_PID_FILE) < 0) // delete PIDFile.
|
||
|
syslog(LOG_ERR, "Can't remove PID file: /var/run/loperIRCLogBot.pid");
|
||
|
syslog(LOG_NOTICE, "Interrupted by SIGTERM"); // change to LOG_NOTICE
|
||
|
closelog();
|
||
|
exit(EXIT_SUCCESS);
|
||
|
}
|
||
|
|
||
|
// Signal handler
|
||
|
void signalHandler (int sig){
|
||
|
switch (sig){
|
||
|
case SIGHUP:
|
||
|
reloadLogSig = 1;
|
||
|
break;
|
||
|
case SIGTERM:
|
||
|
terminateSig = 1;
|
||
|
break;
|
||
|
case SIGINT:
|
||
|
_exit(2); // TODO: document this behavior as variant of application returned values
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
void daemonMode(){
|
||
|
setlogmask (LOG_UPTO (LOG_ERR));
|
||
|
openlog("loperIRCLogBot", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_DAEMON);
|
||
|
|
||
|
FILE * pidFile;
|
||
|
|
||
|
pid_t pid;
|
||
|
|
||
|
// PERFORM FIRST FORK
|
||
|
pid = fork();
|
||
|
if (pid < 0) {
|
||
|
syslog(LOG_ERR, "Failed to make first fork");
|
||
|
exit(EXIT_FAILURE); // report to log
|
||
|
}
|
||
|
if (pid > 0) // Exit parent process. pid of is not 0, then it's parent. pid = 0 then it's child.
|
||
|
exit(EXIT_SUCCESS); // report to log?
|
||
|
if (chdir("/") < 0) { // change working directory of the process to /
|
||
|
syslog(LOG_ERR, "Failed to change process dir to /");
|
||
|
exit(EXIT_FAILURE); // it's safe to replace to 'return' statement
|
||
|
}
|
||
|
umask(0); // set umask for using filesystem as we want
|
||
|
if (setsid() < 0) { // set SID
|
||
|
syslog(LOG_ERR, "Failed to set SID");
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
// PERFORM SECOND FORK
|
||
|
pid = fork();
|
||
|
if (pid < 0){
|
||
|
syslog(LOG_ERR, "Failed to make second fork");
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
if (pid > 0)
|
||
|
exit(EXIT_SUCCESS);
|
||
|
|
||
|
// Save process PID to file /var/run/loperIRCLogBot.pid // TODO: consider using of 'PIDFile' from libutil.h
|
||
|
if ((pidFile = fopen(DEF_PID_FILE, "w")) != NULL){ // + Consider using HFS3 and /run instead of /var/run. NOTE: could be a problem for embedded system, i.e. OWRT doesn't provide this filder
|
||
|
fprintf(pidFile,"%ld\n", (long) getpid());
|
||
|
fclose(pidFile);
|
||
|
}
|
||
|
else {
|
||
|
syslog(LOG_ERR, "Failed to create PID file /var/run/loperIRCLogBot.pid");
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
// ############# DEFINE SIGNAL HANDLERS #######################
|
||
|
struct sigaction sa;
|
||
|
memset(&sa, 0, sizeof(sa));
|
||
|
|
||
|
sa.sa_handler = signalHandler;
|
||
|
|
||
|
if (sigfillset(&sa.sa_mask) < 0){
|
||
|
syslog(LOG_ERR, "Can't set mask of blocked signals");
|
||
|
exit(EXIT_FAILURE);
|
||
|
}; // block all signals when execute
|
||
|
sa.sa_flags = SA_RESTART; // restart interrupted system calls
|
||
|
|
||
|
if (sigaction(SIGHUP, &sa, NULL) < 0) {
|
||
|
syslog(LOG_ERR, "Can't set sigaction() to handle application signals: SIGHUP");
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
if (sigaction(SIGINT, &sa, NULL) < 0) {
|
||
|
syslog(LOG_ERR, "Can't set sigaction() to handle application signals: SIGINT");
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
if (sigaction(SIGTERM, &sa, NULL) < 0) {
|
||
|
syslog(LOG_ERR, "Can't set sigaction() to handle application signals: SIGTERM");
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
|
||
|
// ############# SIGNAL HANDLERS SET #######################
|
||
|
//doing it using guidelines form man daemon
|
||
|
if (freopen("/dev/null", "rb", stdin) == NULL ){
|
||
|
syslog(LOG_ERR, "Failed to close 'stdin'");
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
if (freopen("/var/log/loperIRCLogBot.log", "a", stdout) == NULL ){
|
||
|
syslog(LOG_ERR, "Failed to redirect 'stdout' to /var/log/loperIRCLogBot.log");
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
setlinebuf(stdout); // line buffer
|
||
|
if (freopen("/var/log/loperIRCLogBot.log", "a", stderr) == NULL ){
|
||
|
syslog(LOG_ERR, "Failed to redirect 'stderr' to /var/log/loperIRCLogBot.log");
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
setvbuf(stderr, NULL, _IONBF, 0); // no buffering for srderr
|
||
|
|
||
|
//syslog(LOG_ERR, "SUCCESS");
|
||
|
syslog(LOG_NOTICE, "loperIRCLogBot successfuly started");
|
||
|
}
|