Probe/src/damon.c

362 lines
7.6 KiB
C

/* $Id$ */
/* Copyright (c) 2005-2016 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS Network Probe */
/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* FIXME: catch SIGPIPE, determine if we can avoid catching it if an AppServer
* exits (eg avoid writing to a closed socket) */
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <System.h>
#include <System/App.h>
#include "rrd.h"
#include "damon.h"
#include "../config.h"
/* constants */
#ifndef PREFIX
# define PREFIX "/usr/local"
#endif
#ifndef SYSCONFDIR
# define SYSCONFDIR PREFIX "/etc"
#endif
#ifndef PROGNAME
# define PROGNAME "DaMon"
#endif
/* DaMon */
/* private */
/* types */
typedef struct _Host
{
DaMon * damon;
AppClient * appclient;
char * hostname;
char ** ifaces;
char ** vols;
} Host;
struct _DaMon
{
char const * prefix;
unsigned int refresh;
Host * hosts;
unsigned int hosts_cnt;
Event * event;
};
/* constants */
#ifdef DEBUG
# define DAMON_DEFAULT_REFRESH 10
#else
# define DAMON_DEFAULT_REFRESH 300
#endif
#define DAMON_SEP '/'
/* prototypes */
static int _damon_init(DaMon * damon, char const * config, Event * event);
static void _damon_destroy(DaMon * damon);
static int _damon_perror(char const * message, int error);
static int _damon_update(DaMon * damon, RRDType type, char const * filename,
int args_cnt, ...);
/* functions */
/* public */
/* essential */
/* damon_new */
DaMon * damon_new(char const * config)
{
DaMon * damon;
Event * event;
if((event = event_new()) == NULL)
return NULL;
/* FIXME let event be deleted eventually */
if((damon = damon_new_event(config, event)) == NULL)
{
event_delete(event);
return NULL;
}
return damon;
}
/* damon_new_event */
DaMon * damon_new_event(char const * config, Event * event)
{
DaMon * damon;
if((damon = object_new(sizeof(*damon))) == NULL)
return NULL;
if(_damon_init(damon, config, event) != 0)
{
object_delete(damon);
return NULL;
}
return damon;
}
/* damon_delete */
void damon_delete(DaMon * damon)
{
_damon_destroy(damon);
object_delete(damon);
}
/* accessors */
/* damon_get_event */
Event * damon_get_event(DaMon * damon)
{
return damon->event;
}
/* useful */
/* damon_refresh */
#include "damon-backend.c"
/* private */
/* functions */
/* damon_init */
static int _init_config(DaMon * damon, char const * filename);
static int _init_config_hosts(DaMon * damon, Config * config,
char const * hosts);
static int _init_config_hosts_host(DaMon * damon, Config * config, Host * host,
char const * h, unsigned int pos);
static char ** _init_config_hosts_host_comma(char const * line);
static int _damon_init(DaMon * damon, char const * config, Event * event)
{
struct timeval tv;
if(_init_config(damon, config) != 0)
return 1;
damon->event = event;
damon_refresh(damon);
tv.tv_sec = damon->refresh;
tv.tv_usec = 0;
event_register_timeout(damon->event, &tv,
(EventTimeoutFunc)damon_refresh, damon);
return 0;
}
static int _init_config(DaMon * damon, char const * filename)
{
Config * config;
char const * p;
char * q;
int tmp;
if((config = config_new()) == NULL)
return 1;
damon->prefix = NULL;
damon->refresh = DAMON_DEFAULT_REFRESH;
damon->hosts = NULL;
damon->hosts_cnt = 0;
if(filename == NULL)
filename = SYSCONFDIR "/" PROGNAME ".conf";
if(config_load(config, filename) != 0)
{
error_print(PROGNAME);
config_delete(config);
return -1;
}
if((damon->prefix = config_get(config, "", "prefix")) == NULL)
damon->prefix = ".";
if((damon->prefix = strdup(damon->prefix)) == NULL)
{
config_delete(config);
return -1;
}
if((p = config_get(config, "", "refresh")) != NULL)
{
tmp = strtol(p, &q, 10);
damon->refresh = (*p == '\0' || *q != '\0' || tmp <= 0)
? DAMON_DEFAULT_REFRESH : tmp;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s() refresh=%d\n", __func__,
damon->refresh);
#endif
}
if((p = config_get(config, "", "hosts")) != NULL)
_init_config_hosts(damon, config, p);
config_delete(config);
return 0;
}
static int _init_config_hosts(DaMon * damon, Config * config,
char const * hosts)
{
char const * h = hosts;
unsigned int pos = 0;
Host * p;
while(h[0] != '\0')
{
if(h[pos] != '\0' && h[pos] != ',')
{
pos++;
continue;
}
if(pos == 0)
{
h++;
continue;
}
if((p = realloc(damon->hosts, sizeof(*p) * (damon->hosts_cnt
+ 1))) == NULL)
return _damon_perror(NULL, -errno);
damon->hosts = p;
p = &damon->hosts[damon->hosts_cnt++];
if(_init_config_hosts_host(damon, config, p, h, pos) != 0)
return -1;
h += pos;
pos = 0;
}
return 0;
}
static int _init_config_hosts_host(DaMon * damon, Config * config, Host * host,
char const * h, unsigned int pos)
{
char const * p;
host->damon = damon;
host->appclient = NULL;
host->ifaces = NULL;
host->vols = NULL;
if((host->hostname = malloc(pos + 1)) == NULL)
return _damon_perror(NULL, -errno);
strncpy(host->hostname, h, pos);
host->hostname[pos] = '\0';
#ifdef DEBUG
fprintf(stderr, "config: Host %s\n", host->hostname);
#endif
if((p = config_get(config, host->hostname, "interfaces")) != NULL)
host->ifaces = _init_config_hosts_host_comma(p);
if((p = config_get(config, host->hostname, "volumes")) != NULL)
host->vols = _init_config_hosts_host_comma(p);
return 0;
}
static char ** _init_config_hosts_host_comma(char const * line)
{
char const * l = line;
unsigned int pos = 0;
char ** values = NULL;
char ** p;
unsigned int cnt = 0;
while(l[0] != '\0')
{
if(l[pos] != '\0' && l[pos] != ',')
{
pos++;
continue;
}
if(pos == 0)
{
l++;
continue;
}
if((p = realloc(values, sizeof(char*) * (cnt + 2))) == NULL)
break;
values = p;
if((values[cnt] = malloc(pos + 1)) != NULL)
{
strncpy(values[cnt], l, pos);
values[cnt][pos] = '\0';
#ifdef DEBUG
fprintf(stderr, "config: %s\n", values[cnt]);
#endif
}
values[++cnt] = NULL;
if(values[cnt - 1] == NULL)
break;
l += pos;
pos = 0;
}
if(l[0] == '\0')
return values;
if(values == NULL)
return NULL;
for(p = values; *p != NULL; p++)
free(*p);
free(values);
return NULL;
}
/* damon_destroy */
static void _damon_destroy(DaMon * damon)
{
unsigned int i;
for(i = 0; i < damon->hosts_cnt; i++)
{
free(damon->hosts[i].hostname);
if(damon->hosts[i].appclient != NULL)
appclient_delete(damon->hosts[i].appclient);
}
event_delete(damon->event);
free(damon->hosts);
}
/* useful */
/* damon_perror */
static int _damon_perror(char const * message, int ret)
{
return error_set_print(PROGNAME, ret, "%s%s%s",
(message != NULL) ? message : "",
(message != NULL) ? ": " : "", strerror(errno));
}
/* damon_update */
static int _damon_update(DaMon * damon, RRDType type, char const * filename,
int args_cnt, ...)
{
int ret;
char * path;
va_list args;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(%u, \"%s\", %d, ...) \"%s\"\n", __func__,
type, filename, args_cnt, damon->prefix);
#endif
if((path = string_new_append(damon->prefix, "/", filename, NULL))
== NULL)
return -1;
va_start(args, args_cnt);
ret = rrd_updatev(type, path, args_cnt, args);
va_end(args);
string_delete(path);
return ret;
}