diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-04-29 18:11:56 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-04-29 18:11:56 +0300 |
commit | 5a1f674eecba607ffa328484ca34c598690ff8d2 (patch) | |
tree | 5dcda78e8352461d2ee7fdc29c64a265024cb219 /src | |
parent | 20d7f1d7e051c6b021a3f5d088985a74c3370b29 (diff) | |
download | tagr-5a1f674eecba607ffa328484ca34c598690ff8d2.tar.gz tagr-5a1f674eecba607ffa328484ca34c598690ff8d2.tar.bz2 |
Fix locking issues. Improve stream interface.
* gnulib.modules: Add c-type, c-strcase, crypto/md5,
xgetdomainname, xgethostname.
* src/Makefile.am (tagr_SOURCES): Add apop.c, udb.c, xhostname.c
* src/graph.c (draw_graph): Rename `now' to `start'.
* src/main.c (hostname, rebuild_last_option): New globals.
(main): Init hostname.
* src/output.c (update_output): Change semantics of the last
parameter.
* src/readconfig.c (cb_facility): Use c_strcasecmp.
(tagr_kw): New keywords: hostname, udb-file, lock-count,
lock-timeout, idle-timeout.
* src/report.c: Fix locking issues.
(update_monitor): Change semantics of the last parameter.
(rebuild): Likewise.
* src/server.c: Rewrite stream interface.
* src/tagr.h (TAGR_ARG_UNUSED, TAGR_PRINTFLIKE): New macros.
(lock_retry_count_option, lock_retry_timeout_option)
(stream_idle_timeout, hostname): New declarations.
(TAGR_UPD_FORCE, TAGR_UPD_LASTTIME): New defines.
(trim_crlf, tagr_local_hostnamem tagr_auth_init, tagr_auth)
(tagr_udb_name)
(udb_get_passwordudb_free_password): New declarations.
* TODO: Update
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 5 | ||||
-rw-r--r-- | src/apop.c | 84 | ||||
-rw-r--r-- | src/graph.c | 17 | ||||
-rw-r--r-- | src/main.c | 19 | ||||
-rw-r--r-- | src/output.c | 11 | ||||
-rw-r--r-- | src/readconfig.c | 23 | ||||
-rw-r--r-- | src/report.c | 37 | ||||
-rw-r--r-- | src/server.c | 193 | ||||
-rw-r--r-- | src/tagr.h | 41 | ||||
-rw-r--r-- | src/udb.c | 90 | ||||
-rw-r--r-- | src/xhostname.c | 56 |
11 files changed, 487 insertions, 89 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 0db1eb6..996c541 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -14,12 +14,13 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. sbin_PROGRAMS=tagr tagr_SOURCES=\ + apop.c\ graph.c\ grid.c\ html.gram.y\ html.lex.l\ log.c\ main.c\ @@ -27,13 +28,15 @@ tagr_SOURCES=\ queue.c\ readconfig.c\ report.c\ report.h\ server.c\ stat.c\ - tagr.h + tagr.h\ + udb.c\ + xhostname.c noinst_HEADERS=html.gram.h LDADD=../grecs/src/libgrecs.a ../gnu/libgnu.a INCLUDES = -I$(top_srcdir)/gnu -I../gnu -I$(top_srcdir)/grecs/src AM_YFLAGS=-vdt diff --git a/src/apop.c b/src/apop.c new file mode 100644 index 0000000..ce423a5 --- /dev/null +++ b/src/apop.c @@ -0,0 +1,84 @@ +/* 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 <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <unistd.h> +#include <fcntl.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <tagr.h> + +#include <md5.h> + +static char *msg_id; + +const char * +tagr_auth_init () +{ + asprintf (&msg_id, "<%lu.%lu@%s>", + (unsigned long) getpid (), + (unsigned long) time (NULL), + hostname); + return msg_id; +} + +static int +verify_apop (const char *password, const char *user_digest) +{ + int i; + struct md5_ctx md5context; + unsigned char md5digest[16]; + char buf[sizeof (md5digest) * 2 + 1]; + char *p; + + md5_init_ctx (&md5context); + md5_process_bytes (msg_id, strlen (msg_id), &md5context); + md5_process_bytes (password, strlen (password), &md5context); + md5_finish_ctx (&md5context, md5digest); + + for (i = 0, p = buf; i < 16; i++, p += 2) + sprintf (p, "%02x", md5digest[i]); + return strcmp (user_digest, buf); +} + +int +tagr_auth (const char *username, const char *authstr) +{ + int rc = 1; + char *password; + + rc = udb_get_password (username, &password); + if (rc == 1) + { + logmsg (L_ERR, _("no such user `%s'"), username); + } + else if (rc == 0) + { + rc = verify_apop (password, authstr); + if (rc) + logmsg (L_ERR, _("authentication failed for `%s'"), + username); + else + verbose (1, _("%s authenticated"), username); + udb_free_password (password); + } + return rc; +} + diff --git a/src/graph.c b/src/graph.c index 1197a7d..02e0586 100644 --- a/src/graph.c +++ b/src/graph.c @@ -70,13 +70,13 @@ draw_vtext (gdImagePtr graph, int color, const char *text) (unsigned char *) text, color); } int draw_graph (FILE *fp, struct monitor *mon, - queue_t *dataq, const struct avg_acc *avg, time_t now, + queue_t *dataq, const struct avg_acc *avg, time_t start, int xstep, unsigned long xmax, int growright, struct grid_class *xgrid, struct grid_class *ygrid) { int x, y; int i, n; @@ -87,13 +87,12 @@ draw_graph (FILE *fp, double xscale, yscale; int dotted_style[3]; int full_xsize = graph_xsize + graph_h_margin[0] + graph_h_margin[1]; int full_ysize = graph_ysize + graph_v_margin[0] + graph_v_margin[1]; grid_t grid; unsigned long ymax = mon->max_rate; - time_t start; yscale = (double) graph_ysize / ymax; xscale = (double) graph_xsize / xmax; #define ytr(y) \ (unsigned long) ((ymax >= (y) ? (ymax - (y)) : ymax) * \ @@ -140,19 +139,19 @@ draw_graph (FILE *fp, gdImageLine (graph, 1, full_ysize - 2, full_xsize - 2, full_ysize - 2, i_dark); n = queue_count (dataq); /* Incoming traffic */ - for (i = n - 1, start = 0; i > 0; i--) + for (i = n - 1; i > 0; i--) { struct traffic_history th, tnext; scale_sample (mon, queue_get_ptr (dataq, i), &th); - if (start == 0) - start = th.time; + if (th.time > start) + continue; scale_sample (mon, queue_get_ptr (dataq, i - 1), &tnext); if (start - tnext.time > xmax) break; if (zero_unknown_option && th.time - tnext.time > xstep * cut_out_fraction) { @@ -169,19 +168,19 @@ draw_graph (FILE *fp, gdImageLine (graph, xtr (start - th.time), ytr (th.inrate), xtr (start - tnext.time), ytr (tnext.inrate), i_in); } /* Outgoing traffic */ gdImageSetBrush (graph, brush_out); - for (i = n - 1, start = 0; i > 0; i--) + for (i = n - 1; i > 0; i--) { struct traffic_history th, tnext; scale_sample (mon, queue_get_ptr (dataq, i), &th); - if (start == 0) - start = th.time; + if (th.time > start) + continue; scale_sample (mon, queue_get_ptr (dataq, i - 1), &tnext); if (start - tnext.time > xmax) break; if (zero_unknown_option && th.time - tnext.time > xstep * cut_out_fraction) @@ -242,13 +241,13 @@ draw_graph (FILE *fp, 23, y - gdFontSmall->h / 2, (unsigned char *) str, i_grid); } grid_destroy (grid); } - grid = grid_create (xgrid, dataq, 0, xmax, &now); + grid = grid_create (xgrid, dataq, 0, xmax, &start); if (grid) { unsigned long i; char *str = NULL; int mark; @@ -54,18 +54,18 @@ char *pidfile = TAGR_PIDFILE; unsigned update_interval = 5*60; char *configfile = TAGR_CONFIGFILE; char *html_template = TAGR_TEMPLATE; char *user; char *basedir; -int port; -int sockfd; +char *hostname; int foreground = 0; int single_process_option = 0; int verbose_level; static int rebuild_option; +static int rebuild_last_option; static int import_option; static int read_option; static int list_option; static char *check_mode = 0; @@ -85,12 +85,13 @@ enum { OPT_PREPROCESSOR, OPT_NO_PREPROCESSOR, OPT_DUMP_GRAMMAR_TRACE, OPT_DUMP_LEX_TRACE, OPT_CONFIG_HELP, OPT_READ, + OPT_REBUILD_LAST }; static struct argp_option options[] = { #define GRID 10 {NULL, 0, NULL, 0, N_("Main operation mode"), GRID }, @@ -105,12 +106,14 @@ static struct argp_option options[] = { N_("import old (mrtg-style) log files from DIR (or the basedir, if not given)"), GRID+1 }, {"read", OPT_READ, NULL, 0, N_("read statistics from given FILEs or standard input") }, {"rebuild", 'b', NULL, 0, N_("rebuild graphs using existing statistics"), GRID+1}, + {"rebuild-last", OPT_REBUILD_LAST, NULL, 0, + N_("same as --rebuild, but refer to the last stored sample"), GRID+1}, {"list", 'l', NULL, 0, N_("list contents of the rate database"), GRID+1}, {"show-defaults", OPT_SHOW_DEFAULTS, NULL, 0, N_("Show configuration default values"), GRID+1}, #undef GRID #define GRID 20 @@ -273,12 +276,17 @@ parse_opt (int key, char *arg, struct argp_state *state) grecs_preprocessor = arg; break; case OPT_READ: read_option = 1; break; + + case OPT_REBUILD_LAST: + rebuild_option = 1; + rebuild_last_option = 1; + break; case OPT_NO_PREPROCESSOR: grecs_preprocessor = NULL; break; case OPT_SYSLOG: @@ -665,13 +673,13 @@ main (int argc, char **argv) int index, rc; fd_set read_fds; save_argv = argv; argp_program_bug_address = "<" PACKAGE_BUGREPORT ">"; argp_program_version_hook = tagr_version; - + if (!isatty (2)) { log_to_stderr = 0; } init_syslog (argv[0]); @@ -679,12 +687,14 @@ main (int argc, char **argv) exit (EX_USAGE); if (html_template_option) html_template = html_template_option; if (user_option) user = user_option; + if (!hostname) + hostname = tagr_local_hostname (); argc -= index; argv += index; if (argc != 0 && !(list_option || import_option)) die (EX_USAGE, _("Too many arguments")); @@ -739,13 +749,14 @@ main (int argc, char **argv) read_input (*argv++); else read_input (NULL); } if (rebuild_option) - rebuild (1); + rebuild (TAGR_UPD_FORCE + | (rebuild_last_option ? TAGR_UPD_LASTTIME : 0)); if (list_option) list_db (); if (rebuild_option || import_option || list_option || read_option) exit (0); diff --git a/src/output.c b/src/output.c index 4b6e206..e2e8b92 100644 --- a/src/output.c +++ b/src/output.c @@ -174,13 +174,14 @@ do_update_output (struct monitor *mon, struct image_descr *dscr, 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 */, + dscr->step*460 + /*^ FIXME: must be queue->size * step */, 0, dscr->xgrid, dscr->ygrid); fclose (fp); } } free (fname); return rc; @@ -233,28 +234,32 @@ format_timestamp (FILE *fp, union value v, const char *fmt, int prec) fprintftime (fp, fmt, tm, 0, 0); } int update_output (struct monitor *mon, struct traffic_record *tr, - time_t timestamp, int force_update) + 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, diff --git a/src/readconfig.c b/src/readconfig.c index e75cae4..a514691 100644 --- a/src/readconfig.c +++ b/src/readconfig.c @@ -23,12 +23,13 @@ #include <stdlib.h> #include <ctype.h> #include <syslog.h> #define obstack_chunk_alloc malloc #define obstack_chunk_free free #include <obstack.h> +#include <c-strcase.h> #include <tagr.h> #define ARG_UNUSED __attribute__ ((__unused__)) static struct obstack mon_stack; static struct monitor *mon_base; @@ -330,13 +331,13 @@ cb_facility (enum grecs_callback_command cmd, } str = value->v.string; if (strncasecmp (str, "LOG_", 4) == 0) str += 4; for (i = 0; xlat_tab[i].name; i++) - if (strcasecmp (str, xlat_tab[i].name) == 0) + if (c_strcasecmp (str, xlat_tab[i].name) == 0) { *iptr = xlat_tab[i].facility; return 0; } grecs_error (locus, 0, _("unknown syslog facility")); @@ -452,13 +453,17 @@ static struct grecs_keyword tagr_kw[] = { { "user", NULL, N_("Run with this user privileges"), grecs_type_string, &user }, { "template", NULL, N_("HTML page template"), grecs_type_string, &html_template }, { "pidfile", NULL, N_("Set pid file name"), grecs_type_string, &pidfile }, - + { "hostname", NULL, N_("Set host name"), + grecs_type_string, &hostname }, + { "udb-file", N_("name"), N_("Name of the user database file"), + grecs_type_string, &tagr_udb_name }, + { "server", N_("id: string"), N_("Configure server"), grecs_type_section, NULL, 0, cb_server, NULL, server_kw }, { "update-interval", NULL, N_("Set graph update interval"), grecs_type_uint, &update_interval }, @@ -467,12 +472,23 @@ static struct grecs_keyword tagr_kw[] = { grecs_type_section, NULL, 0, cb_monitor, NULL, monitor_kw }, { "log", NULL, N_("Configure logging"), grecs_type_section, NULL, 0, NULL, NULL, log_kw }, + + { "lock-count", NULL, + N_("Set maximum number of attempts to acquire the lock on a database"), + grecs_type_uint, &lock_retry_count_option }, + { "lock-timeout", N_("seconds"), + N_("Set the time span between the two locking attempts"), + grecs_type_uint, &lock_retry_timeout_option }, + + { "idle-timeout", N_("seconds"), + N_("Idle timeout for stream connections"), + grecs_type_uint, &stream_idle_timeout }, { "rate-units", NULL, N_("Name of rate units"), grecs_type_string, &rate_unit }, { "number-suffixes", N_("suffixes"), N_("Not implemented") /* FIXME */, grecs_type_string, NULL, 0, cb_number_suffixes }, @@ -509,14 +525,13 @@ static struct grecs_keyword tagr_kw[] = { { "color-grid", NULL, N_("Grid and axes color"), grecs_type_int, color_grid, 0, cb_color }, { "color-in-max", NULL, N_("Not implemented") /* FIXME */, grecs_type_int, color_in_max, 0, cb_color }, { "color-out-max", NULL, N_("Not implemented") /* FIXME */, grecs_type_int, color_out_max, 0, cb_color }, - - /* FIXME */ + { NULL } }; void config_help () { diff --git a/src/report.c b/src/report.c index 71a735f..ab4cada 100644 --- a/src/report.c +++ b/src/report.c @@ -30,31 +30,41 @@ #include <arpa/inet.h> #include <tagr.h> #include <report.h> #include <fprintftime.h> #include <gdbm.h> +unsigned lock_retry_count_option = 5; +unsigned lock_retry_timeout_option = 1; + 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); + unsigned i; + + dbname = mkfilename (basedir, TAGR_DBNAME, NULL); + + for (i = 0; i < lock_retry_count_option; i++) + { + dbf = gdbm_open (dbname, 0, + flag == TAGR_DB_WR ? GDBM_WRCREAT : GDBM_READER, + TAGR_DBMODE, tagr_db_report); + if (dbf || errno != EAGAIN) + break; + sleep (lock_retry_timeout_option); + } + if (dbf == NULL) { logmsg (L_ERR, _("cannot open database %s: %s"), dbname, gdbm_strerror (gdbm_errno)); return 1; } @@ -248,13 +258,13 @@ report (Stat *stat, time_t timestamp) } else logmsg (L_WARNING, _("%s not found in config"), stat->name); } int -update_monitor (datum key, time_t timestamp, int force) +update_monitor (datum key, time_t timestamp, int flags) { char id[MAX_NAME_LENGTH+1]; struct traffic_record *tr = NULL; struct monitor *mon; if (key.dsize > MAX_NAME_LENGTH) @@ -270,35 +280,34 @@ update_monitor (datum key, time_t timestamp, int force) 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); + update_output (mon, tr, timestamp, flags); free (tr); } return 0; } void -rebuild (int force) +rebuild (int flags) { 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); + datum nextkey = gdbm_nextkey (dbf, key); + update_monitor (key, now, flags); free (key.dptr); key = nextkey; } close_db (); } verbose (1, _("rebuild finished")); diff --git a/src/server.c b/src/server.c index 82aae0e..e514f37 100644 --- a/src/server.c +++ b/src/server.c @@ -34,24 +34,27 @@ #include <errno.h> #include <string.h> #include <syslog.h> #include <tagr.h> #include <report.h> #include <inttypes.h> +#include <c-strcase.h> #include <wordsplit.h> +unsigned stream_idle_timeout = 10; + struct tagr_server { struct tagr_server *next; char *id; enum tagr_server_type type; int fd; struct grecs_sockaddr addr; }; -struct tagr_server *server_head, *server_tail; +static struct tagr_server *server_head, *server_tail; struct server_class { int (*srv_open) (struct tagr_server *); void (*srv_run) (struct tagr_server *); void (*srv_close) (struct tagr_server *); @@ -191,14 +194,15 @@ subprocess (void (*fun) (void *data), void *data, int fd) if (pid > 0) return; else if (pid < 0) logmsg (L_ERR, _("cannot fork: %s"), strerror (errno)); else { - signal (SIGHUP, SIG_IGN); - signal (SIGCHLD, SIG_IGN); + signal (SIGHUP, SIG_DFL); + signal (SIGCHLD, SIG_DFL); + signal (SIGALRM, SIG_DFL); child = 1; if (fd != -1) close (fd); } } fun (data); @@ -299,13 +303,13 @@ tcp_open (struct tagr_server *srv) close (srv->fd); return 1; } return 0; } -static void +void trim_crlf (char *buf) { size_t len = strlen (buf); if (len > 0 && buf[len-1] == '\n') { buf[--len] = 0; @@ -341,81 +345,172 @@ convert_ulong (const char *str, unsigned long *pt) *pt = val; if (*pt != val) return 1; return 0; } +static RETSIGTYPE +sig_child_alrm (int sig) +{ + logmsg (L_NOTICE, _("child timed out")); + exit (EX_TEMPFAIL); +} + +enum tagr_dialog_state + { + initial_dialog_state, + auth_dialog_state, + quit_dialog_state + }; + +struct tagr_dialog +{ + enum tagr_dialog_state state; + FILE *in; + FILE *out; +}; + +#define STATEMASK(n) (1u<<(n)) +#define ANYSTATE ((unsigned)~0) + +struct command +{ + const char *name; + unsigned statemask; + int minargs; + int maxargs; + void (*handler) (struct tagr_dialog *, struct command *, + struct wordsplit *); +}; + +static void +cmd_auth (struct tagr_dialog *dlg, struct command *cmd, + struct wordsplit *ws) +{ + if (tagr_auth (ws->ws_wordv[1], ws->ws_wordv[2]) == 0) + { + dlg->state = auth_dialog_state; + fprintf (dlg->out, "+OK welcome, %s\r\n", ws->ws_wordv[1]); + } + else + fprintf (dlg->out, "-ERR authorization failed\r\n"); +} + +static void +cmd_sample (struct tagr_dialog *dlg, struct command *cmd, + struct wordsplit *ws) +{ + Stat st; + time_t t; + + if (strlen (ws->ws_wordv[1]) > MAX_NAME_LENGTH) + { + fprintf (dlg->out, "-ERR id too long\r\n"); + return; + } + + strcpy (st.name, ws->ws_wordv[1]); + if (convert_ts (ws->ws_wordv[2], &t) + || convert_ulong (ws->ws_wordv[3], &st.in) + || convert_ulong (ws->ws_wordv[4], &st.out)) + { + fprintf (dlg->out, "-ERR invalid input\r\n"); + return; + } + + if (open_db (TAGR_DB_WR)) + fprintf (dlg->out, "-TEMP database not available\r\n"); + else + { + report (&st, t); + close_db (); + fprintf (dlg->out, "+OK thank you\r\n"); + } +} + +static void +cmd_quit (struct tagr_dialog *dlg, struct command *cmd, + struct wordsplit *ws) +{ + dlg->state = quit_dialog_state; + fprintf (dlg->out, "+OK bye\r\n"); +} + +static struct command command_tab[] = { + { "AUTH", STATEMASK (initial_dialog_state), 3, 3, cmd_auth }, + { "SAMPLE", STATEMASK (auth_dialog_state), 5, 5, cmd_sample }, + { "QUIT", ANYSTATE, 1, 1, cmd_quit }, + { NULL } +}; + +static struct command * +find_command (const char *name) +{ + struct command *cmd; + + for (cmd = command_tab; cmd->name; cmd++) + if (c_strcasecmp (cmd->name, name) == 0) + return cmd; + return NULL; +} + + static void tcp_server_loop (void *data) { int fd = *(int*)data; - FILE *in = fdopen (fd, "r"); - FILE *out = fdopen (fd, "w"); + struct tagr_dialog dlg; size_t bufsize = 0; char *buf = NULL; - int quit = 0; - - setvbuf (in, NULL, _IOLBF, 0); - setvbuf (out, NULL, _IOLBF, 0); + const char *authid; + + signal (SIGALRM, sig_child_alrm); - fprintf (out, "+OK tagr experimental stream service\r\n"); - while (!quit && getline (&buf, &bufsize, in) > 0) + dlg.state = initial_dialog_state; + dlg.in = fdopen (fd, "r"); + dlg.out = fdopen (fd, "w"); + setvbuf (dlg.in, NULL, _IOLBF, 0); + setvbuf (dlg.out, NULL, _IOLBF, 0); + + authid = tagr_auth_init (); + fprintf (dlg.out, "+OK tagr experimental stream service %s\r\n", authid); + while (dlg.state != quit_dialog_state + && getline (&buf, &bufsize, dlg.in) > 0) { struct wordsplit ws; - + struct command *cmd; + + alarm (stream_idle_timeout); trim_crlf (buf); if (wordsplit (buf, &ws, WRDSF_DEFFLAGS)) { - logmsg (L_ERR, "failed to parse input line"); - fprintf (out, "-ERR parsing failed\r\n"); + logmsg (L_ERR, _("failed to parse input line")); + fprintf (dlg.out, "-ERR parsing failed\r\n"); continue; } if (ws.ws_wordc == 0) - fprintf (out, "-ERR invalid input\r\n"); - else if (strcasecmp (ws.ws_wordv[0], "SAMPLE") == 0 - && ws.ws_wordc == 5) + fprintf (dlg.out, "-ERR invalid input\r\n"); + else if (cmd = find_command (ws.ws_wordv[0])) { - Stat st; - time_t t; - - if (strlen (ws.ws_wordv[1]) > MAX_NAME_LENGTH) - fprintf (out, "-ERR id too long\r\n"); + if (!(STATEMASK (dlg.state) & cmd->statemask)) + fprintf (dlg.out, "-ERR wrong state\r\n"); + else if (ws.ws_wordc < cmd->minargs + || (cmd->maxargs > 0 && ws.ws_wordc > cmd->maxargs)) + fprintf (dlg.out, "-ERR invalid number of arguments\r\n"); else - { - strcpy (st.name, ws.ws_wordv[1]); - if (convert_ts (ws.ws_wordv[2], &t) - || convert_ulong (ws.ws_wordv[3], &st.in) - || convert_ulong (ws.ws_wordv[4], &st.out)) - fprintf (out, "-ERR invalid input\r\n"); - else - { - if (open_db (TAGR_DB_WR)) - fprintf (out, "-ERR database not available\r\n"); - else - { - report (&st, t); - close_db (); - fprintf (out, "+OK thank you\r\n"); - } - } - } - } - else if (strcasecmp (ws.ws_wordv[0], "QUIT") == 0) - { - quit = 1; - fprintf (out, "+OK bye\r\n"); + cmd->handler (&dlg, cmd, &ws); } else - fprintf (out, "-ERR invalid input\r\n"); + fprintf (dlg.out, "-ERR invalid input\r\n"); wordsplit_free (&ws); } free (buf); - fclose (in); - fclose (out); + fclose (dlg.in); + fclose (dlg.out); close (fd); } static void tcp_run (struct tagr_server *srv) { @@ -17,12 +17,21 @@ #include <time.h> #include <errno.h> #include <xalloc.h> #include <sysexits.h> #include <grecs.h> +#ifndef TAGR_ARG_UNUSED +# define TAGR_ARG_UNUSED __attribute__ ((__unused__)) +#endif + +#ifndef TAGR_PRINTFLIKE +# define TAGR_PRINTFLIKE(fmt,narg) \ + __attribute__ ((__format__ (__printf__, fmt, narg))) +#endif + #define TAGR_CONFIGFILE SYSCONFDIR "/tagr.conf" #define TAGR_TEMPLATE SYSCONFDIR "/tagr.tmpl" #define TAGR_PIDFILE "/var/run/tagr.pid" #define TAGR_DBNAME "tagr.db" #define TAGR_DBMODE 0600 #define TAGR_CUT_OUT 1.5 @@ -48,12 +57,19 @@ extern int preprocess_only; extern int log_to_stderr; extern char *pidfile; extern unsigned update_interval; extern int single_process_option; extern double cut_out_fraction; +extern unsigned lock_retry_count_option; +extern unsigned lock_retry_timeout_option; + +extern unsigned stream_idle_timeout; + +extern char *hostname; + extern char *user; extern char *basedir; extern char *configfile; extern int foreground; extern char *html_template; extern char *html_input_file; @@ -140,15 +156,15 @@ extern int log_print_severity; #define L_NOTICE 2 #define L_WARNING 3 #define L_ERR 4 #define L_CRIT 5 void init_syslog (char *tag); -void logmsg (int level, const char *fmt, ...); -void die (int code, const char *fmt, ...); -void verbose (int level, const char *fmt, ...); +void logmsg (int level, const char *fmt, ...) TAGR_PRINTFLIKE(2,3); +void die (int code, const char *fmt, ...) TAGR_PRINTFLIKE(2,3); +void verbose (int level, const char *fmt, ...) TAGR_PRINTFLIKE(2,3); /* Traffic history */ #define DAY_COUNT (600) /* 400 samples is 33.33 hours */ @@ -215,15 +231,19 @@ struct traffic_record #define TAGR_DB_WR 1 int open_db (int); void close_db (); void read_db (struct monitor *mon, struct traffic_record **tr); void write_db (struct monitor *mon, struct traffic_record *tr); void list_db (void); -void rebuild (int force); void tr_init (struct traffic_record *tr); +#define TAGR_UPD_FORCE 0x0001 +#define TAGR_UPD_LASTTIME 0x0002 + +void rebuild (int flags); + /* stat.c */ void update_stats (struct monitor *mon, struct traffic_sample *sample, struct traffic_record *tr); void import (const char *dir); /* queue.c */ @@ -239,13 +259,13 @@ char *mkfilename (const char *dir, const char *name, const char *suffix); /* output.c */ void scale_sample (struct monitor *mon, const struct traffic_history *in, struct traffic_history *out); int update_output (struct monitor *mon, struct traffic_record *tr, - time_t timestamp, int force); + time_t timestamp, int flags); /* graph.c */ typedef struct grid *grid_t; struct grid_class @@ -285,10 +305,21 @@ void register_server (const char *id, enum tagr_server_type type, struct grecs_sockaddr addr); void open_servers (void); void close_servers (void); void server_loop (void); +void trim_crlf (char *buf); + int tagr_idle (void); + +char *tagr_local_hostname (void); +const char *tagr_auth_init (void); +int tagr_auth (const char *username, const char *authstr); + +/* udb.c */ +extern char *tagr_udb_name; +int udb_get_password (const char *username, char **password); +void udb_free_password (char *pass); diff --git a/src/udb.c b/src/udb.c new file mode 100644 index 0000000..aad5982 --- /dev/null +++ b/src/udb.c @@ -0,0 +1,90 @@ +/* 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 <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <wordsplit.h> +#include <tagr.h> + +char *tagr_udb_name = SYSCONFDIR "/tagr.udb"; + +int +udb_get_password (const char *username, char **password) +{ + FILE *fp; + size_t bufsize = 0; + char *buf = NULL; + unsigned line = 0; + int rc = 1; + + fp = fopen (tagr_udb_name, "r"); + if (!fp) + { + logmsg (L_ERR, _("cannot open file %s: %s"), + tagr_udb_name, strerror (errno)); + return -1; + } + + while (rc == 1 && getline (&buf, &bufsize, fp) > 0) + { + struct wordsplit ws; + + line++; + trim_crlf (buf); + if (wordsplit (buf, &ws, WRDSF_DEFFLAGS)) + { + logmsg (L_ERR, _("%s:%u: failed to parse input line"), + tagr_udb_name, line); + } + if (ws.ws_wordc == 0 || ws.ws_wordv[0][0] == '#') + /* next */; + else if (ws.ws_wordc < 2) + { + logmsg (L_WARNING, _("%s:%u: too few words on line"), + tagr_udb_name, line); + } + else if (ws.ws_wordc > 2) + { + logmsg (L_WARNING, _("%s:%u: too many words on line"), + tagr_udb_name, line); + } + else if (strcmp (ws.ws_wordv[0], username) == 0) + { + *password = xstrdup (ws.ws_wordv[1]); + rc = 0; + } + wordsplit_free (&ws); + } + + free (buf); + fclose (fp); + return rc; +} +< |