- 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
|
PREFIX=/usr/local
|
||||||
INC=-I$(PREFIX)/include
|
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
|
FLAGS=-Wall -O2 -pipe -funroll-loops -ffast-math -fno-strict-aliasing -mssse3
|
||||||
CC?=cc
|
CC?=cc
|
||||||
|
|
||||||
|
161
ifstatd.c
161
ifstatd.c
@ -1,27 +1,27 @@
|
|||||||
/*
|
/*-
|
||||||
Copyright (c) 2015, Babak Farrokhi
|
* Copyright (c) 2015, Babak Farrokhi
|
||||||
All rights reserved.
|
* All rights reserved.
|
||||||
|
*
|
||||||
Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
* Redistributions of source code must retain the above copyright notice, this
|
* * Redistributions of source code must retain the above copyright notice, this
|
||||||
list of conditions and the following disclaimer.
|
* list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
* Redistributions in binary form must reproduce the above copyright notice,
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
this list of conditions and the following disclaimer in the documentation
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
and/or other materials provided with the distribution.
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
* 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
|
* 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.
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sysexits.h>
|
#include <sysexits.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <libutil.h>
|
||||||
|
|
||||||
#define IFA_STAT(s) (((struct if_data *)ifa->ifa_data)->ifi_ ## s)
|
#define IFA_STAT(s) (((struct if_data *)ifa->ifa_data)->ifi_ ## s)
|
||||||
#define RESOLUTION 10
|
#define RESOLUTION 10
|
||||||
@ -67,12 +68,38 @@ char *program_name = "ifstatd_";
|
|||||||
char *interface;
|
char *interface;
|
||||||
char *pid_filename;
|
char *pid_filename;
|
||||||
char *cache_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).
|
* Obtain stats for interface(s).
|
||||||
*/
|
*/
|
||||||
static void
|
static void fill_iftot(struct iftot *st)
|
||||||
fill_iftot(struct iftot *st)
|
|
||||||
{
|
{
|
||||||
struct ifaddrs *ifap, *ifa;
|
struct ifaddrs *ifap, *ifa;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
@ -93,14 +120,9 @@ fill_iftot(struct iftot *st)
|
|||||||
}
|
}
|
||||||
|
|
||||||
st->ift_ip += IFA_STAT(ipackets);
|
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_ib += IFA_STAT(ibytes);
|
||||||
st->ift_op += IFA_STAT(opackets);
|
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_ob += IFA_STAT(obytes);
|
||||||
/*st->ift_co += IFA_STAT(collisions);*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interface && found == false)
|
if (interface && found == false)
|
||||||
@ -109,6 +131,9 @@ fill_iftot(struct iftot *st)
|
|||||||
freeifaddrs(ifap);
|
freeifaddrs(ifap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print out munin plugin configuration
|
||||||
|
*/
|
||||||
int config(char *iface)
|
int config(char *iface)
|
||||||
{
|
{
|
||||||
printf(
|
printf(
|
||||||
@ -135,6 +160,9 @@ int config(char *iface)
|
|||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wait for a certain amount of time
|
||||||
|
*/
|
||||||
time_t wait_for(int seconds) {
|
time_t wait_for(int seconds) {
|
||||||
|
|
||||||
struct timespec tp;
|
struct timespec tp;
|
||||||
@ -153,17 +181,45 @@ time_t wait_for(int seconds) {
|
|||||||
return current_epoch + seconds;
|
return current_epoch + seconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
int acquire()
|
/*
|
||||||
|
* Daemonize and persist pid
|
||||||
|
*/
|
||||||
|
int daemon_start()
|
||||||
{
|
{
|
||||||
struct iftot ift, *tot;
|
struct iftot ift, *tot;
|
||||||
time_t epoch;
|
time_t epoch;
|
||||||
|
struct sigaction sig_action;
|
||||||
|
sigset_t sig_set;
|
||||||
|
pid_t otherpid;
|
||||||
|
|
||||||
tot = &ift;
|
tot = &ift;
|
||||||
|
|
||||||
/* fork ourselves if not asked otherwise */
|
|
||||||
char* no_fork = getenv("no_fork");
|
char* no_fork = getenv("no_fork");
|
||||||
if (! no_fork || strcmp("1", 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 */
|
/* we are the child, complete the daemonization */
|
||||||
|
|
||||||
/* Close standard IO */
|
/* Close standard IO */
|
||||||
@ -171,31 +227,45 @@ int acquire()
|
|||||||
fclose(stdout);
|
fclose(stdout);
|
||||||
fclose(stderr);
|
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 */
|
/* create new session and process group */
|
||||||
setsid();
|
setsid();
|
||||||
}
|
|
||||||
|
|
||||||
/* persist pid */
|
/* persist pid */
|
||||||
FILE *pid_file = fopen(pid_filename, "w");
|
pidfile_write(pfh);
|
||||||
fprintf(pid_file, "%d\n", getpid());
|
|
||||||
fclose(pid_file);
|
}
|
||||||
|
|
||||||
FILE *cache_file = fopen(cache_filename, "a");
|
FILE *cache_file = fopen(cache_filename, "a");
|
||||||
|
|
||||||
|
|
||||||
/* looping to collect traffic stat every RESOLUTION seconds */
|
/* looping to collect traffic stat every RESOLUTION seconds */
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
|
|
||||||
epoch=wait_for(RESOLUTION);
|
epoch=wait_for(RESOLUTION);
|
||||||
|
|
||||||
flock(fileno(cache_file), LOCK_EX);
|
flockfile(cache_file);
|
||||||
|
|
||||||
fill_iftot(tot);
|
fill_iftot(tot);
|
||||||
fprintf(cache_file, "obytes.value %ld:%lu\nrbytes.value %ld:%lu\n", epoch, tot->ift_ob, epoch, tot->ift_ib);
|
fprintf(cache_file, "obytes.value %ld:%lu\nrbytes.value %ld:%lu\n", epoch, tot->ift_ob, epoch, tot->ift_ib);
|
||||||
fflush(cache_file);
|
fflush(cache_file);
|
||||||
|
|
||||||
flock(fileno(cache_file), LOCK_UN);
|
funlockfile(cache_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(cache_file);
|
fclose(cache_file);
|
||||||
@ -208,7 +278,7 @@ int fetch()
|
|||||||
FILE* cache_file = fopen(cache_filename, "r+");
|
FILE* cache_file = fopen(cache_filename, "r+");
|
||||||
|
|
||||||
/* lock */
|
/* lock */
|
||||||
flock(fileno(cache_file), LOCK_EX);
|
flockfile(cache_file);
|
||||||
|
|
||||||
/* cat the cache_file to stdout */
|
/* cat the cache_file to stdout */
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
@ -222,8 +292,7 @@ int fetch()
|
|||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int main(int argc, char* argv[])
|
||||||
main(int argc, char* argv[])
|
|
||||||
{
|
{
|
||||||
if (argv[0] && argv[0][0])
|
if (argv[0] && argv[0][0])
|
||||||
program_name = argv[0];
|
program_name = argv[0];
|
||||||
@ -260,7 +329,7 @@ main(int argc, char* argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (! strcmp(first_arg, "acquire")) {
|
if (! strcmp(first_arg, "acquire")) {
|
||||||
return acquire();
|
return daemon_start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user