/* This file is part of tagr. Copyright (C) 2000, 2005, 2009 Max Bouglacoff, 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 #include #include #include #include #include #include #include static char *dbname; static GDBM_FILE dbf; static void tagr_db_report (char *str) { logmsg (L_CRIT, "%s: %s", dbname, str); } int open_db (int flag) { dbname = xmalloc (strlen (basedir) + 1 + sizeof (TAGR_DBNAME)); strcpy (dbname, basedir); strcat (dbname, "/"); strcat (dbname, TAGR_DBNAME); dbf = gdbm_open (dbname, 0, flag == TAGR_DB_WR ? GDBM_WRCREAT : GDBM_READER, TAGR_DBMODE, tagr_db_report); if (dbf == NULL) { logmsg (L_ERR, _("cannot open database %s: %s"), dbname, gdbm_strerror (gdbm_errno)); return 1; } return 0; } void close_db () { gdbm_close (dbf); free (dbname); dbname = NULL; } /* FIXME: Spurious initialization of .size member. */ void tr_init (struct traffic_record *tr) { tr->day_hist.queue = tr->history; tr->day_hist.size = DAY_COUNT; tr->week_hist.queue = tr->day_hist.queue + tr->day_hist.size; tr->week_hist.size = WEEK_COUNT; tr->month_hist.queue = tr->week_hist.queue + tr->week_hist.size; tr->month_hist.size = MONTH_COUNT; tr->year_hist.queue = tr->month_hist.queue + tr->month_hist.size; tr->year_hist.size = YEAR_COUNT; } static void _read_db (datum key, struct traffic_record **tr) { datum content; content = gdbm_fetch (dbf, key); if (content.dptr == NULL) logmsg (L_NOTICE, _("record for %*.*s not found"), key.dsize, key.dsize, key.dptr); else if (content.dsize != sizeof **tr) { logmsg (L_ERR, _("wrong record size for %*.*s: %lu"), key.dsize, key.dsize, key.dptr, content.dsize); } else { *tr = (struct traffic_record *) content.dptr; tr_init (*tr); return; } logmsg (L_NOTICE, _("creating record for %*.*s"), key.dsize, key.dsize, key.dptr); *tr = xmalloc (sizeof **tr); memset (*tr, 0, sizeof **tr); tr_init (*tr); } void read_db (struct monitor *mon, struct traffic_record **tr) { datum key; datum content; key.dptr = mon->id; key.dsize = strlen (mon->id); _read_db (key, tr); } void write_db (struct monitor *mon, struct traffic_record *tr) { datum key; datum content; key.dptr = mon->id; key.dsize = strlen (mon->id); content.dsize = sizeof *tr; content.dptr = (char *) tr; if (gdbm_store (dbf, key, content, GDBM_REPLACE)) { logmsg (L_ERR, _("failed to write data for %s: %s"), mon->id, gdbm_strerror (gdbm_errno)); } } static void print_time (FILE *fp, time_t time) { fprintf (fp, "%lu [", (unsigned long) time); fprintftime (fp, "%Y-%m-%d %H:%M:%S %z", localtime (&time), 0, 0); fprintf (fp, "]"); } static void print_queue (const char *title, queue_t *q) { int i, count; count = queue_count (q); printf (ngettext ("%s (%d entry):\n", "%s (%d entries):\n", count), title, count); for (i = count - 1; i >= 0; i--) { struct traffic_history *th = queue_get_ptr (q, i); printf ("%d ", count - i); print_time (stdout, th->time); printf (" %g %g\n", th->inrate, th->outrate); } } static void print_avg (const char *title, struct avg_acc *avg) { char buf[512]; strftime (buf, sizeof buf, "%c", localtime (&avg->time)); printf ("%s: %lu (%s) %u %g %g\n", title, avg->time, buf, avg->count, avg->inrate, avg->outrate); } static void print_tr (datum key, struct traffic_record *tr) { int i, count; printf ("ID: %*.*s\n", key.dsize, key.dsize, key.dptr); printf (_("Last sample: ")); print_time (stdout, tr->last.time); printf (" %lu %lu\n", tr->last.in, tr->last.out); printf (_("Last rates: %g %g\n"), tr->last_rates.inrate, tr->last_rates.outrate); print_queue (_("Daily rates"), &tr->day_hist); print_avg (_("Weekly average"), &tr->week_avg); print_queue (_("Weekly rates"), &tr->week_hist); print_avg (_("Monthly average"), &tr->month_avg); print_queue (_("Monthly rates"), &tr->month_hist); print_avg (_("Yearly average"), &tr->year_avg); print_queue (_("Yearly rates"), &tr->year_hist); } void list_db () { datum key; datum content; struct monitor *mon; if (open_db (TAGR_DB_RD)) exit (EX_UNAVAILABLE); key = gdbm_firstkey (dbf); while (key.dptr) { struct traffic_record *tr; datum nextkey = gdbm_nextkey (dbf, key); _read_db (key, &tr); print_tr (key, tr); free (tr); free (key.dptr); key = nextkey; } close_db (); } void report (Stat *stat, time_t timestamp) { struct monitor *mon = find_monitor_id (stat->name); if (mon) { struct traffic_record *tr; struct traffic_sample s; s.in = stat->in; s.out = stat->out; s.time = timestamp; read_db (mon, &tr); update_stats (mon, &s, tr); write_db (mon, tr); free (tr); } else logmsg (L_WARNING, _("%s not found in config"), stat->name); } int update_monitor (datum key, time_t timestamp, int force) { char id[MAX_NAME_LENGTH+1]; struct traffic_record *tr = NULL; struct monitor *mon; if (key.dsize > MAX_NAME_LENGTH) { logmsg (L_ERR, _("tag name too long (%u)"), key.dsize); return 1; } memcpy (id, key.dptr, key.dsize); id[key.dsize] = 0; mon = find_monitor_id (id); if (!mon) { logmsg (L_ERR, _("%s: no such monitor"), id); return 1; } _read_db (key, &tr); if (tr) { update_output (mon, tr, tr->last.time /*FIXME: must be now? */, force); free (tr); } return 0; } void rebuild (int force) { datum key; datum content; time_t now = time (NULL); verbose (1, _("rebuild initiated")); if (open_db (TAGR_DB_RD) == 0) { key = gdbm_firstkey (dbf); while (key.dptr) { datum nextkey = gdbm_nextkey ( dbf, key ); update_monitor (key, now, force); free (key.dptr); key = nextkey; } close_db (); } verbose (1, _("rebuild finished")); }