diff options
-rw-r--r-- | TODO | 9 | ||||
-rw-r--r-- | gnulib.modules | 5 | ||||
-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 |
13 files changed, 499 insertions, 91 deletions
@@ -1,2 +1,2 @@ -Tagr TODO list. 2009-04-28 +Tagr TODO list. 2009-04-29 Copyright (C) 2009 Sergey Poznyakoff @@ -5,5 +5,10 @@ Copyright (C) 2009 Sergey Poznyakoff -S: +OK tagr ready +Currently implemented are: + +S: +OK <msgid> +C: AUTH name digest +S: +OK C: SAMPLE id 1240903636 12345 3456 S: +OK accepted +... C: QUIT diff --git a/gnulib.modules b/gnulib.modules index d4887b3..0a23f34 100644 --- a/gnulib.modules +++ b/gnulib.modules @@ -4,2 +4,5 @@ argp +c-ctype +c-strcase +crypto/md5 fprintftime @@ -19 +22,3 @@ xalloc xalloc-die +xgetdomainname +xgethostname
\ No newline at end of file diff --git a/src/Makefile.am b/src/Makefile.am index 0db1eb6..996c541 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -19,2 +19,3 @@ sbin_PROGRAMS=tagr tagr_SOURCES=\ + apop.c\ graph.c\ @@ -32,3 +33,5 @@ tagr_SOURCES=\ stat.c\ - tagr.h + tagr.h\ + udb.c\ + xhostname.c 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 @@ -75,3 +75,3 @@ 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, @@ -92,3 +92,2 @@ draw_graph (FILE *fp, unsigned long ymax = mon->max_rate; - time_t start; @@ -145,3 +144,3 @@ draw_graph (FILE *fp, /* Incoming traffic */ - for (i = n - 1, start = 0; i > 0; i--) + for (i = n - 1; i > 0; i--) { @@ -150,4 +149,4 @@ draw_graph (FILE *fp, 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); @@ -174,3 +173,3 @@ draw_graph (FILE *fp, gdImageSetBrush (graph, brush_out); - for (i = n - 1, start = 0; i > 0; i--) + for (i = n - 1; i > 0; i--) { @@ -179,4 +178,4 @@ draw_graph (FILE *fp, 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); @@ -247,3 +246,3 @@ draw_graph (FILE *fp, - grid = grid_create (xgrid, dataq, 0, xmax, &now); + grid = grid_create (xgrid, dataq, 0, xmax, &start); if (grid) @@ -59,4 +59,3 @@ char *user; char *basedir; -int port; -int sockfd; +char *hostname; int foreground = 0; @@ -65,2 +64,3 @@ int verbose_level; static int rebuild_option; +static int rebuild_last_option; @@ -90,2 +90,3 @@ enum { OPT_READ, + OPT_REBUILD_LAST }; @@ -110,2 +111,4 @@ static struct argp_option options[] = { 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}, @@ -278,2 +281,7 @@ parse_opt (int key, char *arg, struct argp_state *state) break; + + case OPT_REBUILD_LAST: + rebuild_option = 1; + rebuild_last_option = 1; + break; @@ -670,3 +678,3 @@ main (int argc, char **argv) argp_program_version_hook = tagr_version; - + if (!isatty (2)) @@ -684,2 +692,4 @@ main (int argc, char **argv) user = user_option; + if (!hostname) + hostname = tagr_local_hostname (); @@ -744,3 +754,4 @@ main (int argc, char **argv) if (rebuild_option) - rebuild (1); + rebuild (TAGR_UPD_FORCE + | (rebuild_last_option ? TAGR_UPD_LASTTIME : 0)); diff --git a/src/output.c b/src/output.c index 4b6e206..e2e8b92 100644 --- a/src/output.c +++ b/src/output.c @@ -179,3 +179,4 @@ do_update_output (struct monitor *mon, struct image_descr *dscr, 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); @@ -238,3 +239,3 @@ int update_output (struct monitor *mon, struct traffic_record *tr, - time_t timestamp, int force_update) + time_t timestamp, int flags) { @@ -247,3 +248,4 @@ update_output (struct monitor *mon, struct traffic_record *tr, pp_value_t *p; - + int force_update = flags & TAGR_UPD_FORCE; + if (!force_update) @@ -254,2 +256,5 @@ update_output (struct monitor *mon, struct traffic_record *tr, + if (flags & TAGR_UPD_LASTTIME) + timestamp = tr->last.time; + rc = do_update_output (mon, &img_day, diff --git a/src/readconfig.c b/src/readconfig.c index e75cae4..a514691 100644 --- a/src/readconfig.c +++ b/src/readconfig.c @@ -28,2 +28,3 @@ #include <obstack.h> +#include <c-strcase.h> #include <tagr.h> @@ -335,3 +336,3 @@ cb_facility (enum grecs_callback_command cmd, 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) { @@ -457,3 +458,7 @@ static struct grecs_keyword tagr_kw[] = { 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"), @@ -472,2 +477,13 @@ static struct grecs_keyword tagr_kw[] = { 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 }, @@ -514,4 +530,3 @@ static struct grecs_keyword tagr_kw[] = { grecs_type_int, color_out_max, 0, cb_color }, - - /* FIXME */ + { NULL } diff --git a/src/report.c b/src/report.c index 71a735f..ab4cada 100644 --- a/src/report.c +++ b/src/report.c @@ -35,2 +35,5 @@ +unsigned lock_retry_count_option = 5; +unsigned lock_retry_timeout_option = 1; + static char *dbname; @@ -47,9 +50,16 @@ 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) @@ -253,3 +263,3 @@ report (Stat *stat, time_t timestamp) int -update_monitor (datum key, time_t timestamp, int force) +update_monitor (datum key, time_t timestamp, int flags) { @@ -275,4 +285,3 @@ update_monitor (datum key, time_t timestamp, int force) { - update_output (mon, tr, tr->last.time /*FIXME: must be now? */, - force); + update_output (mon, tr, timestamp, flags); free (tr); @@ -284,3 +293,3 @@ update_monitor (datum key, time_t timestamp, int force) void -rebuild (int force) +rebuild (int flags) { @@ -289,3 +298,3 @@ rebuild (int force) time_t now = time (NULL); - + verbose (1, _("rebuild initiated")); @@ -296,4 +305,4 @@ rebuild (int force) { - 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); diff --git a/src/server.c b/src/server.c index 82aae0e..e514f37 100644 --- a/src/server.c +++ b/src/server.c @@ -39,4 +39,7 @@ #include <inttypes.h> +#include <c-strcase.h> #include <wordsplit.h> +unsigned stream_idle_timeout = 10; + struct tagr_server @@ -50,3 +53,3 @@ struct tagr_server -struct tagr_server *server_head, *server_tail; +static struct tagr_server *server_head, *server_tail; @@ -196,4 +199,5 @@ subprocess (void (*fun) (void *data), void *data, int fd) { - signal (SIGHUP, SIG_IGN); - signal (SIGCHLD, SIG_IGN); + signal (SIGHUP, SIG_DFL); + signal (SIGCHLD, SIG_DFL); + signal (SIGALRM, SIG_DFL); child = 1; @@ -304,3 +308,3 @@ tcp_open (struct tagr_server *srv) -static void +void trim_crlf (char *buf) @@ -346,2 +350,108 @@ convert_ulong (const char *str, unsigned long *pt) +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 @@ -350,16 +460,24 @@ 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); @@ -367,4 +485,4 @@ tcp_server_loop (void *data) { - 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; @@ -373,38 +491,15 @@ tcp_server_loop (void *data) 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); @@ -413,4 +508,4 @@ tcp_server_loop (void *data) free (buf); - fclose (in); - fclose (out); + fclose (dlg.in); + fclose (dlg.out); close (fd); @@ -22,2 +22,11 @@ +#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" @@ -53,2 +62,9 @@ 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; @@ -145,5 +161,5 @@ extern int log_print_severity; 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); @@ -220,5 +236,9 @@ 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 */ @@ -244,3 +264,3 @@ void scale_sample (struct monitor *mon, int update_output (struct monitor *mon, struct traffic_record *tr, - time_t timestamp, int force); + time_t timestamp, int flags); @@ -290,5 +310,16 @@ 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; +} + +void +udb_free_password (char *pass) +{ + char *p; + for (p = pass; *p; p++) + *p = 0; + free (pass); +} diff --git a/src/xhostname.c b/src/xhostname.c new file mode 100644 index 0000000..8ffd499 --- /dev/null +++ b/src/xhostname.c @@ -0,0 +1,56 @@ +/* This file is part of tagr. + Copyright (C) 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 <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <stdlib.h> +#include <string.h> +#include <netdb.h> +#include <xalloc.h> +#include <xgethostname.h> +#include <xgetdomainname.h> + +char * +tagr_local_hostname () +{ + struct hostent *hp; + char *hostpart = xgethostname (); + char *ret; + + hp = gethostbyname (hostpart); + if (hp) + ret = xstrdup (hp->h_name); + else + { + char *domainpart = xgetdomainname (); + + if (domainpart && domainpart[0] && strcmp(domainpart, "(none)")) + { + ret = xmalloc(strlen( hostpart) + 1 + + strlen (domainpart) + 1); + strcpy(ret, hostpart); + strcat(ret, "."); + strcat(ret, domainpart); + free (hostpart); + } + else + ret = hostpart; + free (domainpart); + } + return ret; +} + |