1.4 release

This commit is contained in:
Dmitry Isaenko 2017-12-03 02:28:34 +03:00
parent 3363bde9a3
commit f5b291600f
4 changed files with 168 additions and 75 deletions

Binary file not shown.

134
daemon.c Normal file
View file

@ -0,0 +1,134 @@
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");
}

View file

@ -5,8 +5,10 @@
// Set if you want to turn mode +x on while connecting // Set if you want to turn mode +x on while connecting
#define X_MODE #define X_MODE
// Set path to loperIRCLogBot.pid file for daemon mode
#define DEF_PID_FILE "/var/run/loperIRCLogBot.pid" // re-define in configuration file
// Current version of the program // Current version of the program
#define __CUR_VER__ "1.3.1" #define __CUR_VER__ "1.4"
#define NPING_DEBUG #define NPING_DEBUG
#define NDEBUG #define NDEBUG
@ -21,7 +23,7 @@
#define DEF_HELP_MSG \ #define DEF_HELP_MSG \
"Avaliable options:\n\n \ "Avaliable options:\n\n \
-d, --daemon Start application as daemon (experimental)\n \ -d, --daemon Start application as daemon. Writes to /var/log/loperIRCLogBot.log and syslog. Stores PID number at /var/run/loperIRCLogBot.pid\n \
-g, --genconf Create configuration file template. Attention! It will overrite your existing configuration file.\n \ -g, --genconf Create configuration file template. Attention! It will overrite your existing configuration file.\n \
-s, --silent Silent mode. All program messages stores to the 'output.txt' file\n \ -s, --silent Silent mode. All program messages stores to the 'output.txt' file\n \
-v, --version Application version\n\n \ -v, --version Application version\n\n \

View file

