Index: cgilib-0.4/cgi.c
===========================================================================
--- cgilib-0.4/cgi.c	2004/11/03 14:26:17	#3
+++ cgilib-0.4/cgi.c	2004/11/03 14:26:17
@@ -33,9 +33,6 @@
 #ifdef HAVE_CTYPE_H
 # include <ctype.h>
 #endif
-#ifdef HAVE_MALLOC_H
-# include <malloc.h>
-#endif
 
 #include <cgi.h>
 
Index: configure.in
===========================================================================
--- configure.in	2004/11/03 14:26:17	#6
+++ configure.in	2004/11/03 14:26:17
@@ -1,12 +1,13 @@
 # 
 # RTG 0.8.1 configure.in
 # Author: Rob Beverly <rbeverly@users.sourceforge.net>
+# $Yahoo$
 #
 
 AC_INIT(src/rtg.h)
 AC_CONFIG_AUX_DIR(config)
 AC_SUBST(ac_aux_dir)
-AM_INIT_AUTOMAKE(rtg, 0.8.1)
+AM_INIT_AUTOMAKE(rtg, 0.8.1-YAHOO)
 AC_SUBST(VERSION)
 AM_CONFIG_HEADER(config/config.h)
 AC_CANONICAL_HOST
@@ -26,10 +27,13 @@
    [  --with-snmp=PATH        SNMP path [default=/usr/local]],,)
 
 AC_ARG_WITH(gd,
-   [  --with-gd=PATH        gd path [default=/usr/local]],,)
+   [  --with-gd=PATH          gd path [default=/usr/local]],,)
 
 AC_ARG_WITH(png,
-   [  --with-png=PATH        png path [default=/usr/local]],,)
+   [  --with-png=PATH         png path [default=/usr/local]],,)
+
+AC_ARG_WITH(setproctitle, 
+   [  --with-setproctitle     use setproctitle(3) to display thread status],,)
 
 
 # For sanity, can't try to build MySQL and Postgres
@@ -69,10 +73,8 @@
 AC_PROG_INSTALL
 AC_PROG_LN_S
 AC_PROG_RANLIB
-# NEW_TARGET_FORMAT
 AC_PROG_YACC
 AM_PROG_LEX
-# END NEW_TARGET
 
 AC_MSG_CHECKING([whether to enable -Wall])
 AC_ARG_ENABLE(warnings,
@@ -105,7 +107,13 @@
 
 dnl Checks for library functions.
 AC_TYPE_SIGNAL
-AC_CHECK_FUNCS(gettimeofday strerror strtoll)
+AC_CHECK_FUNCS(gettimeofday strerror strtoull strtoll strdup)
+
+if test "x$with_setproctitle" != "x"
+then
+	AC_CHECK_FUNCS(setproctitle)
+	AC_DEFINE(HAVE_SPT, 1, [use setproctitle to display thread status])
+fi
 
 dnl Determine RTG home installation path for script substitution
 if test "x$prefix" != "xNONE"; then
Index: contrib/convtargets.php
===========================================================================
*** /dev/null	Wed Nov  3 14:22:00 2004
--- contrib/convtargets.php	Wed Nov  3 14:26:18 2004
***************
*** 0 ****
--- 1,56 ----
+ #!/usr/local/bin/php
+ <?php
+ 
+ # convtargets.php - convert old rtg targets files to rtg 0.8 format
+ # (c) 2004 bill fumerola, yahoo! <fumerola@yahoo-inc.com>
+ # 
+ # Redistribution and use in source and binary forms, with or without
+ # modification, are permitted provided that the following conditions
+ # are met:
+ # 1. Redistributions of source code must retain the above copyright
+ #    notice, this list of conditions and the following disclaimer.
+ # 2. Redistributions in binary form must reproduce the above copyright
+ #    notice, this list of conditions and the following disclaimer in the
+ #    documentation and/or other materials provided with the distribution.
+ # 
+ # THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ # ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ # SUCH DAMAGE.
+ #
+ # $Yahoo: //depot/fumerola/rtg-contrib/contrib/convtargets.php#2 $
+ 
+ 
+ $stdin = fopen('php://stdin', 'r') or die('cannot read stdin?!');
+ $hosts = array();
+ $hostconf = array();
+ 
+ while (($line = fgetcsv($stdin, 2048, "\t")) !== FALSE) {
+ 	if (strpos($line[0], '#') === 0)
+ 		continue;
+ 	$hostconf[$line[0]] = $line[3];
+ 	$target = array('bits' => $line[2], 'table' => $line[4],
+ 			'id' => $line[5], 'speed' => '0',
+ 			'descr' => '"' . addslashes($line[6]) . '"');
+ 	$hosts[$line[0]][$line[1]] = $target;
+ }
+ 
+ foreach ($hosts as $host => $targets):
+ echo "host $host {\n";
+ echo "\tcommunity {$hostconf[$host]};\n";
+ foreach ($targets as $oid => $target) {
+ 	echo "\ttarget $oid {\n";
+ 	foreach ($target as $k => $v)
+ 		echo "\t\t$k $v;\n";
+ 	echo "\t};\n";
+ }
+ echo "};\n";
+ endforeach;
+ ?>
Index: etc/rtg.conf
===========================================================================
--- etc/rtg.conf	2004/11/03 14:26:17	#2
+++ etc/rtg.conf	2004/11/03 14:26:17
@@ -4,9 +4,6 @@
 Interval	300
 HighSkewSlop	3
 LowSkewSlop	.5
-OutOfRange	93750000000
-SNMP_Ver	1
-SNMP_Port       161
 DB_Host	localhost
 DB_Database	rtg
 DB_User	snmp
Index: src/Makefile.am
===========================================================================
--- src/Makefile.am	2004/11/03 14:26:17	#4
+++ src/Makefile.am	2004/11/03 14:26:17
@@ -1,4 +1,5 @@
 ## Makefile.am -- Process this file with automake to produce Makefile.in
+## $Yahoo$
 
 CGI_LIB_DIR        = $(top_srcdir)/@CGI_LIB_DIR@
 # REMOVE
@@ -12,30 +13,19 @@
 #           $(PNG_LIB_DIR)/libpng.a $(ZLIB_LIB_DIR)/libzlib.a
 RTG_LIBS = $(CGI_LIB_DIR)/libcgi.a 
 
-# NEW_TARGET_FORMAT
 AM_YFLAGS= -d
 BUILT_SOURCES = rtgtarg.h rtgtarg.c
 CLEANFILES = rtgtarg.c rtgtarg.h
-# END NEW_TARGET
-
-# Uncomment the following two lines to enable OLD target parsing
-#rtgpoll_SOURCES = rtgsnmp.c rtgmysql.c rtgpgsql.c rtgpoll.c rtgutil.c rtghash.c
-#rtgplot_SOURCES = rtgplot.c rtgmysql.c rtgpgsql.c rtgparse.c rtgutil.c rtghash.c 
 
-# NEW_TARGET_FORMAT
 rtgpoll_SOURCES = rtgsnmp.c rtgmysql.c rtgpgsql.c rtgpoll.c rtgutil.c \
-                  rtgtarg.y rtggram.l rtghash.c
+                  rtgtarg.y rtggram.l rtghash.c rtgsqlbuf.c
 
 rtgplot_SOURCES = rtgplot.c rtgmysql.c rtgpgsql.c rtgparse.c rtgutil.c
 
-# END NEW_TARGET
-
 include_HEADERS = rtg.h rtgplot.h common.h
 #
 
-# NEW_TARGET_FORMAT
 rtgpoll_LDADD = $(LEXLIB)
-# END NEW_TARGET
 rtgplot_LDADD = $(RTG_LIBS)
 
 bin_PROGRAMS = rtgpoll rtgplot
Index: src/common.h
===========================================================================
--- src/common.h	2004/11/03 14:26:17	#2
+++ src/common.h	2004/11/03 14:26:17
@@ -1,3 +1,5 @@
+/* $Yahoo$ */
+
 #ifndef RTG_COMMON_H
 #define RTG_COMMON_H 1
 
@@ -72,4 +74,8 @@
 # include <libpq-fe.h>
 #endif
 
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+
 #endif /* RTG_COMMON_H */
Index: src/rtg.h
===========================================================================
--- src/rtg.h	2004/11/03 14:26:17	#6
+++ src/rtg.h	2004/11/03 14:26:17
@@ -3,6 +3,7 @@
    Author:      $Author: rbeverly $
    Date:        $Date: 2004/10/30 16:38:24 $
    Description: RTG headers
+   Do You:      $Yahoo$
 ****************************************************************************/
 
 #ifndef _RTG_H_
@@ -10,7 +11,6 @@
 
 /****** XXX 0.8 FEATURES -- Remove, resolve or fix for release */
 #define FEATURES 1
-#define NEW_TARGET_FORMAT 1
 #define RATE_INSERT 0
 /****** XXX 0.8 FEATURES -- Remove, resolve or fix for release */
 
@@ -26,7 +26,7 @@
 /* #define BROKEN_LINUX 1 */
 
 /* Constants */
-#define MAX_THREADS 100
+#define MAX_THREADS 128
 #define BUFSIZE 512
 #define BITSINBYTE 8
 #define THIRTYTWO 4294967295ul
@@ -45,7 +45,7 @@
    that RTG_HOME, as determined during autoconf is one path */
 #define CONFIG_PATHS 3
 #define CONFIG_PATH_1 ""
-#define CONFIG_PATH_2 "/etc/"
+#define CONFIG_PATH_2 RTG_HOME"/etc/"
 
 /* Defaults */
 #define DEFAULT_CONF_FILE "rtg.conf"
@@ -58,6 +58,7 @@
 #define DEFAULT_DB_DB "rtg"
 #define DEFAULT_DB_USER "snmp"
 #define DEFAULT_DB_PASS "rtgdefault"
+#define DEFAULT_DB_PORT 3306
 #define DEFAULT_SNMP_VER 1
 #define DEFAULT_SNMP_PORT 161
 #define DEFAULT_SYSLOG_FACILITY LOG_LOCAL2
@@ -66,58 +67,98 @@
 #define PIDFILE "/var/run/rtgpoll.pid"
 
 #define STAT_DESCRIP_ERROR 99
-#define HASHSIZE 5000
 
-/* pthread error messages */
-#define PML_ERR "pthread_mutex_lock error\n"
-#define PMU_ERR "pthread_mutex_unlock error\n"
-#define PCW_ERR "pthread_cond_wait error\n"
-#define PCB_ERR "pthread_cond_broadcast error\n"
-
 /* pthread macros */
-#define PT_MUTEX_LOCK(x) if (pthread_mutex_lock(x) != 0) printf(PML_ERR)
-#define PT_MUTEX_UNLOCK(x) if (pthread_mutex_unlock(x) != 0) printf(PMU_ERR)
-#define PT_COND_WAIT(x,y) if (pthread_cond_wait(x, y) != 0) printf(PCW_ERR)
-#define PT_COND_BROAD(x) if (pthread_cond_broadcast(x) != 0) printf(PCB_ERR)
+#define PT_MUTEX_LOCK(x) \
+	do { int pterr; \
+		debug(THREAD, "lock: %s::%s(%u)\n", __FILE__, __func__, __LINE__); \
+		if ((pterr = pthread_mutex_lock(x)) != 0) \
+			fprintf(stderr, "pthread_mutex_lock error (%s)\n", \
+			       strerror(pterr)); \
+	} while(0)
+#define PT_MUTEX_UNLOCK(x) \
+	do { int pterr; \
+		debug(THREAD, "unlock: %s::%s(%u)\n", __FILE__, __func__, __LINE__); \
+		if ((pterr = pthread_mutex_unlock(x)) != 0) \
+			fprintf(stderr, "pthread_mutex_unlock error (%s)\n", \
+			       strerror(pterr)); \
+	} while(0)
+#define PT_COND_WAIT(x,y) \
+	do { int pterr; \
+		debug(THREAD, "condwait: %s::%s(%u)\n", __FILE__, __func__, __LINE__); \
+		if ((pterr = pthread_cond_wait(x, y)) != 0) \
+			fprintf(stderr, "pthread_cond_wait error (%s)\n",\
+			       strerror(pterr)); \
+	} while(0)
+#define PT_COND_BROAD(x) \
+	do { int pterr; \
+		debug(THREAD, "condbroad: %s::%s(%u)\n", __FILE__, __func__, __LINE__); \
+		if ((pterr = pthread_cond_broadcast(x)) != 0) \
+			fprintf(stderr, "pthread_cond_broadcast error (%s)\n",\
+			       strerror(pterr)); \
+	} while(0)
+#define PT_COND_SIGNAL(x) \
+	do { int pterr; \
+		debug(THREAD, "condsignal: %s::%s(%u)\n", __FILE__, __func__, __LINE__); \
+		if ((pterr = pthread_cond_signal(x)) != 0) \
+			fprintf(stderr, "pthread_cond_signal error (%s)\n",\
+			       strerror(pterr)); \
+	} while(0)
 
 /* Verbosity levels LOW=info HIGH=info+SQL DEBUG=info+SQL+junk */
-enum debugLevel {OFF, LOW, HIGH, DEBUG, DEVELOP}; 
+enum debugLevel {OFF = 1, LOW, HIGH, DEBUG, DEVELOP, THREAD}; 
 
 /* These ugly macros keep the code clean and everything inline for speed */
-#define sysloginfo(x...) syslog(LOG_INFO |  LOG_LOCAL2, x) // replace with conf'g facility
-#define syslogcrit(x...) syslog(LOG_CRIT |  LOG_LOCAL2, x) // replace with conf'g facility
-#define debug(level,x...) do {if (set.verbose >= level) {if (set.daemon) sysloginfo(x); else fprintf(stdout,x);} } while (0)
-#define debugfile(dfp,level,x...) do {if (set.verbose >= level) {if (set.daemon) sysloginfo(x); else fprintf(dfp,x);} } while (0)
-#define fatal(x...) do { if (set.daemon) syslogcrit(x); else fprintf(stderr,x); exit(-1); } while (0)
-#define fatalfile(dfp,x...) do { fprintf(dfp,x); exit(-1); } while (0)
+#define sysloginfo(x...) syslog(LOG_INFO |  LOG_LOCAL2, x) /* replace with conf'g facility */
+#define syslogcrit(x...) syslog(LOG_CRIT |  LOG_LOCAL2, x) /* replace with conf'g facility */
+
+#define debugfile(dfp,level,x...) \
+	do { \
+		if (set.verbose >= level) { \
+			if (set.daemon && dfp == stdout) \
+				sysloginfo(x); \
+			else \
+				fprintf(dfp,x); \
+		} \
+	} while (0)
+#define debug(level, x...) debugfile(stdout, level, x)
+
+#define fatalfile(dfp, x...) \
+	do { \
+		if (set.daemon && dfp == stderr) \
+			syslogcrit(x); \
+		else \
+			fprintf(dfp, x); \
+		exit(-1); \
+	} while (0)
+#define fatal(x...) fatalfile(stderr, x)
 
-/* Target state */
-enum targetState {NEW, LIVE, STALE};
+/* use setproctitle if available, otherwise use debug macro */
+#ifdef HAVE_SPT
+#define SPT(x...) setproctitle(x)
+#else
+#define SPT(x...) debug(DEBUG, x)
+#endif
 
 /* Typedefs */
 typedef struct worker_struct {
-    int index;
+    unsigned int index;
     pthread_t thread;
     struct crew_struct *crew;
 } worker_t;
 
 typedef struct config_struct {
     unsigned int interval;
-#if !NEW_TARGET_FORMAT
-    unsigned long long out_of_range;
-#endif
     char dbhost[80];
     char dbdb[80];
     char dbuser[80];
     char dbpass[80];
+    char dbsock[80];
+    unsigned short dbport;
     enum debugLevel verbose;
     unsigned short withzeros;
     unsigned short dboff;
     unsigned short multiple;
-#if !NEW_TARGET_FORMAT
-    unsigned short snmp_ver;
-#endif
-    unsigned short snmp_port;
     unsigned short threads;
     unsigned short daemon;
     unsigned short syslog;
@@ -125,43 +166,8 @@
     float lowskewslop;
 } config_t;
 
-typedef struct target_struct {
-#if !NEW_TARGET_FORMAT
-    char host[64];
-    char community[64];
-    char objoid[128];
-    char table[64];
-#else
-    struct host_struct *host;
-    char *objoid;
-    char *description;
-    char *table;
-#endif
-    unsigned short bits;
-    unsigned int iid;
-#ifdef HAVE_STRTOLL
-    unsigned long long maxspeed;
-#else
-    unsigned long maxspeed;
-#endif
-    enum targetState init;
-    unsigned long long last_value;
-#ifdef FEATURES
-    struct timeval last_time;
-#endif
-    struct target_struct *next;
-} target_t;
-
-#if NEW_TARGET_FORMAT
-typedef struct host_struct {
-    char *host;
-    char *community;
-    unsigned short snmp_ver;
-} host_t;
-#endif
-
 typedef struct crew_struct {
-    int work_count;
+    unsigned int work_count;
     worker_t member[MAX_THREADS];
     pthread_mutex_t mutex;
     pthread_cond_t done;
@@ -184,32 +190,19 @@
 #endif
     double poll_time; 
 } stats_t;
-
-#if !NEW_TARGET_FORMAT
-typedef struct hash_struct {
-    target_t *table[HASHSIZE];
-    int bucket;
-    target_t *target;
-} hash_t;
-#endif
-
+extern stats_t stats;
 
 /* Precasts: rtgpoll.c */
 void *sig_handler(void *);
 void usage(char *);
 
-/* Precasts: rtgpoll.c */
-void *poller(void *);
-
 #if HAVE_MYSQL
 /* Precasts: rtgmysql.c */
 int mysql_db_insert(char *, MYSQL *);
 int mysql_dbconnect(char *, MYSQL *);
 void mysql_dbdisconnect(MYSQL *);
 void mysql_close_db(void *);
-#endif
-
-#if HAVE_PGSQL
+#elif HAVE_PGSQL
 /* Precasts: rtgpgsql.c */
 PGresult * pgsql_db_query(char *, PGconn *);
 int pgsql_db_insert(char *, PGconn *);
@@ -222,49 +215,17 @@
 #endif
 
 /* Precasts: rtgutil.c */
-int read_rtg_config(char *, config_t *);
-int write_rtg_config(char *, config_t *);
-void config_defaults(config_t *);
-void print_stats (stats_t);
+int read_rtg_config(char *);
+int write_rtg_config(char *);
+void config_defaults(void);
 int sleepy(float);
 void timestamp(char *);
 double timediff(struct timeval, struct timeval);
 int checkPID(char *);
-#if !NEW_TARGET_FORMAT
-int alldigits(char *);
-#endif
-int daemon_init();
+int daemon_init(void);
 
-/* Precasts: rtghash.c */
-void init_hash();
-void init_hash_walk();
-target_t *getNext();
-#if !NEW_TARGET_FORMAT
-void free_hash();
-unsigned long make_key(const void *);
-void mark_targets(int);
-int delete_targets(int);
-void walk_target_hash();
-void *in_hash(target_t *, target_t *);
-int compare_targets(target_t *, target_t *);
-#endif
-int del_hash_entry(target_t *);
-int add_hash_entry(target_t *);
-int hash_target_file(char *);
-
-/* Globals */
-#if !NEW_TARGET_FORMAT
-config_t set;
-int lock;
-int waiting;
-char config_paths[CONFIG_PATHS][BUFSIZE];
-hash_t hash;
-#else
 extern config_t set;
-extern int lock;
-extern int waiting;
 extern char config_paths[CONFIG_PATHS][BUFSIZE];
 extern FILE *dfp;
-#endif
 
 #endif /* not _RTG_H_ */
Index: src/rtggram.l
===========================================================================
--- src/rtggram.l	2004/11/03 14:26:17	#2
+++ src/rtggram.l	2004/11/03 14:26:17
@@ -1,66 +1,95 @@
 %option yylineno
 %option noyywrap
 %{
+/* (c) 2004 bill fumerola, yahoo!
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Yahoo$
+ */
+
+#include <err.h>
 #include <stdio.h>
 #include <string.h>
 #include "common.h"
 #include "rtgtarg.h"
 
-
 unsigned int lineno = 1;
 int yylex(void);
 %}
 
-token         [{};]
-endtoken      ;$
-newline       [\n]*
-whitespace    [ \t\v\f]+
-hashcmnt      ^#.*$
-cppcmnt               "//".*$
-ipv4addr      ([0-9]{1,3}\.){1,3}[0-9]{1,3}
-oid           (\.[0-9]+)+
-string                \"[^\"\n]+\"
-number                [0-9]+
+token		[{};]
+endtoken	;$
+newline		[\n\r]
+whitespace	[ \t\v\f]+
+hashcmnt	^#.*$
+cppcmnt		"//".*$
+ipv4addr	([0-9]{1,3}\.){1,3}[0-9]{1,3}
+oid		(\.[0-9]+)+
+string		\"[^\"\n]*\"
+number		[0-9]+
 identifier      [a-zA-Z0-9]([^; \t]|[:print:])*
 
 %%
-{newline}     { ++lineno; }
-{whitespace}  { }
-{hashcmnt}    { }
-{cppcmnt}     { }
-{endtoken}    { }
+{newline}	{ ++lineno; }
+{whitespace}	{ }
+{hashcmnt}	{ }
+{cppcmnt}	{ }
+{endtoken}	{ }
 
-host          { return T_HOST; }
+host		{ return T_HOST; }
 
-community     { return HST_COMM; }
-snmpver               { return HST_SVER; }
-target                { return HST_TRGT; }
+community	{ return HST_COMM; }
+snmpver		{ return HST_SVER; }
+target		{ return HST_TRGT; }
+snmp_port	{ return HST_PORT; }
+timeout		{ return HST_TIME; }
+retries		{ return HST_RTRY; }
 
-bits          { return TGT_BITS; }
-table         { return TGT_TBL; }
-id            { return TGT_ID; }
-speed         { return TGT_SPEED; }
-descr         { return TGT_DESCR; }
+bits		{ return TGT_BITS; }
+table		{ return TGT_TBL; }
+id		{ return TGT_ID; }
+speed		{ return TGT_SPEED; }
+descr		{ return TGT_DESCR; }
 
-{token}               { return yytext[0]; }
-{number}      {
-#ifdef HAVE_STRTOLL
-                yylval.number = strtoll(yytext, NULL, 0);
+{token}		{ return yytext[0]; }
+{number}	{ 
+#ifdef HAVE_STRTOULL
+		  yylval.number = strtoull(yytext, NULL, 0);
 #else
-                yylval.number = strtol(yytext, NULL, 0);
+		  yylval.number = strtoul(yytext, NULL, 0);
 #endif
-                return L_NUMBER;
-              }
+		  return L_NUMBER;
+		}
 {ipv4addr}      { yylval.string = strdup(yytext); return L_IPADDR; }
-{oid}         { yylval.string = strdup(yytext); return L_OID; }
+{oid}		{ yylval.string = strdup(yytext); return L_OID; }
 {string}        { yylval.string = strdup(yytext+1);
                   if(yylval.string[yyleng-2] != '"')
-                      fprintf(stderr,"Unterminated character string\n");
+			fprintf(stderr,"Unterminated character string\n");
                   else
-                      yylval.string[yyleng-2] = '\0'; /* remove close quote */
-                return L_STRING;
-              }
+			yylval.string[yyleng-2] = '\0'; /* remove close quote */
+		  return L_STRING;
+		}
 {identifier}    { yylval.string = strdup(yytext); return L_IDENT; }
 
