- Improve pidfile handling
- Clean shutdown if daemon is killed - Prevent daemon from running twice - Minor code cleanup and refactoring
This commit is contained in:
parent
49202f073a
commit
620e51230e
2
Makefile
2
Makefile
@ -1,6 +1,6 @@
|
||||
PREFIX=/usr/local
|
||||
INC=-I$(PREFIX)/include
|
||||
LIB=-L$(PREFIX)/lib
|
||||
LIB=-L$(PREFIX)/lib -lutil
|
||||
FLAGS=-Wall -O2 -pipe -funroll-loops -ffast-math -fno-strict-aliasing -mssse3
|
||||
CC?=cc
|
||||
|
||||
|
163
ifstatd.c
163
ifstatd.c
@ -1,27 +1,27 @@
|
||||
/*
|
||||
Copyright (c) 2015, Babak Farrokhi
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
/*-
|
||||
* Copyright (c) 2015, Babak Farrokhi
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <string.h>
|
||||
#include <sysexits.h>
|
||||
#include <unistd.h>
|
||||
#include <libutil.h>
|
||||
|
||||
#define IFA_STAT(s) (((struct if_data *)ifa->ifa_data)->ifi_ ## s)
|
||||
#define RESOLUTION 10
|
||||
@ -67,12 +68,38 @@ char *program_name = "ifstatd_";
|
||||
char *interface;
|
||||
char *pid_filename;
|
||||
char *cache_filename;
|
||||
struct pidfh *pfh;
|
||||
|
||||
/*
|
||||
* Prepare for a clean shutdown
|
||||
*/
|
||||
void daemon_shutdown()
|
||||
{
|
||||
pidfile_remove(pfh);
|
||||
}
|
||||
|
||||
/*
|
||||
* Act upon receiving signals
|
||||
*/
|
||||
void signal_handler(int sig)
|
||||
{
|
||||
switch(sig) {
|
||||
|
||||
case SIGHUP:
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
daemon_shutdown();
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Obtain stats for interface(s).
|
||||
*/
|
||||
static void
|
||||
fill_iftot(struct iftot *st)
|
||||
static void fill_iftot(struct iftot *st)
|
||||
{
|
||||
struct ifaddrs *ifap, *ifa;
|
||||
bool found = false;
|
||||
@ -93,14 +120,9 @@ fill_iftot(struct iftot *st)
|
||||
}
|
||||
|
||||
st->ift_ip += IFA_STAT(ipackets);
|
||||
/*st->ift_ie += IFA_STAT(ierrors);*/
|
||||
/*st->ift_id += IFA_STAT(iqdrops);*/
|
||||
st->ift_ib += IFA_STAT(ibytes);
|
||||
st->ift_op += IFA_STAT(opackets);
|
||||
/*st->ift_oe += IFA_STAT(oerrors);*/
|
||||
/* st->ift_od += IFA_STAT(oqdrops);*/
|
||||
st->ift_ob += IFA_STAT(obytes);
|
||||
/*st->ift_co += IFA_STAT(collisions);*/
|
||||
}
|
||||
|
||||
if (interface && found == false)
|
||||
@ -109,6 +131,9 @@ fill_iftot(struct iftot *st)
|
||||
freeifaddrs(ifap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print out munin plugin configuration
|
||||
*/
|
||||
int config(char *iface)
|
||||
{
|
||||
printf(
|
||||
@ -135,6 +160,9 @@ int config(char *iface)
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for a certain amount of time
|
||||
*/
|
||||
time_t wait_for(int seconds) {
|
||||
|
||||
struct timespec tp;
|
||||
@ -153,17 +181,45 @@ time_t wait_for(int seconds) {
|
||||
return current_epoch + seconds;
|
||||
}
|
||||
|
||||
int acquire()
|
||||
/*
|
||||
* Daemonize and persist pid
|
||||
*/
|
||||
int daemon_start()
|
||||
{
|
||||
struct iftot ift, *tot;
|
||||
time_t epoch;
|
||||
struct sigaction sig_action;
|
||||
sigset_t sig_set;
|
||||
pid_t otherpid;
|
||||
|
||||
tot = &ift;
|
||||
|
||||
/* fork ourselves if not asked otherwise */
|
||||
char* no_fork = getenv("no_fork");
|
||||
if (! no_fork || strcmp("1", no_fork)) {
|
||||
if (fork()) return(0);
|
||||
|
||||
/* Check if parent process id is set */
|
||||
if (getppid() == 1)
|
||||
{
|
||||
/* PPID exists, therefore we are already a daemon */
|
||||
return(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Check if we can acquire the pid file */
|
||||
pfh = pidfile_open(pid_filename, 0600, &otherpid);
|
||||
|
||||
if (pfh == NULL) {
|
||||
if (errno == EEXIST) {
|
||||
errx(EXIT_FAILURE, "Daemon already running, pid: %jd.", (intmax_t)otherpid);
|
||||
}
|
||||
warn("Cannot open or create pidfile: %s", pid_filename);
|
||||
}
|
||||
|
||||
/* fork ourselves if not asked otherwise */
|
||||
if (fork())
|
||||
{
|
||||
return(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* we are the child, complete the daemonization */
|
||||
|
||||
/* Close standard IO */
|
||||
@ -171,31 +227,45 @@ int acquire()
|
||||
fclose(stdout);
|
||||
fclose(stderr);
|
||||
|
||||
/* Block unnecessary signals */
|
||||
sigemptyset(&sig_set);
|
||||
sigaddset(&sig_set, SIGCHLD); /* ignore child - i.e. we don't need to wait for it */
|
||||
sigaddset(&sig_set, SIGTSTP); /* ignore Tty stop signals */
|
||||
sigaddset(&sig_set, SIGTTOU); /* ignore Tty background writes */
|
||||
sigaddset(&sig_set, SIGTTIN); /* ignore Tty background reads */
|
||||
sigprocmask(SIG_BLOCK, &sig_set, NULL); /* Block the above specified signals */
|
||||
|
||||
/* Catch necessary signals */
|
||||
sig_action.sa_handler = signal_handler;
|
||||
sigemptyset(&sig_action.sa_mask);
|
||||
sig_action.sa_flags = 0;
|
||||
|
||||
sigaction(SIGTERM, &sig_action, NULL);
|
||||
sigaction(SIGHUP, &sig_action, NULL);
|
||||
sigaction(SIGINT, &sig_action, NULL);
|
||||
|
||||
/* create new session and process group */
|
||||
setsid();
|
||||
}
|
||||
|
||||
/* persist pid */
|
||||
pidfile_write(pfh);
|
||||
|
||||
/* persist pid */
|
||||
FILE *pid_file = fopen(pid_filename, "w");
|
||||
fprintf(pid_file, "%d\n", getpid());
|
||||
fclose(pid_file);
|
||||
}
|
||||
|
||||
FILE *cache_file = fopen(cache_filename, "a");
|
||||
|
||||
|
||||
/* looping to collect traffic stat every RESOLUTION seconds */
|
||||
|
||||
while(1) {
|
||||
|
||||
epoch=wait_for(RESOLUTION);
|
||||
|
||||
flock(fileno(cache_file), LOCK_EX);
|
||||
flockfile(cache_file);
|
||||
|
||||
fill_iftot(tot);
|
||||
fprintf(cache_file, "obytes.value %ld:%lu\nrbytes.value %ld:%lu\n", epoch, tot->ift_ob, epoch, tot->ift_ib);
|
||||
fflush(cache_file);
|
||||
|
||||
flock(fileno(cache_file), LOCK_UN);
|
||||
funlockfile(cache_file);
|
||||
}
|
||||
|
||||
fclose(cache_file);
|
||||
@ -208,7 +278,7 @@ int fetch()
|
||||
FILE* cache_file = fopen(cache_filename, "r+");
|
||||
|
||||
/* lock */
|
||||
flock(fileno(cache_file), LOCK_EX);
|
||||
flockfile(cache_file);
|
||||
|
||||
/* cat the cache_file to stdout */
|
||||
char buffer[1024];
|
||||
@ -222,8 +292,7 @@ int fetch()
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argv[0] && argv[0][0])
|
||||
program_name = argv[0];
|
||||
@ -260,7 +329,7 @@ main(int argc, char* argv[])
|
||||
}
|
||||
|
||||
if (! strcmp(first_arg, "acquire")) {
|
||||
return acquire();
|
||||
return daemon_start();
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user