/* This file is part of tagr.
Copyright (C) 2009 Sergey Poznyakoff
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; either version 3, or (at your option)
any later version.
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 . */
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#include
#include
#include
#include
#include
#include
void
scale_sample (struct monitor *mon,
const struct traffic_history *in,
struct traffic_history *out)
{
if (mon->swap)
{
out->inrate = in->outrate;
out->outrate = in->inrate;
}
else
{
out->inrate = in->inrate;
out->outrate = in->outrate;
}
out->inrate *= mon->scale;
out->outrate *= mon->scale;
}
int
create_hierarchy (char *dir, int perm)
{
int rc;
struct stat st;
char *p;
if (stat (dir, &st) == 0)
{
if (!S_ISDIR (st.st_mode))
{
logmsg (L_ERR, _("component %s is not a directory"), dir);
return 1;
}
return 0;
}
else if (errno != ENOENT)
{
logmsg (L_ERR, _("cannot stat file %s: %s"), dir, strerror (errno));
return 1;
}
p = strrchr (dir, '/');
if (p)
*p = 0;
rc = create_hierarchy (dir, perm);
if (rc == 0)
{
if (p)
*p = '/';
if (mkdir (dir, perm))
{
logmsg (L_ERR, _("cannot create directory %s: %s"),
dir, strerror (errno));
rc = 1;
}
}
return rc;
}
struct image_descr
{
const char *suffix;
size_t step;
struct grid_class *xgrid;
struct grid_class *ygrid;
const char *symname[6];
};
enum symname_index
{
maxin_name,
avgin_name,
curin_name,
maxout_name,
avgout_name,
curout_name
};
static void
add_stats (pp_tab_t **ptab, struct monitor *mon, queue_t *q,
const char **symname)
{
double val[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
int i, n = queue_count (q);
struct traffic_history *tptr, th;
if (!n)
return;
for (i = 0; i < n; i++)
{
tptr = queue_get_ptr (q, i);
scale_sample (mon, tptr, &th);
val[avgin_name] += th.inrate;
if (th.inrate > val[maxin_name])
val[maxin_name] = th.inrate;
val[avgout_name] += th.outrate;
if (th.outrate > val[maxout_name])
val[maxout_name] = th.outrate;
}
val[avgin_name] /= n;
val[avgout_name] /= n;
tptr = queue_get_tail (q);
scale_sample (mon, tptr, &th);
val[curin_name] = th.inrate;
val[curout_name] = th.outrate;
for (i = 0; i < sizeof (val) / sizeof (val[0]); i++)
add_numeric_value (ptab, symname[i], val[i]);
}
static int
do_update_output (struct monitor *mon, struct image_descr *dscr,
queue_t *queue, const struct avg_acc *avg,
pp_tab_t **ptab,
time_t timestamp,
char *dirname,
int needs_update)
{
char *fname;
int rc = 0;
if (create_hierarchy (dirname, 0755))
{
logmsg (L_ERR, _("cannot create directory %s"),
dirname);
return 1;
}
fname = mkfilename (dirname, mon->name, dscr->suffix);
if (access (fname, R_OK) || needs_update)
{
FILE *fp;
add_stats (ptab, mon, queue, dscr->symname);
fp = fopen (fname, "w");
if (!fp)
{
logmsg (L_ERR, _("cannot create file %s: %s"),
fname, strerror (errno));
rc = 1;
}
else
{
rc = draw_graph (fp, mon, queue, avg, timestamp, dscr->step,
dscr->step*460 /* FIXME: must be queue->size * step */,
0, dscr->xgrid, dscr->ygrid);
fclose (fp);
}
}
free (fname);
return rc;
}
struct image_descr img_day = {
"-day.png",
DAY_SAMPLE,
&grid_class_x_2h, &grid_class_y,
{ "MAXIN", "AVGIN", "CURIN",
"MAXOUT", "AVGOUT", "CUROUT" }
};
struct image_descr img_week = {
"-week.png",
WEEK_SAMPLE,
&grid_class_x_wday, &grid_class_y,
{ "HMAXIN", "HAVGIN", "HCURIN",
"HMAXOUT", "HAVGOUT", "HCUROUT" }
};
struct image_descr img_month = {
"-month.png",
MONTH_SAMPLE,
&grid_class_x_week, &grid_class_y,
{ "TMAXIN", "TAVGIN", "TCURIN",
"TMAXOUT", "TAVGOUT", "TCUROUT" }
};
struct image_descr img_year = {
"-year.png",
YEAR_SAMPLE,
&grid_class_x_month, &grid_class_y,
{ "DMAXIN", "DAVGIN", "DCURIN",
"DMAXOUT", "DAVGOUT", "DCUROUT" }
};
static void
format_timestamp (FILE *fp, union value v, const char *fmt, int prec)
{
time_t t = v.number;
struct tm *tm = localtime (&t);
if (!fmt)
fmt = "%c";
fprintftime(fp, fmt, tm, 0, 0);
}
int
update_output (struct monitor *mon, struct traffic_record *tr,
time_t timestamp, int force_update)
{
char *dirname = mkfilename (basedir, mon->dir, NULL);
int rc;
struct tm *tm = localtime (×tamp);
pp_tab_t *tab = NULL;
char *tabfile = mkfilename (dirname, mon->name, ".tab");
char *htmlname;
pp_value_t *p;
if (!force_update)
{
if (read_symtab (&tab, tabfile))
force_update = 1;
}
rc = do_update_output (mon, &img_day,
&tr->day_hist, NULL, &tab,
timestamp, dirname, 1);
rc += do_update_output (mon, &img_week,
&tr->week_hist, &tr->week_avg, &tab,
timestamp,
dirname,
force_update
|| (tm->tm_min >= 0 && tm->tm_min < 5)
|| (tm->tm_min >= 30 && tm->tm_min < 35));
rc += do_update_output (mon, &img_month,
&tr->month_hist, &tr->month_avg, &tab,
timestamp,
dirname,
force_update
|| (tm->tm_min >= 0 && tm->tm_min < 5
&& (tm->tm_hour % 2) == 0));
rc += do_update_output (mon, &img_year,
&tr->year_hist, &tr->year_avg, &tab,
timestamp,
dirname,
force_update
|| (tm->tm_min >= 0 && tm->tm_min < 5
&& tm->tm_hour == 0));
add_string_value (&tab, "PROGRAM", PACKAGE_NAME);
add_string_value (&tab, "VERSION", PACKAGE_VERSION);
add_string_value (&tab, "MONITOR", mon->name);
add_string_value (&tab, "ID", mon->id);
p = add_numeric_value (&tab, "NOW", timestamp);
p->format = format_timestamp;
p->fmt = "%c";
add_numeric_value (&tab, "SPEED", mon->max_rate);
htmlname = mkfilename (dirname, mon->name, ".html");
create_html (tab, html_template, htmlname);
free (htmlname);
write_symtab (tab, tabfile);
free (tabfile);
free_tab (&tab);
free (dirname);
return rc;
}