-.             { fprintf(stderr,"unexpected character: %c", yytext[0]); }
+.		{ warnx("unexpected character: %c", yytext[0]); }
 %%
Index: src/rtghash.c
===========================================================================
--- src/rtghash.c	2004/11/03 14:26:17	#3
+++ src/rtghash.c	2004/11/03 14:26:17
@@ -3,398 +3,376 @@
    Author:      $Author: cbrotsos $
    Date:        $Date: 2004/08/25 19:18:26 $
    Description: RTG target hash table routines
+   Do You:      $Yahoo$
 ****************************************************************************/
 
 #include "common.h"
+
+#ifdef OLD_UCD_SNMP
+ #include "asn1.h"
+ #include "snmp_api.h"
+ #include "snmp_impl.h"
+ #include "snmp_client.h"
+ #include "mib.h"
+ #include "snmp.h"
+#else
+ #include "net-snmp-config.h"
+ #include "net-snmp-includes.h"
+#endif
+
 #include "rtg.h"
+#include "rtghash.h"
+#include "rtgsqlbuf.h"
+#include "rtgsnmp.h"
 
-#if NEW_TARGET_FORMAT
 extern FILE *yyin;
 extern int yyparse(void);
 extern int yylex(void);
 
-static void free_hash(void);
-static void *in_hash(target_t *entry, target_t *list);
-static void mark_targets(int state);
-static void walk_target_hash(void);
+struct tgthash *thash;
+RTGLL_HEAD(, dbtable_struct) dbtable_h = RTGLL_HEAD_INITIALIZER();
+RTGLL_HEAD(, host_struct) host_h = RTGLL_HEAD_INITIALIZER();
+static unsigned int hosts = 0U;
+
 static int compare_targets(target_t *t1, target_t *t2);
-static unsigned int delete_targets(int state);
-static unsigned long make_key(const void *entry);
+static target_t *in_hash(struct tgthead *table, target_t *entry);
+static int tgthead_delete(struct tgthead *tblhead, target_t *new);
 
-static int entries = 0;
-struct {
-        int bucket;
-        target_t *target;
-		target_t **table;
-} hash;
-#endif
-
+static void host_decrement(struct host_struct *dhst);
+static void dbtable_decrement(struct dbtable_struct *dtbl);
 
 /* Initialize hash table */
