1 /*
2  ex: set tabstop=4 shiftwidth=4 autoindent:
3  +-------------------------------------------------------------------------+
4  | Copyright (C) 2004-2021 The Cacti Group                                 |
5  |                                                                         |
6  | This program is free software; you can redistribute it and/or           |
7  | modify it under the terms of the GNU Lesser General Public              |
8  | License as published by the Free Software Foundation; either            |
9  | version 2.1 of the License, or (at your option) any later version. 	   |
10  |                                                                         |
11  | This program is distributed in the hope that it will be useful,         |
12  | but WITHOUT ANY WARRANTY; without even the implied warranty of          |
13  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           |
14  | GNU Lesser General Public License for more details.                     |
15  |                                                                         |
16  | You should have received a copy of the GNU Lesser General Public        |
17  | License along with this library; if not, write to the Free Software     |
18  | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA           |
19  | 02110-1301, USA                                                         |
20  |                                                                         |
21  +-------------------------------------------------------------------------+
22  | spine: a backend data gatherer for cacti                                |
23  +-------------------------------------------------------------------------+
24  | This poller would not have been possible without:                       |
25  |   - Larry Adams (current development and enhancements)                  |
26  |   - Rivo Nurges (rrd support, mysql poller cache, misc functions)       |
27  |   - RTG (core poller code, pthreads, snmp, autoconf examples)           |
28  |   - Brady Alleman/Doug Warner (threading ideas, implimentation details) |
29  +-------------------------------------------------------------------------+
30  | - Cacti - http://www.cacti.net/                                         |
31  +-------------------------------------------------------------------------+
32 */
33 
34 #include "common.h"
35 #include "spine.h"
36 
37 extern int pending_threads;
38 
39 /*! \fn void *child(void *arg)
40  *  \brief function is called via the fork command and initiates a poll of a host
41  *  \param arg a pointer to an integer point to the host_id to be polled
42  *
43  *	This function will call the primary Spine polling function to poll a host
44  *  and then reduce the number of active threads by one so that the next host
45  *  can be polled.
46  *
47  */
child(void * arg)48 void *child(void *arg) {
49 	int host_id;
50 	int host_thread;
51 	int last_host_thread;
52 	int host_data_ids;
53 	int host_errors;
54 	double host_time_double;
55 	char host_time[SMALL_BUFSIZE];
56 	int a_threads_value;
57 
58 	host_errors      = 0;
59 
60 	poller_thread_t poller_details = *(poller_thread_t*) arg;
61 	host_id          = poller_details.host_id;
62 	host_thread      = poller_details.host_thread;
63 	last_host_thread = poller_details.last_host_thread;
64 	host_data_ids    = poller_details.host_data_ids;
65 	host_time_double = poller_details.host_time_double;
66 	snprintf(host_time, SMALL_BUFSIZE, "%s", poller_details.host_time);
67 
68 	/* Allows main thread to proceed with creation of other threads */
69 	sem_post(poller_details.thread_init_sem);
70 
71 	if (is_debug_device(host_id)) {
72 		SPINE_LOG(("DEBUG: In Poller, About to Start Polling of Device for Device ID %i", host_id));
73 	} else {
74 		SPINE_LOG_DEBUG(("DEBUG: In Poller, About to Start Polling of Device for Device ID %i", host_id));
75 	}
76 
77 	poll_host(host_id, host_thread, last_host_thread, host_data_ids, host_time, &host_errors, host_time_double);
78 
79 	sem_post(&active_threads);
80 
81 	sem_getvalue(&active_threads, &a_threads_value);
82 
83 	if (is_debug_device(host_id)) {
84 		SPINE_LOG(("DEBUG: The Value of Active Threads is %i for Device ID %i", set.threads - a_threads_value, host_id));
85 	} else {
86 		SPINE_LOG_DEBUG(("DEBUG: The Value of Active Threads is %i for Device ID %i", set.threads - a_threads_value, host_id));
87 	}
88 
89 	thread_mutex_lock(LOCK_PEND);
90 	pending_threads--;
91 	poller_details.complete = TRUE;
92 
93 	SPINE_LOG_MEDIUM(("Active Threads is %i, Pending is %i", set.threads - a_threads_value, pending_threads));
94 	thread_mutex_unlock(LOCK_PEND);
95 
96 	/* end the thread */
97 	pthread_exit(0);
98 
99 	exit(0);
100 }
101 
102 /*! \fn void poll_host(int host_id, int host_thread, int last_host_thread, int host_data_ids, char *host_time, int *host_errors, double *host_time_double)
103  *  \brief core Spine function that polls a host
104  *  \param host_id integer value for the host_id from the hosts table in Cacti
105  *
106  *	This function is core to Spine.  It will take a host_id and then poll it.
107  *
108  *  Prior to the poll, the system will ping the host to verifiy that it is up.
109  *  In addition, the system will check to see if any reindexing of data query's
110  *  is required.
111  *
112  *  If reindexing is required, the Cacti poller.php function will spawn that
113  *  reindexing process.
114  *
115  *  In the case of hosts that require reindexing because of a sysUptime
116  *  rollback, Spine will store an unknown (NaN) value for all objects to prevent
117  *  spikes in the graphs.
118  *
119  *  With regard to snmp calls, if the host has multiple snmp agents running
120  *  Spine will re-initialize the snmp session and poll under those new ports
121  *  as the host poller_items table dictates.
122  *
123  */
poll_host(int host_id,int host_thread,int last_host_thread,int host_data_ids,char * host_time,int * host_errors,double host_time_double)124 void poll_host(int host_id, int host_thread, int last_host_thread, int host_data_ids, char *host_time, int *host_errors, double host_time_double) {
125 	char query1[BUFSIZE];
126 	char query2[BIG_BUFSIZE];
127 	char *query3 = NULL;
128 	char query4[BUFSIZE];
129 	char query5[BUFSIZE];
130 	char query6[BUFSIZE];
131 	char query8[BUFSIZE];
132 	char query9[BUFSIZE];
133 	char query10[BUFSIZE];
134 	char query11[BUFSIZE];
135 	char *query12 = NULL;
136 	char posuffix[BUFSIZE];
137 
138 	int query1_len   = 0;
139 	int query2_len   = 0;
140 	int query4_len   = 0;
141 	int query5_len   = 0;
142 	int query6_len   = 0;
143 	int query8_len   = 0;
144 	int query9_len   = 0;
145 	int query10_len  = 0;
146 	int query11_len  = 0;
147 	int posuffix_len = 0;
148 
149 	char sysUptime[BUFSIZE];
150 	char result_string[RESULTS_BUFFER+SMALL_BUFSIZE];
151 	int  result_length;
152 	char temp_result[RESULTS_BUFFER];
153 	int  errors = 0;
154 	int  *buf_errors;
155 	int  *buf_size;
156 	char *error_string;
157 	int  error_len = 0;
158 
159 	int    num_rows;
160 	int    assert_fail = FALSE;
161 	int    reindex_err = FALSE;
162 	int    spike_kill = FALSE;
163 	int    rows_processed = 0;
164 	int    i = 0;
165 	int    j = 0;
166 	int    k = 0;
167 	int    num_oids = 0;
168 	int    snmp_poller_items = 0;
169 	size_t out_buffer;
170 	int    php_process;
171 
172 	char *poll_result = NULL;
173 	char update_sql[BIG_BUFSIZE];
174 	char temp_poll_result[BUFSIZE];
175 	char temp_arg1[BUFSIZE];
176 	char limits[SMALL_BUFSIZE];
177 
178 	int  num_snmp_agents   = 0;
179 	int  last_snmp_version = 0;
180 	int  last_snmp_port    = 0;
181 	char last_snmp_community[50];
182 	char last_snmp_username[50];
183 	char last_snmp_password[50];
184 	char last_snmp_auth_protocol[5];
185 	char last_snmp_priv_passphrase[200];
186 	char last_snmp_priv_protocol[7];
187 	char last_snmp_context[65];
188 	char last_snmp_engine_id[30];
189 	double poll_time = get_time_as_double();
190 	double thread_start = 0;
191 	double thread_end = 0;
192 
193 	/* reindex shortcuts to speed polling */
194 	int previous_assert_failure = FALSE;
195 	int last_data_query_id      = 0;
196 	int perform_assert          = TRUE;
197 	int new_buffer              = TRUE;
198 	int ignore_sysinfo          = TRUE;
199 	int buf_length              = 0;
200 
201 	pool_t *local_cnn;
202 	pool_t *remote_cnn;
203 
204 	reindex_t   *reindex;
205 	host_t      *host;
206 	ping_t      *ping;
207 	target_t    *poller_items;
208 	snmp_oids_t *snmp_oids;
209 
210 	error_string = malloc(DBL_BUFSIZE);
211 	buf_size     = malloc(sizeof(int));
212 	buf_errors   = malloc(sizeof(int));
213 
214 	*buf_size     = 0;
215 	*buf_errors   = 0;
216 
217 	MYSQL     mysql;
218 	MYSQL     mysqlr;
219 	MYSQL     mysqlt;
220 	MYSQL_RES *result;
221 	MYSQL_ROW row;
222 
223 	//db_connect(LOCAL, &mysql);
224 	local_cnn = db_get_connection(LOCAL);
225 	mysql = local_cnn->mysql;
226 
227 	if (set.poller_id > 1 && set.mode == REMOTE_ONLINE) {
228 		remote_cnn = db_get_connection(REMOTE);
229 		mysqlr = remote_cnn->mysql;
230 	}
231 
232 	/* allocate host and ping structures with appropriate values */
233 	if (!(host = (host_t *) malloc(sizeof(host_t)))) {
234 		die("ERROR: Fatal malloc error: poller.c host struct!");
235 	}
236 
237 	/* set zeros */
238 	memset(host, 0, sizeof(host_t));
239 
240 	if (!(ping = (ping_t *) malloc(sizeof(ping_t)))) {
241 		die("ERROR: Fatal malloc error: poller.c ping struct!");
242 	}
243 
244 	/* set zeros */
245 	memset(ping, 0, sizeof(ping_t));
246 
247 	if (!(reindex = (reindex_t *) malloc(sizeof(reindex_t)))) {
248 		die("ERROR: Fatal malloc error: poller.c reindex poll!");
249 	}
250 	memset(reindex, 0, sizeof(reindex_t));
251 
252 	/* determine the SQL limits using the poller instructions */
253 	if (host_data_ids > 0) {
254 		snprintf(limits, SMALL_BUFSIZE, "LIMIT %i, %i", host_data_ids * (host_thread - 1), host_data_ids);
255 	} else {
256 		limits[0] = '\0';
257 	}
258 
259 	/* single polling interval query for items */
260 	if (set.poller_id == 0) {
261 		snprintf(query1, BUFSIZE,
262 			"SELECT action, hostname, snmp_community, "
263 				"snmp_version, snmp_username, snmp_password, "
264 				"rrd_name, rrd_path, arg1, arg2, arg3, local_data_id, "
265 				"rrd_num, snmp_port, snmp_timeout, "
266 				"snmp_auth_protocol, snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id "
267 			" FROM poller_item"
268 			" WHERE host_id = %i"
269 			" AND deleted = ''"
270 			" ORDER BY snmp_port %s", host_id, limits);
271 
272 		/* host structure for uptime checks */
273 		snprintf(query2, BIG_BUFSIZE,
274 			"SELECT id, hostname, snmp_community, snmp_version, "
275 				"snmp_username, snmp_password, snmp_auth_protocol, "
276 				"snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id, snmp_port, snmp_timeout, max_oids, "
277 				"availability_method, ping_method, ping_port, ping_timeout, ping_retries, "
278 				"status, status_event_count, UNIX_TIMESTAMP(status_fail_date), "
279 				"UNIX_TIMESTAMP(status_rec_date), status_last_error, "
280 				"min_time, max_time, cur_time, avg_time, "
281 				"total_polls, failed_polls, availability, snmp_sysUpTimeInstance, snmp_sysDescr, snmp_sysObjectID, "
282                 "snmp_sysContact, snmp_sysName, snmp_sysLocation"
283 			" FROM host"
284 			" WHERE id = %i"
285 			" AND deleted = ''", host_id);
286 
287 		/* data query structure for reindex detection */
288 		snprintf(query4, BUFSIZE,
289 			"SELECT data_query_id, action, op, assert_value, arg1"
290 				" FROM poller_reindex"
291 				" WHERE host_id = %i", host_id);
292 
293 		/* multiple polling interval query for items */
294 		snprintf(query5, BUFSIZE,
295 			"SELECT action, hostname, snmp_community, "
296 				"snmp_version, snmp_username, snmp_password, "
297 				"rrd_name, rrd_path, arg1, arg2, arg3, local_data_id, "
298 				"rrd_num, snmp_port, snmp_timeout, "
299 				"snmp_auth_protocol, snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id "
300 			" FROM poller_item"
301 			" WHERE host_id = %i"
302 			" AND rrd_next_step <= 0"
303 			" ORDER by snmp_port %s", host_id, limits);
304 
305 		/* query to setup the next polling interval in cacti */
306 		snprintf(query6, BUFSIZE,
307 			"UPDATE poller_item"
308 			" SET rrd_next_step = IF(rrd_step = %i, 0, IF(rrd_next_step - %i < 0, rrd_step, rrd_next_step - %i))"
309 			" WHERE host_id = %i", set.poller_interval, set.poller_interval, set.poller_interval, host_id);
310 
311 		/* query to add output records to the poller output table */
312 		snprintf(query8, BUFSIZE,
313 			"INSERT INTO poller_output"
314 			" (local_data_id, rrd_name, time, output) VALUES");
315 
316 		/* query suffix to add rows to the poller output table */
317 		snprintf(posuffix, BUFSIZE,
318 			" ON DUPLICATE KEY UPDATE output=VALUES(output)");
319 
320 		/* number of agent's count for single polling interval */
321 		snprintf(query9, BUFSIZE,
322 			"SELECT snmp_port, count(snmp_port)"
323 			" FROM poller_item"
324 			" WHERE host_id = %i"
325 			" GROUP BY snmp_port %s", host_id, limits);
326 
327 		/* number of agent's count for multiple polling intervals */
328 		snprintf(query10, BUFSIZE,
329 			"SELECT snmp_port, count(snmp_port)"
330 			" FROM poller_item"
331 			" WHERE host_id = %i"
332 			" AND rrd_next_step <= 0"
333 			" GROUP BY snmp_port %s", host_id, limits);
334 	} else {
335 		snprintf(query1, BUFSIZE,
336 			"SELECT action, hostname, snmp_community, "
337 				"snmp_version, snmp_username, snmp_password, "
338 				"rrd_name, rrd_path, arg1, arg2, arg3, local_data_id, "
339 				"rrd_num, snmp_port, snmp_timeout, "
340 				"snmp_auth_protocol, snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id "
341 			" FROM poller_item"
342 			" WHERE host_id = %i"
343 			" AND poller_id=%i"
344 			" ORDER BY snmp_port %s", host_id, set.poller_id, limits);
345 
346 		/* host structure for uptime checks */
347 		snprintf(query2, BIG_BUFSIZE,
348 			"SELECT id, hostname, snmp_community, snmp_version, "
349 				"snmp_username, snmp_password, snmp_auth_protocol, "
350 				"snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id, snmp_port, snmp_timeout, max_oids, "
351 				"availability_method, ping_method, ping_port, ping_timeout, ping_retries, "
352 				"status, status_event_count, UNIX_TIMESTAMP(status_fail_date), "
353 				"UNIX_TIMESTAMP(status_rec_date), status_last_error, "
354 				"min_time, max_time, cur_time, avg_time, "
355 				"total_polls, failed_polls, availability, snmp_sysUpTimeInstance, snmp_sysDescr, snmp_sysObjectID, "
356 				"snmp_sysContact, snmp_sysName, snmp_sysLocation"
357 			" FROM host"
358 			" WHERE id = %i"
359 			" AND deleted = ''", host_id);
360 
361 		/* data query structure for reindex detection */
362 		snprintf(query4, BUFSIZE,
363 			"SELECT data_query_id, action, op, assert_value, arg1"
364 				" FROM poller_reindex"
365 				" WHERE host_id = %i", host_id);
366 
367 		/* multiple polling interval query for items */
368 		snprintf(query5, BUFSIZE,
369 			"SELECT action, hostname, snmp_community, "
370 				"snmp_version, snmp_username, snmp_password, "
371 				"rrd_name, rrd_path, arg1, arg2, arg3, local_data_id, "
372 				"rrd_num, snmp_port, snmp_timeout, "
373 				"snmp_auth_protocol, snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id "
374 			" FROM poller_item"
375 			" WHERE host_id = %i"
376 			" AND rrd_next_step <= 0"
377 			" AND poller_id = %i"
378 			" ORDER by snmp_port %s", host_id, set.poller_id, limits);
379 
380 		/* query to setup the next polling interval in cacti */
381 		snprintf(query6, BUFSIZE,
382 			"UPDATE poller_item"
383 			" SET rrd_next_step = IF(rrd_step = %i, 0, IF(rrd_next_step - %i < 0, rrd_step, rrd_next_step - %i))"
384 			" WHERE host_id = %i"
385 			" AND poller_id = %i", set.poller_interval, set.poller_interval, set.poller_interval, host_id, set.poller_id);
386 
387 		/* query to add output records to the poller output table */
388 		snprintf(query8, BUFSIZE,
389 			"INSERT INTO poller_output"
390 			" (local_data_id, rrd_name, time, output) VALUES");
391 
392 		/* query suffix to add rows to the poller output table */
393 		snprintf(posuffix, BUFSIZE,
394 			" ON DUPLICATE KEY UPDATE output=VALUES(output)");
395 
396 		/* number of agent's count for single polling interval */
397 		snprintf(query9, BUFSIZE,
398 			"SELECT snmp_port, count(snmp_port)"
399 			" FROM poller_item"
400 			" WHERE host_id = %i"
401 			" AND poller_id = %i"
402 			" GROUP BY snmp_port %s", host_id, set.poller_id, limits);
403 
404 		/* number of agent's count for multiple polling intervals */
405 		snprintf(query10, BUFSIZE,
406 			"SELECT snmp_port, count(snmp_port)"
407 			" FROM poller_item"
408 			" WHERE host_id = %i"
409 			" AND rrd_next_step <= 0"
410 			" AND poller_id = %i"
411 			" GROUP BY snmp_port %s", host_id, set.poller_id, limits);
412 	}
413 
414 	/* query to add output records to the poller output table */
415 	snprintf(query11, BUFSIZE,
416 		"INSERT INTO poller_output_boost"
417 		" (local_data_id, rrd_name, time, output) VALUES");
418 
419 	query1_len   = strlen(query1);
420 	query2_len   = strlen(query2);
421 	query4_len   = strlen(query4);
422 	query5_len   = strlen(query5);
423 	query6_len   = strlen(query6);
424 	query8_len   = strlen(query8);
425 	query9_len   = strlen(query9);
426 	query10_len  = strlen(query10);
427 	query11_len  = strlen(query11);
428 	posuffix_len = strlen(posuffix);
429 
430 	/* initialize the ping structure variables */
431 	snprintf(ping->ping_status,   50,            "down");
432 	snprintf(ping->ping_response, SMALL_BUFSIZE, "Ping not performed due to setting.");
433 	snprintf(ping->snmp_status,   50,            "down");
434 	snprintf(ping->snmp_response, SMALL_BUFSIZE, "SNMP not performed due to setting or ping result");
435 
436 	/* if the host is a real host.  Note host_id=0 is not host based data source */
437 	if (host_id) {
438 		/* get data about this host */
439 		if ((result = db_query(&mysql, LOCAL, query2)) != 0) {
440 			num_rows = mysql_num_rows(result);
441 
442 			if (num_rows != 1) {
443 				mysql_free_result(result);
444 				db_release_connection(LOCAL, local_cnn->id);
445 
446 				if (set.poller_id > 1 && set.mode == REMOTE_ONLINE) {
447 					db_release_connection(REMOTE, remote_cnn->id);
448 				}
449 
450 				return;
451 			}
452 
453 			/* fetch the result */
454 			row = mysql_fetch_row(result);
455 
456 			if (row) {
457 				/* initialize variables first */
458 				host->id                      = 0;					// 0
459 				host->hostname[0]             = '\0';				// 1
460 				host->snmp_session            = NULL;              // -
461 				host->snmp_community[0]       = '\0';              // 2
462 				host->snmp_version            = 1;                 // 3
463 				host->snmp_username[0]        = '\0';              // 4
464 				host->snmp_password[0]        = '\0';              // 5
465 				host->snmp_auth_protocol[0]   = '\0';              // 6
466 				host->snmp_priv_passphrase[0] = '\0';              // 7
467 				host->snmp_priv_protocol[0]   = '\0';              // 8
468 				host->snmp_context[0]         = '\0';              // 9
469 				host->snmp_engine_id[0]       = '\0';              // 10
470 				host->snmp_port               = 161;               // 11
471 				host->snmp_timeout            = 500;               // 12
472 				host->snmp_retries            = set.snmp_retries;  // -
473 				host->max_oids                = 10;                // 13
474 				host->availability_method     = 0;                 // 14
475 				host->ping_method             = 0;                 // 15
476 				host->ping_port               = 23;                // 16
477 				host->ping_timeout            = 500;               // 17
478 				host->ping_retries            = 2;                 // 18
479 				host->status                  = HOST_UP;           // 19
480 				host->status_event_count      = 0;                 // 20
481 				host->status_fail_date[0]     = '\0';              // 21
482 				host->status_rec_date[0]      = '\0';              // 22
483 				host->status_last_error[0]    = '\0';              // 23
484 				host->min_time                = 0;                 // 24
485 				host->max_time                = 0;                 // 25
486 				host->cur_time                = 0;                 // 26
487 				host->avg_time                = 0;                 // 27
488 				host->total_polls             = 0;                 // 28
489 				host->failed_polls            = 0;                 // 29
490 				host->availability            = 100;               // 30
491 				host->snmp_sysUpTimeInstance  = 0;                 // 31
492 				host->snmp_sysDescr[0]        = '\0';              // 32
493 				host->snmp_sysObjectID[0]     = '\0';              // 33
494 				host->snmp_sysContact[0]      = '\0';              // 34
495 				host->snmp_sysName[0]         = '\0';              // 35
496 				host->snmp_sysLocation[0]     = '\0';              // 36
497 
498 				/* populate host structure */
499 				host->ignore_host = FALSE;
500 				if (row[0]  != NULL) host->id = atoi(row[0]);
501 
502 				if (row[1]  != NULL) STRNCOPY(host->hostname,             row[1]);
503 				if (row[2]  != NULL) STRNCOPY(host->snmp_community,       row[2]);
504 
505 				if (row[3]  != NULL) host->snmp_version = atoi(row[3]);
506 
507 				if (row[4]  != NULL) STRNCOPY(host->snmp_username,        row[4]);
508 				if (row[5]  != NULL) STRNCOPY(host->snmp_password,        row[5]);
509 				if (row[6]  != NULL) STRNCOPY(host->snmp_auth_protocol,   row[6]);
510 				if (row[7]  != NULL) STRNCOPY(host->snmp_priv_passphrase, row[7]);
511 				if (row[8]  != NULL) STRNCOPY(host->snmp_priv_protocol,   row[8]);
512 				if (row[9]  != NULL) STRNCOPY(host->snmp_context,         row[9]);
513 				if (row[10]  != NULL) STRNCOPY(host->snmp_engine_id,       row[10]);
514 
515 				if (row[11] != NULL) host->snmp_port           = atoi(row[11]);
516 				if (row[12] != NULL) host->snmp_timeout        = atoi(row[12]);
517 				if (row[13] != NULL) host->max_oids            = atoi(row[13]);
518 
519 				if (row[14] != NULL) host->availability_method = atoi(row[14]);
520 				if (row[15] != NULL) host->ping_method         = atoi(row[15]);
521 				if (row[16] != NULL) host->ping_port           = atoi(row[16]);
522 				if (row[17] != NULL) host->ping_timeout        = atoi(row[17]);
523 				if (row[18] != NULL) host->ping_retries        = atoi(row[18]);
524 
525 				if (row[19] != NULL) host->status              = atoi(row[19]);
526 				if (row[20] != NULL) host->status_event_count  = atoi(row[20]);
527 
528 				if (row[21] != NULL) STRNCOPY(host->status_fail_date, row[21]);
529 				if (row[22] != NULL) STRNCOPY(host->status_rec_date,  row[22]);
530 
531 				if (row[23] != NULL) STRNCOPY(host->status_last_error, row[23]);
532 
533 				if (row[24] != NULL) host->min_time     = atof(row[24]);
534 				if (row[25] != NULL) host->max_time     = atof(row[25]);
535 				if (row[26] != NULL) host->cur_time     = atof(row[26]);
536 				if (row[27] != NULL) host->avg_time     = atof(row[27]);
537 				if (row[28] != NULL) host->total_polls  = atoi(row[28]);
538 				if (row[29] != NULL) host->failed_polls = atoi(row[29]);
539 				if (row[30] != NULL) host->availability = atof(row[30]);
540 
541 				if (row[31] != NULL) host->snmp_sysUpTimeInstance=atoi(row[31]);
542 				if (row[32] != NULL) db_escape(&mysql, host->snmp_sysDescr, sizeof(host->snmp_sysDescr), row[32]);
543 				if (row[33] != NULL) db_escape(&mysql, host->snmp_sysObjectID, sizeof(host->snmp_sysObjectID), row[33]);
544 				if (row[34] != NULL) db_escape(&mysql, host->snmp_sysContact, sizeof(host->snmp_sysContact), row[34]);
545 				if (row[35] != NULL) db_escape(&mysql, host->snmp_sysName, sizeof(host->snmp_sysName), row[35]);
546 				if (row[36] != NULL) db_escape(&mysql, host->snmp_sysLocation, sizeof(host->snmp_sysLocation), row[36]);
547 
548 				/* correct max_oid bounds issues */
549 				if ((host->max_oids == 0) || (host->max_oids > 100)) {
550 					SPINE_LOG(("Device[%i] HT[%i] WARNING: Max OIDS is out of range with value of '%i'.  Resetting to default of 5", host_id, host_thread, host->max_oids));
551 					host->max_oids = 5;
552 				}
553 
554 				/* free the host result */
555 				mysql_free_result(result);
556 
557 				if (((host->snmp_version >= 1) && (host->snmp_version <= 2) &&
558 					(strlen(host->snmp_community) > 0)) ||
559 					(host->snmp_version == 3)) {
560 					host->snmp_session = snmp_host_init(host->id,
561 						host->hostname,
562 						host->snmp_version,
563 						host->snmp_community,
564 						host->snmp_username,
565 						host->snmp_password,
566 						host->snmp_auth_protocol,
567 						host->snmp_priv_passphrase,
568 						host->snmp_priv_protocol,
569 						host->snmp_context,
570 						host->snmp_engine_id,
571 						host->snmp_port,
572 						host->snmp_timeout);
573 				} else {
574 					host->snmp_session = NULL;
575 				}
576 
577 				/* perform a check to see if the host is alive by polling it's SysDesc
578 				 * if the host down from an snmp perspective, don't poll it.
579 				 * function sets the ignore_host bit */
580 				if ((host->availability_method == AVAIL_SNMP) &&
581 					(strlen(host->snmp_community) == 0) &&
582 					(host->snmp_version < 3)) {
583 					host->ignore_host = FALSE;
584 					update_host_status(HOST_UP, host, ping, host->availability_method);
585 
586 					if (is_debug_device(host->id)) {
587 						SPINE_LOG(("Device[%i] HT[%i] No host availability check possible for '%s'", host->id, host_thread, host->hostname));
588 					} else {
589 						SPINE_LOG_MEDIUM(("Device[%i] HT[%i] No host availability check possible for '%s'", host->id, host_thread, host->hostname));
590 					}
591 				} else {
592 					if (ping_host(host, ping) == HOST_UP) {
593 						host->ignore_host = FALSE;
594 						if (host_thread == 1) {
595 							update_host_status(HOST_UP, host, ping, host->availability_method);
596 
597 							if ((host->availability_method != AVAIL_PING) && (host->availability_method != AVAIL_NONE)) {
598 								if (host->snmp_session != NULL) {
599 									get_system_information(host, &mysql, 1);
600 									ignore_sysinfo = FALSE;
601 								}
602 							}
603 						}
604 					} else {
605 						host->ignore_host = TRUE;
606 						if (host_thread == 1) {
607 							update_host_status(HOST_DOWN, host, ping, host->availability_method);
608 						}
609 					}
610 				}
611 
612 				/* update host table */
613 				if (host_thread == 1) {
614 					if (!ignore_sysinfo) {
615 						if (host->ignore_host != TRUE) {
616 							snprintf(update_sql, BIG_BUFSIZE, "UPDATE host "
617 								"SET status='%i', status_event_count='%i', status_fail_date=FROM_UNIXTIME(%s),"
618 									" status_rec_date=FROM_UNIXTIME(%s), status_last_error='%s', min_time='%f',"
619 									" max_time='%f', cur_time='%f', avg_time='%f', total_polls='%i',"
620 									" failed_polls='%i', availability='%.4f', snmp_sysDescr='%s', "
621 									" snmp_sysObjectID='%s', snmp_sysUpTimeInstance='%u', "
622 									" snmp_sysContact='%s', snmp_sysName='%s', snmp_sysLocation='%s' "
623 								"WHERE id='%i'",
624 								host->status,
625 								host->status_event_count,
626 								host->status_fail_date,
627 								host->status_rec_date,
628 								host->status_last_error,
629 								host->min_time,
630 								host->max_time,
631 								host->cur_time,
632 								host->avg_time,
633 								host->total_polls,
634 								host->failed_polls,
635 								host->availability,
636 								host->snmp_sysDescr,
637 								host->snmp_sysObjectID,
638 								host->snmp_sysUpTimeInstance,
639 								host->snmp_sysContact,
640 								host->snmp_sysName,
641 								host->snmp_sysLocation,
642 								host->id);
643 						} else {
644 							snprintf(update_sql, BIG_BUFSIZE, "UPDATE host "
645 								"SET status='%i', status_event_count='%i', status_fail_date=FROM_UNIXTIME(%s),"
646 									" status_rec_date=FROM_UNIXTIME(%s), status_last_error='%s', min_time='%f',"
647 									" max_time='%f', cur_time='%f', avg_time='%f', total_polls='%i',"
648 									" failed_polls='%i', availability='%.4f' "
649 								"WHERE id='%i'",
650 								host->status,
651 								host->status_event_count,
652 								host->status_fail_date,
653 								host->status_rec_date,
654 								host->status_last_error,
655 								host->min_time,
656 								host->max_time,
657 								host->cur_time,
658 								host->avg_time,
659 								host->total_polls,
660 								host->failed_polls,
661 								host->availability,
662 								host->id);
663 						}
664 					} else {
665 						snprintf(update_sql, BIG_BUFSIZE, "UPDATE host "
666 							"SET status='%i', status_event_count='%i', status_fail_date=FROM_UNIXTIME(%s),"
667 								" status_rec_date=FROM_UNIXTIME(%s), status_last_error='%s', min_time='%f',"
668 								" max_time='%f', cur_time='%f', avg_time='%f', total_polls='%i',"
669 								" failed_polls='%i', availability='%.4f' "
670 							"WHERE id='%i'",
671 							host->status,
672 							host->status_event_count,
673 							host->status_fail_date,
674 							host->status_rec_date,
675 							host->status_last_error,
676 							host->min_time,
677 							host->max_time,
678 							host->cur_time,
679 							host->avg_time,
680 							host->total_polls,
681 							host->failed_polls,
682 							host->availability,
683 							host->id);
684 					}
685 
686 					db_insert(&mysql, LOCAL, update_sql);
687 				}
688 			} else {
689 				SPINE_LOG(("Device[%i] HT[%i] ERROR: MySQL Returned a Null Device Result", host->id, host_thread));
690 				num_rows = 0;
691 				host->ignore_host = TRUE;
692 			}
693 		} else {
694 			num_rows = 0;
695 			host->ignore_host = TRUE;
696 		}
697 	} else {
698 		host->id           = 0;
699 		host->max_oids     = 1;
700 		host->snmp_session = NULL;
701 		host->ignore_host  = FALSE;
702 	}
703 
704 	/* do the reindex check for this host if not script based */
705 	if ((!host->ignore_host) && (host_id)) {
706 		if ((result = db_query(&mysql, LOCAL, query4)) != 0) {
707 			num_rows = mysql_num_rows(result);
708 
709 			if (num_rows > 0) {
710 				if (is_debug_device(host->id)) {
711 					SPINE_LOG(("DEBUG: Device[%i] HT[%i] RECACHE: Processing %i items in the auto reindex cache for '%s'", host->id, host_thread, num_rows, host->hostname));
712 				} else {
713 					SPINE_LOG_DEBUG(("DEBUG: Device[%i] HT[%i] RECACHE: Processing %i items in the auto reindex cache for '%s'", host->id, host_thread, num_rows, host->hostname));
714 				}
715 
716 				// Cache uptime in case we need it again
717 				sysUptime[0] = '\0';
718 				while ((row = mysql_fetch_row(result))) {
719 					assert_fail = FALSE;
720 					reindex_err = FALSE;
721 
722 					/* initialize the reindex struction */
723 					reindex->data_query_id   = 0;
724 					reindex->action          = -1;
725 					reindex->op[0]           = '\0';
726 					reindex->assert_value[0] = '\0';
727 					reindex->arg1[0]         = '\0';
728 
729 					if (row[0] != NULL) reindex->data_query_id = atoi(row[0]);
730 					if (row[1] != NULL) reindex->action        = atoi(row[1]);
731 
732 					if (row[2] != NULL) snprintf(reindex->op, sizeof(reindex->op), "%s", row[2]);
733 
734 					if (row[3] != NULL) snprintf(reindex->assert_value, sizeof(reindex->assert_value), "%s", row[3]);
735 
736 					if (row[4] != NULL) snprintf(reindex->arg1, sizeof(reindex->arg1), "%s", row[4]);
737 
738 					/* shortcut assertion checks if a data query reindex has already been queued */
739 					if ((last_data_query_id == reindex->data_query_id) &&
740 						(!previous_assert_failure)) {
741 						perform_assert = TRUE;
742 					} else if (last_data_query_id != reindex->data_query_id) {
743 						last_data_query_id = reindex->data_query_id;
744 						perform_assert = TRUE;
745 						previous_assert_failure = FALSE;
746 					} else {
747 						perform_assert = FALSE;
748 					}
749 
750 					poll_result = NULL;
751 
752 					if (perform_assert) {
753 						switch(reindex->action) {
754 						case POLLER_ACTION_SNMP: /* snmp */
755 							/* if there is no snmp session, don't probe */
756 							if (!host->snmp_session) {
757 								reindex_err = TRUE;
758 							}
759 
760 							/* check to see if you are checking uptime */
761 							if (!reindex_err) {
762 								if (strstr(reindex->arg1, ".1.3.6.1.2.1.1.3.0") &&
763 								   (strlen(sysUptime) > 0)) {
764 									if (!(poll_result = (char *) malloc(BUFSIZE))) {
765 										die("ERROR: Fatal malloc error: poller.c poll_result");
766 									}
767 									poll_result[0] = '\0';
768 									snprintf(poll_result, BUFSIZE, "%s", sysUptime);
769 								} else if (strstr(reindex->arg1, ".1.3.6.1.2.1.1.3.0")) {
770 									poll_result = snmp_get(host, reindex->arg1);
771 									snprintf(sysUptime, BUFSIZE, "%s", poll_result);
772 								} else {
773 									poll_result = snmp_get(host, reindex->arg1);
774 								}
775 
776 								if (is_debug_device(host->id)) {
777 									SPINE_LOG(("Device[%i] HT[%i] DQ[%i] RECACHE OID: %s, (assert: %s %s output: %s)", host->id, host_thread, reindex->data_query_id, reindex->arg1, reindex->assert_value, reindex->op, poll_result));
778 								} else {
779 									SPINE_LOG_MEDIUM(("Device[%i] HT[%i] DQ[%i] RECACHE OID: %s, (assert: %s %s output: %s)", host->id, host_thread, reindex->data_query_id, reindex->arg1, reindex->assert_value, reindex->op, poll_result));
780 								}
781 							} else {
782 								SPINE_LOG(("WARNING: Device[%i] HT[%i] DQ[%i] Reindex Check FAILED: No SNMP Session.  If not an SNMP host, don't use Uptime Goes Backwards!", host->id, host_thread, reindex->data_query_id));
783 							}
784 
785 							break;
786 						case POLLER_ACTION_SCRIPT: /* script (popen) */
787 							poll_result = trim(exec_poll(host, reindex->arg1, reindex->data_query_id, "DQ"));
788 							if (is_debug_device(host->id)) {
789 								SPINE_LOG(("Device[%i] HT[%i] DQ[%i] RECACHE CMD: %s, output: %s", host->id, host_thread, reindex->data_query_id, reindex->arg1, poll_result));
790 							} else {
791 								SPINE_LOG_MEDIUM(("Device[%i] HT[%i] DQ[%i] RECACHE CMD: %s, output: %s", host->id, host_thread, reindex->data_query_id, reindex->arg1, poll_result));
792 							}
793 
794 							break;
795 						case POLLER_ACTION_PHP_SCRIPT_SERVER: /* script (php script server) */
796 							php_process = php_get_process();
797 							poll_result = trim(php_cmd(reindex->arg1, php_process));
798 							if (is_debug_device(host->id)) {
799 								SPINE_LOG(("Device[%i] HT[%i] DQ[%i] RECACHE SERVER: %s, output: %s", host->id, host_thread, reindex->data_query_id, reindex->arg1, poll_result));
800 							} else {
801 								SPINE_LOG_MEDIUM(("Device[%i] HT[%i] DQ[%i] RECACHE SERVER: %s, output: %s", host->id, host_thread, reindex->data_query_id, reindex->arg1, poll_result));
802 							}
803 
804 							break;
805 						case POLLER_ACTION_SNMP_COUNT: /* snmp; count items */
806 							if (!(poll_result = (char *) malloc(BUFSIZE))) {
807 								die("ERROR: Fatal malloc error: poller.c poll_result");
808 							}
809 							poll_result[0] = '\0';
810 
811 							snprintf(poll_result, BUFSIZE, "%d", snmp_count(host, reindex->arg1));
812 							if (is_debug_device(host->id)) {
813 								SPINE_LOG(("Device[%i] HT[%i] DQ[%i] RECACHE OID COUNT: %s, output: %s", host->id, host_thread, reindex->data_query_id, reindex->arg1, poll_result));
814 							} else {
815 								SPINE_LOG_MEDIUM(("Device[%i] HT[%i] DQ[%i] RECACHE OID COUNT: %s, output: %s", host->id, host_thread, reindex->data_query_id, reindex->arg1, poll_result));
816 							}
817 
818 							break;
819 						case POLLER_ACTION_SCRIPT_COUNT: /* script (popen); count items by counting line feeds */
820 							if (!(poll_result = (char *) malloc(BUFSIZE))) {
821 								die("ERROR: Fatal malloc error: poller.c poll_result");
822 							}
823 							poll_result[0] = '\0';
824 
825 							snprintf(poll_result, BUFSIZE, "%d", char_count(exec_poll(host, reindex->arg1, reindex->data_query_id, "DQ"), '\n'));
826 							if (is_debug_device(host->id)) {
827 								SPINE_LOG(("Device[%i] HT[%i] DQ[%i] RECACHE CMD COUNT: %s, output: %s", host->id, host_thread, reindex->data_query_id, reindex->arg1, poll_result));
828 							} else {
829 								SPINE_LOG_MEDIUM(("Device[%i] HT[%i] DQ[%i] RECACHE CMD COUNT: %s, output: %s", host->id, host_thread, reindex->data_query_id, reindex->arg1, poll_result));
830 							}
831 
832 							break;
833 						case POLLER_ACTION_PHP_SCRIPT_SERVER_COUNT: /* script (php script server); count number of lines */
834 							if (!(poll_result = (char *) malloc(BUFSIZE))) {
835 								die("ERROR: Fatal malloc error: poller.c poll_result");
836 							}
837 							poll_result[0] = '\0';
838 
839 							php_process = php_get_process();
840 							sprintf(poll_result, "%d", char_count(php_cmd(reindex->arg1, php_process), '\n'));
841 							if (is_debug_device(host->id)) {
842 								SPINE_LOG(("Device[%i] HT[%i] DQ[%i] RECACHE SERVER COUNT: %s, output: %s", host->id, host_thread, reindex->data_query_id, reindex->arg1, poll_result));
843 							} else {
844 								SPINE_LOG_MEDIUM(("Device[%i] HT[%i] DQ[%i] RECACHE SERVER COUNT: %s, output: %s", host->id, host_thread, reindex->data_query_id, reindex->arg1, poll_result));
845 							}
846 
847 							break;
848 						default:
849 							SPINE_LOG(("Device[%i] HT[%i] ERROR: Unknown Assert Action!", host->id, host_thread));
850 						}
851 
852 						if (!reindex_err) {
853 							if (!(query3 = (char *)malloc(LRG_BUFSIZE))) {
854 								die("ERROR: Fatal malloc error: poller.c reindex insert!");
855 							}
856 							query3[0] = '\0';
857 
858 							/* assume ok if host is up and result wasn't obtained */
859 							if (poll_result == NULL || (IS_UNDEFINED(poll_result)) || (STRIMATCH(poll_result, "No Such Instance"))) {
860 								if (is_debug_device(host->id) || set.spine_log_level == 2) {
861 									SPINE_LOG(("Device[%i] HT[%i] DQ[%i] RECACHE ASSERT FAILED: '%s=%s'", host->id, host_thread, reindex->data_query_id, reindex->assert_value, poll_result));
862 								}
863 								assert_fail = FALSE;
864 							} else if ((!strcmp(reindex->op, "=")) && (strcmp(reindex->assert_value, poll_result))) {
865 								if (is_debug_device(host->id) || set.spine_log_level == 2) {
866 									SPINE_LOG(("Device[%i] HT[%i] DQ[%i] RECACHE ASSERT FAILED: '%s=%s'", host->id, host_thread, reindex->data_query_id, reindex->assert_value, poll_result));
867 								} else {
868 									if (set.spine_log_level == 1) {
869 										errors++;
870 									}
871 
872 									SPINE_LOG(("Device[%i] HT[%i] DQ[%i] RECACHE ASSERT FAILED: '%s=%s'", host->id, host_thread, reindex->data_query_id, reindex->assert_value, poll_result));
873 								}
874 
875 								if (host_thread == 1) {
876 									snprintf(query3, LRG_BUFSIZE, "REPLACE INTO poller_command (poller_id, time, action,command) values (%i, NOW(), %i, '%i:%i')", set.poller_id, POLLER_COMMAND_REINDEX, host->id, reindex->data_query_id);
877 
878 									if (set.poller_id > 1 && set.mode == REMOTE_ONLINE) {
879 										db_insert(&mysqlr, REMOTE, query3);
880 									} else {
881 										db_insert(&mysql, LOCAL, query3);
882 									}
883 
884 									/* set zeros */
885 									memset(query3, 0, buf_length);
886 								}
887 								assert_fail = TRUE;
888 								previous_assert_failure = TRUE;
889 							} else if ((!strcmp(reindex->op, ">")) && (strtoll(reindex->assert_value, (char **)NULL, 10) < strtoll(poll_result, (char **)NULL, 10))) {
890 								if (is_debug_device(host->id) || set.spine_log_level == 2) {
891 									SPINE_LOG(("Device[%i] HT[%i] DQ[%i] RECACHE ASSERT FAILED: '%s>%s'", host->id, host_thread, reindex->data_query_id, reindex->assert_value, poll_result));
892 								} else {
893 									if (set.spine_log_level == 1) {
894 										errors++;
895 									}
896 
897 									SPINE_LOG(("Device[%i] HT[%i] DQ[%i] RECACHE ASSERT FAILED: '%s>%s'", host->id, host_thread, reindex->data_query_id, reindex->assert_value, poll_result));
898 								}
899 
900 								if (host_thread == 1) {
901 									snprintf(query3, LRG_BUFSIZE, "REPLACE INTO poller_command (poller_id, time, action, command) ValueS (%i, NOW(), %i, '%i:%i')", set.poller_id, POLLER_COMMAND_REINDEX, host->id, reindex->data_query_id);
902 
903 									if (set.poller_id > 1 && set.mode == REMOTE_ONLINE) {
904 										db_insert(&mysqlr, REMOTE, query3);
905 									} else {
906 										db_insert(&mysql, LOCAL, query3);
907 									}
908 
909 									/* set zeros */
910 									memset(query3, 0, buf_length);
911 								}
912 								assert_fail = TRUE;
913 								previous_assert_failure = TRUE;
914 							/* if uptime is set to '0' don't fail out */
915 							} else if (strcmp(reindex->assert_value, "0")) {
916 								if ((!strcmp(reindex->op, "<")) && (strtoll(reindex->assert_value, (char **)NULL, 10) > strtoll(poll_result, (char **)NULL, 10))) {
917 									if (is_debug_device(host->id) || set.spine_log_level == 2) {
918 										SPINE_LOG(("Device[%i] HT[%i] DQ[%i] RECACHE ASSERT FAILED: '%s<%s'", host->id, host_thread, reindex->data_query_id, reindex->assert_value, poll_result));
919 									} else {
920 										if (set.spine_log_level == 1) {
921 											errors++;
922 										}
923 
924 										SPINE_LOG(("Device[%i] HT[%i] DQ[%i] RECACHE ASSERT FAILED: '%s<%s'", host->id, host_thread, reindex->data_query_id, reindex->assert_value, poll_result));
925 									}
926 
927 									if (host_thread == 1) {
928 										snprintf(query3, LRG_BUFSIZE, "REPLACE INTO poller_command (poller_id, time, action, command) VALUES (%i, NOW(), %i, '%i:%i')", set.poller_id, POLLER_COMMAND_REINDEX, host->id, reindex->data_query_id);
929 
930 										if (set.poller_id > 1 && set.mode == REMOTE_ONLINE) {
931 											db_insert(&mysqlr, REMOTE, query3);
932 										} else {
933 											db_insert(&mysql, LOCAL, query3);
934 										}
935 
936 										/* set zeros */
937 										memset(query3, 0, buf_length);
938 									}
939 									assert_fail = TRUE;
940 									previous_assert_failure = TRUE;
941 								}
942 							}
943 
944 							/* update 'poller_reindex' with the correct information if:
945 							 * 1) the assert fails
946 							 * 2) the OP code is > or < meaning the current value could have changed without causing
947 							 *     the assert to fail */
948 							if ((assert_fail) || (!strcmp(reindex->op, ">")) || (!strcmp(reindex->op, "<"))) {
949 								if (host_thread == 1) {
950 									db_escape(&mysql, temp_poll_result, sizeof(temp_poll_result), poll_result);
951 									db_escape(&mysql, temp_arg1, sizeof(temp_arg1), reindex->arg1);
952 									snprintf(query3, LRG_BUFSIZE, "UPDATE poller_reindex SET assert_value='%s' WHERE host_id='%i' AND data_query_id='%i' AND arg1='%s'", temp_poll_result, host_id, reindex->data_query_id, temp_arg1);
953 									db_insert(&mysql, LOCAL, query3);
954 
955 									/* set zeros */
956 									memset(query3, 0, buf_length);
957 								}
958 
959 								if ((assert_fail) &&
960 									((!strcmp(reindex->op, "<")) || (!strcmp(reindex->arg1,".1.3.6.1.2.1.1.3.0")))) {
961 									spike_kill = TRUE;
962 									if (is_debug_device(host->id) || set.spine_log_level == 2) {
963 										SPINE_LOG(("Device[%i] HT[%i] NOTICE: Spike Kill in Effect for '%s'", host_id, host_thread, host->hostname));
964 									} else {
965 										if (set.spine_log_level == 1) {
966 											errors++;
967 										}
968 
969 										SPINE_LOG_MEDIUM(("Device[%i] HT[%i] NOTICE: Spike Kill in Effect for '%s'", host_id, host_thread, host->hostname));
970 									}
971 								}
972 							}
973 
974 							free(query3);
975 
976 							if (poll_result != NULL) {
977 								free(poll_result);
978 							}
979 						}
980 					}
981 				}
982 			} else {
983 				if (is_debug_device(host->id)) {
984 					SPINE_LOG(("Device[%i] HT[%i] Device has no information for recache.", host->id, host_thread));
985 				} else {
986 					SPINE_LOG_HIGH(("Device[%i] HT[%i] Device has no information for recache.", host->id, host_thread));
987 				}
988 			}
989 
990 			/* free the host result */
991 			mysql_free_result(result);
992 		} else {
993 			SPINE_LOG(("Device[%i] HT[%i] ERROR: RECACHE Query Returned Null Result!", host->id, host_thread));
994 		}
995 
996 		/* close the host snmp session, we will create again momentarily */
997 		if (host->snmp_session) {
998 			snmp_host_cleanup(host->snmp_session);
999 			host->snmp_session = NULL;
1000 		}
1001 	}
1002 
1003 	/* calculate the number of poller items to poll this cycle */
1004 	num_rows = 0;
1005 	if (set.poller_interval == 0) {
1006 		/* get the number of agents */
1007 		if ((result = db_query(&mysql, LOCAL, query9)) != 0) {
1008 			num_snmp_agents = mysql_num_rows(result);
1009 			mysql_free_result(result);
1010 
1011 			/* get the poller items */
1012 			if ((result = db_query(&mysql, LOCAL, query1)) != 0) {
1013 				num_rows = mysql_num_rows(result);
1014 			} else {
1015 				SPINE_LOG(("Device[%i] HT[%i] ERROR: Unable to Retrieve Rows due to Null Result!", host->id, host_thread));
1016 			}
1017 		} else {
1018 			SPINE_LOG(("Device[%i] HT[%i] ERROR: Agent Count Query Returned Null Result!", host->id, host_thread));
1019 		}
1020 	} else {
1021 		/* get the number of agents */
1022 		if ((result = db_query(&mysql, LOCAL, query10)) != 0) {
1023 			num_snmp_agents = (int)mysql_num_rows(result);
1024 			mysql_free_result(result);
1025 
1026 			/* get the poller items */
1027 			if ((result = db_query(&mysql, LOCAL, query5)) != 0) {
1028 				num_rows = mysql_num_rows(result);
1029 			} else {
1030 				SPINE_LOG(("Device[%i] HT[%i] ERROR: Unable to Retrieve Rows due to Null Result!", host->id, host_thread));
1031 			}
1032 		} else {
1033 			SPINE_LOG(("Device[%i] HT[%i] ERROR: Agent Count Query Returned Null Result!", host->id, host_thread));
1034 		}
1035 	}
1036 
1037 	if (num_rows > 0) {
1038 		/* retreive each hosts polling items from poller cache and load into array */
1039 		poller_items = (target_t *) calloc(num_rows, sizeof(target_t));
1040 
1041 		i = 0;
1042 		while ((row = mysql_fetch_row(result))) {
1043 			/* initialize monitored object */
1044 			poller_items[i].target_id                = 0;
1045 			poller_items[i].action                   = -1;
1046 			poller_items[i].hostname[0]              = '\0';
1047 			poller_items[i].snmp_community[0]        = '\0';
1048 			poller_items[i].snmp_version             = 1;
1049 			poller_items[i].snmp_username[0]         = '\0';
1050 			poller_items[i].snmp_password[0]         = '\0';
1051 			poller_items[i].snmp_auth_protocol[0]    = '\0';
1052 			poller_items[i].snmp_priv_passphrase[0]  = '\0';
1053 			poller_items[i].snmp_priv_protocol[0]    = '\0';
1054 			poller_items[i].snmp_context[0]          = '\0';
1055 			poller_items[i].snmp_engine_id[0]        = '\0';
1056 			poller_items[i].snmp_port                = 161;
1057 			poller_items[i].snmp_timeout             = 500;
1058 			poller_items[i].rrd_name[0]              = '\0';
1059 			poller_items[i].rrd_path[0]              = '\0';
1060 			poller_items[i].arg1[0]                  = '\0';
1061 			poller_items[i].arg2[0]                  = '\0';
1062 			poller_items[i].arg3[0]                  = '\0';
1063 			poller_items[i].local_data_id            = 0;
1064 			poller_items[i].rrd_num                  = 0;
1065 
1066 			if (row[0] != NULL)  poller_items[i].action = atoi(row[0]);
1067 
1068 			if (row[1] != NULL)  snprintf(poller_items[i].hostname, sizeof(poller_items[i].hostname), "%s", row[1]);
1069 			if (row[2] != NULL)  snprintf(poller_items[i].snmp_community, sizeof(poller_items[i].snmp_community), "%s", row[2]);
1070 
1071 			if (row[3] != NULL)  poller_items[i].snmp_version = atoi(row[3]);
1072 
1073 			if (row[4] != NULL)  snprintf(poller_items[i].snmp_username, sizeof(poller_items[i].snmp_username), "%s", row[4]);
1074 			if (row[5] != NULL)  snprintf(poller_items[i].snmp_password, sizeof(poller_items[i].snmp_password), "%s", row[5]);
1075 
1076 			if (row[6]  != NULL) snprintf(poller_items[i].rrd_name,      sizeof(poller_items[i].rrd_name),      "%s", row[6]);
1077 			if (row[7]  != NULL) snprintf(poller_items[i].rrd_path,      sizeof(poller_items[i].rrd_path),      "%s", row[7]);
1078 			if (row[8]  != NULL) snprintf(poller_items[i].arg1,          sizeof(poller_items[i].arg1),          "%s", row[8]);
1079 			if (row[9]  != NULL) snprintf(poller_items[i].arg2,          sizeof(poller_items[i].arg2),          "%s", row[9]);
1080 			if (row[10] != NULL) snprintf(poller_items[i].arg3,          sizeof(poller_items[i].arg3),          "%s", row[10]);
1081 
1082 			if (row[11] != NULL) poller_items[i].local_data_id = atoi(row[11]);
1083 
1084 			if (row[12] != NULL) poller_items[i].rrd_num       = atoi(row[12]);
1085 			if (row[13] != NULL) poller_items[i].snmp_port     = atoi(row[13]);
1086 			if (row[14] != NULL) poller_items[i].snmp_timeout  = atoi(row[14]);
1087 
1088 			if (row[15] != NULL)  snprintf(poller_items[i].snmp_auth_protocol,
1089 				sizeof(poller_items[i].snmp_auth_protocol), "%s", row[15]);
1090 			if (row[16] != NULL)  snprintf(poller_items[i].snmp_priv_passphrase,
1091 				sizeof(poller_items[i].snmp_priv_passphrase), "%s", row[16]);
1092 			if (row[17] != NULL)  snprintf(poller_items[i].snmp_priv_protocol,
1093 				sizeof(poller_items[i].snmp_priv_protocol), "%s", row[17]);
1094 			if (row[18] != NULL)  snprintf(poller_items[i].snmp_context,
1095 				sizeof(poller_items[i].snmp_context), "%s", row[18]);
1096 			if (row[19] != NULL)  snprintf(poller_items[i].snmp_engine_id,
1097 				sizeof(poller_items[i].snmp_engine_id), "%s", row[19]);
1098 
1099 			SET_UNDEFINED(poller_items[i].result);
1100 
1101 			if (poller_items[i].action == POLLER_ACTION_SNMP) {
1102 				snmp_poller_items++;
1103 			}
1104 
1105 			i++;
1106 		}
1107 
1108 		/* free the mysql result */
1109 		mysql_free_result(result);
1110 
1111 		/* create an array for snmp oids */
1112 		snmp_oids = (snmp_oids_t *) calloc(host->max_oids, sizeof(snmp_oids_t));
1113 
1114 		/* initialize all the memory to insure we don't get issues */
1115 		memset(snmp_oids, 0, sizeof(snmp_oids_t)*host->max_oids);
1116 
1117 		/* log an informative message */
1118 		if (is_debug_device(host_id)) {
1119 			SPINE_LOG(("Device[%i] HT[%i] NOTE: There are '%i' Polling Items for this Device", host_id, host_thread, num_rows));
1120 		} else {
1121 			SPINE_LOG_MEDIUM(("Device[%i] HT[%i] NOTE: There are '%i' Polling Items for this Device", host_id, host_thread, num_rows));
1122 		}
1123 
1124 		i = 0; k = 0;
1125 		while ((i < num_rows) && (!host->ignore_host)) {
1126 			thread_start = get_time_as_double();
1127 
1128 			switch(poller_items[i].action) {
1129 			case POLLER_ACTION_SNMP: /* raw SNMP poll */
1130 				/* initialize or reinitialize snmp as required */
1131 				if (k == 0) {
1132 					last_snmp_port = poller_items[i].snmp_port;
1133 					last_snmp_version = poller_items[i].snmp_version;
1134 
1135 					STRNCOPY(last_snmp_community,       poller_items[i].snmp_community);
1136 					STRNCOPY(last_snmp_username,        poller_items[i].snmp_username);
1137 					STRNCOPY(last_snmp_password,        poller_items[i].snmp_password);
1138 					STRNCOPY(last_snmp_auth_protocol,   poller_items[i].snmp_auth_protocol);
1139 					STRNCOPY(last_snmp_priv_passphrase, poller_items[i].snmp_priv_passphrase);
1140 					STRNCOPY(last_snmp_priv_protocol,   poller_items[i].snmp_priv_protocol);
1141 					STRNCOPY(last_snmp_context,         poller_items[i].snmp_context);
1142 					STRNCOPY(last_snmp_engine_id,       poller_items[i].snmp_engine_id);
1143 
1144 					host->snmp_session = snmp_host_init(host->id, poller_items[i].hostname,
1145 						poller_items[i].snmp_version, poller_items[i].snmp_community,
1146 						poller_items[i].snmp_username, poller_items[i].snmp_password,
1147 						poller_items[i].snmp_auth_protocol, poller_items[i].snmp_priv_passphrase,
1148 						poller_items[i].snmp_priv_protocol, poller_items[i].snmp_context,
1149 						poller_items[i].snmp_engine_id,
1150 						poller_items[i].snmp_port, poller_items[i].snmp_timeout);
1151 
1152 					k++;
1153 				}
1154 
1155 				/* catch snmp initialization issues */
1156 				if (!host->snmp_session) {
1157 					host->ignore_host = TRUE;
1158 					break;
1159 				}
1160 
1161 				/* some snmp data changed from poller item to poller item.  therefore, poll host and store data */
1162 				if ((last_snmp_port != poller_items[i].snmp_port) ||
1163 					(last_snmp_version != poller_items[i].snmp_version) ||
1164 					(poller_items[i].snmp_version < 3 &&
1165 					(!STRMATCH(last_snmp_community, poller_items[i].snmp_community))) ||
1166 					(poller_items[i].snmp_version > 2 &&
1167 					((!STRMATCH(last_snmp_username, poller_items[i].snmp_username)) ||
1168 					(!STRMATCH(last_snmp_password, poller_items[i].snmp_password)) ||
1169 					(!STRMATCH(last_snmp_auth_protocol, poller_items[i].snmp_auth_protocol)) ||
1170 					(!STRMATCH(last_snmp_priv_passphrase, poller_items[i].snmp_priv_passphrase)) ||
1171 					(!STRMATCH(last_snmp_priv_protocol, poller_items[i].snmp_priv_protocol)) ||
1172 					(!STRMATCH(last_snmp_context, poller_items[i].snmp_context)) ||
1173 					(!STRMATCH(last_snmp_engine_id, poller_items[i].snmp_engine_id))))) {
1174 
1175 					if (num_oids > 0) {
1176 						snmp_get_multi(host, poller_items, snmp_oids, num_oids);
1177 
1178 						for (j = 0; j < num_oids; j++) {
1179 							if (host->ignore_host) {
1180 								SPINE_LOG(("Device[%i] HT[%i] DS[%i] WARNING: SNMP timeout detected [%i ms], ignoring host '%s'", host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id, host->snmp_timeout, host->hostname));
1181 								SET_UNDEFINED(snmp_oids[j].result);
1182 							} else if (IS_UNDEFINED(snmp_oids[j].result)) {
1183 								if (set.spine_log_level == 2) {
1184 									SPINE_LOG(("WARNING: Invalid Response, Device[%i] HT[%i] DS[%i] SNMP: v%i: %s, dsname: %s, oid: %s, value: %s",
1185 										host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id,
1186 										host->snmp_version, host->hostname, poller_items[snmp_oids[j].array_position].rrd_name,
1187 										poller_items[snmp_oids[j].array_position].arg1, snmp_oids[j].result));
1188 								} else if (set.spine_log_level == 1) {
1189 									errors++;
1190 									buffer_output_errors(error_string, buf_size, buf_errors, host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id, false);
1191 								}
1192 
1193 								/* continue */
1194 							} else if ((is_numeric(snmp_oids[j].result)) || (is_multipart_output(snmp_oids[j].result))) {
1195 								/* continue */
1196 							} else if (is_hexadecimal(snmp_oids[j].result, TRUE)) {
1197 								snprintf(snmp_oids[j].result, RESULTS_BUFFER, "%lld", hex2dec(snmp_oids[j].result));
1198 							} else if ((STRIMATCH(snmp_oids[j].result, "U")) ||
1199 								(STRIMATCH(snmp_oids[j].result, "Nan"))) {
1200 								if (set.spine_log_level == 2) {
1201 									SPINE_LOG(("WARNING: Invalid Response, Device[%i] HT[%i] DS[%i] SNMP: v%i: %s, dsname: %s, oid: %s, value: %s",
1202 										host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id,
1203 										host->snmp_version, host->hostname, poller_items[snmp_oids[j].array_position].rrd_name,
1204 										poller_items[snmp_oids[j].array_position].arg1, snmp_oids[j].result));
1205 								} else if (set.spine_log_level == 1) {
1206 									errors++;
1207 									buffer_output_errors(error_string, buf_size, buf_errors, host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id, false);
1208 								}
1209 
1210 								/* is valid output, continue */
1211 							} else {
1212 								/* remove double or single quotes from string */
1213 								snprintf(temp_result, RESULTS_BUFFER, "%s", strip_alpha(trim(snmp_oids[j].result)));
1214 								snprintf(snmp_oids[j].result , RESULTS_BUFFER, "%s", temp_result);
1215 
1216 								/* detect erroneous non-numeric result */
1217 								if (!validate_result(snmp_oids[j].result)) {
1218 									if (set.spine_log_level == 2) {
1219 										SPINE_LOG(("WARNING: Invalid Response, Device[%i] HT[%i] DS[%i] SNMP: v%i: %s, dsname: %s, oid: %s, value: %s",
1220 											host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id,
1221 											host->snmp_version, host->hostname, poller_items[snmp_oids[j].array_position].rrd_name,
1222 											poller_items[snmp_oids[j].array_position].arg1, snmp_oids[j].result));
1223 									} else if (set.spine_log_level == 1) {
1224 										errors++;
1225 										buffer_output_errors(error_string, buf_size, buf_errors, host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id, false);
1226 									}
1227 
1228 									SET_UNDEFINED(snmp_oids[j].result);
1229 								}
1230 							}
1231 
1232 							snprintf(poller_items[snmp_oids[j].array_position].result, RESULTS_BUFFER, "%s", snmp_oids[j].result);
1233 
1234 							thread_end = get_time_as_double();
1235 
1236 							if (is_debug_device(host_id)) {
1237 								SPINE_LOG(("Device[%i] HT[%i] DS[%i] TT[%.2f] SNMP: v%i: %s, dsname: %s, oid: %s, value: %s", host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id, (thread_end - thread_start) * 1000, host->snmp_version, host->hostname, poller_items[snmp_oids[j].array_position].rrd_name, poller_items[snmp_oids[j].array_position].arg1, poller_items[snmp_oids[j].array_position].result));
1238 							} else {
1239 								SPINE_LOG_MEDIUM(("Device[%i] HT[%i] DS[%i] TT[%.2f] SNMP: v%i: %s, dsname: %s, oid: %s, value: %s", host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id, (thread_end - thread_start) * 1000, host->snmp_version, host->hostname, poller_items[snmp_oids[j].array_position].rrd_name, poller_items[snmp_oids[j].array_position].arg1, poller_items[snmp_oids[j].array_position].result));
1240 							}
1241 						}
1242 
1243 						/* reset num_snmps */
1244 						num_oids = 0;
1245 
1246 						/* initialize all the memory to insure we don't get issues */
1247 						memset(snmp_oids, 0, sizeof(snmp_oids_t)*host->max_oids);
1248 					}
1249 
1250 					snmp_host_cleanup(host->snmp_session);
1251 					host->snmp_session = snmp_host_init(host->id, poller_items[i].hostname,
1252 						poller_items[i].snmp_version, poller_items[i].snmp_community,
1253 						poller_items[i].snmp_username, poller_items[i].snmp_password,
1254 						poller_items[i].snmp_auth_protocol, poller_items[i].snmp_priv_passphrase,
1255 						poller_items[i].snmp_priv_protocol, poller_items[i].snmp_context,
1256 						poller_items[i].snmp_engine_id,
1257 						poller_items[i].snmp_port, poller_items[i].snmp_timeout);
1258 
1259 					last_snmp_port    = poller_items[i].snmp_port;
1260 					last_snmp_version = poller_items[i].snmp_version;
1261 
1262 					STRNCOPY(last_snmp_community,       poller_items[i].snmp_community);
1263 					STRNCOPY(last_snmp_username,        poller_items[i].snmp_username);
1264 					STRNCOPY(last_snmp_password,        poller_items[i].snmp_password);
1265 					STRNCOPY(last_snmp_auth_protocol,   poller_items[i].snmp_auth_protocol);
1266 					STRNCOPY(last_snmp_priv_passphrase, poller_items[i].snmp_priv_passphrase);
1267 					STRNCOPY(last_snmp_priv_protocol,   poller_items[i].snmp_priv_protocol);
1268 					STRNCOPY(last_snmp_context,         poller_items[i].snmp_context);
1269 					STRNCOPY(last_snmp_engine_id,       poller_items[i].snmp_engine_id);
1270 				}
1271 
1272 				if (num_oids >= host->max_oids) {
1273 					snmp_get_multi(host, poller_items, snmp_oids, num_oids);
1274 
1275 					for (j = 0; j < num_oids; j++) {
1276 						if (host->ignore_host) {
1277 							SPINE_LOG(("Device[%i] HT[%i] DS[%i] WARNING: SNMP timeout detected [%i ms], ignoring host '%s'", host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id, host->snmp_timeout, host->hostname));
1278 							SET_UNDEFINED(snmp_oids[j].result);
1279 						} else if (IS_UNDEFINED(snmp_oids[j].result)) {
1280 							if (set.spine_log_level == 2) {
1281 								SPINE_LOG(("WARNING: Invalid Response, Device[%i] HT[%i] DS[%i] SNMP: v%i: %s, dsname: %s, oid: %s, value: %s",
1282 									host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id,
1283 									host->snmp_version, host->hostname, poller_items[snmp_oids[j].array_position].rrd_name,
1284 									poller_items[snmp_oids[j].array_position].arg1, snmp_oids[j].result));
1285 							} else if (set.spine_log_level == 1) {
1286 								errors++;
1287 								buffer_output_errors(error_string, buf_size, buf_errors, host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id, false);
1288 							}
1289 
1290 							/* continue */
1291 						} else if ((is_numeric(snmp_oids[j].result)) || (is_multipart_output(snmp_oids[j].result))) {
1292 							/* continue */
1293 						} else if (is_hexadecimal(snmp_oids[j].result, TRUE)) {
1294 							snprintf(snmp_oids[j].result, RESULTS_BUFFER, "%lld", hex2dec(snmp_oids[j].result));
1295 						} else if ((STRIMATCH(snmp_oids[j].result, "U")) ||
1296 							(STRIMATCH(snmp_oids[j].result, "Nan"))) {
1297 							if (set.spine_log_level == 2) {
1298 								SPINE_LOG(("WARNING: Invalid Response, Device[%i] HT[%i] DS[%i] SNMP: v%i: %s, dsname: %s, oid: %s, value: %s",
1299 									host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id,
1300 									host->snmp_version, host->hostname, poller_items[snmp_oids[j].array_position].rrd_name,
1301 									poller_items[snmp_oids[j].array_position].arg1, snmp_oids[j].result));
1302 							} else if (set.spine_log_level == 1) {
1303 								errors++;
1304 								buffer_output_errors(error_string, buf_size, buf_errors, host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id, false);
1305 							}
1306 
1307 							/* is valid output, continue */
1308 						} else {
1309 							/* remove double or single quotes from string */
1310 							snprintf(temp_result, RESULTS_BUFFER, "%s", snmp_oids[j].result);
1311 							snprintf(snmp_oids[j].result , RESULTS_BUFFER, "%s", temp_result);
1312 
1313 							/* detect erroneous non-numeric result */
1314 							if (!validate_result(snmp_oids[j].result)) {
1315 								if (set.spine_log_level == 2) {
1316 									SPINE_LOG(("WARNING: Invalid Response, Device[%i] HT[%i] DS[%i] SNMP: v%i: %s, dsname: %s, oid: %s, value: %s",
1317 										host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id,
1318 										host->snmp_version, host->hostname, poller_items[snmp_oids[j].array_position].rrd_name,
1319 										poller_items[snmp_oids[j].array_position].arg1, snmp_oids[j].result));
1320 								} else if (set.spine_log_level == 1) {
1321 									errors++;
1322 									buffer_output_errors(error_string, buf_size, buf_errors, host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id, false);
1323 								}
1324 
1325 								SET_UNDEFINED(snmp_oids[j].result);
1326 							}
1327 						}
1328 
1329 						snprintf(poller_items[snmp_oids[j].array_position].result, RESULTS_BUFFER, "%s", snmp_oids[j].result);
1330 
1331 						thread_end = get_time_as_double();
1332 
1333 						if (is_debug_device(host_id)) {
1334 							SPINE_LOG(("Device[%i] HT[%i] DS[%i] TT[%.2f] SNMP: v%i: %s, dsname: %s, oid: %s, value: %s", host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id, (thread_end - thread_start) * 1000, host->snmp_version, host->hostname, poller_items[snmp_oids[j].array_position].rrd_name, poller_items[snmp_oids[j].array_position].arg1, poller_items[snmp_oids[j].array_position].result));
1335 						} else {
1336 							SPINE_LOG_MEDIUM(("Device[%i] HT[%i] DS[%i] TT[%.2f] SNMP: v%i: %s, dsname: %s, oid: %s, value: %s", host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id, (thread_end - thread_start) * 1000, host->snmp_version, host->hostname, poller_items[snmp_oids[j].array_position].rrd_name, poller_items[snmp_oids[j].array_position].arg1, poller_items[snmp_oids[j].array_position].result));
1337 						}
1338 
1339 						if (!IS_UNDEFINED(poller_items[snmp_oids[j].array_position].result)) {
1340 							/* insert a NaN in place of the actual value if the snmp agent restarts */
1341 							if ((spike_kill) && (!strstr(poller_items[snmp_oids[j].array_position].result,":"))) {
1342 								SET_UNDEFINED(poller_items[snmp_oids[j].array_position].result);
1343 							}
1344 						}
1345 					}
1346 
1347 					/* reset num_snmps */
1348 					num_oids = 0;
1349 
1350 					/* initialize all the memory to insure we don't get issues */
1351 					memset(snmp_oids, 0, sizeof(snmp_oids_t)*host->max_oids);
1352 				}
1353 
1354 				snprintf(snmp_oids[num_oids].oid, sizeof(snmp_oids[num_oids].oid), "%s", poller_items[i].arg1);
1355 				snmp_oids[num_oids].array_position = i;
1356 				num_oids++;
1357 
1358 				break;
1359 			case POLLER_ACTION_SCRIPT: /* execute script file */
1360 				poll_result = exec_poll(host, poller_items[i].arg1, poller_items[i].local_data_id, "DS");
1361 
1362 				/* process the result */
1363 				if (IS_UNDEFINED(poll_result)) {
1364 					SET_UNDEFINED(poller_items[i].result);
1365 					if (set.spine_log_level == 2) {
1366 						SPINE_LOG(("WARNING: Invalid Response, Device[%i] HT[%i] DS[%i] SCRIPT: %s, output: %s",
1367 							host_id, host_thread, poller_items[i].local_data_id,
1368 							poller_items[i].arg1, poller_items[i].result));
1369 					} else if (set.spine_log_level == 1) {
1370 						errors++;
1371 						buffer_output_errors(error_string, buf_size, buf_errors, host_id, host_thread, poller_items[i].local_data_id, false);
1372 					}
1373 				} else if ((is_numeric(poll_result)) || (is_multipart_output(trim(poll_result)))) {
1374 					snprintf(poller_items[i].result, RESULTS_BUFFER, "%s", poll_result);
1375 				} else if (is_hexadecimal(poll_result, TRUE)) {
1376 					snprintf(poller_items[i].result, RESULTS_BUFFER, "%lld", hex2dec(poll_result));
1377 				} else {
1378 					/* remove double or single quotes from string */
1379 					snprintf(temp_result, RESULTS_BUFFER, "%s", strip_alpha(trim(poll_result)));
1380 					snprintf(poller_items[i].result , RESULTS_BUFFER, "%s", temp_result);
1381 
1382 					/* detect erroneous result. can be non-numeric */
1383 					if (!validate_result(poller_items[i].result)) {
1384 						if (set.spine_log_level == 2) {
1385 							SPINE_LOG(("WARNING: Invalid Response, Device[%i] HT[%i] DS[%i] SCRIPT: %s, output: %s",
1386 								host_id, host_thread, poller_items[i].local_data_id,
1387 								poller_items[i].arg1, poller_items[i].result));
1388 						} else if (set.spine_log_level == 1) {
1389 							errors++;
1390 							buffer_output_errors(error_string, buf_size, buf_errors, host_id, host_thread, poller_items[i].local_data_id, false);
1391 						}
1392 
1393 						SET_UNDEFINED(poller_items[i].result);
1394 					}
1395 				}
1396 
1397 				if (poll_result) free(poll_result);
1398 
1399 				thread_end = get_time_as_double();
1400 
1401 				if (is_debug_device(host_id)) {
1402 					SPINE_LOG(("Device[%i] HT[%i] DS[%i] TT[%.2f] SCRIPT: %s, output: %s", host_id, host_thread, poller_items[i].local_data_id, (thread_end - thread_start) * 1000, poller_items[i].arg1, poller_items[i].result));
1403 				} else {
1404 					SPINE_LOG_MEDIUM(("Device[%i] HT[%i] DS[%i] TT[%.2f] SCRIPT: %s, output: %s", host_id, host_thread, poller_items[i].local_data_id, (thread_end - thread_start) * 1000, poller_items[i].arg1, poller_items[i].result));
1405 				}
1406 
1407 				if (!IS_UNDEFINED(poller_items[i].result)) {
1408 					/* insert a NaN in place of the actual value if the snmp agent restarts */
1409 					if ((spike_kill) && (!strstr(poller_items[i].result,":"))) {
1410 						SET_UNDEFINED(poller_items[i].result);
1411 					}
1412 				}
1413 
1414 				break;
1415 			case POLLER_ACTION_PHP_SCRIPT_SERVER: /* execute script server */
1416 				php_process = php_get_process();
1417 
1418 				poll_result = php_cmd(poller_items[i].arg1, php_process);
1419 
1420 				/* process the output */
1421 				if (IS_UNDEFINED(poll_result)) {
1422 					SET_UNDEFINED(poller_items[i].result);
1423 					if (set.spine_log_level == 2) {
1424 						SPINE_LOG(("WARNING: Invalid Response, Device[%i] HT[%i] DS[%i] SCRIPT: %s, output: %s",
1425 							host_id, host_thread, poller_items[i].local_data_id,
1426 							poller_items[i].arg1, poller_items[i].result));
1427 					} else if (set.spine_log_level == 1) {
1428 						errors++;
1429 						buffer_output_errors(error_string, buf_size, buf_errors, host_id, host_thread, poller_items[i].local_data_id, false);
1430 					}
1431 				} else if ((is_numeric(poll_result)) || (is_multipart_output(trim(poll_result)))) {
1432 					snprintf(poller_items[i].result, RESULTS_BUFFER, "%s", poll_result);
1433 				} else if (is_hexadecimal(poll_result, TRUE)) {
1434 					snprintf(poller_items[i].result, RESULTS_BUFFER, "%lld", hex2dec(poll_result));
1435 				} else {
1436 					/* remove double or single quotes from string */
1437 					snprintf(temp_result, RESULTS_BUFFER, "%s", strip_alpha(trim(poll_result)));
1438 					snprintf(poller_items[i].result , RESULTS_BUFFER, "%s", temp_result);
1439 
1440 					/* detect erroneous result. can be non-numeric */
1441 					if (!validate_result(poller_items[i].result)) {
1442 						if (set.spine_log_level == 2) {
1443 							SPINE_LOG(("WARNING: Invalid Response, Device[%i] HT[%i] DS[%i] SCRIPT: %s, output: %s",
1444 								host_id, host_thread, poller_items[i].local_data_id,
1445 								poller_items[i].arg1, poller_items[i].result));
1446 						} else if (set.spine_log_level == 1) {
1447 							errors++;
1448 							buffer_output_errors(error_string, buf_size, buf_errors, host_id, host_thread, poller_items[i].local_data_id, false);
1449 						}
1450 
1451 						SET_UNDEFINED(poller_items[i].result);
1452 					}
1453 				}
1454 
1455 				if (poll_result) free(poll_result);
1456 
1457 				thread_end = get_time_as_double();
1458 
1459 				if (is_debug_device(host_id)) {
1460 					SPINE_LOG(("Device[%i] HT[%i] DS[%i] TT[%.2f] SS[%i] SERVER: %s, output: %s", host_id, host_thread, poller_items[i].local_data_id, (thread_end - thread_start) * 1000, php_process, poller_items[i].arg1, poller_items[i].result));
1461 				} else {
1462 					SPINE_LOG_MEDIUM(("Device[%i] HT[%i] DS[%i] TT[%.2f] SS[%i] SERVER: %s, output: %s", host_id, host_thread, poller_items[i].local_data_id, (thread_end - thread_start) * 1000, php_process, poller_items[i].arg1, poller_items[i].result));
1463 				}
1464 
1465 				if (IS_UNDEFINED(poller_items[i].result)) {
1466 					/* insert a NaN in place of the actual value if the snmp agent restarts */
1467 					if ((spike_kill) && (!STRIMATCH(poller_items[i].result,":"))) {
1468 						SET_UNDEFINED(poller_items[i].result);
1469 					}
1470 				}
1471 
1472 				break;
1473 			default: /* unknown action, generate error */
1474 				SPINE_LOG(("Device[%i] HT[%i] DS[%i] ERROR: Unknown Poller Action: %s", host_id, host_thread, poller_items[i].local_data_id, poller_items[i].arg1));
1475 
1476 				break;
1477 			}
1478 
1479 			i++;
1480 			rows_processed++;
1481 		}
1482 
1483 		/* process last multi-get request if applicable */
1484 		if (num_oids > 0) {
1485 			snmp_get_multi(host, poller_items, snmp_oids, num_oids);
1486 
1487 			for (j = 0; j < num_oids; j++) {
1488 				if (host->ignore_host) {
1489 					SPINE_LOG(("Device[%i] HT[%i] DS[%i] WARNING: SNMP timeout detected [%i ms], ignoring host '%s'", host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id, host->snmp_timeout, host->hostname));
1490 					SET_UNDEFINED(snmp_oids[j].result);
1491 				} else if (IS_UNDEFINED(snmp_oids[j].result)) {
1492 					if (set.spine_log_level == 2) {
1493 						SPINE_LOG(("WARNING: Invalid Response, Device[%i] HT[%i] DS[%i] SNMP: v%i: %s, dsname: %s, oid: %s, value: %s",
1494 							host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id, host->snmp_version,
1495 							host->hostname, poller_items[snmp_oids[j].array_position].rrd_name,
1496 							poller_items[snmp_oids[j].array_position].arg1, snmp_oids[j].result));
1497 					} else if (set.spine_log_level == 1) {
1498 						errors++;
1499 						buffer_output_errors(error_string, buf_size, buf_errors, host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id, false);
1500 					}
1501 
1502 					/* continue */
1503 				} else if ((is_numeric(snmp_oids[j].result)) || (is_multipart_output(snmp_oids[j].result))) {
1504 					/* continue */
1505 				} else if (is_hexadecimal(snmp_oids[j].result, TRUE)) {
1506 					snprintf(snmp_oids[j].result, RESULTS_BUFFER, "%lld", hex2dec(snmp_oids[j].result));
1507 				} else if ((STRIMATCH(snmp_oids[j].result, "U")) ||
1508 					(STRIMATCH(snmp_oids[j].result, "Nan"))) {
1509 					if (set.spine_log_level == 2) {
1510 						SPINE_LOG(("WARNING: Invalid Response, Device[%i] HT[%i] DS[%i] SNMP: v%i: %s, dsname: %s, oid: %s, value: %s",
1511 							host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id, host->snmp_version,
1512 							host->hostname, poller_items[snmp_oids[j].array_position].rrd_name,
1513 							poller_items[snmp_oids[j].array_position].arg1, snmp_oids[j].result));
1514 					} else if (set.spine_log_level == 1) {
1515 						errors++;
1516 						buffer_output_errors(error_string, buf_size, buf_errors, host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id, false);
1517 					}
1518 
1519 					/* is valid output, continue */
1520 				} else {
1521 					/* remove double or single quotes from string */
1522 					snprintf(temp_result, RESULTS_BUFFER, "%s", strip_alpha(trim(snmp_oids[j].result)));
1523 					snprintf(snmp_oids[j].result , RESULTS_BUFFER, "%s", temp_result);
1524 
1525 					/* detect erroneous non-numeric result */
1526 					if (!validate_result(snmp_oids[j].result)) {
1527 						if (set.spine_log_level == 2) {
1528 							SPINE_LOG(("WARNING: Invalid Response, Device[%i] HT[%i] DS[%i] SNMP: v%i: %s, dsname: %s, oid: %s, value: %s",
1529 								host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id, host->snmp_version,
1530 								host->hostname, poller_items[snmp_oids[j].array_position].rrd_name,
1531 								poller_items[snmp_oids[j].array_position].arg1, snmp_oids[j].result));
1532 						} else if (set.spine_log_level == 1) {
1533 							errors++;
1534 							buffer_output_errors(error_string, buf_size, buf_errors, host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id, false);
1535 						}
1536 
1537 						SET_UNDEFINED(snmp_oids[j].result);
1538 					}
1539 				}
1540 
1541 				snprintf(poller_items[snmp_oids[j].array_position].result, RESULTS_BUFFER, "%s", snmp_oids[j].result);
1542 
1543 				thread_end = get_time_as_double();
1544 
1545 				if (is_debug_device(host_id)) {
1546 					SPINE_LOG(("Device[%i] HT[%i] DS[%i] TT[%.2f] SNMP: v%i: %s, dsname: %s, oid: %s, value: %s", host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id, (thread_end - thread_start) * 1000, host->snmp_version, host->hostname, poller_items[snmp_oids[j].array_position].rrd_name, poller_items[snmp_oids[j].array_position].arg1, poller_items[snmp_oids[j].array_position].result));
1547 				} else {
1548 					SPINE_LOG_MEDIUM(("Device[%i] HT[%i] DS[%i] TT[%.2f] SNMP: v%i: %s, dsname: %s, oid: %s, value: %s", host_id, host_thread, poller_items[snmp_oids[j].array_position].local_data_id, (thread_end - thread_start) * 1000, host->snmp_version, host->hostname, poller_items[snmp_oids[j].array_position].rrd_name, poller_items[snmp_oids[j].array_position].arg1, poller_items[snmp_oids[j].array_position].result));
1549 				}
1550 
1551 				if (!IS_UNDEFINED(poller_items[snmp_oids[j].array_position].result)) {
1552 					/* insert a NaN in place of the actual value if the snmp agent restarts */
1553 					if ((spike_kill) && (!strstr(poller_items[snmp_oids[j].array_position].result,":"))) {
1554 						SET_UNDEFINED(poller_items[snmp_oids[j].array_position].result);
1555 					}
1556 				}
1557 			}
1558 		}
1559 
1560 		buf_length = MAX_MYSQL_BUF_SIZE+RESULTS_BUFFER;
1561 
1562 		/* insert the query results into the database */
1563 		if (!(query3 = (char *)malloc(buf_length))) {
1564 			die("ERROR: Fatal malloc error: poller.c query3 output buffer!");
1565 		}
1566 
1567 		/* set zeros */
1568 		memset(query3, 0, buf_length);
1569 
1570 		/* append data */
1571 		strncat(query3, query8, query8_len);
1572 
1573 		out_buffer = strlen(query3);
1574 
1575 		if (set.boost_redirect && set.boost_enabled) {
1576 			/* insert the query results into the database */
1577 			if (!(query12 = (char *)malloc(buf_length))) {
1578 				die("ERROR: Fatal malloc error: poller.c query12 boost output buffer!");
1579 			}
1580 
1581 			/* set zeros */
1582 			memset(query12, 0, buf_length);
1583 
1584 			/* append data */
1585 			strncat(query12, query11, query11_len);
1586 		}
1587 
1588 		int mode;
1589 		if (set.poller_id > 1 && set.mode == REMOTE_ONLINE) {
1590 			SPINE_LOG_DEBUG(("DEBUG: Setting up writes to remote database"));
1591 			mysqlt = mysqlr;
1592 			mode   = REMOTE;
1593 		} else {
1594 			SPINE_LOG_DEBUG(("DEBUG: Setting up writes to local database"));
1595 			mysqlt = mysql;
1596 			mode   = LOCAL;
1597 		}
1598 
1599 		i = 0;
1600 		while (i < rows_processed) {
1601 			snprintf(result_string, RESULTS_BUFFER+SMALL_BUFSIZE, " (%i,'%s',FROM_UNIXTIME(%s),'%s')",
1602 				poller_items[i].local_data_id,
1603 				poller_items[i].rrd_name,
1604 				host_time,
1605 				poller_items[i].result);
1606 
1607 			result_length = strlen(result_string);
1608 
1609 			/* if the next element to the buffer will overflow it, write to the database */
1610 			if ((out_buffer + result_length) >= MAX_MYSQL_BUF_SIZE) {
1611 				/* append the suffix */
1612 				strncat(query3, posuffix, posuffix_len);
1613 
1614 				/* insert the record */
1615 				db_insert(&mysqlt, mode, query3);
1616 
1617 				/* re-initialize the query buffer */
1618 				memset(query3, 0, MAX_MYSQL_BUF_SIZE+RESULTS_BUFFER);
1619 
1620 				strncat(query3, query8, query8_len);
1621 
1622 				/* insert the record for boost */
1623 				if (set.boost_redirect && set.boost_enabled) {
1624 					/* append the suffix */
1625 					strncat(query12, posuffix, posuffix_len);
1626 
1627 					db_insert(&mysqlt, mode, query12);
1628 
1629 					memset(query12, 0, MAX_MYSQL_BUF_SIZE+RESULTS_BUFFER);
1630 
1631 					strncat(query12, query11, query11_len);
1632 				}
1633 
1634 				/* reset the output buffer length */
1635 				out_buffer = strlen(query3);
1636 
1637 				/* set binary, let the system know we are a new buffer */
1638 				new_buffer = TRUE;
1639 			}
1640 
1641 			/* if this is our first pass, or we just outputted to the database, need to change the delimeter */
1642 			if (new_buffer) {
1643 				result_string[0] = ' ';
1644 			} else {
1645 				result_string[0] = ',';
1646 			}
1647 
1648 			strncat(query3, result_string, result_length);
1649 
1650 			if (set.boost_redirect && set.boost_enabled) {
1651 				strncat(query12, result_string, result_length);
1652 			}
1653 
1654 			out_buffer = out_buffer + strlen(result_string);
1655 			new_buffer = FALSE;
1656 			i++;
1657 		}
1658 
1659 		/* perform the last insert if there is data to process */
1660 		if (out_buffer > strlen(query8)) {
1661 			/* append the suffix */
1662 			strncat(query3, posuffix, posuffix_len);
1663 
1664 			/* insert records into database */
1665 			db_insert(&mysqlt, mode, query3);
1666 
1667 			/* insert the record for boost */
1668 			if (set.boost_redirect && set.boost_enabled) {
1669 				/* append the suffix */
1670 				strncat(query12, posuffix, posuffix_len);
1671 
1672 				db_insert(&mysqlt, mode, query12);
1673 			}
1674 		}
1675 
1676 		/* cleanup memory and prepare for function exit */
1677 		if (host->snmp_session) {
1678 			snmp_host_cleanup(host->snmp_session);
1679 		}
1680 
1681 		free(query3);
1682 		if (set.boost_redirect && set.boost_enabled) {
1683 			free(query12);
1684 		}
1685 
1686 		free(poller_items);
1687 		free(snmp_oids);
1688 	} else {
1689 		/* free the mysql result */
1690 		mysql_free_result(result);
1691 	}
1692 
1693 	free(host);
1694 	free(reindex);
1695 	free(ping);
1696 
1697 	/* update poller_items table for next polling interval */
1698 	if (host_thread == last_host_thread) {
1699 		db_query(&mysql, LOCAL, query6);
1700 	}
1701 
1702 	/* record the polling time for the device */
1703 	poll_time = get_time_as_double() - poll_time;
1704 	if (is_debug_device(host_id)) {
1705 		SPINE_LOG(("Device[%i] HT[%i] Total Time: %0.2g Seconds", host_id, host_thread, poll_time));
1706 	} else {
1707 		SPINE_LOG_MEDIUM(("Device[%i] HT[%i] Total Time: %0.2g Seconds", host_id, host_thread, poll_time));
1708 	}
1709 
1710 	/* record the total time for the host */
1711 	poll_time = get_time_as_double();
1712 	query1[0] = '\0';
1713 	snprintf(query1, BUFSIZE, "UPDATE host SET polling_time=%.3f - %.3f WHERE id=%i", poll_time, host_time_double, host_id);
1714 	db_query(&mysql, LOCAL, query1);
1715 
1716 	db_release_connection(LOCAL, local_cnn->id);
1717 
1718 	if (set.poller_id > 1 && set.mode == REMOTE_ONLINE) {
1719 		db_release_connection(REMOTE, remote_cnn->id);
1720 	}
1721 
1722 	#ifndef OLD_MYSQL
1723 	mysql_thread_end();
1724 	#endif
1725 
1726 	if (is_debug_device(host_id)) {
1727 		SPINE_LOG(("DEBUG: Device[%i] HT[%i] DEBUG: HOST COMPLETE: About to Exit Device Polling Thread Function", host_id, host_thread));
1728 	} else {
1729 		SPINE_LOG_DEBUG(("DEBUG: Device[%i] HT[%i] DEBUG: HOST COMPLETE: About to Exit Device Polling Thread Function", host_id, host_thread));
1730 	}
1731 
1732 	buffer_output_errors(error_string, buf_size, buf_errors, host_id, host_thread, 0, true);
1733 
1734 	free(error_string);
1735 	free(buf_size);
1736 	free(buf_errors);
1737 
1738 	*host_errors = errors;
1739 }
1740 
1741 /*! \fn void buffer_output_errors(local_data_id) {
1742  *  \brief buffers output errors and pushes those errors to standard
1743  *         output as required.
1744  *  \param char* buffer - pointer to the output buffer
1745  *  \param int device_id - the device id
1746  *  \param int thread id - the device thread
1747  *  \param int local_data_id - the local data id
1748  *  \param boolean flush - flush any part of buffer
1749  */
buffer_output_errors(char * error_string,int * buf_size,int * buf_errors,int device_id,int thread_id,int local_data_id,bool flush)1750 void buffer_output_errors(char *error_string, int *buf_size, int *buf_errors, int device_id, int thread_id, int local_data_id, bool flush) {
1751 	int error_len;
1752 	char tbuffer[SMALL_BUFSIZE];
1753 
1754 	if (flush && *buf_errors > 0) {
1755 		SPINE_LOG(("WARNING: Invalid Response(s), Errors[%i] Device[%i] Thread[%i] DS[%s]", *buf_errors, device_id, thread_id, error_string));
1756 	} else if (!flush) {
1757 		snprintf(tbuffer, SMALL_BUFSIZE, *buf_errors > 0 ? ", %i" : "%i", local_data_id);
1758 		error_len = strlen(tbuffer);
1759 		if (*buf_size + error_len >= DBL_BUFSIZE) {
1760 			SPINE_LOG(("WARNING: Invalid Response(s), Errors[%i] Device[%i] Thread[%i] DS[%s]", *buf_errors, device_id, thread_id, error_string));
1761 			*buf_errors  = 1;
1762 			*buf_size = snprintf(error_string, DBL_BUFSIZE, "%i", local_data_id);
1763 		} else {
1764 			(*buf_errors)++;
1765 			snprintf(error_string + *buf_size, DBL_BUFSIZE, "%s", tbuffer);
1766 			*buf_size += error_len;
1767 		}
1768 	}
1769 }
1770 
1771 /*! \fn int is_multipart_output(char *result)
1772  *  \brief validates the output syntax is a valid name value pair syntax
1773  *  \param result the value to be checked for legality
1774  *
1775  *	This function will poll a specific host using the script pointed to by
1776  *  the command variable.
1777  *
1778  *  \return TRUE if the result is valid, otherwise FALSE.
1779  *
1780  */
is_multipart_output(char * result)1781 int is_multipart_output(char *result) {
1782 	int space_cnt = 0;
1783 	int delim_cnt = 0;
1784 	int i;
1785 
1786 	/* check the easy cases first */
1787 	if (result) {
1788 		/* it must have delimiters */
1789 		if ((strstr(result, ":")) || (strstr(result, "!"))) {
1790 			if (!strstr(result, " ")) {
1791 				return TRUE;
1792 			} else {
1793 				const int len = strlen(result);
1794 
1795 				for (i=0; i<len; i++) {
1796 					if ((result[i] == ':') || (result[i] == '!')) {
1797 						delim_cnt = delim_cnt + 1;
1798 					} else if (result[i] == ' ') {
1799 						space_cnt = space_cnt + 1;
1800 					}
1801 				}
1802 
1803 				if (space_cnt+1 == delim_cnt) {
1804 					return TRUE;
1805 				} else {
1806 					return FALSE;
1807 				}
1808 			}
1809 		}
1810 	}
1811 
1812 	return FALSE;
1813 }
1814 
get_system_information(host_t * host,MYSQL * mysql,int system)1815 void get_system_information(host_t *host, MYSQL *mysql, int system)  {
1816 	char *poll_result;
1817 
1818 	SPINE_LOG_MEDIUM(("Device[%d] Checking for System Information Update", host->id));
1819 
1820 	if (set.mibs || system) {
1821 		if (is_debug_device(host->id)) {
1822 			SPINE_LOG(("Device[%d] Updating Full System Information Table", host->id));
1823 		} else {
1824 			SPINE_LOG_MEDIUM(("Device[%d] Updating Full System Information Table", host->id));
1825 		}
1826 
1827 		SPINE_LOG_DEVDBG(("DEVDBG: Device[%d] poll_result = snmp_get(host, '.1.3.6.1.2.1.1.1.0');", host->id));
1828 		poll_result = snmp_get(host, ".1.3.6.1.2.1.1.1.0");
1829 		SPINE_LOG_DEVDBG(("DEVDBG: Device[%d] poll_result = snmp_get(host, '.1.3.6.1.2.1.1.1.0'); [complete]", host->id));
1830 
1831 		if (poll_result) {
1832 			db_escape(mysql, host->snmp_sysDescr, sizeof(host->snmp_sysDescr), poll_result);
1833 			free(poll_result);
1834 		}
1835 
1836 		SPINE_LOG_DEVDBG(("DEVDBG: Device[%d] poll_result = snmp_get(host, '.1.3.6.1.2.1.1.2.0');", host->id));
1837 		poll_result = snmp_get(host, ".1.3.6.1.2.1.1.2.0");
1838 		SPINE_LOG_DEVDBG(("DEVDBG: Device[%d] poll_result = snmp_get(host, '.1.3.6.1.2.1.1.2.0'); [complete]", host->id));
1839 
1840 		if (poll_result) {
1841 			db_escape(mysql, host->snmp_sysObjectID, sizeof(host->snmp_sysObjectID), poll_result);
1842 			free(poll_result);
1843 		}
1844 
1845 		SPINE_LOG_DEVDBG(("DEVDBG: Device[%d] poll_result = snmp_get(host, '.1.3.6.1.2.1.1.3.0');", host->id));
1846 		poll_result = snmp_get(host, ".1.3.6.1.2.1.1.3.0");
1847 		SPINE_LOG_DEVDBG(("DEVDGB: Device[%d] poll_result = snmp_get(host, '.1.3.6.1.2.1.1.3.0'); [complete]", host->id));
1848 
1849 		if (poll_result) {
1850 			host->snmp_sysUpTimeInstance = atoi(poll_result);
1851 			free(poll_result);
1852 		}
1853 
1854 		SPINE_LOG_DEVDBG(("DEVDBG: Device [%d] poll_result = snmp_get(host, '.1.3.6.1.2.1.1.4.0');", host->id));
1855 		poll_result = snmp_get(host, ".1.3.6.1.2.1.1.4.0");
1856 		SPINE_LOG_DEVDBG(("DEVDBG: Device [%d] poll_result = snmp_get(host, '.1.3.6.1.2.1.1.4.0'); [complete]", host->id));
1857 
1858 		if (poll_result) {
1859 			db_escape(mysql, host->snmp_sysContact, sizeof(host->snmp_sysContact), poll_result);
1860 			free(poll_result);
1861 		}
1862 
1863 		SPINE_LOG_DEVDBG(("DEVDBG: Device [%d] poll_result = snmp_get(host, '.1.3.6.1.2.1.1.5.0');", host->id));
1864 		poll_result = snmp_get(host, ".1.3.6.1.2.1.1.5.0");
1865 		SPINE_LOG_DEVDBG(("DEVDBG: Device [%d] poll_result = snmp_get(host, '.1.3.6.1.2.1.1.5.0'); [complete]", host->id));
1866 
1867 		if (poll_result) {
1868 			db_escape(mysql, host->snmp_sysName, sizeof(host->snmp_sysName), poll_result);
1869 			free(poll_result);
1870 		}
1871 
1872 		SPINE_LOG_DEVDBG(("DEVDBG: Device [%d] poll_result = snmp_get(host, '.1.3.6.1.2.1.1.6.0');", host->id));
1873 		poll_result = snmp_get(host, ".1.3.6.1.2.1.1.6.0");
1874 		SPINE_LOG_DEVDBG(("DEVDBG: Device [%d] poll_result = snmp_get(host, '.1.3.6.1.2.1.1.6.0'); [complete]", host->id));
1875 
1876 		if (poll_result) {
1877 			db_escape(mysql, host->snmp_sysLocation, sizeof(host->snmp_sysLocation), poll_result);
1878 			free(poll_result);
1879 		}
1880 	} else {
1881 		if (is_debug_device(host->id)) {
1882 			SPINE_LOG(("Device[%d] Updating Short System Information Table", host->id));
1883 		} else {
1884 			SPINE_LOG_MEDIUM(("Device[%d] Updating Short System Information Table", host->id));
1885 		}
1886 
1887 		SPINE_LOG_DEVDBG(("DEVDBG: Device [%d] poll_result = snmp_get(host, '.1.3.6.1.2.1.1.3.0');", host->id));
1888 		poll_result = snmp_get(host, ".1.3.6.1.2.1.1.3.0");
1889 		SPINE_LOG_DEVDBG(("DEVDBG: Device [%d] poll_result = snmp_get(host, '.1.3.6.1.2.1.1.3.0'); [complete]", host->id));
1890 
1891 		if (poll_result) {
1892 			host->snmp_sysUpTimeInstance = atoi(poll_result);
1893 			free(poll_result);
1894 		}
1895 	}
1896 }
1897 
1898 /*! \fn int validate_result(char *result)
1899  *  \brief validates the output from the polling action is valid
1900  *  \param result the value to be checked for legality
1901  *
1902  *	This function will poll a specific host using the script pointed to by
1903  *  the command variable.
1904  *
1905  *  \return TRUE if the result is valid, otherwise FALSE.
1906  *
1907  */
validate_result(char * result)1908 int validate_result(char *result) {
1909 	/* check the easy cases first */
1910 	if (result) {
1911 		if (is_numeric(result)) {
1912 			return TRUE;
1913 		} else {
1914 			if (is_multipart_output(trim(result))) {
1915 				return TRUE;
1916 			} else {
1917 				return FALSE;
1918 			}
1919 		}
1920 	}
1921 
1922 	return FALSE;
1923 }
1924 
1925 /*! \fn char *exec_poll(host_t *current_host, char *command, int id, char *type)
1926  *  \brief polls a host using a script
1927  *  \param current_host a pointer to the current host structure
1928  *  \param command the command to be executed
1929  *  \param id either the local_data_id or the data_query_id
1930  *
1931  *	This function will poll a specific host using the script pointed to by
1932  *  the command variable.
1933  *
1934  *  \return a pointer to a character buffer containing the result.
1935  *
1936  */
exec_poll(host_t * current_host,char * command,int id,char * type)1937 char *exec_poll(host_t *current_host, char *command, int id, char *type) {
1938 	extern sem_t active_scripts;
1939 	int cmd_fd;
1940 	int pid;
1941 	int close_fd = TRUE;
1942 
1943 	#ifdef USING_TPOPEN
1944 	FILE *fd;
1945 	#endif
1946 
1947 	int bytes_read;
1948 	fd_set fds;
1949 	double begin_time = 0;
1950 	double end_time = 0;
1951 	double script_timeout;
1952 	struct timeval timeout;
1953 	char *proc_command;
1954 	char *result_string;
1955 
1956 	/* compensate for back slashes in arguments */
1957 	#if defined(__CYGWIN__)
1958 	proc_command = add_slashes(command);
1959 	#else
1960 	proc_command = command;
1961 	#endif
1962 
1963 	if (!(result_string = (char *) malloc(RESULTS_BUFFER))) {
1964 		die("ERROR: Fatal malloc error: poller.c exec_poll!");
1965 	}
1966 
1967 	/* set zeros */
1968 	memset(result_string, 0, RESULTS_BUFFER);
1969 
1970 	/* set script timeout as double */
1971 	script_timeout = set.script_timeout;
1972 
1973 	/* establish timeout of 25 seconds for pipe response */
1974 	timeout.tv_sec = set.script_timeout;
1975 	timeout.tv_usec = 0;
1976 
1977 	/* don't run too many scripts, operating systems do not like that. */
1978 	sem_wait(&active_scripts);
1979 
1980 	/* record start time */
1981 	begin_time = get_time_as_double();
1982 
1983 	#ifdef USING_TPOPEN
1984 	fd = popen((char *)proc_command, "r");
1985 	cmd_fd = fileno(fd);
1986 	if (is_debug_device(current_host->id)) {
1987 		SPINE_LOG(("DEBUG: Device[%i] DEBUG: The POPEN returned the following File Descriptor %i", current_host->id, cmd_fd));
1988 	} else {
1989 		SPINE_LOG_DEBUG(("DEBUG: Device[%i] DEBUG: The POPEN returned the following File Descriptor %i", current_host->id, cmd_fd));
1990 	}
1991 	#else
1992 	cmd_fd = nft_popen((char *)proc_command, "r");
1993 	if (is_debug_device(current_host->id)) {
1994 		SPINE_LOG(("DEBUG: Device[%i] DEBUG: The NIFTY POPEN returned the following File Descriptor %i", current_host->id, cmd_fd));
1995 	} else {
1996 		SPINE_LOG_DEBUG(("DEBUG: Device[%i] DEBUG: The NIFTY POPEN returned the following File Descriptor %i", current_host->id, cmd_fd));
1997 	}
1998 	#endif
1999 
2000 	if (cmd_fd > 0) {
2001 		retry:
2002 
2003 		/* Initialize File Descriptors to Review for Input/Output */
2004 		FD_ZERO(&fds);
2005 		FD_SET(cmd_fd, &fds);
2006 
2007 		/* wait x seconds for pipe response */
2008 		switch (select(FD_SETSIZE, &fds, NULL, NULL, &timeout)) {
2009 		case -1:
2010 			switch (errno) {
2011 			case EBADF:
2012 				SPINE_LOG(("Device[%i] ERROR: One or more of the file descriptor sets specified a file descriptor that is not a valid open file descriptor.", current_host->id));
2013 				SET_UNDEFINED(result_string);
2014 				close_fd = FALSE;
2015 				break;
2016 			case EINTR:
2017 				#ifndef SOLAR_THREAD
2018 				/* take a moment */
2019 				usleep(2000);
2020 				#endif
2021 
2022 				/* record end time */
2023 				end_time = get_time_as_double();
2024 
2025 				/* re-establish new timeout value */
2026 				timeout.tv_sec = rint(floor(script_timeout-(end_time-begin_time)));
2027 				timeout.tv_usec = rint((script_timeout-(end_time-begin_time)-timeout.tv_sec)*1000000);
2028 
2029 				if ((end_time - begin_time) < set.script_timeout) {
2030 					goto retry;
2031 				} else {
2032 					SPINE_LOG(("WARNING: A script timed out while processing EINTR's."));
2033 					SET_UNDEFINED(result_string);
2034 					close_fd = FALSE;
2035 				}
2036 				break;
2037 			case EINVAL:
2038 				SPINE_LOG(("Device[%i] ERROR: Possible invalid timeout specified in select() statement.", current_host->id));
2039 				SET_UNDEFINED(result_string);
2040 				close_fd = FALSE;
2041 				break;
2042 			default:
2043 				SPINE_LOG(("Device[%i] ERROR: The script/command select() failed", current_host->id));
2044 				SET_UNDEFINED(result_string);
2045 				close_fd = FALSE;
2046 				break;
2047 			}
2048 		case 0:
2049 			#ifdef USING_TPOPEN
2050 			SPINE_LOG_MEDIUM(("Device[%i] ERROR: The POPEN timed out", current_host->id));
2051 
2052 			close_fd = FALSE;
2053 			#else
2054 			SPINE_LOG_MEDIUM(("Device[%i] ERROR: The NIFTY POPEN timed out", current_host->id));
2055 
2056 			pid = nft_pchild(cmd_fd);
2057 			kill(pid, SIGKILL);
2058 			#endif
2059 
2060 			SET_UNDEFINED(result_string);
2061 			break;
2062 		default:
2063 			/* get only one line of output, we will ignore the rest */
2064 			bytes_read = read(cmd_fd, result_string, RESULTS_BUFFER-1);
2065 			if (bytes_read > 0) {
2066 				result_string[bytes_read] = '\0';
2067 			} else {
2068 				if (STRIMATCH(type,"DS")) {
2069 					SPINE_LOG(("Device[%i] DS[%i] ERROR: Empty result [%s]: '%s'", current_host->id, id, current_host->hostname, command));
2070 				} else {
2071 					SPINE_LOG(("Device[%i] DQ[%i] ERROR: Empty result [%s]: '%s'", current_host->id, id, current_host->hostname, command));
2072 				}
2073 				SET_UNDEFINED(result_string);
2074 			}
2075 		}
2076 
2077 		/* close pipe */
2078 		#ifdef USING_TPOPEN
2079 		/* we leave the old fd open if it timed out. It will have to exit on it's own */
2080 		if (close_fd) {
2081 			pclose(fd);
2082 		}
2083 		#else
2084 		nft_pclose(cmd_fd);
2085 		#endif
2086 	} else {
2087 		SPINE_LOG(("Device[%i] ERROR: Problem executing POPEN [%s]: '%s'", current_host->id, current_host->hostname, command));
2088 		SET_UNDEFINED(result_string);
2089 	}
2090 
2091 	#if defined(__CYGWIN__)
2092 	free(proc_command);
2093 	#endif
2094 
2095 	/* reduce the active script count */
2096 	sem_post(&active_scripts);
2097 
2098 	return result_string;
2099 }
2100