/* 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->time = in->time; 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 flags) { 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; int force_update = flags & TAGR_UPD_FORCE; if (!force_update) { if (read_symtab (&tab, tabfile)) force_update = 1; } if (flags & TAGR_UPD_LASTTIME) timestamp = tr->last.time; 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; }