-void init_hash() {
-	int i;
+void
+tgthash_init(struct tgthash *hash, unsigned int hashsize)
+{
+	unsigned int i;
 
-#if !NEW_TARGET_FORMAT
-	for(i=0;i<HASHSIZE;i++) {
-		hash.table[i] = NULL;
+	hash->entries = 0;
+	hash->hashsize = hashsize;
+	hash->table = calloc(hashsize, sizeof(struct tgthead *));
+	for (i = 0; i < hashsize; i++) {
+		hash->table[i] = malloc(sizeof(struct tgthead));
+		RTGLL_INIT(hash->table[i]);
 	}
-#else
-	hash.table = calloc(HASHSIZE, sizeof(target_t *));
-#endif
-	debug(LOW, "Initialize hash table pointers: %d bytes.\n",
-		HASHSIZE * sizeof(target_t *));
+	debug(LOW, "Hashtable allocated: %u buckets, %d bytes.\n",
+		hashsize, (hashsize * sizeof(struct tgthead)) +
+			  (hashsize * sizeof(struct tgthead *)));
+	tgthash_init_walk(hash);
 }
 
-
-void init_hash_walk() {
-	hash.bucket = 0;
-	hash.target = hash.table[hash.bucket];
+void
+tgthash_init_walk(struct tgthash *hash)
+{
+	hash->bucket = 0;
+	hash->target = RTGLL_FIRST(hash->table[0]);
 }
 
+target_t *
+tgthash_next(struct tgthash *hash)
+{
+	target_t *new;
 
-target_t *getNext() {
-	target_t *next = NULL;
-
-	while (!(hash.target)) {
-		(hash.bucket)++;
-		if (hash.bucket >= HASHSIZE) 
-			return NULL;
-		hash.target = hash.table[hash.bucket];	
+	while (hash->target == NULL) {
+		if (++(hash->bucket) == hash->hashsize) 
+			return (NULL);
+		if (RTGLL_EMPTY(hash->table[hash->bucket]))
+			continue;
+		hash->target = RTGLL_FIRST(hash->table[hash->bucket]);
 	}
-	next = hash.target;
-	hash.target = (hash.target)->next;
-	return next;
+	new = hash->target;
+	hash->target = RTGLL_NEXT(new, next);
+	return (new);
 }
 
-
 /* Free hash table memory */
-#if !NEW_TARGET_FORMAT
-void free_hash() {
-#else
-static void free_hash() {
-#endif
-	target_t *ptr = NULL;
-	target_t *f = NULL;
-	int i;
+static void
+tgthash_free(struct tgthash *hash)
+{
+	target_t *ptr = NULL, *f = NULL;
+	unsigned int i;
 
-	for(i=0;i<HASHSIZE;i++) {
-		ptr = hash.table[i];
-		while (ptr) {
-			f = ptr;
-			ptr = ptr->next;
-#if NEW_TARGET_FORMAT
-			if (f->host != NULL) {
-				free(f->host);
-			}
-#endif
-			free(f);	
+	for (i = 0; i < hash->hashsize; i++) {
+		struct tgthead *tbl = hash->table[i];
+		RTGLL_FOREACH_SAFE(ptr, tbl, next, f) {
+			RTGLL_REMOVE(tbl, ptr, target_struct, next);
+			free(ptr);	
 		}	
 	}
 }
 
-
 /* Hash the target */
-#if !NEW_TARGET_FORMAT
-unsigned long make_key(const void *entry) {
-#else
-static unsigned long make_key(const void * entry) {
-#endif
-	const target_t *t = (const target_t *) entry;
-	const char *h = (const char *) t->host;
-	const char *o = (const char *) t->objoid;
+static unsigned long
+make_key(target_t *t)
+{
 	unsigned long hashval;
 
-    if (!h) return 0;
-
-	for (hashval = 0; *o != '\0'; o++)
-		hashval = (((unsigned int) *o) | 0x20) + 31 * hashval;
-	for (;*h != '\0'; h++)
-		hashval = (((unsigned int) *h) | 0x20) + 31 * hashval;
-    
-    return (hashval % HASHSIZE);
+	hashval = fnv_32_str(t->host->s->peername, FNV1_32_INIT);
+	if (t->description)
+		hashval = fnv_32_str(t->description, hashval);
+	hashval = fnv_32_str(t->objoid, hashval);
+	return (fnv_32_str(t->dbt->table, hashval));
 }
 
-
 /* Set state of all targets to state - used on init, update targets, etc */ 
-#if !NEW_TARGET_FORMAT
-void mark_targets(int state) {
-#else
-static void mark_targets(int state) {
-#endif
+static unsigned int
+mark_targets(struct tgthash *hash, enum targetState state)
+{
 	target_t *p = NULL;
-	int i = 0;
+	unsigned int i, x = 0;
 
-	for (i=0;i<HASHSIZE;i++) {
-		p = hash.table[i];
-		while (p) {
+	for (i = 0; i < hash->hashsize; i++) {
+		RTGLL_FOREACH(p, hash->table[i], next) {
 			p->init = state;
-			p = p->next;
+			x++;
 		}
 	}
+	return (x);
 }
 
-
 /* Delete targets marked with state = state */
-#if !NEW_TARGET_FORMAT
-int delete_targets(int state) {
-#else
-static unsigned int delete_targets(int state) {
-#endif
-	target_t *p = NULL;
-	target_t *d = NULL;
-	int i = 0;
-#if !NEW_TARGET_FORMAT
-	int entries = 0;
-#else
-	unsigned int deleted = 0;
-#endif
+unsigned int
+delete_targets(struct tgthash *hash, enum targetState state)
+{
+	target_t *p, *d;
+	unsigned int i, deleted = 0;
 
-	for (i=0;i<HASHSIZE;i++) {
-		p = hash.table[i];
-		while (p) {
-			d = p;
-			p = p->next;
-			if (d->init == state) {
-				del_hash_entry(d);
-#if !NEW_TARGET_FORMAT
-				entries++;
-#else
+	for (i = 0; i < hash->hashsize; i++) {
+		struct tgthead *tbl = hash->table[i];
+		RTGLL_FOREACH_SAFE(p, tbl, next, d) {
+			if (p->init != state)
+				continue;
+			if (tgthead_delete(tbl, p)) {
+				hash->entries--;
 				deleted++;
-#endif
 			}
 		}
 	}
-#if !NEW_TARGET_FORMAT
-	return entries;
-#else
-	return deleted;
-#endif
+	return (deleted);
 }
 
-
-/* Dump the entire target hash [sequential num/bucket number] */
-#if !NEW_TARGET_FORMAT
-void walk_target_hash() {
-#else
-static void walk_target_hash() {
-#endif
-	target_t *p = NULL;
-	int targets = 0;
-	int i = 0;
+/* Dump the entire target hash */
+void
+walk_target_hash(struct tgthash *hash)
+{
+	target_t *p;
+	unsigned int i, targets = 0;
 	
-    printf("Dumping Target List:\n");
-	for (i=0;i<HASHSIZE;i++) {
-		p = hash.table[i];
-		while (p) {
-#if NEW_TARGET_FORMAT
-			printf("[%d/%d]: %s %s %d %s %s %d\n", targets, i,
-				p->host->host, p->objoid, p->bits,
-				p->host->community, p->table, p->iid);
-#else
-			printf("[%d/%d]: %s %s %d %s %s %d\n", targets, i, p->host,
-				p->objoid, p->bits, p->community, p->table, 
-				p->iid);
-#endif
-			targets++;
-			p = p->next;
+	fprintf(dfp, "Dumping Target List:\n");
+	for (i=0; i < hash->hashsize; i++) {
+		RTGLL_FOREACH(p, hash->table[i], next) {
+			fprintf(dfp, "[%d/%d]: %01x/%s/%s/%d/%s/%s/%d/%lld\n",
+				++targets, i, p->init, p->host->s->peername,
+				p->objoid, p->bits, p->host->s->community,
+				p->dbt->table, p->iid, p->maxspeed);
 		}
 	}
-    printf("Total of %u targets [%u bytes of memory].\n",
-	   targets, targets * sizeof(target_t));
+	fprintf(dfp, "Total of %u targets [%u bytes of memory].\n",
+		targets, targets * sizeof(target_t));
 }
 
+/* return ptr to target if the entry exists in the named list */
+static target_t *
+in_hash(struct tgthead *table, target_t *entry)
+{
+	target_t *p = NULL;
 
-/* return ptr to target if the entry exists in the named list */
-#if !NEW_TARGET_FORMAT
-void *in_hash(target_t *entry, target_t *list) {
-#else
-static void *in_hash(target_t *entry, target_t *list) {
-#endif
-	while (list) {
-		if (compare_targets(entry, list)) {
-			debug(HIGH, "Found existing %s %s %s %d\n", list->host,
-				list->objoid, list->table, list->iid);
-			return list;
-		}
-		list = list->next;
+	RTGLL_FOREACH(p, table, next) {
+		if (p == entry)
+			return (p);
+		if (compare_targets(p, entry) == FALSE)
+			continue;
+		return (p);
 	}
-	return NULL;
+	return (NULL);
 }
 
+/* TRUE if target 1 == target 2 */
+static int
+compare_targets(target_t *t1, target_t *t2)
+{
 
-/* TRUE if target 1 == target 2 */
-#if !NEW_TARGET_FORMAT
-int compare_targets(target_t *t1, target_t *t2) {
-	if (!strcmp(t1->host, t2->host) &&
-		!strcmp(t1->objoid, t2->objoid) &&
-		!strcmp(t1->table, t2->table) &&
-		!strcmp(t1->community, t2->community) &&
-		(t1->iid == t2->iid)) 
-			return TRUE;
-#else
-static int compare_targets(target_t *t1, target_t *t2) {
-	if (!strcmp(t1->host->host, t2->host->host) &&
-		!strcmp(t1->objoid, t2->objoid) &&
-		!strcmp(t1->table, t2->table) &&
-		!strcmp(t1->host->community, t2->host->community) &&
-		(t1->iid == t2->iid)) 
-			return TRUE;
-#endif
-	return FALSE;
+	debug(DEVELOP, "compare: %p=%p %p=%p %u=%u %s=%s\n",
+	      t1->host, t2->host, t1->dbt, t2->dbt, t1->iid, t2->iid,
+	      t1->objoid, t2->objoid);
+	if ((t1->iid != t2->iid) ||
+	    (t1->host != t2->host) ||
+	    (t1->dbt != t2->dbt) ||
+	    (strcmp(t1->objoid, t2->objoid) != 0)) {
+			return (FALSE);
+	}
+	return (TRUE);
 }
 
-
 /* Remove an item from the list.  Returns TRUE if successful. */
-int del_hash_entry(target_t *new) {
-    target_t *p = NULL;
-    target_t *prev = NULL;
-	unsigned int key;
+static int
+tgthead_delete(struct tgthead *tblhead, target_t *del)
+{
+	target_t *p;
 
-	key = make_key(new);
-#if !NEW_TARGET_FORMAT
-	if (!in_hash(new, hash.table[key]))
-		return FALSE;
-#else
-	if(in_hash(new, hash.table[key]) == NULL)
-		return FALSE;
-#endif
+	p = in_hash(tblhead, del);
+	if (p == NULL)
+		return (FALSE);
 	
-	p = hash.table[key];
-	/* assert(p != NULL) */
-	while (p) {
-		if (compare_targets(p, new)) {
-			/* if successor, we need to point predecessor to it (if exists) */
-			if (p->next) {
-				/* there is a predecessor */
-				if (prev) 
-					prev->next = p->next;
-				/* there is no predecessor */
-				else 
-					hash.table[key] = p->next;
-			}
-			/* no successor, delete just this target */
-			else {
-				if (prev) 
-					prev->next = NULL;
-				else 
-					hash.table[key] = NULL;
-			}
-			free (p);
-			return TRUE;
-		}
-		prev = p;
-		p = p->next;
-	}	
-	return FALSE;
+	RTGLL_REMOVE(tblhead, p, target_struct, next);
+	dbtable_decrement(p->dbt);
+	host_decrement(p->host);
+	free(p->description);
+	free(p->objoid);
+	free(p->oid);
+	free(p);
+
+	return (TRUE);
 }
 
-
 /* Add an entry to hash if it is unique, otherwise free() it */
-int add_hash_entry(target_t *new) {
-    target_t *p = NULL;
-	unsigned int key;
+int
+tgthash_insert(struct tgthash *hash, target_t *new)
+{
+	struct tgthead *head; 
+	target_t *p;
 
-	key = make_key(new);
-#if !NEW_TARGET_FORMAT
-	p = hash.table[key];
-#endif
-
-	p = in_hash(new, hash.table[key]);
-	if (p) {
+	head = hash->table[make_key(new) % hash->hashsize];
+	if ((p = in_hash(head, new)) != NULL) {
 		p->init = LIVE;
 		free(new);
-		return FALSE;
+		return (FALSE);
 	} 
 
-	if (!hash.table[key]) {
-		hash.table[key] = new;
-	} else {
-		p = hash.table[key];
-		while (p->next) p = p->next;
-		p->next = new;
-	}
-#if NEW_TARGET_FORMAT
-	entries++;
-#endif
-	return TRUE;
+	new->init = NEW;
+	if (!rtg_read_objid(new))
+		return (FALSE);
+	if (new->maxspeed == 0)
+		new->maxspeed = DEFAULT_OUT_OF_RANGE;
+	RTGLL_INSERT_HEAD(head, new, next);
+	hash->entries++;
+	new->host->refcnt++;
+	return (TRUE);
 }
 
-
 /* Read a target file into a target_t hash table. 
- * Our hash algorithm roughly randomizes targets, easing SNMP load
+ * The fnv hash algorithm effectively randomizes targets, easing SNMP load
  * on end devices during polling.
  * hash_target_file() can be called again to update the target
  * hash.  If hash_target_file() finds new target entries in the file, it
- * adds them to the hash via add_hash_entry().
- * If hash_target_file() finds entries in hash but not in file,
- * it removes said entries from hash via delete_targets().
- * The return values of the addition/deletion functions are then
- * added to/subtracted from the static integer 'entries' which keeps a running
- * count of the total number of targets being polled since the start of rtgpoll.
+ * adds them to the hash via tgthash_insert().
+ * If hash_target_file() finds stale entries in the hash,
+ * it removes those entries from the hash via delete_targets().
  */
-int hash_target_file(char *file) {
-#if !NEW_TARGET_FORMAT
-    FILE *fp;
-    target_t *new = NULL;
-    char buffer[BUFSIZE];
-    static int entries = 0;
-    int removed = 0;
-    char maxspeed[30];
-#else
-    unsigned int removed = 0;
-#endif
+unsigned int
+hash_target_file(char *file)
+{
+	unsigned int removed;
 
-    /* Open the target file */
-#if !NEW_TARGET_FORMAT
-	if ((fp = fopen(file, "r")) == NULL) {
-#else
+	if (file == NULL) {
+		fprintf(stderr, "targets file must be provided.\n");
+		return (0);
+	}
 	if ((yyin = fopen(file, "r")) == NULL) {
-#endif
-		fprintf(stderr, "\nCould not open %s for reading.\n", file);
-		return (-1);
+		fprintf(stderr, "Could not open %s for reading.\n", file);
+		return (0);
 	} 
+	removed = delete_targets(thash, ERR);
+	mark_targets(thash, STALE);
 	debug(LOW, "Reading RTG target list [%s].\n", file);
+	yyparse();
+	fclose(yyin);
+	removed += delete_targets(thash, STALE);
+	debug(LOW, "Successfully hashed [%u] targets, (%u bytes).\n",
+		thash->entries, thash->entries * sizeof(target_t));
+	if (removed)
+		debug(LOW, "Removed [%u] stale targets from hash.\n", removed);
+	if (set.verbose >= DEBUG)
+		walk_target_hash(thash);
+	return (thash->entries);
+}
+
+struct host_struct *
+host_insert(struct config_snmphost *c)
+{
+	struct host_struct *thst;
+
+	RTGLL_FOREACH(thst, &host_h, next) {
+		if (snmp_comparehost(thst->s, c))
+			return (thst);
+	}
+	thst = malloc(sizeof(struct host_struct));
+	debug(DEVELOP, "inserting host %s (%p)\n", c->host, thst);
+	thst->refcnt = 1;
+	snmp_confighost(thst, c);
+	if (pthread_mutex_init(&thst->mutex, NULL))
+		fatal("cannot init mutex for %s\n", c->host);
+	RTGLL_INSERT_HEAD(&host_h, thst, next);
+	hosts++;
+	return (thst);
+}
+
+static void
+host_decrement(struct host_struct *dhst)
+{
+
+	if (--(dhst->refcnt))
+		return;
+
+	RTGLL_REMOVE(&host_h, dhst, host_struct, next);
+	if (pthread_mutex_destroy(&dhst->mutex))
+		fatal("cannot destroy mutex for %s", dhst->s->peername);
+	free(dhst->s->peername);
+	free(dhst->s->community);
+	free(dhst->s);
+	free(dhst);
+	hosts--;
+}
+
+unsigned int
+host_count(void)
+{
+
+	return (hosts);
+}
+
+struct dbtable_struct *
+dbtable_insert(const char *ntable)
+{
+	struct dbtable_struct *tdbt;
+
+	RTGLL_FOREACH(tdbt, &dbtable_h, next) {
+		if (strcmp(tdbt->table, ntable))
+			continue;
+		tdbt->refcnt++;
+		return (tdbt);
+	}
+	tdbt = malloc(sizeof(struct dbtable_struct));
+	tdbt->table = strdup(ntable);
+	tdbt->sbuf = sqlbuf_create(ntable);
+	tdbt->refcnt = 1;
+	if (pthread_mutex_init(&tdbt->mutex, NULL))
+		fatal("cannot init mutex for %s\n", ntable);
+	RTGLL_INSERT_HEAD(&dbtable_h, tdbt, next);
+	return (tdbt);
+}
 
-	mark_targets(STALE);
-#if !NEW_TARGET_FORMAT
-    /* Read each unique target into hash table */
-	while (!feof(fp)) {
-		fgets(buffer, BUFSIZE, fp);
-		if (!feof(fp) && buffer[0] != '#' && buffer[0] != ' ' && buffer[0] != '\n') {
-			new = (target_t *) malloc(sizeof(target_t));
-			if (!new) 
-				fatal("Fatal target malloc error!\n");
-			sscanf(buffer, "%64s %128s %hu %64s %64s %d %30s",
-			       new->host, new->objoid, &(new->bits),
-			       new->community, new->table,
-			       &(new->iid), maxspeed);
-			if (alldigits(maxspeed)) {
-#ifdef HAVE_STRTOLL
-				new->maxspeed = strtoll(maxspeed, NULL, 0);
-#else
-				new->maxspeed = strtol(maxspeed, NULL, 0);
-#endif
-			} else {
-				new->maxspeed = set.out_of_range;
-			}
-			debug(DEBUG, "Host[OID][OutOfRange]:%s[%s][%lld]\n",
-				new->host, new->objoid, new->maxspeed);
-			new->init = NEW;
-			new->last_value = 0;
-			new->next = NULL;
-			entries += add_hash_entry(new);
-		}
+static void
+dbtable_decrement(struct dbtable_struct *dtbl)
+{
+
+	if (--(dtbl->refcnt)) {
+		sqlbuf_resize(dtbl->sbuf, dtbl->refcnt);
+		return;
+	}
+	RTGLL_REMOVE(&dbtable_h, dtbl, dbtable_struct, next);
+	sqlbuf_free(dtbl->sbuf);
+	if (pthread_mutex_destroy(&(dtbl->mutex)))
+		fatal("cannot destroy mutex for %s", dtbl->table);
+	free(dtbl->table);
+	free(dtbl);
+}
+
+void
+dbtable_sqltune_all(void)
+{
+	struct dbtable_struct *tdbt;
+
+	RTGLL_FOREACH(tdbt, &dbtable_h, next) {
+		sqlbuf_resize(tdbt->sbuf, tdbt->refcnt);
 	}
-	fclose(fp);
-#else
-	yyparse();
-	fclose(yyin);
-#endif
-	removed = delete_targets(STALE);
-	entries -= removed;
-	debug(LOW, "Successfully hashed [%d] targets, (%d bytes).\n",
-		entries, entries * sizeof(target_t));
-	if (removed > 0)
-		debug(LOW, "Removed [%d] stale targets from hash.\n", removed);
-	return (entries);
 }
Index: src/rtghash.h
===========================================================================
*** /dev/null	Wed Nov  3 14:22:00 2004
--- src/rtghash.h	Wed Nov  3 14:26:18 2004
***************
*** 0 ****
--- 1,140 ----
+ /*
+  * Fowler / Noll / Vo Hash (FNV Hash)
+  * http://www.isthe.com/chongo/tech/comp/fnv/
+  *
+  * This is an implementation of the algorithms posted above.
+  * This file is placed in the public domain by Peter Wemm.
+  *
+  * $FreeBSD: src/sys/sys/fnv_hash.h,v 1.2 2001/03/20 02:10:18 peter Exp $
+  */
+ 
+ typedef u_int32_t Fnv32_t;
+ 
+ #define FNV1_32_INIT ((Fnv32_t) 33554467UL)
+ #define FNV_32_PRIME ((Fnv32_t) 0x01000193UL)
+ 
+ static __inline Fnv32_t
+ fnv_32_buf(const void *buf, size_t len, Fnv32_t hval)
+ {
+ 	const u_int8_t *s = (const u_int8_t *)buf;
+ 
+ 	while (len-- != 0) {
+ 		hval *= FNV_32_PRIME;
+ 		hval ^= *s++;
+ 	}
+ 	return hval;
+ }
+ 
+ static __inline Fnv32_t
+ fnv_32_str(const char *str, Fnv32_t hval)
+ {
+ 	const u_int8_t *s = (const u_int8_t *)str;
+ 	Fnv32_t c;
+ 
+ 	while ((c = *s++) != 0) {
+ 		hval *= FNV_32_PRIME;
+ 		hval ^= c;
+ 	}
+ 	return hval;
+ }
+ 
+ /*
+  * Copyright (C) 2004 bill fumerola. All rights reserved.
+  * 
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions
+  * are met:
+  * 1. Redistributions of source code must retain the above copyright
+  *    notice, this list of conditions and the following disclaimer.
+  * 2. Redistributions in binary form must reproduce the above copyright
+  *    notice, this list of conditions and the following disclaimer in the
+  *    documentation and/or other materials provided with the distribution.
+  * 
+  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+  * SUCH DAMAGE.
+  *
+  * $Yahoo: //depot/fumerola/rtg-contrib/src/rtghash.h#28 $
+  */ 
+ 
+ #include "rtglist.h"
+ 
+ struct dbtable_struct {
+ 	char *table;
+ 	unsigned int refcnt;
+ 	struct sqlbuf *sbuf;
+ 	pthread_mutex_t mutex;
+ 	RTGLL_ENTRY(dbtable_struct) next;
+ };
+ 
+ struct host_struct {
+ 	unsigned int refcnt;
+ 	struct snmp_session *s;
+ 	pthread_mutex_t mutex;
+ 	RTGLL_ENTRY(host_struct) next;
+ };
+ 
+ /* Target state */
+ enum targetState {
+ 	NEW =	0x01,	/* added but never polled */
+ 	LIVE =	0x02,	/* successfully been polled */
+ 	STALE = 0x04,	/* in memory, but not in targets file */
+ 	ERR = 	0x08,	/* poll resulted in a hard or non-transient error */
+ 	TIME =	0x10	/* poll resulted in a timeout or soft error */
+ };
+ 
+ typedef struct target_struct {
+ 	struct host_struct *host;
+ 	struct dbtable_struct *dbt;
+ 	char *description;
+ 	char *objoid;
+ 	struct rtg_oid *oid;
+ 	unsigned short bits;
+ 	unsigned int iid;
+ #ifdef HAVE_UNSIGNED_LONG_LONG
+ 	unsigned long long maxspeed;
+ 	unsigned long long last_value;
+ #else
+ 	unsigned long maxspeed;
+ 	unsigned long last_value;
+ #endif
+ 	enum targetState init;
+ #ifdef FEATURES
+ 	struct timeval last_time;
+ #endif
+ 	RTGLL_ENTRY(target_struct) next;
+ } target_t;
+ 
+ struct tgthash {
+ 	unsigned int bucket, entries, hashsize;
+ 	target_t *target;
+ 	RTGLL_HEAD(tgthead, target_struct) **table;
+ };
+ 
+ extern struct tgthash *thash;
+ 
+ struct config_snmphost {
+ 	char *host, *community;
+ 	unsigned short snmp_ver, snmp_port;
+ 	long timeout;
+ 	int retries;
+ };
+ 
+ unsigned int delete_targets(struct tgthash *hash, enum targetState state);
+ void tgthash_init(struct tgthash *hash, unsigned int hashsize);
+ void tgthash_init_walk(struct tgthash *hash);
+ target_t *tgthash_next(struct tgthash *hash);
+ int tgthash_insert(struct tgthash *hash, target_t *new);
+ unsigned int hash_target_file(char *file);
+ struct host_struct *host_insert(struct config_snmphost *c);
+ unsigned int host_count(void);
+ struct dbtable_struct *dbtable_insert(const char *ntable);
+ void dbtable_sqltune_all(void);
Index: src/rtglist.h
===========================================================================
*** /dev/null	Wed Nov  3 14:22:00 2004
--- src/rtglist.h	Wed Nov  3 14:26:18 2004
***************
*** 0 ****
--- 1,96 ----
+ /*
+  * Copyright (c) 1991, 1993
+  *	The Regents of the University of California.  All rights reserved.
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions
+  * are met:
+  * 1. Redistributions of source code must retain the above copyright
+  *    notice, this list of conditions and the following disclaimer.
+  * 2. Redistributions in binary form must reproduce the above copyright
+  *    notice, this list of conditions and the following disclaimer in the
+  *    documentation and/or other materials provided with the distribution.
+  * 4. Neither the name of the University nor the names of its contributors
+  *    may be used to endorse or promote products derived from this software
+  *    without specific prior written permission.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+  * SUCH DAMAGE.
+  *
+  *	@(#)queue.h	8.5 (Berkeley) 8/20/94
+  * $FreeBSD: src/sys/sys/queue.h,v 1.58 2004/04/07 04:19:49 imp Exp $
+  * $Yahoo: //depot/fumerola/rtg-contrib/src/rtglist.h#3 $
+  */
+ 
+ #define	RTGLL_HEAD(name, type)						\
+ struct name {								\
+ 	struct type *rlh_first;	/* first element */			\
+ }
+ 
+ #define	RTGLL_HEAD_INITIALIZER()					\
+ 	{ NULL }
+ 
+ #define	RTGLL_ENTRY(type)						\
+ struct {								\
+ 	struct type *rle_next;	/* next element */			\
+ }
+ 
+ #define	RTGLL_EMPTY(head)	((head)->rlh_first == NULL)
+ 
+ #define	RTGLL_FIRST(head)	((head)->rlh_first)
+ 
+ #define	RTGLL_FOREACH(var, head, field)					\
+ 	for ((var) = RTGLL_FIRST((head));				\
+ 	    (var);							\
+ 	    (var) = RTGLL_NEXT((var), field))
+ 
+ #define	RTGLL_FOREACH_SAFE(var, head, field, tvar)			\
+ 	for ((var) = RTGLL_FIRST((head));				\
+ 	    (var) && ((tvar) = RTGLL_NEXT((var), field), 1);		\
+ 	    (var) = (tvar))
+ 
+ #define	RTGLL_FOREACH_PREVPTR(var, varp, head, field)			\
+ 	for ((varp) = &RTGLL_FIRST((head));				\
+ 	    ((var) = *(varp)) != NULL;					\
+ 	    (varp) = &RTGLL_NEXT((var), field))
+ 
+ #define	RTGLL_INIT(head) do {						\
+ 	RTGLL_FIRST((head)) = NULL;					\
+ } while (0)
+ 
+ #define	RTGLL_INSERT_AFTER(slistelm, elm, field) do {			\
+ 	RTGLL_NEXT((elm), field) = RTGLL_NEXT((slistelm), field);	\
+ 	RTGLL_NEXT((slistelm), field) = (elm);				\
+ } while (0)
+ 
+ #define	RTGLL_INSERT_HEAD(head, elm, field) do {			\
+ 	RTGLL_NEXT((elm), field) = RTGLL_FIRST((head));			\
+ 	RTGLL_FIRST((head)) = (elm);					\
+ } while (0)
+ 
+ #define	RTGLL_NEXT(elm, field)	((elm)->field.rle_next)
+ 
+ #define	RTGLL_REMOVE(head, elm, type, field) do {			\
+ 	if (RTGLL_FIRST((head)) == (elm)) {				\
+ 		RTGLL_REMOVE_HEAD((head), field);			\
+ 	} else {							\
+ 		struct type *curelm = RTGLL_FIRST((head));		\
+ 		while (RTGLL_NEXT(curelm, field) != (elm))		\
+ 			curelm = RTGLL_NEXT(curelm, field);		\
+ 		RTGLL_NEXT(curelm, field) =				\
+ 		    RTGLL_NEXT(RTGLL_NEXT(curelm, field), field);	\
+ 	}								\
+ } while (0)
+ 
+ #define	RTGLL_REMOVE_HEAD(head, field) do {				\
+ 	RTGLL_FIRST((head)) = RTGLL_NEXT(RTGLL_FIRST((head)), field);	\
+ } while (0)
Index: src/rtgmysql.c
===========================================================================
--- src/rtgmysql.c	2004/11/03 14:26:17	#3
+++ src/rtgmysql.c	2004/11/03 14:26:17
@@ -3,38 +3,25 @@
    Author:      $Author: rbeverly $
    Date:        $Date: 2004/03/07 02:53:45 $
    Purpose:     RTG MySQL routines
+   Do You:      $Yahoo$
 ****************************************************************************/
 
 #include "common.h"
 #include "rtg.h"
 
 #if HAVE_MYSQL
-extern FILE *dfp;
 
-int mysql_db_insert(char *query, MYSQL * mysql)
+int mysql_dbconnect(char *database, MYSQL * mysql)
 {
-    if (mysql_query(mysql, query)) {
-		debug(LOW, "** MySQL Error: %s\n", mysql_error(mysql));
-		return (FALSE);
-    }
-	return (TRUE);
-}
 
-
-int mysql_dbconnect(char *database, MYSQL * mysql)
-{
-    if (set.verbose >= LOW) {
-		if(set.daemon)
-			sysloginfo("Connecting to MySQL database '%s' on '%s'...", database, set.dbhost);
-		else
-			fprintf(dfp, "Connecting to MySQL database '%s' on '%s'...", database, set.dbhost);
+	debug(LOW, "Connecting to MySQL database '%s' on '%s'...", database,
+	      set.dbhost);
+	mysql_init(mysql);
+	if (!mysql_real_connect(mysql, set.dbhost, set.dbuser, set.dbpass,
+	    database, set.dbport, (set.dbsock[0]) ? set.dbsock : NULL, 0)) {
+		fprintf(dfp, "** Failed: %s\n", mysql_error(mysql));
+		return (-1);
 	}
-    mysql_init(mysql);
-    if (!mysql_real_connect
-     (mysql, set.dbhost, set.dbuser, set.dbpass, database, 0, NULL, 0)) {
-	fprintf(dfp, "** Failed: %s\n", mysql_error(mysql));
-	return (-1);
-    } else
 	return (0);
 }
 
@@ -47,10 +34,11 @@
 void mysql_close_db(void *arg)
 {
 	/* to be called from the cleanup handler */
-	if (MYSQL_VERSION_ID > 40000)
-		mysql_thread_end();
-	else
-		my_thread_end();
+#if MYSQL_VERSION_ID > 40000
+	mysql_thread_end();
+#else
+	my_thread_end();
+#endif
 	mysql_close(arg);
 }
 
Index: src/rtgplot.c
===========================================================================
--- src/rtgplot.c	2004/11/03 14:26:17	#7
+++ src/rtgplot.c	2004/11/03 14:26:17
@@ -5,6 +5,7 @@
    Description: RTG traffic grapher
                 Utilizes cgilib (http://www.infodrom.org/projects/cgilib/)
                 for the CGI interface.
+   Do You:      $Yahoo$
 ****************************************************************************/
 
 /*
@@ -54,12 +55,10 @@
 #include "rtgplot.h"
 #include "cgi.h"
 
-#if NEW_TARGET_FORMAT
 config_t set;
 int lock;
 int waiting;
 char config_paths[CONFIG_PATHS][BUFSIZE];
-#endif
 
 /* dfp is a debug file pointer.  Points to stderr unless debug=level is set */
 FILE *dfp = NULL;
@@ -157,7 +156,7 @@
 
 	bzero(&arguments, sizeof(arguments_t));
 	bzero(&graph, sizeof(graph_t));
-	config_defaults(&set);
+	config_defaults();
 	sizeDefaults(&graph);
 
 	/* Called from the command line with arguments */
@@ -172,20 +171,15 @@
 
 	/* Read configuration file to establish local environment */
 	if (arguments.conf_file) {
-		if ((read_rtg_config(arguments.conf_file, &set)) < 0) 
+		if ((read_rtg_config(arguments.conf_file)) < 0) 
 			fatalfile(dfp, "Could not read config file: %s\n", arguments.conf_file);
 	} else {
 		arguments.conf_file = malloc(BUFSIZE);
 		for (i = 0; i < CONFIG_PATHS; i++) {
-			snprintf(arguments.conf_file, BUFSIZE, "%s%s", config_paths[i], DEFAULT_CONF_FILE);
-			if (read_rtg_config(arguments.conf_file, &set) >= 0) {
+			snprintf(arguments.conf_file, BUFSIZE, "%s%s",
+			    config_paths[i], DEFAULT_CONF_FILE);
+			if (read_rtg_config(arguments.conf_file) == 0)
 				break;
-			}
-			if (i == CONFIG_PATHS - 1) {
-				snprintf(arguments.conf_file, BUFSIZE, "%s%s", config_paths[0], DEFAULT_CONF_FILE);
-				if ((write_rtg_config(arguments.conf_file, &set)) < 0) 
-					fatalfile(dfp, "Couldn't write config file.\n");
-			}
 		}
 	}
 
@@ -396,7 +390,7 @@
 	fprintf(dfp, "Dumping data:\n");
 	entry = head;
 	while (entry != NULL) {
-		fprintf(dfp, "  [%d] Count: %lld TS: %ld Rate: %2.3f X: %d Y: %d\n",
+		fprintf(dfp, "  [%d] Count: %llu TS: %ld Rate: %2.3f X: %d Y: %d\n",
 		       ++i, entry->counter, entry->timestamp, entry->rate,
 		       entry->x, entry->y);
 		entry = entry->next;
@@ -459,17 +453,17 @@
 			fprintf(dfp, "  Fatal malloc error in populate.\n");
 		/* Seems atoll is not very portable, nor desirable */
 		/* new->counter = atoll(row[0]); */
-#ifdef HAVE_STRTOLL
+#ifdef HAVE_STRTOULL
 #if HAVE_MYSQL
-		new->counter = strtoll(row[0], NULL, 0);
+		new->counter = strtoull(row[0], NULL, 0);
 #elif HAVE_PGSQL
-		new->counter = strtoll(PQgetvalue(result, i, 0), NULL, 0);
+		new->counter = strtoull(PQgetvalue(result, i, 0), NULL, 0);
 #endif
 #else
 #if HAVE_MYSQL
-		new->counter = strtol(row[0], NULL, 0);
+		new->counter = strtoul(row[0], NULL, 0);
 #elif HAVE_PGSQL
-		new->counter = strtol(PQgetvalue(result, i, 0), NULL, 0);
+		new->counter = strtoul(PQgetvalue(result, i, 0), NULL, 0);
 #endif
 #endif
 #if HAVE_MYSQL
@@ -1201,7 +1195,7 @@
 }
 
 
-#ifdef HAVE_STRTOLL
+#ifdef HAVE_LONG_LONG
 //long long intSpeed(MYSQL *mysql, int iid) {
 long long intSpeed(void *sql, int iid) {
 #else
Index: src/rtgplot.h
===========================================================================
--- src/rtgplot.h	2004/11/03 14:26:17	#5
+++ src/rtgplot.h	2004/11/03 14:26:17
@@ -47,7 +47,11 @@
 
 /* Populate a data_t per item to plot */
 typedef struct data_struct {
-    long long counter;		// interval sample value
+#ifdef HAVE_UNSIGNED_LONG_LONG
+    unsigned long long counter;	// interval sample value
+#else
+    unsigned long counter;
+#endif
     unsigned long timestamp;	// UNIX timestamp
     float rate;			// floating point rate
     int x;			// X plot coordinate
@@ -57,7 +61,11 @@
 
 /* If calculating rate, a rate_t stores total, max, avg, cur rates */
 typedef struct rate_struct {
+#ifdef HAVE_UNSIGNED_LONG_LONG
     unsigned long long total;
+#else
+    unsigned long total;
+#endif
     float max;
     float avg;
     float cur;
@@ -184,7 +192,7 @@
 void init_colors(gdImagePtr *, color_t **);
 void calculate_rate(data_t **, rate_t *, int);
 void calculate_total(data_t **, rate_t *, int);
-#ifdef HAVE_STRTOLL
+#ifdef HAVE_LONG_LONG
 long long intSpeed(void *, int);
 #else
 long intSpeed(void *, int);
Index: src/rtgpoll.c
===========================================================================
--- src/rtgpoll.c	2004/11/03 14:26:17	#5
+++ src/rtgpoll.c	2004/11/03 14:26:17
@@ -3,35 +3,41 @@
    Author:      $Author: cbrotsos $
    Date:        $Date: 2004/08/25 19:22:33 $
    Description: RTG SNMP get dumps to MySQL database
+   Do You:      $Yahoo$
 ****************************************************************************/
 
 #define _REENTRANT
 #include "common.h"
 #include "rtg.h"
+#include "rtghash.h"
+#include "rtgsqlbuf.h"
+#include "rtgsnmp.h"
 
 /* Yes.  Globals. */
 stats_t stats =
-{PTHREAD_MUTEX_INITIALIZER, 0, 0, 0, 0, 0, 0, 0, 0, 0.0};
-char *target_file = NULL;
-target_t *current = NULL;
-char *pid_file = PIDFILE;
-#ifndef FEATURES
-  #if HAVE_MYSQL
-  MYSQL mysql;
-  #endif
+{ PTHREAD_MUTEX_INITIALIZER, 0, 0, 0, 0, 0, 0, 0, 0,
+#ifdef FEATURES
+	0, 0,
 #endif
-int entries = 0;
+	0.0 };
 
-#if NEW_TARGET_FORMAT
+target_t *current = NULL;
 config_t set;
-int lock;
-int waiting;
 char config_paths[CONFIG_PATHS][BUFSIZE];
-#endif
 
 /* dfp is a debug file pointer.  Points to stderr unless debug=level is set */
 FILE *dfp = NULL;
 
+/* Yes. File-scoped statics. */
+static char *pid_file;
+static char *target_file = NULL;
+static int waiting;
+static int lock;
+static unsigned int hashsize = 10000U;
+static void print_stats(void);
+#if HAVE_MYSQL
+static MYSQL dbh_mysql;
+#endif
 
 /* Main rtgpoll */
 int main(int argc, char *argv[]) {
@@ -41,23 +47,17 @@
     struct timeval now;
     double begin_time, end_time, sleep_time;
     char *conf_file = NULL;
-    char errstr[BUFSIZE];
-    int ch, i;
+    int ch;
+    unsigned int i;
 
-	dfp = stderr;
-
-    /* Check argument count */
-    if (argc < 3)
-	usage(argv[0]);
+    dfp = stderr;
+    pid_file = PIDFILE;
 
 	/* Set default environment */
-    config_defaults(&set);
-#if NEW_TARGET_FORMAT
-    init_hash();
-#endif
+    config_defaults();
 
     /* Parse the command-line. */
-    while ((ch = getopt(argc, argv, "c:dhmDt:vz")) != EOF)
+    while ((ch = getopt(argc, argv, "c:dhmDs:t:vz")) != EOF) {
 	switch ((char) ch) {
 	case 'c':
 	    conf_file = optarg;
@@ -79,6 +79,9 @@
 	case 'p':
 	    pid_file = optarg;
 	    break;
+	case 's':
+	    hashsize = atoi(optarg);
+	    break;
 	case 't':
 	    target_file = optarg;
 	    break;
@@ -88,16 +91,23 @@
 	case 'z':
 	    set.withzeros = TRUE;
 	    break;
+	default:
+	    usage(argv[0]);
+	    break;
 	}
+    }
 
 	debug(LOW, "RTG version %s starting.\n", VERSION);
 
 	if (set.daemon) {
 		if (daemon_init() < 0)
 			fatal("Could not fork daemon!\n");
-		debug(LOW, "Daemon detached\n");
+		debug(HIGH, "Daemon detached\n");
 	}
 
+	thash = malloc(sizeof(struct tgthash));
+	tgthash_init(thash, hashsize);
+	sqlbuf_init();
 
     /* Initialize signal handler */
     sigemptyset(&signal_set);
@@ -110,77 +120,61 @@
 	if (!set.multiple) 
 		checkPID(pid_file);
 
-    if (pthread_sigmask(SIG_BLOCK, &signal_set, NULL) != 0)
-		printf("pthread_sigmask error\n");
+	if (pthread_sigmask(SIG_BLOCK, &signal_set, NULL) != 0)
+		fatalfile(dfp, "pthread_sigmask error\n");
 
     /* Read configuration file to establish local environment */
     if (conf_file) {
-      if ((read_rtg_config(conf_file, &set)) < 0) 
-		fatal("Could not read config file: %s\n", conf_file);
+      if ((read_rtg_config(conf_file)) < 0) 
+		fatalfile(dfp, "Could not read config file: %s\n", conf_file);
     } else {
       conf_file = malloc(BUFSIZE);
       if (!conf_file) 
          fatal("Fatal malloc error!\n");
       for(i=0;i<CONFIG_PATHS;i++) {
         snprintf(conf_file, BUFSIZE, "%s%s", config_paths[i], DEFAULT_CONF_FILE); 
-        if (read_rtg_config(conf_file, &set) >= 0)
+        if (read_rtg_config(conf_file) == 0)
            break;
-        if (i == CONFIG_PATHS-1) {
-			snprintf(conf_file, BUFSIZE, "%s%s", config_paths[0], DEFAULT_CONF_FILE); 
-			if ((write_rtg_config(conf_file, &set)) < 0) 
-				fatal("Couldn't write config file.\n");
-        }
       }
     }
 
+    /* Initialize the SNMP session */
+    debug(HIGH, "Initializing SNMP.\n");
+    rtg_init_snmp();
+
     /* hash list of targets to be polled */
-	entries = hash_target_file(target_file);
-    if (entries <= 0) 
-		fatal("Error updating target list.");
+    if (!hash_target_file(target_file))
+	fatal("Error initializing target list.\n");
 
-	debug(LOW, "Initializing threads (%d).\n", set.threads);
-    pthread_mutex_init(&(crew.mutex), NULL);
-    pthread_cond_init(&(crew.done), NULL);
-    pthread_cond_init(&(crew.go), NULL);
-    crew.work_count = 0;
 
-    /* Initialize the SNMP session */
-#if NEW_TARGET_FORMAT
-	debug(LOW, "Initializing SNMP (port %d).\n", set.snmp_port);
-#else
-	debug(LOW, "Initializing SNMP (v%d, port %d).\n", 
-		set.snmp_ver, set.snmp_port);
-#endif
-    init_snmp("RTG");
-
     /* Attempt to connect to the MySQL Database */
-#ifndef FEATURES
- #if HAVE_MYSQL
-    if (!(set.dboff)) {
-		if (mysql_dbconnect(set.dbdb, &mysql) < 0) 
+#if HAVE_MYSQL
+	if (!(set.dboff)) {
+		if (mysql_dbconnect(set.dbdb, &dbh_mysql) != 0) 
 			fatal("** Database error - check configuration.\n");
-		if (!mysql_ping(&mysql))
+		if (!mysql_ping(&dbh_mysql))
 			debug(LOW, "connected.\n");
 		else
 			fatal("server not responding.\n");
-    }
- #endif
-#else
- #if HAVE_MYSQL
-	my_init();
- #endif
+		sqlbuf_db_mysql(&dbh_mysql);
+		dbtable_sqltune_all();
+	}
 #endif
 
-
-	debug(HIGH, "\nStarting threads.\n");
-    for (i = 0; i < set.threads; i++) {
+	pthread_mutex_init(&(crew.mutex), NULL);
+	pthread_cond_init(&(crew.done), NULL);
+	pthread_cond_init(&(crew.go), NULL);
+	crew.work_count = 0;
+	debug(LOW, "Initializing threads (%hu).\n", set.threads);
+	for (i = 0; i < set.threads; i++) {
 		crew.member[i].index = i;
 		crew.member[i].crew = &crew;
-		if (pthread_create(&(crew.member[i].thread), NULL, poller, (void *) &(crew.member[i])) != 0)
-			printf("pthread_create error\n");
+		if (pthread_create(&(crew.member[i].thread), NULL, poller,
+		    &(crew.member[i])))
+			fatal("pthread_create poller %u error\n", i);
 	}
-    if (pthread_create(&sig_thread, NULL, sig_handler, (void *) &(signal_set)) != 0)
-		printf("pthread_create error\n");
+	if (pthread_create(&sig_thread, NULL, sig_handler, &(signal_set)))
+		fatal("pthread_create sig_handler error\n");
 
     /* give threads time to start up */
     sleep(1);
@@ -192,62 +186,60 @@
 	lock = TRUE;
 	gettimeofday(&now, NULL);
 	begin_time = (double) now.tv_usec / 1000000 + now.tv_sec;
+        stats.round++;
 
 	PT_MUTEX_LOCK(&(crew.mutex));
-	init_hash_walk();
-	current = getNext();
-	crew.work_count = entries;
+	tgthash_init_walk(thash);
+	current = tgthash_next(thash);
+	crew.work_count = thash->entries;
 	PT_MUTEX_UNLOCK(&(crew.mutex));
 	    
-	if (set.verbose >= LOW) {
-		if (set.daemon)
-			sysloginfo("Queue ready, broadcasting thread go condition.");
-		else
-        	timestamp("Queue ready, broadcasting thread go condition.");
-	}
+	SPT("polling %u targets, %u hosts", thash->entries, host_count());
+	debug(LOW, "Queue ready (%u), broadcasting go condition.\n",
+	      crew.work_count);
 	PT_COND_BROAD(&(crew.go));
 	PT_MUTEX_LOCK(&(crew.mutex));
 	    
-	while (crew.work_count > 0) {
+	while (crew.work_count) {
 		PT_COND_WAIT(&(crew.done), &(crew.mutex));
 	}
 	PT_MUTEX_UNLOCK(&(crew.mutex));
+	if (stats.round) {
+		SPT("flushing result into database");
+		sqlbuf_flush();
+	}
 
+	lock = FALSE;
+	if (waiting) {
+		SPT("reloading %s", target_file);
+		debug(HIGH, "Processing pending SIGHUP.\n");
+		hash_target_file(target_file);
+		dbtable_sqltune_all();
+		waiting = FALSE;
+	} else if (delete_targets(thash, ERR))
+		dbtable_sqltune_all();
+
 	gettimeofday(&now, NULL);
-	lock = FALSE;
 	end_time = (double) now.tv_usec / 1000000 + now.tv_sec;
 	stats.poll_time = end_time - begin_time;
-        stats.round++;
 	sleep_time = set.interval - stats.poll_time;
 
-	if (waiting) {
-		debug(HIGH, "Processing pending SIGHUP.\n");
-	    entries = hash_target_file(target_file);
-	    waiting = FALSE;
-	}
-
-	if (set.verbose >= LOW) {
-        snprintf(errstr, sizeof(errstr), "Poll round %d complete.\n", stats.round);
-		if (set.daemon)
-			sysloginfo(errstr);
-		else
-			timestamp(errstr);
-	    print_stats(stats);
-    }
+	debug(LOW, "Poll round %d complete.\n", stats.round);
+	if (set.verbose >= LOW)
+	    print_stats();
 
 	if (sleep_time <= 0)
 	    stats.slow++;
-	else
+	else {
+	    SPT("resting after round %u", stats.round);
 	    sleepy(sleep_time);
+	}
     } /* while */
 
-#ifndef FEATURES
-  #if HAVE_MYSQL
     /* Disconnect from the MySQL Database, exit. */
     if (!(set.dboff))
-	mysql_dbdisconnect(&mysql);
-  #endif
-#endif
+	mysql_dbdisconnect(&dbh_mysql);
+
     exit(0);
 }
 
@@ -260,6 +252,7 @@
     int sig_number;
 
     while (1) {
+	SPT("signal handler [waiting]");
 	sigwait(signal_set, &sig_number);
 	switch (sig_number) {
             case SIGHUP:
@@ -267,26 +260,25 @@
                     waiting = TRUE;
                 }
                 else {
-                    entries = hash_target_file(target_file);
+		    SPT("signal handler [reading targets]");
+                    hash_target_file(target_file);
                     waiting = FALSE;
                 }
                 break;
             case SIGUSR1:
-                set.verbose++;
+		if (set.verbose < THREAD)
+			set.verbose++;
                 break;
             case SIGUSR2:
-                set.verbose--;
+		if (set.verbose > OFF)
+			set.verbose--;
                 break;
             case SIGTERM:
             case SIGINT:
             case SIGQUIT:
-				debug(LOW, "Quiting: received signal %d.\n", sig_number);
+		debug(LOW, "Quiting: received signal %d.\n", sig_number);
 
-#if HAVE_MYSQL
-  #ifndef FEATURES
-                mysql_dbdisconnect(&mysql);
-  #endif
-#endif
+                mysql_dbdisconnect(&dbh_mysql);
                 unlink(pid_file);
                 exit(1);
                 break;
@@ -295,19 +287,36 @@
 }
 
 
-void usage(char *prog)
+void
+usage(char *prog)
 {
-    printf("rtgpoll - RTG v%s\n", VERSION);
-    printf("Usage: %s [-dDmz] [-vvv] [-c <file>] -t <file>\n", prog);
-    printf("\nOptions:\n");
-    printf("  -c <file>   Specify configuration file\n");
-    printf("  -d          Disable database inserts\n");
-    printf("  -D          Act as daemon\n");
-    printf("  -t <file>   Specify target file\n");
-    printf("  -v          Increase verbosity\n");
-	printf("  -m          Allow multiple instances\n");
-    printf("  -p <file>	  Specify PID file [default /var/run/rtgpoll.pid]\n"); 
-	printf("  -z          Database zero delta inserts\n");
-    printf("  -h          Help\n");
+    fprintf(stderr, "rtgpoll - RTG v%s\n", VERSION);
+    fprintf(stderr, "Usage: %s [-dDhmz] [-vvv] [-c <file>] [-p <file>] [-s <size>] -t <file>\n",
+	   prog);
+    fprintf(stderr, "\nOptions:\n");
+    fprintf(stderr, "  -c <file>   Specify configuration file\n");
+    fprintf(stderr, "  -d          Disable database inserts\n");
+    fprintf(stderr, "  -D          Act as daemon\n");
+    fprintf(stderr, "  -h          Help\n");
+    fprintf(stderr, "  -m          Allow multiple instances\n");
+    fprintf(stderr, "  -p <file>   Specify PID file [default %s]\n", PIDFILE); 
+    fprintf(stderr, "  -s <cnt>    Buckets to allocate for targets' hash (currently: %u)\n", hashsize);
+    fprintf(stderr, "  -t <file>   Specify target file\n");
+    fprintf(stderr, "  -v          Increase verbosity\n");
+    fprintf(stderr, "  -z          Database zero delta inserts\n");
     exit(-1);
 }
+
+/* Print RTG stats */
+static void
+print_stats(void)
+{
+  debug(OFF, "[Polls = %llu] [DBInserts = %llu] [Wraps = %u] [OutOfRange = %u]\n",
+      stats.polls, stats.db_inserts, stats.wraps, stats.out_of_range);
+  debug(OFF, "[No Resp = %u] [SNMP Errs = %u] [Slow = %u] [PollTime = %2.3f%c]\n",
+      stats.no_resp, stats.errors, stats.slow, stats.poll_time, 's');
+  debug(OFF, "[Hosts = %u] [Targets = %u]\n", host_count(), thash->entries);
+#ifdef FEATURES
+  debug(OFF, "[Zero = %u] [Flatline = %u]\n", stats.zero, stats.flat);
+#endif
+}
Index: src/rtgsnmp.c
===========================================================================
--- src/rtgsnmp.c	2004/11/03 14:26:17	#4
+++ src/rtgsnmp.c	2004/11/03 14:26:17
@@ -3,10 +3,14 @@
    Author:      $Author: cbrotsos $
    Date:        $Date: 2004/04/22 18:33:54 $
    Description: RTG SNMP Routines
+   Do You:      $Yahoo$
 ****************************************************************************/
 
 #include "common.h"
 #include "rtg.h"
+#include "rtghash.h"
+#include "rtgsqlbuf.h"
+#include "rtgsnmp.h"
 
 #ifdef OLD_UCD_SNMP
  #include "asn1.h"
@@ -20,16 +24,17 @@
  #include "net-snmp-includes.h"
 #endif
 
+struct rtg_oid {
+	oid Oid[MAX_OID_LEN];
+	size_t OidLen;
+};
+
 extern target_t *current;
-extern stats_t stats;
-
-#ifndef FEATURES
-/* REB - goes away if each thread starts own DB connection */
-extern MYSQL mysql;
-#endif
 
 #ifdef FEATURES
-void cancel_lock(void *arg)
+static void cancel_lock(void *arg);
+static void
+cancel_lock(void *arg)
 {
     /* to be called from the cleanup handler */
     PT_MUTEX_UNLOCK(arg);
@@ -42,30 +47,29 @@
     crew_t *crew = worker->crew;
     target_t *entry = NULL;
     void *sessp = NULL;
-    struct snmp_session session;
     struct snmp_pdu *pdu = NULL;
     struct snmp_pdu *response = NULL;
-    oid anOID[MAX_OID_LEN];
-    size_t anOID_len = MAX_OID_LEN;
     struct variable_list *vars = NULL;
-    unsigned long long result = 0;
-    unsigned long long last_value = 0;
-    unsigned long long insert_val = 0;
-    int poll_status = 0, db_status = 0, bits = 0, init = 0;
+    struct timeval current_time;
+    struct timezone tzp;
+#ifdef HAVE_UNSIGNED_LONG_LONG
+    unsigned long long result;
+    unsigned long long last_value;
+    unsigned long long insert_val;
+#else
+    unsigned long result;
+    unsigned long last_value;
+    unsigned long insert_val;
+#endif
+    int poll_status, bits;
     char query[BUFSIZE];
-    char storedoid[BUFSIZE];
-    char result_string[BUFSIZE];
 
 #ifdef FEATURES
 	/* Per thread SQL connection testing */
-  #if HAVE_MYSQL
-	MYSQL mysql;
-  #elif HAVE_PGSQL
+  #if HAVE_PGSQL
 	PGconn *pgsql;
   #endif
 	double rate = 0;
-	struct timezone tzp;
-	struct timeval current_time;
 	struct timeval last_time;
 
 	/* for thread settings */
@@ -73,16 +77,8 @@
 #endif
 
 	debug(HIGH, "Thread [%d] starting.\n", worker->index);
-#if HAVE_MYSQL
-    if (MYSQL_VERSION_ID > 40000)
-       mysql_thread_init();
-    else 
-       my_thread_init();
-
-    pthread_cleanup_push(mysql_close_db, &mysql);
+#if HAVE_PGSQL
 
-#elif HAVE_PGSQL
-
     pthread_cleanup_push(pgsql_close_db, pgsql);
 
 #endif
@@ -92,14 +88,7 @@
 #ifdef FEATURES
 	/* Per thread MySQL connection testing */
     if (!(set.dboff)) {
-#if HAVE_MYSQL
-		if (mysql_dbconnect(set.dbdb, &mysql) < 0) 
-			fatal("** Database error - check configuration.\n");
-		if (!mysql_ping(&mysql))
-			debug(LOW, "connected.\n");
-		else
-			fatal("server not responding.\n");
-#elif HAVE_PGSQL
+#if HAVE_PGSQL
 		pgsql = PQsetdbLogin(set.dbhost, NULL, NULL, NULL, 
 					set.dbdb, set.dbuser, set.dbpass);
 		if (PQstatus(pgsql) != CONNECTION_OK) {
@@ -123,6 +112,7 @@
 #endif
 	debug(DEVELOP, "Thread [%d] locking (wait on work)\n", worker->index);
 
+	SPT("waiting for work");
 	PT_MUTEX_LOCK(&crew->mutex);
 #ifdef FEATURES
 	/* add an unlock to the cancel stack */
@@ -132,190 +122,217 @@
 	while (current == NULL) {
 		PT_COND_WAIT(&crew->go, &crew->mutex);
 	}
-	debug(DEVELOP, "Thread [%d] done waiting, received go (work cnt: %d)\n",
-		worker->index, crew->work_count);
 
-	if (current != NULL) {
-		debug(HIGH, "Thread [%d] processing %s %s (%d work units remain in queue)\n",
-			worker->index, current->host, current->objoid, crew->work_count);
-	    snmp_sess_init(&session);
-#if NEW_TARGET_FORMAT
-		if (current->host->snmp_ver == 2)
-			session.version = SNMP_VERSION_2c;
-		else
-			session.version = SNMP_VERSION_1;
-	    session.peername = current->host->host;
-	    session.community = current->host->community;
-#else
-		if (set.snmp_ver == 2)
-	      session.version = SNMP_VERSION_2c;
-		else
-	      session.version = SNMP_VERSION_1;
-	    session.peername = current->host;
-	    session.community = current->community;
-#endif
-		session.remote_port = set.snmp_port;
-	    session.community_len = strlen(session.community);
-
-	    sessp = snmp_sess_open(&session);
-	    anOID_len = MAX_OID_LEN;
+	debug(DEVELOP,
+	    "Thread [%hu] done waiting, received go (work cnt: %u)\n",
+	    worker->index, crew->work_count);
+	    entry = current;
+	    current = tgthash_next(thash);
+		debug(DEVELOP,
+		    "Thread [%d] processing %s %s (%d work units remain in queue)\n",
+		    worker->index, entry->host->s->peername, entry->objoid,
+		    crew->work_count);
+	SPT("polling %s (%s)", entry->host->s->peername, entry->objoid);
+	    sessp = snmp_sess_open(entry->host->s);
 	    pdu = snmp_pdu_create(SNMP_MSG_GET);
-	    read_objid(current->objoid, anOID, &anOID_len);
-	    entry = current;
-	    last_value = current->last_value;
+	    response = NULL;
+	    last_value = entry->last_value;
 #ifdef FEATURES
-		/* save the time so we can calculate rate */
-		last_time = current->last_time;
+	    /* save the time so we can calculate rate */
+	    last_time = entry->last_time;
 #endif
-	    init = current->init;
 	    insert_val = 0;
-	    bits = current->bits;
-	    strncpy(storedoid, current->objoid, sizeof(storedoid));
-		current = getNext();
-	}
-	debug(DEVELOP, "Thread [%d] unlocking (done grabbing current)\n", worker->index);
+	    result = 0;
+	    bits = entry->bits;
+	debug(DEVELOP, "Thread [%d] unlocking (done grabbing current)\n",
+	    worker->index);
 	PT_MUTEX_UNLOCK(&crew->mutex);
 #ifdef FEATURES
 	/* take the unlock off the cancel stack */
 	pthread_cleanup_pop(FALSE);
 #endif
 
-	snmp_add_null_var(pdu, anOID, anOID_len);
-	if (sessp != NULL) 
+	snmp_add_null_var(pdu, entry->oid->Oid, entry->oid->OidLen);
+	if (sessp != NULL) {
+	   unsigned int x;
+	   for (x = 1; pthread_mutex_trylock(&entry->host->mutex); x++)
+		   usleep(250000 / x);
 	   poll_status = snmp_sess_synch_response(sessp, pdu, &response);
-	else
+	   PT_MUTEX_UNLOCK(&entry->host->mutex);
+	} else
 	   poll_status = STAT_DESCRIP_ERROR;
 
 	/* Collect response and process stats */
 	PT_MUTEX_LOCK(&stats.mutex);
 	if (poll_status == STAT_DESCRIP_ERROR) {
+	    entry->init = ERR;
 	    stats.errors++;
-            printf("*** SNMP Error: (%s) Bad descriptor.\n", session.peername);
+            debug(LOW, "*** SNMP Error: (%s) Bad descriptor.\n",
+	       entry->host->s->peername);
 	} else if (poll_status == STAT_TIMEOUT) {
+	    if (entry->init == TIME)
+		entry->init = ERR;
+	    else
+		entry->init = TIME;
 	    stats.no_resp++;
-	    printf("*** SNMP No response: (%s@%s).\n", session.peername,
-	       storedoid);
+	    debug(LOW, "*** SNMP No response: (%s@%s).\n",
+	       entry->host->s->peername, entry->objoid);
 	} else if (poll_status != STAT_SUCCESS) {
+	    entry->init = ERR;
 	    stats.errors++;
-	    printf("*** SNMP Error: (%s@%s) Unsuccessuful (%d).\n", session.peername,
-	       storedoid, poll_status);
+	    debug(LOW, "*** SNMP Error: (%s@%s) Unsuccessful (%d).\n",
+	       entry->host->s->peername, entry->objoid, poll_status);
 	} else if (poll_status == STAT_SUCCESS && response->errstat != SNMP_ERR_NOERROR) {
+	    entry->init = ERR;
 	    stats.errors++;
-	    printf("*** SNMP Error: (%s@%s) %s\n", session.peername,
-	       storedoid, snmp_errstring(response->errstat));
+	    debug(LOW, "*** SNMP Error: (%s@%s) %s\n", entry->host->s->peername,
+	       entry->objoid, snmp_errstring(response->errstat));
 	} else if (poll_status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR && response->variables->type == SNMP_NOSUCHINSTANCE) {
+	    entry->init = ERR;
 	    stats.errors++;
-	    printf("*** SNMP Error: No Such Instance Exists (%s@%s)\n", session.peername, storedoid);
+	    debug(LOW, "*** SNMP Error: No Such Instance Exists (%s@%s)\n",
+	       entry->host->s->peername, entry->objoid);
 	} else if (poll_status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR) {
 	    stats.polls++;
-	} 
+	    if (entry->init == TIME)
+		entry->init = LIVE;
+	} else if (poll_status == STAT_ERROR) {
+	    entry->init = ERR;
+	    stats.errors++;
+	    debug(LOW, "*** SNMP Poll Error: (%s@%s) %s\n",
+		entry->host->s->peername, entry->objoid,
+		snmp_errstring(response->errstat));
+	}
 	PT_MUTEX_UNLOCK(&stats.mutex);
 
 	/* Liftoff, successful poll, process it */
-#ifdef FEATURES
+
 	/* Get the current time */
 	gettimeofday(&current_time, &tzp);
-#endif
 
-	if (poll_status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR && response->variables->type != SNMP_NOSUCHINSTANCE) {
+	if (poll_status == STAT_SUCCESS && response &&
+	    response->errstat == SNMP_ERR_NOERROR &&
+	    response->variables->type != SNMP_NOSUCHINSTANCE) {
+	    const char *d;
+	    enum debugLevel dl = DEBUG;
 	    vars = response->variables;
-#ifdef OLD_UCD_SNMP
-            sprint_value(result_string, anOID, anOID_len, vars);
-#else
-	    snprint_value(result_string, BUFSIZE, anOID, anOID_len, vars);
-#endif
 	    switch (vars->type) {
 		/*
 		 * Switch over vars->type and modify/assign result accordingly.
 		 */
 		case ASN_COUNTER64:
-		    debug(DEBUG, "64-bit result: (%s@%s) %s\n", session.peername, storedoid, result_string);
+		    d = "64-bit result: (%s@%s) %s\n";
 		    result = vars->val.counter64->high;
-		    result = result << 32;
-		    result = result + vars->val.counter64->low;
+		    result <<= 32;
+		    result += vars->val.counter64->low;
+		    if (bits != 64)
+			    debug(LOW, "%s@%s is 64 bits!\n", entry->objoid,
+				  entry->host->s->peername);
 		    break;
 		case ASN_COUNTER:
-		    debug(DEBUG, "32-bit result: (%s@%s) %s\n", session.peername, storedoid, result_string);
+		    d = "32-bit result: (%s@%s) %s\n";
+		    if (bits != 32)
+			    debug(LOW, "%s@%s is 32 bits!\n", entry->objoid,
+				  entry->host->s->peername);
 		    result = (unsigned long) *(vars->val.integer);
 		    break;
 		case ASN_INTEGER:
-		    debug(DEBUG, "Integer result: (%s@%s) %s\n", session.peername, storedoid, result_string);
+		    d = "Integer result: (%s@%s) %s\n";
+		    if (bits != 32)
+			    debug(LOW, "%s@%s is 32 bits!\n", entry->objoid,
+				  entry->host->s->peername);
 		    result = (unsigned long) *(vars->val.integer);
 		    break;
 		case ASN_GAUGE:
-		    debug(DEBUG, "32-bit gauge: (%s@%s) %s\n", session.peername, storedoid, result_string);
+		    d = "32-bit gauge: (%s@%s) %s\n";
 		    result = (unsigned long) *(vars->val.integer);
 		    break;
 		case ASN_TIMETICKS:
-		    debug(DEBUG, "Timeticks result: (%s@%s) %s\n", session.peername, storedoid, result_string);
+		    d = "Timeticks result: (%s@%s) %s\n";
 		    result = (unsigned long) *(vars->val.integer);
 		    break;
 		case ASN_OPAQUE:
-		    debug(DEBUG, "Opaque result: (%s@%s) %s\n", session.peername, storedoid, result_string);
+		    d = "Opaque result: (%s@%s) %s\n";
 		    result = (unsigned long) *(vars->val.integer);
 		    break;
 		case ASN_OCTET_STR:
-		    debug(DEBUG, "String Result: (%s@%s) %s\n", session.peername, storedoid, result_string);
-#ifdef HAVE_STRTOLL
-		    result = strtoll(vars->val.string, NULL, 0);
+		    d = "String Result: (%s@%s) %s\n";
+#ifdef HAVE_STRTOULL
+		    result = strtoull(vars->val.string, NULL, 0);
 #else
-		    result = strtol(vars->val.string, NULL, 0);
+		    result = strtoul(vars->val.string, NULL, 0);
 #endif
 		    break;
 		default:
-		    debug(LOW, "Unknown result type: (%s@%s) %s\n", session.peername, storedoid, result_string);
+		    d = "Unknown result type: (%s@%s) %s\n";
+		    dl = LOW;
+		    entry->init = ERR;
+		    result = 0;
+		    PT_MUTEX_LOCK(&stats.mutex);
+		    stats.polls--;
+		    stats.errors++;
+		    PT_MUTEX_UNLOCK(&stats.mutex);
+		    break;
+	    }
+	    if (set.verbose >= dl) {
+		char result_string[BUFSIZE];
+#ifdef OLD_UCD_SNMP
+		sprint_value(result_string, entry->oid->Oid,
+                             entry->oid->OidLen, vars);
+#else
+		snprint_value(result_string, BUFSIZE, entry->oid->Oid,
+			      entry->oid->OidLen, vars);
+#endif
+		debug(OFF, d, entry->host->s->peername, entry->objoid,
+		      result_string);
 	    }
 
-		/* Gauge Type */
-		if (bits == 0) {
-			if (result != last_value) {
+	    if (bits == 0) {
+		if (result != last_value) {
+			insert_val = result;
+			debug(HIGH,
+			    "Thread [%u]: Gauge change from %llu to %llu\n",
+			    worker->index, last_value, insert_val);
+		} else {
+			if (set.withzeros) 
 				insert_val = result;
-				debug(HIGH, "Thread [%d]: Gauge change from %lld to %lld\n", worker->index, last_value, insert_val);
-			} else {
-				if (set.withzeros) 
-					insert_val = result;
-				debug(HIGH, "Thread [%d]: Gauge steady at %lld\n", worker->index, insert_val);
-			}
-	    /* Counter Wrap Condition */
-	    } else if (result < last_value) {
-			PT_MUTEX_LOCK(&stats.mutex);
-              stats.wraps++;
-			PT_MUTEX_UNLOCK(&stats.mutex);
-	      if (bits == 32) insert_val = (THIRTYTWO - last_value) + result;
-	      else if (bits == 64) insert_val = (SIXTYFOUR - last_value) + result;
-
+			debug(HIGH, "Thread [%u]: Gauge steady at %llu\n",
+			    worker->index, insert_val);
+		}
+	    } else if (result && (result < last_value)) {
+		PT_MUTEX_LOCK(&stats.mutex);
+		stats.wraps++;
+		PT_MUTEX_UNLOCK(&stats.mutex);
+		switch (bits) {
+		case 32:
+			insert_val = (THIRTYTWO - last_value) + result;
+			break;
+		case 64:
+	      		insert_val = (SIXTYFOUR - last_value) + result;
+			break;
+		}
 #ifdef FEATURES
-			rate = insert_val / timediff(current_time, last_time);
+		rate = insert_val / timediff(current_time, last_time);
 #endif
 
-	      debug(LOW, "*** Counter Wrap (%s@%s) [poll: %llu][last: %llu][insert: %llu]\n",
-	         session.peername, storedoid, result, last_value, insert_val);
+		debug(LOW,
+		    "*** Counter Wrap (%s@%s) [poll: %llu][last: %llu][insert: %llu]\n",
+		    entry->host->s->peername, entry->objoid, result,
+		    last_value, insert_val);
 	    /* Not a counter wrap and this is not the first poll */
-	    } else if ((last_value >= 0) && (init != NEW)) {
+	    } else if (entry->init == LIVE) {
 		insert_val = result - last_value;
+#ifdef FEATURES
 
-#ifdef FEATURES
 			rate = insert_val / timediff(current_time, last_time);
 #endif
-		
-	        /* Print out SNMP result if verbose */
-	        if (set.verbose == DEBUG)
-		  printf("Thread [%d]: (%lld-%lld) = %llu\n", worker->index, result, last_value, insert_val);
-	        if (set.verbose == HIGH)
-		  printf("Thread [%d]: %llu\n", worker->index, insert_val);
-            /* last_value < 0, so this must be the first poll */
-	    } else {
-#ifdef FEATURES
-			/* set up this result for the next poll */
-			entry->last_value = result;
-#endif
-			debug(HIGH, "Thread [%d]: First Poll, Normalizing\n", worker->index);
-	    }
-
-		/* Check for bogus data, either negative or unrealistic */
-	    if (insert_val > entry->maxspeed || result < 0) {
-			debug(LOW, "*** Out of Range (%s@%s) [insert_val: %llu] [oor: %lld]\n",
-				session.peername, storedoid, insert_val, entry->maxspeed);
+		debug(DEBUG, "Thread [%u]: (%llu-%llu) = %llu\n",
+		    worker->index, result, last_value, insert_val);
+	    } else if (insert_val > entry->maxspeed) {
+			debug(LOW,
+			    "*** Out of Range (%s@%s) [insert_val: %llu] [oor: %lld]\n",
+			    entry->host->s->peername, entry->objoid,
+			    insert_val, entry->maxspeed);
 			insert_val = 0;
 #ifdef FEATURES
 			rate = 0;
@@ -325,80 +342,131 @@
 			PT_MUTEX_UNLOCK(&stats.mutex);
 	    }
 
-		if (!(set.dboff)) {
-			if ( (insert_val > 0) || (set.withzeros) ) {
-#ifndef FEATURES
-				/* MP - since we have our own database connection we don't need to lock it anymore */
-				PT_MUTEX_LOCK(&crew->mutex);
+		if (entry->init == NEW) {
+			debug(DEBUG, "Thread [%u]: First Poll, Normalizing\n",
+			    worker->index);
+			entry->init = LIVE;
+		}
+#ifdef FEATURES
+		  else if (entry->init == LIVE && insert_val == 0) {
+			PT_MUTEX_LOCK(&stats.mutex);
+			stats.zero++;
+			PT_MUTEX_UNLOCK(&stats.mutex);
+		}
 #endif
-
+		if (!(set.dboff) && (insert_val || set.withzeros)) {
 #if HAVE_MYSQL
   #if RATE_INSERT
-				snprintf(query, sizeof(query), "INSERT INTO %s (id,dtime,counter,rate) VALUES (%d, NOW(), %llu, %.6f)",
-					entry->table, entry->iid, insert_val, rate);
+			sprintf(query, "(%d,FROM_UNIXTIME(%li),%llu,%.6f),",
+			    entry->iid, current_time.tv_sec, insert_val, rate);
   #else
-				snprintf(query, sizeof(query), "INSERT INTO %s (id,dtime,counter) VALUES (%d, NOW(), %llu)",
-					entry->table, entry->iid, insert_val);
+			sprintf(query, "(%d,FROM_UNIXTIME(%li),%llu),",
+			    entry->iid, current_time.tv_sec, insert_val);
   #endif
-				db_status = mysql_db_insert(query, &mysql);
+			if (entry->dbt->sbuf != NULL)
+				sqlbuf_push(entry->dbt->sbuf, query);
 #elif HAVE_PGSQL
-				snprintf(query, sizeof(query), "INSERT INTO %s VALUES (%d, %li::abstime::timestamp, %llu, %.6f)",
-					entry->table, entry->iid, current_time.tv_sec, insert_val, rate);
-				db_status = pgsql_db_insert(query, pgsql);
+			sprintf(query,
+			    "INSERT INTO %s VALUES (%d, %li::abstime::timestamp, %llu, %.6f)",
+			    entry->dbt->table, entry->iid, current_time.tv_sec,
+			    insert_val, rate);
+			if (pgsql_db_insert(query, pgsql)) {
+				PT_MUTEX_LOCK(&stats.mutex);
+				stats.db_inserts++;
+				PT_MUTEX_UNLOCK(&stats.mutex);
+			} 
 #endif
-				debug(DEBUG, "SQL: %s\n", query);
+		} /* !dboff && (insert_val > 0 || withzeros) */
 
-#ifndef FEATURES
-				/* MP - since we have our own database connection we don't need to lock it anymore */
-				PT_MUTEX_UNLOCK(&crew->mutex);
-#endif
-
-				if (db_status) {
-					PT_MUTEX_LOCK(&stats.mutex);
-					stats.db_inserts++;
-					PT_MUTEX_UNLOCK(&stats.mutex);
-				} 
-			} /* insert_val > 0 or withzeros */	
-		} /* !dboff */
-
+		entry->last_value = result;
 	} /* STAT_SUCCESS */
 
-        if (sessp != NULL) {
+        if (sessp) {
            snmp_sess_close(sessp);
-           if (response != NULL) snmp_free_pdu(response);
+           if (response)
+		   snmp_free_pdu(response);
         }
 
-	debug(DEVELOP, "Thread [%d] locking (update work_count)\n", worker->index);
+	debug(DEVELOP, "Thread [%d] locking (update work_count)\n",
+	    worker->index);
 	PT_MUTEX_LOCK(&crew->mutex);
 	crew->work_count--;
-	/* Only if we received a positive result back do we update the
-	   last_value object */
-	if (poll_status == STAT_SUCCESS) {
-		entry->last_value = result;
-		if (init == NEW) entry->init = LIVE;
-	}
 
 #ifdef FEATURES
 	/* always update the time */
 	entry->last_time = current_time;	
 #endif
 
-	if (crew->work_count <= 0) {
-	    debug(HIGH, "Queue processed. Broadcasting thread done condition.\n");
+	if (crew->work_count == 0) {
+	    debug(HIGH, "Broadcasting thread done condition.\n");
 		PT_COND_BROAD(&crew->done);
 	}
-	debug(DEVELOP, "Thread [%d] unlocking (update work_count)\n", worker->index);
+	debug(DEVELOP, "Thread [%d] unlocking (update work_count)\n",
+	    worker->index);
 
+		fflush(NULL);
 		PT_MUTEX_UNLOCK(&crew->mutex);
     }				/* while(1) */
+#ifdef HAVE_PGSQL
     pthread_cleanup_pop(FALSE);
+#endif
 
 /* Not reached */
-#ifdef FEATURES
-  #if HAVE_MYSQL
-    /* Disconnect from the MySQL Database, exit. */
-    if (!(set.dboff))
-	mysql_dbdisconnect(&mysql);
-  #endif
-#endif
+}
+
+#define SNMPVER(ver) ((ver == 2) ? SNMP_VERSION_2c : SNMP_VERSION_1)
+#define SNMPPORT(port) ((port) ? port : DEFAULT_SNMP_PORT)
+void
+snmp_confighost(struct host_struct *thst, struct config_snmphost *c)
+{
+
+	thst->s = malloc(sizeof(struct snmp_session));
+	snmp_sess_init(thst->s);
+	thst->s->peername = c->host;
+	thst->s->community = c->community;
+	thst->s->community_len = strlen(c->community);
+	thst->s->version = SNMPVER(c->snmp_ver);
+	thst->s->remote_port = SNMPPORT(c->snmp_port);
+	thst->s->retries = c->retries;
+	thst->s->timeout = c->timeout;
+}
+
+unsigned int
+snmp_comparehost(struct snmp_session *s, struct config_snmphost *c)
+{
+
+	if ((strcmp(s->peername, c->host) != 0) ||
+	    (s->community_len != strlen(c->community)) ||
+	    (s->version != SNMPVER(c->snmp_ver)) ||
+	    (strcmp(s->community, c->community) != 0) ||
+	    (s->timeout != c->timeout) ||
+	    (s->retries != c->retries) ||
+	    (s->remote_port != SNMPPORT(c->snmp_port)))
+		return (FALSE);
+
+	return (TRUE);
+}
+#undef SNMPVER
+#undef SNMPPORT
+
+void
+rtg_init_snmp(void)
+{
+
+	init_snmp("RTG");
+}
+
+unsigned int
+rtg_read_objid(struct target_struct *t)
+{
+
+	t->oid = malloc(sizeof(struct rtg_oid));
+	t->oid->OidLen = MAX_OID_LEN;
+	if (!read_objid(t->objoid, t->oid->Oid, &t->oid->OidLen)) {
+		debug(LOW, "cannot parse %s\n", t->objoid);
+		free(t->oid);
+		return (0);
+	}
+
+	return (1);
 }
Index: src/rtgsnmp.h
===========================================================================
*** /dev/null	Wed Nov  3 14:22:00 2004
--- src/rtgsnmp.h	Wed Nov  3 14:26:19 2004
***************
*** 0 ****
--- 1,33 ----
+ /*
+  * Copyright (C) 2004 bill fumerola. All rights reserved.
+  * 
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions
+  * are met:
+  * 1. Redistributions of source code must retain the above copyright
+  *    notice, this list of conditions and the following disclaimer.
+  * 2. Redistributions in binary form must reproduce the above copyright
+  *    notice, this list of conditions and the following disclaimer in the
+  *    documentation and/or other materials provided with the distribution.
+  * 
+  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+  * SUCH DAMAGE.
+  *
+  * $Yahoo: //depot/fumerola/rtg-contrib/src/rtgsnmp.h#3 $
+  */ 
+ 
+ void *poller(void *);
+ void rtg_init_snmp(void);
+ unsigned int snmp_comparehost(struct snmp_session *s,
+ 			      struct config_snmphost *c);
+ void snmp_confighost(struct host_struct *nhst, struct config_snmphost *c);
+ unsigned int rtg_read_objid(struct target_struct *t);
Index: src/rtgsqlbuf.c
===========================================================================
*** /dev/null	Wed Nov  3 14:22:00 2004
--- src/rtgsqlbuf.c	Wed Nov  3 14:26:19 2004
***************
*** 0 ****
--- 1,476 ----
+ /*
+  * (c) 2004 bill fumerola, yahoo!
+  * 
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions
+  * are met:
+  * 1. Redistributions of source code must retain the above copyright
+  *    notice, this list of conditions and the following disclaimer.
+  * 2. Redistributions in binary form must reproduce the above copyright
+  *    notice, this list of conditions and the following disclaimer in the
+  *    documentation and/or other materials provided with the distribution.
+  * 
+  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+  * SUCH DAMAGE.
+  *
+  * $Yahoo: //depot/fumerola/rtg-contrib/src/rtgsqlbuf.c#12 $
+  */
+ 
+ #include <mysql/errmsg.h>
+ #include "common.h"
+ #include "rtg.h"
+ #include "rtgsqlbuf.h"
+ 
+ #define	SQLBUF_TOILET	0x01
+ #define	SQLBUF_MASK	0x01
+ 
+ struct sqlbuf {
+ 	char *table;
+ 	char *buffer, *currbuf;
+ 	unsigned short flags;
+ 	unsigned int pfxlen;	/* length of query up to the values */
+ 	unsigned int currlen;	/* current length of buffer */
+ 	unsigned int datalen;	/* length of an individual datum */
+ 	unsigned int currcnt;	/* current count of datums */
+ 	unsigned int roundcnt;	/* count of possible datums per round */
+ 	RTGLL_ENTRY(sqlbuf) next;
+ 	RTGLL_ENTRY(sqlbuf) flush;
+ 	pthread_mutex_t mutex;
+ };
+ 
+ static struct {
+ 	RTGLL_HEAD(, sqlbuf) head; 
+ 	pthread_mutex_t mutex;
+ } sbufh;
+ 
+ /*
+  * sqlbufs that must to be flushed or at least resized before the next round
+  */
+ static struct {
+ 	unsigned int count;
+ 	RTGLL_HEAD(, sqlbuf) head; 
+ 	pthread_cond_t empty;
+ 	pthread_mutex_t swirl;
+ } toilet;
+ 
+ static struct {
+ #if HAVE_MYSQL
+ 	MYSQL *mysql;
+ #elif HAVE_PGSQL
+ #warning pgsql sqlbuf not yet implemented
+ #endif
+ 	pthread_mutex_t mutex;
+ } dbh;
+ 
+ static unsigned int maxbuf;
+ static enum { FLUSH_WAITING, FLUSH_SWIRLING, FLUSH_SIGNALING } flushing;
+ static pthread_t plumber_thread;
+ static void *plumber(void *arg);
+ 
+ /* sqlbuf_cfg_all(): teach all sqlbufs about table column sizes */
+ static void sqlbuf_cfg_all(void);
+ /* sqlbuf_flush1(): database-indepedent flush of the data in 'sbuf' */
+ static __inline void sqlbuf_flush1(struct sqlbuf *sbuf);
+ /* sqlbuf_flush_all(): flush all sqlbufs in system */
+ static void sqlbuf_flush_all(void);
+ /* sqlbuf_flush_mysql(): database-dependent flush of the data in 'sbuf' */
+ static void sqlbuf_flush_mysql(struct sqlbuf *sbuf, MYSQL *mysql);
+ /* sqlbuf_mysql_cfg(): configure 'sbuf' to get field info */
+ static void sqlbuf_mysql_cfg(struct sqlbuf *sbuf);
+ /* sqlbuf_realloc(): resize 'sbuf' to hold 'size' rows */
+ static int sqlbuf_realloc(struct sqlbuf *sbuf, unsigned int size);
+ /* sqlbuf_reset(): clear and forget any unflushed data in 'sbuf' */
+ static void sqlbuf_reset(struct sqlbuf *sbuf);
+ 
+ /* sqlbuf_flush1() is always called with a locked sqlbuf */
+ static __inline void
+ sqlbuf_flush1(struct sqlbuf *sbuf)
+ {
+ 
+ 	if (sbuf->currcnt == 0 || sbuf->buffer == NULL) {
+ 		debug(DEVELOP, "skipping %s with %u buffers\n", sbuf->table,
+ 		    sbuf->currcnt);
+ 		return;
+ 	}
+ 	SPT("inserting into %s", sbuf->table);
+ #if HAVE_MYSQL
+ 	sqlbuf_flush_mysql(sbuf, dbh.mysql);
+ #elif HAVE_PGSQL
+ #endif
+ 	SPT("done inserting into %s", sbuf->table);
+ }
+ 
+ /* sqlbuf_flush_mysql() is always called with a locked sqlbuf */
+ static void
+ sqlbuf_flush_mysql(struct sqlbuf *sbuf, MYSQL *mysql)
+ {
+ 	MYSQL_RES *res;
+ 	unsigned long long rows;
+ 	unsigned int myerrno;
+ 	const char *myerror;
+ 
+ 	sbuf->buffer[sbuf->currlen - 1] = '\0';
+ 	debug(DEBUG, "FLUSHING %s: %s\n", sbuf->table, sbuf->buffer);
+ 	PT_MUTEX_LOCK(&dbh.mutex);
+ 	if (mysql_query(mysql, sbuf->buffer)) {
+ 		myerrno = mysql_errno(mysql);
+ 		myerror = mysql_error(mysql);
+ 		PT_MUTEX_UNLOCK(&dbh.mutex);
+ 		switch (myerrno) {
+ 		case CR_SERVER_GONE_ERROR:
+ 		case CR_SERVER_LOST:
+ 		case CR_CONN_HOST_ERROR:
+ 			debug(LOW, "*** mysql unavailable (%u), buffering\n",
+ 			    myerrno);
+ 			/* 
+ 			 * if the allocation succeeds: tack a comma back on the
+ 			 * end of the buffer and resume queueing.
+ 			 * if the allocation fails: reset and hope for better
+ 			 * days.
+ 			 */
+ 			if (sqlbuf_realloc(sbuf, sbuf->currlen +
+ 			   (sbuf->roundcnt * sbuf->datalen * 2))) {
+ 				sbuf->buffer[sbuf->currlen - 1] = ',';
+ 				return;
+ 			}
+ 			break;
+ 		default:
+ 			debug(LOW, "*** mysql flush error %u: %s\n", myerrno,
+ 			    myerror);
+ 			break;
+ 		}
+ 		sqlbuf_reset(sbuf);
+ 		return;
+ 	}
+ 	res = mysql_store_result(mysql);
+ 	rows = mysql_affected_rows(mysql);
+ 	mysql_free_result(res);
+ 	PT_MUTEX_UNLOCK(&dbh.mutex);
+ 	if (rows) {
+ 		PT_MUTEX_LOCK(&stats.mutex);
+ 		stats.db_inserts += rows;
+ 		PT_MUTEX_UNLOCK(&stats.mutex);
+ 	}
+ 	if (sbuf->currcnt != rows) {
+ 		debug(LOW, "*** table %s: %u rows queued, inserted %llu\n",
+ 		    sbuf->table, sbuf->currcnt, rows);
+ 	}
+ 	/* 
+ 	 * shrink down buffer if we had to grow it
+ 	 * if the realloc fails, the reset will still work.
+ 	 */
+ 	if (sbuf->roundcnt < sbuf->currcnt) {
+ 		sqlbuf_realloc(sbuf, (sbuf->roundcnt * sbuf->datalen * 2) +
+ 		    sbuf->pfxlen);
+ 	}
+ 	sqlbuf_reset(sbuf);
+ }
+ 
+ static void
+ sqlbuf_flush_all(void)
+ {
+ 	struct sqlbuf *tbuf;
+ 
+ 	PT_MUTEX_LOCK(&sbufh.mutex);
+ 	RTGLL_FOREACH(tbuf, &sbufh.head, next) {
+ 		PT_MUTEX_LOCK(&tbuf->mutex);
+ 		sqlbuf_flush1(tbuf);
+ 		PT_MUTEX_UNLOCK(&tbuf->mutex);
+ 	}
+ 	PT_MUTEX_UNLOCK(&sbufh.mutex);
+ }
+ 
+ void
+ sqlbuf_free(struct sqlbuf *sbuf)
+ {
+ 
+ 	debug(DEVELOP, "SQLBUF: retiring sqlbuf %s\n", sbuf->table);
+ 	PT_MUTEX_LOCK(&sbuf->mutex);
+ 	PT_MUTEX_LOCK(&sbufh.mutex);
+ 	RTGLL_REMOVE(&sbufh.head, sbuf, sqlbuf, next);
+ 	PT_MUTEX_UNLOCK(&sbufh.mutex);
+ 	free(sbuf->table);
+ 	if (sbuf->buffer)
+ 		free(sbuf->buffer);
+ 	PT_MUTEX_UNLOCK(&sbuf->mutex);
+ 	if (pthread_mutex_destroy(&sbuf->mutex))
+ 		fatal("cannot destroy mutex for %s\n", sbuf->table);
+ 	free(sbuf);
+ }
+ 
+ struct sqlbuf *
+ sqlbuf_create(const char *table)
+ {
+ 	struct sqlbuf *tbuf = NULL;
+ 	char prefix[256];
+ 
+ 	tbuf = calloc(1, sizeof(struct sqlbuf));
+ 	tbuf->table = strdup(table);
+ 	if (tbuf == NULL)
+ 		exit(1);
+ 	tbuf->pfxlen = sprintf(prefix, "INSERT DELAYED INTO %s VALUES ", table);
+ 	if (tbuf->pfxlen == 0)
+ 		exit(1);
+ 	tbuf->buffer = strdup(prefix);
+ 	if (tbuf->buffer == NULL)
+ 		exit(1);
+ 	tbuf->currbuf = NULL;
+ 	if (pthread_mutex_init(&tbuf->mutex, NULL))
+ 		fatal("cannot init mutex for %s\n", table);
+ 	sqlbuf_reset(tbuf);
+ 	PT_MUTEX_LOCK(&sbufh.mutex);
+ 	debug(DEVELOP, "SQLBUF: inserting sqlbuf %s\n", table);
+ 	RTGLL_INSERT_HEAD(&sbufh.head, tbuf, next);
+ 	PT_MUTEX_UNLOCK(&sbufh.mutex);
+ 	if (maxbuf)
+ 		sqlbuf_mysql_cfg(tbuf);
+ 
+ 	return (tbuf);
+ }
+ 
+ /* sqlbuf_mysql_cfg() is always called with a locked sbuf */
+ static void
+ sqlbuf_mysql_cfg(struct sqlbuf *sbuf)
+ {
+ 	MYSQL_RES *mres;
+ 	MYSQL_FIELD *field;
+ 	unsigned int cnt, dlen;
+ 
+ 	if (sbuf->datalen)
+ 		return;
+ 
+ 	PT_MUTEX_LOCK(&dbh.mutex);
+ 	/* size the individual value groups */
+ 	mres = mysql_list_fields(dbh.mysql, sbuf->table, NULL);
+ 	if (mysql_errno(dbh.mysql)) {
+ 		debug(LOW, "failed to configure %s (%s), skipping\n",
+ 			   sbuf->table, mysql_error(dbh.mysql));
+ 		free(sbuf->buffer);
+ 		sbuf->buffer = NULL;
+ 		PT_MUTEX_UNLOCK(&dbh.mutex);
+ 		return;
+ 	}
+ 	dlen = 17; /*strlen("()") + strlen("FROM_UNIXTIME()")*/;
+ 	for (cnt = 0; (field = mysql_fetch_field(mres)); cnt++)
+ 		dlen += field->length + 2 /* '' */ + 1 /* , */;
+ 	mysql_free_result(mres);
+ 	PT_MUTEX_UNLOCK(&dbh.mutex);
+ 	sbuf->datalen = dlen;
+ 	sqlbuf_reset(sbuf);
+ }
+ 
+ static void
+ sqlbuf_cfg_all(void)
+ {
+ 	struct sqlbuf *tbuf;
+ 
+ 	PT_MUTEX_LOCK(&sbufh.mutex);
+ 	RTGLL_FOREACH(tbuf, &sbufh.head, next) {
+ 		PT_MUTEX_LOCK(&tbuf->mutex);
+ #if HAVE_MYSQL
+ 		sqlbuf_mysql_cfg(tbuf);
+ #elif HAVE_PGSQL
+ #endif
+ 		PT_MUTEX_UNLOCK(&tbuf->mutex);
+ 	}
+ 	PT_MUTEX_UNLOCK(&sbufh.mutex);
+ }
+ 
+ void
+ sqlbuf_init(void)
+ {
+ 
+ 	RTGLL_INIT(&sbufh.head);
+ 	RTGLL_INIT(&toilet.head);
+ 	if (pthread_mutex_init(&sbufh.mutex, NULL))
+ 		fatal("cannot init sqlbuf system mutex\n");
+ 	if (pthread_mutex_init(&toilet.swirl, NULL))
+ 		fatal("cannot init end of flush mutex\n");
+ 	if (pthread_cond_init(&toilet.empty, NULL))
+ 		fatal("cannot init toilet empty condition variable\n");
+ 	if (pthread_mutex_init(&dbh.mutex, NULL))
+ 		fatal("cannot init database handle mutex\n");
+ 	if (pthread_create(&plumber_thread, NULL, plumber, NULL))
+ 		fatal("cannot create plumber thread\n");
+ }
+ 
+ /* 
+  * run once, after sqlbuf_init() and targets have been read in to
+  * initialize database dependent system
+  */ 
+ void
+ sqlbuf_db_mysql(MYSQL *mysql)
+ {
+ 	MYSQL_RES *mres;
+ 	MYSQL_ROW row;
+ 
+ 	if (mysql_query(mysql, "show variables like 'max_allowed_packet'"))
+ 		fatal("*** max_allowed_packet err: %s\n", mysql_error(mysql));
+ 
+ 	mres = mysql_store_result(mysql);
+ 	row = mysql_fetch_row(mres);
+ 	maxbuf = atoi(row[1]);
+ 	mysql_free_result(mres);
+ 
+ 	dbh.mysql = mysql;
+ 	sqlbuf_cfg_all();
+ }
+ 
+ void
+ sqlbuf_push(struct sqlbuf *sbuf, const char *data)
+ {
+ 	size_t dlen;
+ 
+ 	if (sbuf->buffer == NULL)
+ 		return;
+ 
+ 	PT_MUTEX_LOCK(&sbuf->mutex);
+ 	dlen = strlen(data);
+ 	if ((dlen + sbuf->currlen) > maxbuf)
+ 		sqlbuf_flush1(sbuf);
+ 	bcopy(data, sbuf->currbuf, dlen);
+ 	sbuf->currbuf += dlen;
+ 	*(sbuf->currbuf) = '\0';
+ 	sbuf->currlen += dlen;
+ 	sbuf->currcnt++;
+ 	/*
+ 	 * add any buffering sqlbuf to the top of the flush queue
+ 	 */
+ 	if (sbuf->currcnt >= sbuf->roundcnt &&
+ 	    (sbuf->flags ^ SQLBUF_TOILET) &&
+ 	    !pthread_mutex_trylock(&toilet.swirl)) {
+ 		RTGLL_INSERT_HEAD(&toilet.head, sbuf, flush);
+ 		toilet.count++;
+ 		sbuf->flags |= SQLBUF_TOILET;
+ 		PT_MUTEX_UNLOCK(&toilet.swirl);
+ 	}
+ 	debug(DEVELOP, "added '%s'[%u] %s\nbuffer now '%s'[%u]\n", data, dlen,
+ 		sbuf->table, sbuf->buffer, sbuf->currlen);
+ 	PT_MUTEX_UNLOCK(&sbuf->mutex);
+ }
+ 
+ static void
+ sqlbuf_reset(struct sqlbuf *sbuf)
+ {
+ 
+ 	sbuf->currbuf = sbuf->buffer + sbuf->pfxlen;
+ 	*(sbuf->currbuf) = '\0';
+ 	sbuf->currlen = sbuf->pfxlen;
+ 	sbuf->currcnt = 0;
+ }
+ 
+ static int
+ sqlbuf_realloc(struct sqlbuf *sbuf, unsigned int size)
+ {
+ 	char *newbuf;
+ 
+ 	newbuf = realloc(sbuf->buffer, size);
+ 	if (newbuf == NULL) {
+ 		debug(LOW, "cannot reallocate memory for %s\n", sbuf->table);
+ 		return (FALSE);
+ 	}
+ 	sbuf->buffer = newbuf;
+ 	sbuf->currbuf = sbuf->buffer + sbuf->currlen;
+ 	return (TRUE);
+ }
+ 
+ void
+ sqlbuf_resize(struct sqlbuf *sbuf, unsigned int n)
+ {
+ 
+ 	if (n == 0)
+ 		return;
+ 
+ 	PT_MUTEX_LOCK(&sbuf->mutex);
+ 
+ 	if (sbuf->roundcnt == n || sbuf->buffer == NULL || sbuf->datalen == 0) {
+ 		PT_MUTEX_UNLOCK(&sbuf->mutex);
+ 		return;
+ 	}
+ 	sbuf->roundcnt = n;
+ 	/* 
+ 	 * if we're holding onto more buffers than are needed for a round
+ 	 * we cannot shrink the buffer without losing data. attempt to flush.
+ 	 * if the flush succeeds the buffer will come back resized.
+ 	 * if the flush fails, the sqlbuf will be reset and will still
+ 	 * hold as many rows as needed for the next poll round.
+ 	 *
+ 	 * if we are unable to reallocate a larger buffer, flush the buffer.
+ 	 * if the flush fails remove the sbuf for now.
+ 	 */
+ 	if (sbuf->roundcnt < sbuf->currcnt)
+ 		sqlbuf_flush1(sbuf);
+ 	else if (!sqlbuf_realloc(sbuf, sbuf->pfxlen + (sbuf->datalen * n * 2))) {
+ 		sqlbuf_flush1(sbuf);
+ 		if (sbuf->currcnt) {
+ 			syslogcrit("SQLBUF: unable to flush or resize %s\n",
+ 			    sbuf->table);
+ #if 0
+ 			sbuf->roundcnt = sbuf->currcnt;
+ 			sqlbuf_reset(sbuf);
+ #endif
+ 			sbuf->buffer = NULL;
+ 		}
+ 	}
+ 	PT_MUTEX_UNLOCK(&sbuf->mutex);
+ }
+ 
+ static void *
+ plumber(void *arg /*unused*/)
+ {
+ 
+ 	for (;;) {
+ 		SPT("waiting for sqlbufs to process");
+ 		debug(DEBUG, "PLUMB: waiting for signal\n");
+ 
+ 		PT_MUTEX_LOCK(&toilet.swirl);
+ 		flushing = FLUSH_WAITING;
+ 		while (flushing == FLUSH_WAITING)
+ 			PT_COND_WAIT(&toilet.empty, &toilet.swirl);
+ 		flushing = FLUSH_SWIRLING;
+ 		PT_MUTEX_UNLOCK(&toilet.swirl);
+ 
+ 		debug(DEBUG, "PLUMB: flushing all bufs\n");
+ 		SPT("background flushing all sqlbufs");
+ 		sqlbuf_flush_all();
+ 
+ 		PT_MUTEX_LOCK(&stats.mutex);
+ 		debug(LOW, "[DBInserts = %llu]\n", stats.db_inserts);
+ 		PT_MUTEX_UNLOCK(&stats.mutex);
+ 		pthread_testcancel();
+ 	}
+ 	/* NOTREACHED */
+ 	pthread_exit(NULL);
+ }
+ 
+ void
+ sqlbuf_flush(void)
+ {
+ 	struct sqlbuf *tbuf;
+ 
+ 	debug(THREAD, "PLUMB: flushing %u sqlbufs\n", toilet.count);
+ 	PT_MUTEX_LOCK(&toilet.swirl);
+ 	while (toilet.count) {
+ 		tbuf = RTGLL_FIRST(&toilet.head);
+ 		PT_MUTEX_LOCK(&tbuf->mutex);
+ 		sqlbuf_flush1(tbuf);
+ 		RTGLL_REMOVE_HEAD(&toilet.head, flush);
+ 		tbuf->flags &= ~SQLBUF_TOILET;
+ 		PT_MUTEX_UNLOCK(&tbuf->mutex);
+ 		toilet.count--;
+ 	}
+ 	if (flushing == FLUSH_WAITING) {
+ 		flushing = FLUSH_SIGNALING;
+ 		PT_COND_SIGNAL(&toilet.empty);
+ 	}
+ 	PT_MUTEX_UNLOCK(&toilet.swirl);
+ }
Index: src/rtgsqlbuf.h
===========================================================================
*** /dev/null	Wed Nov  3 14:22:00 2004
--- src/rtgsqlbuf.h	Wed Nov  3 14:26:19 2004
***************
*** 0 ****
--- 1,46 ----
+ /*
+  * (c) 2004 bill fumerola, yahoo!
+  * 
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions
+  * are met:
+  * 1. Redistributions of source code must retain the above copyright
+  *    notice, this list of conditions and the following disclaimer.
+  * 2. Redistributions in binary form must reproduce the above copyright
+  *    notice, this list of conditions and the following disclaimer in the
+  *    documentation and/or other materials provided with the distribution.
+  * 
+  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+  * SUCH DAMAGE.
+  *
+  * $Yahoo: //depot/fumerola/rtg-contrib/src/rtgsqlbuf.h#8 $
+  */
+ 
+ #include "rtglist.h"
+ #include "common.h"
+ 
+ struct sqlbuf;
+ 
+ /* sqlbuf_create(): allocate an sqlbuf for 'table' */
+ struct sqlbuf *sqlbuf_create(const char *table);
+ /* sqlbuf_db_mysql(): initialize system based on the connection 'mysql' */
+ void sqlbuf_db_mysql(MYSQL *mysql);
+ /* sqlbuf_flush(): flush all buffers */
+ void sqlbuf_flush(void);
+ /* sqlbuf_free(): remove 'sbuf' and free associated memory */
+ void sqlbuf_free(struct sqlbuf *sbuf);
+ /* sqlbuf_init(): initialize the sqlbuf system */
+ void sqlbuf_init(void);
+ /* sqlbuf_push(): push 'data' into 'sbuf' possibly using 'dbh' to flush */
+ void sqlbuf_push(struct sqlbuf *sbuf, const char *data);
+ /* sqlbuf_resize(): reallocate memory for a possible 'nvals' rows */
+ void sqlbuf_resize(struct sqlbuf *sbuf, unsigned int nvals);
Index: src/rtgtarg.y
===========================================================================
--- src/rtgtarg.y	2004/11/03 14:26:17	#2
+++ src/rtgtarg.y	2004/11/03 14:26:17
@@ -1,140 +1,203 @@
 %{
+/*
+ * (c) 2004 bill fumerola, yahoo!
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Yahoo$
+ */
+
+#include <err.h>
 #include "common.h"
 #include "rtg.h"
+#include "rtghash.h"
 
 int yyerror(const char *s);
 extern int yylineno, lineno;
 extern char *yytext;
 
-
-static host_t *thst;
+static struct config_snmphost thst;
+static struct host_struct *nhst;
 static target_t *ttgt;
+static struct tgthead htargets;
 
 #define YYDEBUG 1
 %}
 
 %union {
-      char *string;
-      unsigned long long number;
+	char *string;
+#ifdef HAVE_UNSIGNED_LONG_LONG
+	unsigned long long number;
+#else
+	unsigned long number;
+#endif
 }
 
-%token <string>               L_STRING
-%token <string>               L_IDENT
-%token <string>               L_IPADDR
-%token <string>               L_OID
-%token <number>               L_NUMBER
+%token <string>		L_STRING
+%token <string>		L_IDENT
+%token <string>		L_IPADDR
+%token <string>		L_OID
+%token <number>		L_NUMBER
 
 /* top level */
 %token T_HOST
 
 /* per-host */
-%token HST_COMM HST_SVER HST_TRGT
+%token HST_COMM HST_SVER HST_TRGT HST_PORT HST_TIME HST_RTRY
 
 /* per-target */
 %token TGT_BITS TGT_TBL TGT_ID TGT_SPEED TGT_DESCR
 
 %%
 
-config                :
-              | statements
-               ;
+config		:
+		| statements
+		;
 
-statements    : statements statement
-              | statement
-              ;
+statements	: statements statement
+	   	| statement
+		;
 
-statement     : host_entry
-              | error ';'
-                      { fprintf(stderr, "';' line %d\n", yylineno); yyerrok; }
-              | error '}'
-                      { fprintf(stderr, "'}' line %d\n", yylineno); yyerrok; }
-              ;
+statement	: host_entry
+	  	| error ';'
+			{ fprintf(stderr, "';' line %d\n", yylineno); yyerrok; }
+		| error '}'
+			{ fprintf(stderr, "'}' line %d\n", yylineno); yyerrok; }
+		;
 
-host_entry:   T_HOST L_IPADDR
+host_entry:	T_HOST L_IPADDR
 {
-      thst = malloc(sizeof(host_t));
-      bzero(thst, sizeof(host_t));
-      thst->host = $2;
+	bzero(&thst, sizeof(thst));
+	thst.host = $2;
+	thst.retries = 5;
+	thst.timeout = 5000000L;
+	RTGLL_INIT(&htargets);
 }
 '{' host_directives '}'
 {
-      thst = NULL;
+	nhst = host_insert(&thst);
+
+	while (!RTGLL_EMPTY(&htargets)) {
+		ttgt = RTGLL_FIRST(&htargets);
+		RTGLL_REMOVE_HEAD(&htargets, next);
+		ttgt->host = nhst;
+		tgthash_insert(thash, ttgt);
+	}
+};
+
+host_directives	: host_directives host_directive
+		| host_directive
+		;
+
+host_directive	: community_directive
+	        | sversion_directive
+		| sport_directive
+		| timeout_directive
+		| retries_directive
+		| target_entry
+		;
+
+community_directive	: HST_COMM L_IDENT
+{
+	thst.community = $2;
 };
 
-host_directives       : host_directives host_directive
-              | host_directive
-              ;
+sversion_directive	: HST_SVER L_NUMBER
+{
+	thst.snmp_ver = (unsigned short)$2;
+};
 
-host_directive        : comm_directive
-              | sver_directive
-              | target_entry
-              ;
+sport_directive		: HST_PORT L_NUMBER
+{
+	thst.snmp_port = (unsigned short)$2;
+};
 
-comm_directive        : HST_COMM L_IDENT
+timeout_directive	: HST_TIME L_NUMBER
 {
-      thst->community = $2;
+	/* microseconds(uS) to milliseconds(ms) */
+	thst.timeout = $2 * 1000;
 };
 
-sver_directive        : HST_SVER L_NUMBER
+retries_directive	: HST_RTRY L_NUMBER
 {
-      thst->snmp_ver = (unsigned short)$2;
+	thst.retries = $2;
 };
 
-target_entry  : HST_TRGT L_OID
+target_entry		: HST_TRGT L_OID
 {
-      ttgt = malloc(sizeof(target_t));
-      bzero(ttgt, sizeof(target_t));
-      ttgt->objoid = $2;
-      ttgt->host = thst;
-      ttgt->maxspeed = DEFAULT_OUT_OF_RANGE;
+	ttgt = malloc(sizeof(target_t));
+	bzero(ttgt, sizeof(target_t));
+	ttgt->objoid = $2;
+	ttgt->maxspeed = DEFAULT_OUT_OF_RANGE;
 }
 '{' tgt_directives '}'
 {
-      add_hash_entry(ttgt);
-      ttgt = NULL;
+	/* XXX - depends on directives coming before targets */
+	RTGLL_INSERT_HEAD(&htargets, ttgt, next);
+	ttgt = NULL;
 };
-tgt_directives        : tgt_directives tgt_directive
-              | tgt_directive
-              ;
+
+tgt_directives	: tgt_directives tgt_directive
+		| tgt_directive
+		;
 
-tgt_directive : bits_directive
-              | table_directive
-              | id_directive
-              | speed_directive
-              | descr_directive
-              ;
+tgt_directive	: bits_directive
+		| table_directive
+		| id_directive
+		| speed_directive
+		| descr_directive
+		;
 
-bits_directive        : TGT_BITS L_NUMBER
+bits_directive	: TGT_BITS L_NUMBER
 {
-      ttgt->bits = $2;
+	ttgt->bits = $2;
 };
 
-table_directive       : TGT_TBL L_IDENT
+table_directive	: TGT_TBL L_IDENT
 {
-      ttgt->table = $2;
+	ttgt->dbt = dbtable_insert($2);
 };
 
-id_directive  : TGT_ID L_NUMBER
+id_directive	: TGT_ID L_NUMBER
 {
-      ttgt->iid = $2;
+	ttgt->iid = $2;
 };
 
-speed_directive       : TGT_SPEED L_NUMBER
+speed_directive	: TGT_SPEED L_NUMBER
 {
-      ttgt->maxspeed = $2;
+	ttgt->maxspeed = $2;
 };
 
-descr_directive       : TGT_DESCR L_STRING
+descr_directive	: TGT_DESCR L_STRING
 {
-      ttgt->description = $2;
+	ttgt->description = $2;
 };
 
 %%
 int yyerror(const char *msg)
 {
 
-      fprintf(stderr, "targets failure on line %d - %s\n", lineno, msg);
-      fprintf(stderr, "last token parsed: %s\n", yytext);
+	fprintf(stderr, "targets failure on line %d - %s\n", lineno, msg);
+	fprintf(stderr, "last token parsed: %s\n", yytext);
 
-      exit(1);
+	exit(1);
 }
Index: src/rtgutil.c
===========================================================================
--- src/rtgutil.c	2004/11/03 14:26:17	#6
+++ src/rtgutil.c	2004/11/03 14:26:17
@@ -3,144 +3,96 @@
    Author:      $Author: cbrotsos $
    Date:        $Date: 2004/08/25 19:24:59 $
    Description: RTG Routines
+   Do You:      $Yahoo$
 ****************************************************************************/
 
+#include <ctype.h>
 #include "common.h"
 #include "rtg.h"
+#include "rtghash.h"
 
-extern FILE *dfp;
-
 /* read configuration file to establish local environment */
-int read_rtg_config(char *file, config_t * set)
+int
+read_rtg_config(char *file)
 {
-    FILE *fp;
-    char buff[BUFSIZE];
-    char p1[BUFSIZE];
-    char p2[BUFSIZE];
+	FILE *fp;
+	char buff[BUFSIZE];
+	char p1[BUFSIZE];
+	char p2[BUFSIZE];
 
-    if ((fp = fopen(file, "r")) == NULL) {
-        return (-1);
-    } else {
-		if (set->verbose >= LOW) {
-			if (set->daemon)
-				sysloginfo("Using RTG config file [%s].\n", file);
-			else
-				fprintf(dfp, "Using RTG config file [%s].\n", file);
-		}
-        while(!feof(fp)) {
-           fgets(buff, BUFSIZE, fp);
-           if (!feof(fp) && *buff != '#' && *buff != ' ' && *buff != '\n') {
-              sscanf(buff, "%20s %20s", p1, p2);
-              if (!strcasecmp(p1, "Interval")) set->interval = atoi(p2);
-              else if (!strcasecmp(p1, "HighSkewSlop")) set->highskewslop = atof(p2);
-              else if (!strcasecmp(p1, "LowSkewSlop")) set->lowskewslop = atof(p2);
-#if !NEW_TARGET_FORMAT
-              else if (!strcasecmp(p1, "SNMP_Ver")) set->snmp_ver = atoi(p2);
-#endif
-              else if (!strcasecmp(p1, "SNMP_Port")) set->snmp_port = atoi(p2);
-              else if (!strcasecmp(p1, "Threads")) set->threads = atoi(p2);
-              else if (!strcasecmp(p1, "DB_Host")) strncpy(set->dbhost, p2, sizeof(set->dbhost));
-              else if (!strcasecmp(p1, "DB_Database")) strncpy(set->dbdb, p2, sizeof(set->dbdb));
-              else if (!strcasecmp(p1, "DB_User")) strncpy(set->dbuser, p2, sizeof(set->dbuser));
-              else if (!strcasecmp(p1, "DB_Pass")) strncpy(set->dbpass, p2, sizeof(set->dbpass));
+	if ((fp = fopen(file, "r")) == NULL)
+		return (-1);
 
-#if !NEW_TARGET_FORMAT
-/* Long longs not ANSI C.  If OS doesn't support atoll() use default. */
-              else if (!strcasecmp(p1, "OutOfRange")) 
-#ifdef HAVE_STRTOLL
-                  set->out_of_range = strtoll(p2, NULL, 0);
-#else
-                  set->out_of_range = DEFAULT_OUT_OF_RANGE;
-#endif
-#endif
+	if (set.verbose >= LOW) {
+		if (set.daemon)
+			sysloginfo("Using RTG config file [%s].\n", file);
+		else
+			fprintf(dfp, "Using RTG config file [%s].\n", file);
+	}
 
-              else { 
-                 fatalfile(dfp, "*** Unrecongized directive: %s=%s in %s\n", 
-                    p1, p2, file);
-              }
-           }
+	while (!feof(fp)) {
+		fgets(buff, BUFSIZE, fp);
+		if (!isalpha(buff[0]))
+			continue;
+		sscanf(buff, "%79s %79s", p1, p2);
+		if (!strcasecmp(p1, "Interval"))
+			set.interval = atoi(p2);
+		else if (!strcasecmp(p1, "HighSkewSlop"))
+			set.highskewslop = atof(p2);
+		else if (!strcasecmp(p1, "LowSkewSlop"))
+			set.lowskewslop = atof(p2);
+		else if (!strcasecmp(p1, "Threads"))
+			set.threads = strtoul(p2, NULL, 10);
+		else if (!strcasecmp(p1, "DB_Host"))
+			strncpy(set.dbhost, p2, sizeof(set.dbhost));
+		else if (!strcasecmp(p1, "DB_Database"))
+			strncpy(set.dbdb, p2, sizeof(set.dbdb));
+		else if (!strcasecmp(p1, "DB_User"))
+			strncpy(set.dbuser, p2, sizeof(set.dbuser));
+		else if (!strcasecmp(p1, "DB_Pass"))
+			strncpy(set.dbpass, p2, sizeof(set.dbpass));
+		else if (!strcasecmp(p1, "DB_Port"))
+			set.dbport = atoi(p2);
+		else if (!strcasecmp(p1, "DB_Socket"))
+			strncpy(set.dbsock, p2, sizeof(set.dbsock));
+		else { 
+			fatalfile(dfp,
+			    "*** Unrecongized directive: %s=%s in %s\n", p1,
+			    p2, file);
+		}
         }
 
-#if !NEW_TARGET_FORMAT
-        if (set->snmp_ver != 1 && set->snmp_ver != 2) 
-          fatalfile(dfp, "*** Unsupported SNMP version: %d.\n", set->snmp_ver);
-#endif
-        if (set->threads < 1 || set->threads > MAX_THREADS) 
-          fatalfile(dfp, "*** Invalid Number of Threads: %d (max=%d).\n", 
-             set->threads, MAX_THREADS);
-        return (0);
-    }
-}
+        if (set.threads == 0 || set.threads > MAX_THREADS) 
+		fatalfile(dfp,
+		    "*** Invalid Number of Threads: %hu (max=%u).\n", 
+		    set.threads, MAX_THREADS);
 
-
-int write_rtg_config(char *file, config_t * set)
-{
-    FILE *fp;
-
-	if (set->verbose >= LOW && !(set->daemon))
-		fprintf(dfp, "Writing default config file [%s].", file);
-    if ((fp = fopen(file, "w")) == NULL) {
-        fprintf(dfp, "\nCould not open '%s' for writing\n", file);
-        return (-1);
-    } else {
-        fprintf(fp, "#\n# RTG v%s Master Config\n#\n", VERSION);
-        fprintf(fp, "Interval\t%d\n", set->interval);
-        fprintf(fp, "HighSkewSlop\t%f\n", set->highskewslop);
-        fprintf(fp, "LowSkewSlop\t%f\n", set->lowskewslop);
-#if !NEW_TARGET_FORMAT
-        fprintf(fp, "OutOfRange\t%lld\n", set->out_of_range);
-        fprintf(fp, "SNMP_Ver\t%d\n", set->snmp_ver);
-#endif
-        fprintf(fp, "SNMP_Port\t%d\n", set->snmp_port);
-        fprintf(fp, "DB_Host\t%s\n", set->dbhost);
-        fprintf(fp, "DB_Database\t%s\n", set->dbdb);
-        fprintf(fp, "DB_User\t%s\n", set->dbuser);
-        fprintf(fp, "DB_Pass\t%s\n", set->dbpass);
-        fprintf(fp, "Threads\t%d\n", set->threads);
-        fclose(fp);
-        return (0);
-    }
+	return (0);
 }
 
-
 /* Populate Master Configuration Defaults */
-void config_defaults(config_t * set)
+void config_defaults(void)
 {
-   set->interval = DEFAULT_INTERVAL;
-   set->highskewslop = DEFAULT_HIGHSKEWSLOP;
-   set->lowskewslop = DEFAULT_LOWSKEWSLOP;
-#if !NEW_TARGET_FORMAT
-   set->out_of_range = DEFAULT_OUT_OF_RANGE;
-   set->snmp_ver = DEFAULT_SNMP_VER;
-#endif
-   set->snmp_port = DEFAULT_SNMP_PORT;
-   set->threads = DEFAULT_THREADS;
-   strncpy(set->dbhost, DEFAULT_DB_HOST, sizeof(set->dbhost));
-   strncpy(set->dbdb, DEFAULT_DB_DB, sizeof(set->dbhost));
-   strncpy(set->dbuser, DEFAULT_DB_USER, sizeof(set->dbhost));
-   strncpy(set->dbpass, DEFAULT_DB_PASS, sizeof(set->dbhost));
-   set->dboff = FALSE;
-   set->withzeros = FALSE;
-   set->verbose = OFF; 
-   set->daemon = FALSE;
+   set.interval = DEFAULT_INTERVAL;
+   set.highskewslop = DEFAULT_HIGHSKEWSLOP;
+   set.lowskewslop = DEFAULT_LOWSKEWSLOP;
+   set.threads = DEFAULT_THREADS;
+   strncpy(set.dbhost, DEFAULT_DB_HOST, sizeof(set.dbhost));
+   strncpy(set.dbdb, DEFAULT_DB_DB, sizeof(set.dbhost));
+   strncpy(set.dbuser, DEFAULT_DB_USER, sizeof(set.dbhost));
+   strncpy(set.dbpass, DEFAULT_DB_PASS, sizeof(set.dbhost));
+   set.dbport = DEFAULT_DB_PORT;
+   *(set.dbsock) = '\0';
+   set.dboff = FALSE;
+   set.withzeros = FALSE;
+   set.verbose = OFF; 
+   set.daemon = FALSE;
    strncpy(config_paths[0], CONFIG_PATH_1, sizeof(config_paths[0]));
    strncpy(config_paths[1], CONFIG_PATH_2, sizeof(config_paths[1]));
    snprintf(config_paths[2], sizeof(config_paths[1]), "%s/etc/", RTG_HOME);
-   return;
 }
 
 
-/* Print RTG stats */
-void print_stats(stats_t stats)
-{
-  debug(OFF, "[Polls = %lld] [DBInserts = %lld] [Wraps = %d] [OutOfRange = %d]\n",
-      stats.polls, stats.db_inserts, stats.wraps, stats.out_of_range);
-  debug(OFF, "[No Resp = %d] [SNMP Errs = %d] [Slow = %d] [PollTime = %2.3f%c]\n",
-      stats.no_resp, stats.errors, stats.slow, stats.poll_time, 's');
-  return;
-}
-
-
 /* A fancy sleep routine */
 int sleepy(float sleep_time)
 {
@@ -171,23 +123,22 @@
 
 /* Timestamp */
 void timestamp(char *str) {
-   time_t clock;
+   time_t tclock;
    struct tm *t;
 
-   clock = time(NULL);
-   t = localtime(&clock);
+   tclock = time(NULL);
+   t = localtime(&tclock);
    printf("[%02d/%02d %02d:%02d:%02d %s]\n", t->tm_mon + 1, 
       t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, str);
-   return;
 }
 
 char *file_timestamp() {
    static char str[BUFSIZE];
-   time_t clock;
+   time_t tclock;
    struct tm *t;
 
-   clock = time(NULL);
-   t = localtime(&clock);
+   tclock = time(NULL);
+   t = localtime(&tclock);
    snprintf(str, sizeof(str), "%02d%02d_%02d:%02d:%02d", t->tm_mon + 1, 
       t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
    return(str);
@@ -208,7 +159,6 @@
 	return (result);
 }
 
-
 int checkPID(char *pidfile) {
 	FILE *pidptr = NULL;
 	pid_t rtgpoll_pid;
@@ -237,23 +187,8 @@
 		fclose(pidptr);
 		return(0);
 	}
-	else {
-		/* Yuck, we can't even write the PID. Goodbye. */
-		return(-1);
-	}
-}
-
-int alldigits(char *s) {
-    int result = TRUE;
-
-	if (*s == '\0') return FALSE;
-
-    while (*s != '\0') {
-        if (!(*s >= '0' && *s <= '9')) 
-			return FALSE;
-        s++;
-    }
-    return result;
+	/* Yuck, we can't even write the PID. Goodbye. */
+	return(-1);
 }
 
 /* As per Stevens */
