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
|
||||
#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
|
||||
#define __CUR_VER__ "1.3.1"
|
||||
#define __CUR_VER__ "1.4"
|
||||
|
||||
#define NPING_DEBUG
|
||||
#define NDEBUG
|
||||
|
@ -21,7 +23,7 @@
|
|||
|
||||
#define DEF_HELP_MSG \
|
||||
"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 \
|
||||
-s, --silent Silent mode. All program messages stores to the 'output.txt' file\n \
|
||||
-v, --version Application version\n\n \
|
||||
|
|
101
loperIRCLogBot.c
101
loperIRCLogBot.c
|
@ -1,7 +1,7 @@
|
|||
/***********************************************************************************
|
||||
* Author: Dmitry Isaenko *
|
||||
* License: GNU GPL v.3 *
|
||||
* Version: 1.3.1 *
|
||||
* Version: 1.4 *
|
||||
* Site: https://developersu.blogspot.com/ *
|
||||
* 2017, Russia *
|
||||
***********************************************************************************/
|
||||
|
@ -14,17 +14,17 @@
|
|||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#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 <signal.h> // Use signals
|
||||
#include <sys/select.h> // Use pselect
|
||||
|
||||
#include "defined_values.h"
|
||||
#include "daemon.c"
|
||||
|
||||
|
||||
// TODO after implementing signals set closelog();
|
||||
// TODO normal deamon-mode functionality
|
||||
// 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 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 {
|
||||
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)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
{ // TODO: Re-write. Actually, this implementation is also pice of shit
|
||||
#ifdef DEBUG // It cause too many system calls even we don't need them
|
||||
char buf[512];
|
||||
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,"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,"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;
|
||||
|
||||
if (!strcmp(event,"KICK")){
|
||||
|
@ -608,16 +608,6 @@ void reportSettingsIssues(int sum){
|
|||
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(){
|
||||
// close stdin, redirect stdout & stderr
|
||||
|
@ -630,65 +620,27 @@ void silentMode(){
|
|||
if ( freopen("/dev/null", "rb", stdin) == NULL )
|
||||
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[]) {
|
||||
configuration config;
|
||||
|
||||
irc_callbacks_t callbacks; // The IRC callbacks structure
|
||||
irc_session_t * session;
|
||||
struct timeval tv;
|
||||
struct timespec ts; // time structure for pselect();
|
||||
fd_set in_set, out_set;
|
||||
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
|
||||
// it creates it on the same folder where user located at, not at the folder where the executable is.
|
||||
// Same for logs.
|
||||
|
@ -826,8 +778,13 @@ int main(int argc, char *argv[]) {
|
|||
///////////////////// irc_run() replacement ///////////////////
|
||||
while ( irc_is_connected(session) )
|
||||
{
|
||||
tv.tv_usec = 250000;
|
||||
tv.tv_sec = 0;
|
||||
if (reloadLogSig == 1) //debugFunction
|
||||
logsReopen();
|
||||
if (terminateSig == 1) //debugFunction
|
||||
killBySignalRecieved(session);
|
||||
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 250000000;
|
||||
|
||||
// Init sets
|
||||
FD_ZERO (&in_set);
|
||||
|
@ -845,8 +802,8 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
|
||||
irc_add_select_descriptors (session, &in_set, &out_set, &maxfd);
|
||||
|
||||
if ( select (maxfd + 1, &in_set, &out_set, 0, &tv) < 0 )
|
||||
// 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 ( 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());
|
||||
break; // 1
|
||||
|
|
Loading…
Reference in a new issue