@ -1,7 +1,7 @@
/*********************************************************************************** /***********************************************************************************
* Author: Dmitry Isaenko * * Author: Dmitry Isaenko *
* License: GNU GPL v.3 * * License: GNU GPL v.3 *
* Version: 1.3.1 * * Version: 1.4 *
* Site: https://developersu.blogspot.com/ * * Site: https://developersu.blogspot.com/ *
* 2017, Russia * * 2017, Russia *
***********************************************************************************/ ***********************************************************************************/
@ -14,17 +14,17 @@
#include <sys/types.h> #include <sys/types.h>
#include <time.h> #include <time.h>
#include <limits.h> // only to get PATH_MAX #include <limits.h> // only to get PATH_MAX
#include <unistd.h> // for using setsid #include <unistd.h> // for using setsid.
#include <syslog.h> // Use syslog #include <syslog.h> // Use syslog
#include <signal.h> // Use signals #include <signal.h> // Use signals
#include <sys/select.h> // Use pselect
#include "defined_values.h" #include "defined_values.h"
#include "daemon.c"
// TODO after implementing signals set closelog(); // TODO after implementing signals set closelog(); +++ use unlink(PID_FILE) to remove PID stored at /var/run/loperIRCLogBot.pid. Make logrotation by SIGHUP. 12.5
// TODO normal deamon-mode functionality
// TODO make it multi-channel // TODO make it multi-channel
// TODO-feachure make an ability to define log path for the bot.conf? Or move it to /etc/
typedef struct conf_sruct { typedef struct conf_sruct {
int status; int status;
@ -345,8 +345,8 @@ void event_connect (irc_session_t * session, const char * event, const char * or
} }
void dump_event (irc_session_t * session, const char * event, const char * origin, const char ** params, unsigned int count) void dump_event (irc_session_t * session, const char * event, const char * origin, const char ** params, unsigned int count)
{ { // TODO: Re-write. Actually, this implementation is also pice of shit
#ifdef DEBUG #ifdef DEBUG // It cause too many system calls even we don't need them
char buf[512]; char buf[512];
int cnt; int cnt;
@ -608,16 +608,6 @@ void reportSettingsIssues(int sum){
printf("\t'%s'\n", setLst[i]); printf("\t'%s'\n", setLst[i]);
} }
} }
// not implemented & not used signal handler
void signalHandler (int sig){
if (sig == SIGHUP){
syslog(LOG_NOTICE, "loperIRCLogBot got SIGHUP");
// close all opened files here
exit(EXIT_SUCCESS);
}
}
void silentMode(){ void silentMode(){
// close stdin, redirect stdout & stderr // close stdin, redirect stdout & stderr
@ -630,65 +620,27 @@ void silentMode(){
if ( freopen("/dev/null", "rb", stdin) == NULL ) if ( freopen("/dev/null", "rb", stdin) == NULL )
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
void daemonMode(){
setlogmask (LOG_UPTO (LOG_ERR));
openlog("loperIRCLogBot", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_DAEMON);
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); // report to log
}
// PERFORM SECOND FORK
pid = fork();
if (pid < 0){
syslog(LOG_ERR, "Failed to make second fork");
exit(EXIT_FAILURE); // report to log
}
if (pid > 0)
exit(EXIT_SUCCESS); // report to log?
//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_NOTICE, "loperIRCLogBot successfuly started");
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
configuration config; configuration config;
irc_callbacks_t callbacks; // The IRC callbacks structure irc_callbacks_t callbacks; // The IRC callbacks structure
irc_session_t * session; irc_session_t * session;
struct timeval tv; struct timespec ts; // time structure for pselect();
fd_set in_set, out_set; fd_set in_set, out_set;
int maxfd = 0; int maxfd = 0;
// ### daemon mode tails.
// Define signals that we will block while using pselect(); See below. pselect set mask provided, then change it to default
sigset_t blockedSignals; // block all signals; to use in pselect()
sigset_t normalSignals; // define default mask
sigfillset(&blockedSignals);
sigdelset(&blockedSignals, SIGINT);
sigfillset(&normalSignals); // Not sure that it could make impact on anything
sigprocmask(SIG_UNBLOCK, &normalSignals, NULL);
// ###
// Let's find out the path to executable file! It's needed, because when we create config file like ../executable -g // Let's find out the path to executable file! It's needed, because when we create config file like ../executable -g
// it creates it on the same folder where user located at, not at the folder where the executable is. // it creates it on the same folder where user located at, not at the folder where the executable is.
// Same for logs. // Same for logs.
@ -826,8 +778,13 @@ int main(int argc, char *argv[]) {
///////////////////// irc_run() replacement /////////////////// ///////////////////// irc_run() replacement ///////////////////
while ( irc_is_connected(session) ) while ( irc_is_connected(session) )
{ {
tv.tv_usec = 250000; if (reloadLogSig == 1) //debugFunction
tv.tv_sec = 0; logsReopen();
if (terminateSig == 1) //debugFunction
killBySignalRecieved(session);
ts.tv_sec = 0;
ts.tv_nsec = 250000000;
// Init sets // Init sets
FD_ZERO (&in_set); FD_ZERO (&in_set);
@ -845,8 +802,8 @@ int main(int argc, char *argv[]) {
irc_add_select_descriptors (session, &in_set, &out_set, &maxfd); irc_add_select_descriptors (session, &in_set, &out_set, &maxfd);
// Set mask to all signals, while neccessary for us are: SIGHUP, SIGTERM. Exclude SIGINT, 'cause no matter how this app fucks up in case of _exit(2).
if ( select (maxfd + 1, &in_set, &out_set, 0, &tv) < 0 ) if ( pselect (maxfd + 1, &in_set, &out_set, 0, &ts, &blockedSignals) < 0 ) // and errno == EINTR !
{ {
printf ("%s Could not connect or I/O error: LIBIRC_ERR_TERMINATED\n", printTimeStamp()); printf ("%s Could not connect or I/O error: LIBIRC_ERR_TERMINATED\n", printTimeStamp());
break; // 1 break; // 1