1.4 release
This commit is contained in:
parent
3363bde9a3
commit
f5b291600f
4 changed files with 168 additions and 75 deletions
Binary file not shown.
134
daemon.c
Normal file
134
daemon.c
Normal 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");
|
||||||
|
}
|
|
@ -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 \
|
||||||
|
|
101
loperIRCLogBot.c
101
loperIRCLogBot.c
|
@ -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;
|
||||||
|
|
||||||
|
@ -393,7 +393,7 @@ void dump_event (irc_session_t * session, const char * event, const char * origi
|
||||||
!(strcmp(event,"MODE")) ? strcmp(nickBuf, hostBuf) == 0 ? 0: fprintf(fp,"%s -!- %s [%s] set %s %s\n",nowTime, nickBuf, hostBuf, params[1], params[2] ? params[2]:""):
|
!(strcmp(event,"MODE")) ? strcmp(nickBuf, hostBuf) == 0 ? 0: fprintf(fp,"%s -!- %s [%s] set %s %s\n",nowTime, nickBuf, hostBuf, params[1], params[2] ? params[2]:""):
|
||||||
!(strcmp(event,"PART")) ? fprintf(fp,"%s << %s [%s] parted: %s \n",nowTime, nickBuf, hostBuf, params[1]):
|
!(strcmp(event,"PART")) ? fprintf(fp,"%s << %s [%s] parted: %s \n",nowTime, nickBuf, hostBuf, params[1]):
|
||||||
!(strcmp(event,"TOPIC")) ? fprintf(fp,"%s -!- %s [%s] has changed topic to: %s \n",nowTime, nickBuf, hostBuf, params[1]):
|
!(strcmp(event,"TOPIC")) ? fprintf(fp,"%s -!- %s [%s] has changed topic to: %s \n",nowTime, nickBuf, hostBuf, params[1]):
|
||||||
!(strcmp(event,"QUIT")) ? fprintf(fp,"%s << %s [%s] quit: %s \n",nowTime, nickBuf, hostBuf, params[0]):
|
!(strcmp(event,"QUIT")) ? fprintf(fp,"%s << %s [%s] quit: %s \n",nowTime, nickBuf, hostBuf, params[0]):
|
||||||
!(strcmp(event,"NICK")) ? fprintf(fp,"%s -!- %s [%s] changed nick to: %s \n",nowTime, nickBuf, hostBuf, params[0]): 0;
|
!(strcmp(event,"NICK")) ? fprintf(fp,"%s -!- %s [%s] changed nick to: %s \n",nowTime, nickBuf, hostBuf, params[0]): 0;
|
||||||
|
|
||||||
if (!strcmp(event,"KICK")){
|
if (!strcmp(event,"KICK")){
|
||||||
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue