<commit_before>/*
 ex: set tabstop=4 shiftwidth=4 autoindent:
 +-------------------------------------------------------------------------+
 | Copyright (C) 2004-2017 The Cacti Group                                 |
 |                                                                         |
 | This program is free software; you can redistribute it and/or           |
 | modify it under the terms of the GNU Lesser General Public              |
 | License as published by the Free Software Foundation; either            |
 | version 2.1 of the License, or (at your option) any later version. 	   |
 |                                                                         |
 | This program is distributed in the hope that it will be useful,         |
 | but WITHOUT ANY WARRANTY; without even the implied warranty of          |
 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           |
 | GNU Lesser General Public License for more details.                     |
 |                                                                         |
 | You should have received a copy of the GNU Lesser General Public        |
 | License along with this library; if not, write to the Free Software     |
 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA           |
 | 02110-1301, USA                                                         |
 |                                                                         |
 +-------------------------------------------------------------------------+
 | spine: a backend data gatherer for cacti                                |
 +-------------------------------------------------------------------------+
 | This poller would not have been possible without:                       |
 |   - <NAME> (current development and enhancements)                  |
 |   - <NAME> (rrd support, mysql poller cache, misc functions)       |
 |   - RTG (core poller code, pthreads, snmp, autoconf examples)           |
 |   - <NAME>/<NAME> (threading ideas, implimentation details) |
 +-------------------------------------------------------------------------+
 | - Cacti - http://www.cacti.net/                                         |
 +-------------------------------------------------------------------------+
*/

#include "common.h"
#include "spine.h"

extern int pending_threads;

/*! \fn void *child(void *arg)
 *  \brief function is called via the fork command and initiates a poll of a host
 *  \param arg a pointer to an integer point to the host_id to be polled
 *
 *	This function will call the primary Spine polling function to poll a host
 *  and then reduce the number of active threads by one so that the next host
 *  can be polled.
 *
 */
void *child(void *arg) {
	int host_id;
	int host_thread;
	int last_host_thread;
	int host_data_ids;
	int host_errors;
	double host_time_double;
	char host_time[SMALL_BUFSIZE];
	int a_threads_value;

	host_errors      = 0;

	poller_thread_t poller_details = *(poller_thread_t*) arg;
	host_id          = poller_details.host_id;
	host_thread      = poller_details.host_thread;
	last_host_thread = poller_details.last_host_thread;
	host_data_ids    = poller_details.host_data_ids;
	host_time_double = poller_details.host_time_double;
	snprintf(host_time, SMALL_BUFSIZE, "%s", poller_details.host_time);

	/* Allows main thread to proceed with creation of other threads */
	sem_post(poller_details.thread_init_sem);

	free(arg);

	if (is_debug_device(host_id)) {
		SPINE_LOG(("DEBUG: In Poller, About to Start Polling of Device for Device ID %i", host_id));
	} else {
		SPINE_LOG_DEBUG(("DEBUG: In Poller, About to Start Polling of Device for Device ID %i", host_id));
	}

	poll_host(host_id, host_thread, last_host_thread, host_data_ids, host_time, &host_errors, host_time_double);

	sem_post(&active_threads);

	sem_getvalue(&active_threads, &a_threads_value);

	if (is_debug_device(host_id)) {
		SPINE_LOG(("DEBUG: The Value of Active Threads is %i for Device ID %i", set.threads - a_threads_value, host_id));
	} else {
		SPINE_LOG_DEBUG(("DEBUG: The Value of Active Threads is %i for Device ID %i", set.threads - a_threads_value, host_id));
	}

	thread_mutex_lock(LOCK_PEND);
	pending_threads--;

	SPINE_LOG_MEDIUM(("POLLR: Active Threads is %i, Pending is %i", set.threads - a_threads_value, pending_threads));
	thread_mutex_unlock(LOCK_PEND);

	/* end the thread */
	pthread_exit(0);

	exit(0);
}

/*! \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)
 *  \brief core Spine function that polls a host
 *  \param host_id integer value for the host_id from the hosts table in Cacti
 *
 *	This function is core to Spine.  It will take a host_id and then poll it.
 *
 *  Prior to the poll, the system will ping the host to verifiy that it is up.
 *  In addition, the system will check to see if any reindexing of data query's
 *  is required.
 *
 *  If reindexing is required, the Cacti poller.php function will spawn that
 *  reindexing process.
 *
 *  In the case of hosts that require reindexing because of a sysUptime
 *  rollback, Spine will store an unknown (NaN) value for all objects to prevent
 *  spikes in the graphs.
 *
 *  With regard to snmp calls, if the host has multiple snmp agents running
 *  Spine will re-initialize the snmp session and poll under those new ports
 *  as the host poller_items table dictates.
 *
 */
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) {
	char query1[BUFSIZE];
	char query2[BUFSIZE];
	char *query3 = NULL;
	char query4[BUFSIZE];
	char query5[BUFSIZE];
	char query6[BUFSIZE];
	char query8[BUFSIZE];
	char query9[BUFSIZE];
	char query10[BUFSIZE];
	char query11[BUFSIZE];
	char *query12 = NULL;
	char posuffix[BUFSIZE];
	char sysUptime[BUFSIZE];
	char result_string[RESULTS_BUFFER+SMALL_BUFSIZE];
	int  result_length;
	char temp_result[RESULTS_BUFFER];
	int  errors = 0;
	char *error_string;
	int  error_len = 0;

	int    num_rows;
	int    assert_fail = FALSE;
	int    reindex_err = FALSE;
	int    spike_kill = FALSE;
	int    rows_processed = 0;
	int    i = 0;
	int    j = 0;
	int    k = 0;
	int    num_oids = 0;
	int    snmp_poller_items = 0;
	size_t out_buffer;
	int    php_process;

	char *poll_result = NULL;
	char update_sql[BUFSIZE];
	char temp_poll_result[BUFSIZE];
	char limits[SMALL_BUFSIZE];

	int  num_snmp_agents   = 0;
	int  last_snmp_version = 0;
	int  last_snmp_port    = 0;
	char last_snmp_community[50];
	char last_snmp_username[50];
	char last_snmp_password[50];
	char last_snmp_auth_protocol[5];
	char last_snmp_priv_passphrase[200];
	char last_snmp_priv_protocol[7];
	char last_snmp_context[65];
	char last_snmp_engine_id[30];
	double poll_time = get_time_as_double();

	/* reindex shortcuts to speed polling */
	int previous_assert_failure = FALSE;
	int last_data_query_id      = 0;
	int perform_assert          = TRUE;
	int new_buffer              = TRUE;
	int ignore_sysinfo          = TRUE;

	reindex_t   *reindex;
	host_t      *host;
	ping_t      *ping;
	target_t    *poller_items;
	snmp_oids_t *snmp_oids;

	error_string = malloc(DBL_BUFSIZE);

	MYSQL     mysql;
	MYSQL_RES *result;
	MYSQL_ROW row;

	db_connect(set.db_db, &mysql);

	/* Since MySQL 5.7 the sql_mode defaults are too strict for cacti */
	db_insert(&mysql, "SET SESSION sql_mode = (SELECT REPLACE(@@sql_mode,'NO_ZERO_DATE', ''))");
	db_insert(&mysql, "SET SESSION sql_mode = (SELECT REPLACE(@@sql_mode,'NO_ZERO_IN_DATE', ''))");
	db_insert(&mysql, "SET SESSION sql_mode = (SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY', ''))");
	db_insert(&mysql, "SET SESSION sql_mode = (SELECT REPLACE(@@sql_mode,'NO_AUTO_VALUE_ON_ZERO', ''))");
	db_insert(&mysql, "SET SESSION sql_mode = (SELECT REPLACE(@@sql_mode,'TRADITIONAL', ''))");
	db_insert(&mysql, "SET SESSION sql_mode = (SELECT REPLACE(@@sql_mode,'STRICT_ALL_TABLES', ''))");
	db_insert(&mysql, "SET SESSION sql_mode = (SELECT REPLACE(@@sql_mode,'STRICT_TRANS_TABLES', ''))");

	/* allocate host and ping structures with appropriate values */
	if (!(host = (host_t *) malloc(sizeof(host_t)))) {
		die("ERROR: Fatal malloc error: poller.c host struct!");
	}
	memset(host, 0, sizeof(host_t));

	if (!(ping = (ping_t *) malloc(sizeof(ping_t)))) {
		die("ERROR: Fatal malloc error: poller.c ping struct!");
	}
	memset(ping, 0, sizeof(ping_t));

	if (!(reindex = (reindex_t *) malloc(sizeof(reindex_t)))) {
		die("ERROR: Fatal malloc error: poller.c reindex poll!");
	}
	memset(reindex, 0, sizeof(reindex_t));

	sysUptime[0] = '\0';

	/* determine the SQL limits using the poller instructions */
	if (host_data_ids > 0) {
		snprintf(limits, SMALL_BUFSIZE, "LIMIT %i, %i", host_data_ids * (host_thread - 1), host_data_ids);
	} else {
		limits[0] = '\0';
	}

	/* single polling interval query for items */
	if (set.poller_id == 0) {
		snprintf(query1, BUFSIZE,
			"SELECT action, hostname, snmp_community, "
				"snmp_version, snmp_username, snmp_password, "
				"rrd_name, rrd_path, arg1, arg2, arg3, local_data_id, "
				"rrd_num, snmp_port, snmp_timeout, "
				"snmp_auth_protocol, snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id "
			" FROM poller_item"
			" WHERE host_id=%i"
			" ORDER BY snmp_port %s", host_id, limits);

		/* host structure for uptime checks */
		snprintf(query2, BUFSIZE,
			"SELECT id, hostname, snmp_community, snmp_version, "
				"snmp_username, snmp_password, snmp_auth_protocol, "
				"snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id, snmp_port, snmp_timeout, max_oids, "
				"availability_method, ping_method, ping_port, ping_timeout, ping_retries, "
				"status, status_event_count, status_fail_date, "
				"status_rec_date, status_last_error, "
				"min_time, max_time, cur_time, avg_time, "
				"total_polls, failed_polls, availability, snmp_sysUptimeInstance, snmp_sysDescr, snmp_sysObjectID, "
                "snmp_sysContact, snmp_sysName, snmp_sysLocation"
			" FROM host"
			" WHERE id=%i", host_id);

		/* data query structure for reindex detection */
		snprintf(query4, BUFSIZE,
			"SELECT data_query_id, action, op, assert_value, arg1"
				" FROM poller_reindex"
				" WHERE host_id=%i", host_id);

		/* multiple polling interval query for items */
		snprintf(query5, BUFSIZE,
			"SELECT action, hostname, snmp_community, "
				"snmp_version, snmp_username, snmp_password, "
				"rrd_name, rrd_path, arg1, arg2, arg3, local_data_id, "
				"rrd_num, snmp_port, snmp_timeout, "
				"snmp_auth_protocol, snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id "
			" FROM poller_item"
			" WHERE host_id=%i AND rrd_next_step <=0"
			" ORDER by snmp_port %s", host_id, limits);

		/* query to setup the next polling interval in cacti */
		snprintf(query6, BUFSIZE,
			"UPDATE poller_item"
			" SET rrd_next_step=IF((rrd_next_step-%i)>=0, (rrd_next_step-%i), (rrd_step-%i))"
			" WHERE host_id=%i", set.poller_interval, set.poller_interval, set.poller_interval, host_id);

		/* query to add output records to the poller output table */
		snprintf(query8, BUFSIZE,
			"INSERT INTO poller_output"
			" (local_data_id, rrd_name, time, output) VALUES");

		/* query suffix to add rows to the poller output table */
		snprintf(posuffix, BUFSIZE,
			" ON DUPLICATE KEY UPDATE output=VALUES(output)");

		/* number of agent's count for single polling interval */
		snprintf(query9, BUFSIZE,
			"SELECT snmp_port, count(snmp_port)"
			" FROM poller_item"
			" WHERE host_id=%i"
			" GROUP BY snmp_port %s", host_id, limits);

		/* number of agent's count for multiple polling intervals */
		snprintf(query10, BUFSIZE,
			"SELECT snmp_port, count(snmp_port)"
			" FROM poller_item"
			" WHERE host_id=%i"
			" AND rrd_next_step <=0"
			" GROUP BY snmp_port %s", host_id, limits);
	} else {
		snprintf(query1, BUFSIZE,
			"SELECT action, hostname, snmp_community, "
				"snmp_version, snmp_username, snmp_password, "
				"rrd_name, rrd_path, arg1, arg2, arg3, local_data_id, "
				"rrd_num, snmp_port, snmp_timeout, "
				"snmp_auth_protocol, snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id "
			" FROM poller_item"
			" WHERE host_id=%i AND poller_id=%i"
			" ORDER BY snmp_port %s", host_id, set.poller_id, limits);

		/* host structure for uptime checks */
		snprintf(query2, BUFSIZE,
			"SELECT id, hostname, snmp_community, snmp_version, "
				"snmp_username, snmp_password, snmp_auth_protocol, "
				"snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id, snmp_port, snmp_timeout, max_oids, "
				"availability_method, ping_method, ping_port, ping_timeout, ping_retries, "
				"status, status_event_count, status_fail_date, "
				"status_rec_date, status_last_error, "
				"min_time, max_time, cur_time, avg_time, "
				"total_polls, failed_polls, availability, snmp_sysUptimeInstance, snmp_sysDescr, snmp_sysObjectID, "
				"snmp_sysContact, snmp_sysName, snmp_sysLocation"
			" FROM host"
			" WHERE id=%i", host_id);

		/* data query structure for reindex detection */
		snprintf(query4, BUFSIZE,
			"SELECT data_query_id, action, op, assert_value, arg1"
				" FROM poller_reindex"
				" WHERE host_id=%i", host_id);

		/* multiple polling interval query for items */
		snprintf(query5, BUFSIZE,
			"SELECT action, hostname, snmp_community, "
				"snmp_version, snmp_username, snmp_password, "
				"rrd_name, rrd_path, arg1, arg2, arg3, local_data_id, "
				"rrd_num, snmp_port, snmp_timeout, "
				"snmp_auth_protocol, snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id "
			" FROM poller_item"
			" WHERE host_id=%i AND rrd_next_step <=0 AND poller_id=%i"
			" ORDER by snmp_port %s", host_id, set.poller_id, limits);

		/* query to setup the next polling interval in cacti */
		snprintf(query6, BUFSIZE,
			"UPDATE poller_item"
			" SET rrd_next_step=IF((rrd_next_step-%i)>=0, (rrd_next_step-%i), (rrd_step-%i))"
			" WHERE host_id=%i AND poller_id=%i", set.poller_interval, set.poller_interval, set.poller_interval, host_id, set.poller_id);

		/* query to add output records to the poller output table */
		snprintf(query8, BUFSIZE,
			"INSERT INTO poller_output"
			" (local_data_id, rrd_name, time, output) VALUES");

		/* query suffix to add rows to the poller output table */
		snprintf(posuffix, BUFSIZE,
			" ON DUPLICATE KEY UPDATE output=VALUES(output)");

		/* number of agent's count for single polling interval */
		snprintf(query9, BUFSIZE,
			"SELECT snmp_port, count(snmp_port)"
			" FROM poller_item"
			" WHERE host_id=%i"
			" AND poller_id=%i"
			" GROUP BY snmp_port %s", host_id, set.poller_id, limits);

		/* number of agent's count for multiple polling intervals */
		snprintf(query10, BUFSIZE,
			"SELECT snmp_port, count(snmp_port)"
			" FROM poller_item"
			" WHERE host_id=%i"
			" AND rrd_next_step <=0"
			" AND poller_id=%i"
			" GROUP BY snmp_port %s", host_id, set.poller_id, limits);
	}

	/* query to add output records to the poller output table */
	snprintf(query11, BUFSIZE,
		"INSERT INTO poller_output_boost"
		" (local_data_id, rrd_name, time, output) VALUES");

	/* initialize the ping structure variables */
	snprintf(ping->ping_status,   50,            "down");
	snprintf(ping->ping_response, SMALL_BUFSIZE, "Ping not performed due to setting.");
	snprintf(ping->snmp_status,   50,            "down");
	snprintf(ping->snmp_response, SMALL_BUFSIZE, "SNMP not performed due to setting or ping result");

	/* if the host is a real host.  Note host_id=0 is not host based data source */
	if (host_id) {
		/* get data about this host */
		if ((result = db_query(&mysql, query2)) != 0) {
			num_rows = mysql_num_rows(result);

			if (num_rows != 1) {
				mysql_free_result(result);
				mysql_close(&mysql);

				#ifndef OLD_MYSQL
				mysql_thread_end();
				#endif

				return;
			}

			/* fetch the result */
			row = mysql_fetch_row(result);

			if (row) {
				/* initialize variables first */
				host->id                      = 0;					// 0
				host->hostname[0]             = '\0';				// 1
				host->snmp_session            = NULL;              // -
				host->snmp_community[0]       = '\0';              // 2
				host->snmp_version            = 1;                 // 3
				host->snmp_username[0]        = '\0';              // 4
				host->snmp_password[0]        = '\0';              // 5
				host->snmp_auth_protocol[0]   = '\0';              // 6
				host->snmp_priv_passphrase[0] = '\0';              // 7
				host->snmp_priv_protocol[0]   = '\0';              // 8
				host->snmp_context[0]         = '\0';              // 9
				host->snmp_engine_id[0]       = '\0';              // 10
				host->snmp_port               = 161;               // 11
				host->snmp_timeout            = 500;               // 12
				host->snmp_retries            = set.snmp_retries;  // -
				host->max_oids                = 10;                // 13
				host->availability_method     = 0;                 // 14
				host->ping_method             = 0;                 // 15
				host->ping_port               = 23;                // 16
				host->ping_timeout            = 500;               // 17
				host->ping_retries            = 2;                 // 18
				host->status                  = HOST_UP;           // 19
				host->status_event_count      = 0;                 // 20
				host->status_fail_date[0]     = '\0';              // 21
				host->status_rec_date[0]      = '\0';              // 22
				host->status_last_error[0]    = '\0';              // 23
				host->min_time                = 0;                 // 24
				host->max_time                = 0;                 // 25
				host->cur_time                = 0;                 // 26
				host->avg_time                = 0;                 // 27
				host->total_polls             = 0;                 // 28
				host->failed_polls            = 0;                 // 29
				host->availability            = 100;               // 30
				host->snmp_sysUpTimeInstance  = 0;                 // 31
				host->snmp_sysDescr[0]        = '\0';              // 32
				host->snmp_sysObjectID[0]     = '\0';              // 33
				host->snmp_sysContact[0]      = '\0';              // 34
				host->snmp_sysName[0]         = '\0';              // 35
				host->snmp_sysLocation[0]     = '\0';              // 36

				/* populate host structure */
				host->ignore_host = FALSE;
				if (row[0]  != NULL) host->id = atoi(row[0]);

				if (row[1]  != NULL) STRNCOPY(host->hostname,             row[1]);
				if (row[2]  != NULL) STRNCOPY(host->snmp_community,       row[2]);

				if (row[3]  != NULL) host->snmp_version = atoi(row[3]);

				if (row[4]  != NULL) STRNCOPY(host->snmp_username,        row[4]);
				if (row[5]  != NULL) STRNCOPY(host->snmp_password,        row[5]);
				if (row[6]  != NULL) STRNCOPY(host->snmp_auth_protocol,   row[6]);
				if (row[7]  != NULL) STRNCOPY(host->snmp_priv_passphrase, row[7]);
				if (row[8]  != NULL) STRNCOPY(host->snmp_priv_protocol,   row[8]);
				if (row[9]  != NULL) STRNCOPY(host->snmp_context,         row[9]);
				if (row[10]  != NULL) STRNCOPY(host->snmp_engine_id,       row[10]);

				if (row[11] != NULL) host->snmp_port           = atoi(row[11]);
				if (row[12] != NULL) host->snmp_timeout        = atoi(row[12]);
				if (row[13] != NULL) host->max_oids            = atoi(row[13]);

				if (row[14] != NULL) host->availability_method = atoi(row[14]);
				if (row[15] != NULL) host->ping_method         = atoi(row[15]);
				if (row[16] != NULL) host->ping_port           = atoi(row[16]);
				if (row[17] != NULL) host->ping_timeout        = atoi(row[17]);
				if (row[18] != NULL) host->ping_retries        = atoi(row[18]);

				if (row[19] != NULL) host->status              = atoi(row[19]);
				if (row[20] != NULL) host->status_event_count  = atoi(row[20]);

				if (row[21] != NULL) STRNCOPY(host->status_fail_date, row[21]);
				if (row[22] != NULL) STRNCOPY(host->status_rec_date,  row[22]);

				if (row[23] != NULL) STRNCOPY(host->status_last_error, row[23]);

				if (row[24] != NULL) host->min_time     = atof(row[24]);
				if (row[25] != NULL) host->max_time     = atof(row[25]);
				if (row[26] != NULL) host->cur_time     = atof(row[26]);
				if (row[27] != NULL) host->avg_time     = atof(row[27]);
				if (row[28] != NULL) host->total_polls  = atoi(row[28]);
				if (row[29] != NULL) host->failed_polls = atoi(row[29]);
				if (row[30] != NULL) host->availability = atof(row[30]);

				if (row[31] != NULL) host->snmp_sysUpTimeInstance=atoi(row[31]);
				if (row[32] != NULL) STRNCOPY(host->snmp_sysDescr, row[32]);
				if (row[33] != NULL) STRNCOPY(host->snmp_sysObjectID, row[33]);
				if (row[34] != NULL) STRNCOPY(host->snmp_sysContact, row[34]);
				if (row[35] != NULL) STRNCOPY(host->snmp_sysName, row[35]);
				if (row[36] != NULL) STRNCOPY(host->snmp_sysLocation, row[36]);

				/* correct max_oid bounds issues */
				if ((host->max_oids == 0) || (host->max_oids > 100)) {
					SPINE_LOG(("Device[%i] TH[%i] WARNING: Max OIDS is out of range with value of '%i'.  Resetting to default of 5", host_id, host_thread, host->max_oids));
					host->max_oids = 5;
				}

				/* free the host result */
				mysql_free_result(result);

				if (((host->snmp_version >= 1) && (host->snmp_version <= 2) &&
					(strlen(host->snmp_community) > 0)) ||
					(host->snmp_version == 3)) {
					host->snmp_session = snmp_host_init(host->id,
						host->hostname,
						host->snmp_version,
						host->snmp_community,
						host->snmp_username,
						host->snmp_password,
						host->snmp_auth_protocol,
						host->snmp_priv_passphrase,
						host->snmp_priv_protocol,
						host->snmp_context,
						host->snmp_engine_id,
						host->snmp_port,
						host->snmp_timeout);
				} else {
					host->snmp_session = NULL;
				}

				/* perform a check to see if the host is alive by polling it's SysDesc
				 * if the host down from an snmp perspective, don't poll it.
				 * function sets the ignore_host bit */
				if ((host->availability_method == AVAIL_SNMP) &&
					(strlen(host->snmp_community) == 0) &&
					(host->snmp_version < 3)) {
					host->ignore_host = FALSE;
					update_host_status(HOST_UP, host, ping, host->availability_method);

					if (is_debug_device(host->id)) {
						SPINE_LOG(("Device[%i] TH[%i] No host availability check possible for '%s'", host->id, host_thread, host->hostname));
					} else {
						SPINE_LOG_MEDIUM(("Device[%i] TH[%i] No host availability check possible for '%s'", host->id, host_thread, host->hostname));
					}
				} else {
					if (ping_host(host, ping) == HOST_UP) {
						host->ignore_host = FALSE;
						if (host_thread == 1) {
							update_host_status(HOST_UP, host, ping, host->availability_method);

							if ((host->availability_method != AVAIL_PING) && (host->availability_method != AVAIL_NONE)) {
								if (host->snmp_session != NULL) {
									get_system_information(host, &mysql, 1);
									ignore_sysinfo = FALSE;
								}
							}
						}
					} else {
						host->ignore_host = TRUE;
						if (host_thread == 1) {
							update_host_status(HOST_DOWN, host, ping, host->availability_method);
						}
					}
				}

				/* update host table */
				if (host_thread == 1) {
					if (!ignore_sysinfo) {
						if (host->ignore_host != TRUE) {
							snprintf(update_sql, BUFSIZE, "UPDATE host "
								"SET status='%i', status_event_count='%i', status_fail_date='%s',"
									" status_rec_date='%s', status_last_error='%s', min_time='%f',"
									" max_time='%f', cur_time='%f', avg_time='%f', total_polls='%i',"
									" failed_polls='%i', availability='%.4f', snmp_sysDescr='%s', "
									" snmp_sysObjectID='%s', snmp_sysUpTimeInstance='%u', "
									" snmp_sysContact='%s', snmp_sysName='%s', snmp_sysLocation='%s' "
								"WHERE id='%i'",
								host->status,
								host->status_event_count,
								host->status_fail_date,
								host->status_rec_date,
								host->status_last_error,
								host->min_time,
								host->max_time,
								host->cur_time,
								host->avg_time,<commit_msg>Avoid truncation of update query statement<commit_after>/*
 ex: set tabstop=4 shiftwidth=4 autoindent:
 +-------------------------------------------------------------------------+
 | Copyright (C) 2004-2017 The Cacti Group                                 |
 |                                                                         |
 | This program is free software; you can redistribute it and/or           |
 | modify it under the terms of the GNU Lesser General Public              |
 | License as published by the Free Software Foundation; either            |
 | version 2.1 of the License, or (at your option) any later version. 	   |
 |                                                                         |
 | This program is distributed in the hope that it will be useful,         |
 | but WITHOUT ANY WARRANTY; without even the implied warranty of          |
 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           |
 | GNU Lesser General Public License for more details.                     |
 |                                                                         |
 | You should have received a copy of the GNU Lesser General Public        |
 | License along with this library; if not, write to the Free Software     |
 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA           |
 | 02110-1301, USA                                                         |
 |                                                                         |
 +-------------------------------------------------------------------------+
 | spine: a backend data gatherer for cacti                                |
 +-------------------------------------------------------------------------+
 | This poller would not have been possible without:                       |
 |   - <NAME> (current development and enhancements)                  |
 |   - <NAME> (rrd support, mysql poller cache, misc functions)       |
 |   - RTG (core poller code, pthreads, snmp, autoconf examples)           |
 |   - <NAME>/<NAME> (threading ideas, implimentation details) |
 +-------------------------------------------------------------------------+
 | - Cacti - http://www.cacti.net/                                         |
 +-------------------------------------------------------------------------+
*/

#include "common.h"
#include "spine.h"

extern int pending_threads;

/*! \fn void *child(void *arg)
 *  \brief function is called via the fork command and initiates a poll of a host
 *  \param arg a pointer to an integer point to the host_id to be polled
 *
 *	This function will call the primary Spine polling function to poll a host
 *  and then reduce the number of active threads by one so that the next host
 *  can be polled.
 *
 */
void *child(void *arg) {
	int host_id;
	int host_thread;
	int last_host_thread;
	int host_data_ids;
	int host_errors;
	double host_time_double;
	char host_time[SMALL_BUFSIZE];
	int a_threads_value;

	host_errors      = 0;

	poller_thread_t poller_details = *(poller_thread_t*) arg;
	host_id          = poller_details.host_id;
	host_thread      = poller_details.host_thread;
	last_host_thread = poller_details.last_host_thread;
	host_data_ids    = poller_details.host_data_ids;
	host_time_double = poller_details.host_time_double;
	snprintf(host_time, SMALL_BUFSIZE, "%s", poller_details.host_time);

	/* Allows main thread to proceed with creation of other threads */
	sem_post(poller_details.thread_init_sem);

	free(arg);

	if (is_debug_device(host_id)) {
		SPINE_LOG(("DEBUG: In Poller, About to Start Polling of Device for Device ID %i", host_id));
	} else {
		SPINE_LOG_DEBUG(("DEBUG: In Poller, About to Start Polling of Device for Device ID %i", host_id));
	}

	poll_host(host_id, host_thread, last_host_thread, host_data_ids, host_time, &host_errors, host_time_double);

	sem_post(&active_threads);

	sem_getvalue(&active_threads, &a_threads_value);

	if (is_debug_device(host_id)) {
		SPINE_LOG(("DEBUG: The Value of Active Threads is %i for Device ID %i", set.threads - a_threads_value, host_id));
	} else {
		SPINE_LOG_DEBUG(("DEBUG: The Value of Active Threads is %i for Device ID %i", set.threads - a_threads_value, host_id));
	}

	thread_mutex_lock(LOCK_PEND);
	pending_threads--;

	SPINE_LOG_MEDIUM(("POLLR: Active Threads is %i, Pending is %i", set.threads - a_threads_value, pending_threads));
	thread_mutex_unlock(LOCK_PEND);

	/* end the thread */
	pthread_exit(0);

	exit(0);
}

/*! \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)
 *  \brief core Spine function that polls a host
 *  \param host_id integer value for the host_id from the hosts table in Cacti
 *
 *	This function is core to Spine.  It will take a host_id and then poll it.
 *
 *  Prior to the poll, the system will ping the host to verifiy that it is up.
 *  In addition, the system will check to see if any reindexing of data query's
 *  is required.
 *
 *  If reindexing is required, the Cacti poller.php function will spawn that
 *  reindexing process.
 *
 *  In the case of hosts that require reindexing because of a sysUptime
 *  rollback, Spine will store an unknown (NaN) value for all objects to prevent
 *  spikes in the graphs.
 *
 *  With regard to snmp calls, if the host has multiple snmp agents running
 *  Spine will re-initialize the snmp session and poll under those new ports
 *  as the host poller_items table dictates.
 *
 */
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) {
	char query1[BUFSIZE];
	char query2[BUFSIZE];
	char *query3 = NULL;
	char query4[BUFSIZE];
	char query5[BUFSIZE];
	char query6[BUFSIZE];
	char query8[BUFSIZE];
	char query9[BUFSIZE];
	char query10[BUFSIZE];
	char query11[BUFSIZE];
	char *query12 = NULL;
	char posuffix[BUFSIZE];
	char sysUptime[BUFSIZE];
	char result_string[RESULTS_BUFFER+SMALL_BUFSIZE];
	int  result_length;
	char temp_result[RESULTS_BUFFER];
	int  errors = 0;
	char *error_string;
	int  error_len = 0;

	int    num_rows;
	int    assert_fail = FALSE;
	int    reindex_err = FALSE;
	int    spike_kill = FALSE;
	int    rows_processed = 0;
	int    i = 0;
	int    j = 0;
	int    k = 0;
	int    num_oids = 0;
	int    snmp_poller_items = 0;
	size_t out_buffer;
	int    php_process;

	char *poll_result = NULL;
	char update_sql[BUFSIZE];
	char temp_poll_result[BUFSIZE];
	char limits[SMALL_BUFSIZE];

	int  num_snmp_agents   = 0;
	int  last_snmp_version = 0;
	int  last_snmp_port    = 0;
	char last_snmp_community[50];
	char last_snmp_username[50];
	char last_snmp_password[50];
	char last_snmp_auth_protocol[5];
	char last_snmp_priv_passphrase[200];
	char last_snmp_priv_protocol[7];
	char last_snmp_context[65];
	char last_snmp_engine_id[30];
	double poll_time = get_time_as_double();

	/* reindex shortcuts to speed polling */
	int previous_assert_failure = FALSE;
	int last_data_query_id      = 0;
	int perform_assert          = TRUE;
	int new_buffer              = TRUE;
	int ignore_sysinfo          = TRUE;

	reindex_t   *reindex;
	host_t      *host;
	ping_t      *ping;
	target_t    *poller_items;
	snmp_oids_t *snmp_oids;

	error_string = malloc(DBL_BUFSIZE);

	MYSQL     mysql;
	MYSQL_RES *result;
	MYSQL_ROW row;

	db_connect(set.db_db, &mysql);

	/* Since MySQL 5.7 the sql_mode defaults are too strict for cacti */
	db_insert(&mysql, "SET SESSION sql_mode = (SELECT REPLACE(@@<EMAIL>mode,'NO_ZERO_DATE', ''))");
	db_insert(&mysql, "SET SESSION sql_mode = (SELECT REPLACE(@@<EMAIL>,'NO_ZERO_IN_DATE', ''))");
	db_insert(&mysql, "SET SESSION sql_mode = (SELECT REPLACE(@<EMAIL>,'ONLY_FULL_GROUP_BY', ''))");
	db_insert(&mysql, "SET SESSION sql_mode = (SELECT REPLACE(@@<EMAIL>mode,'NO_AUTO_VALUE_ON_ZERO', ''))");
	db_insert(&mysql, "SET SESSION sql_mode = (SELECT REPLACE(@@sql_mode,'TRADITIONAL', ''))");
	db_insert(&mysql, "SET SESSION sql_mode = (SELECT REPLACE(@@sql_mode,'STRICT_ALL_TABLES', ''))");
	db_insert(&mysql, "SET SESSION sql_mode = (SELECT REPLACE(@@sql_mode,'STRICT_TRANS_TABLES', ''))");

	/* allocate host and ping structures with appropriate values */
	if (!(host = (host_t *) malloc(sizeof(host_t)))) {
		die("ERROR: Fatal malloc error: poller.c host struct!");
	}
	memset(host, 0, sizeof(host_t));

	if (!(ping = (ping_t *) malloc(sizeof(ping_t)))) {
		die("ERROR: Fatal malloc error: poller.c ping struct!");
	}
	memset(ping, 0, sizeof(ping_t));

	if (!(reindex = (reindex_t *) malloc(sizeof(reindex_t)))) {
		die("ERROR: Fatal malloc error: poller.c reindex poll!");
	}
	memset(reindex, 0, sizeof(reindex_t));

	sysUptime[0] = '\0';

	/* determine the SQL limits using the poller instructions */
	if (host_data_ids > 0) {
		snprintf(limits, SMALL_BUFSIZE, "LIMIT %i, %i", host_data_ids * (host_thread - 1), host_data_ids);
	} else {
		limits[0] = '\0';
	}

	/* single polling interval query for items */
	if (set.poller_id == 0) {
		snprintf(query1, BUFSIZE,
			"SELECT action, hostname, snmp_community, "
				"snmp_version, snmp_username, snmp_password, "
				"rrd_name, rrd_path, arg1, arg2, arg3, local_data_id, "
				"rrd_num, snmp_port, snmp_timeout, "
				"snmp_auth_protocol, snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id "
			" FROM poller_item"
			" WHERE host_id=%i"
			" ORDER BY snmp_port %s", host_id, limits);

		/* host structure for uptime checks */
		snprintf(query2, BIG_BUFSIZE,
			"SELECT id, hostname, snmp_community, snmp_version, "
				"snmp_username, snmp_password, snmp_auth_protocol, "
				"snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id, snmp_port, snmp_timeout, max_oids, "
				"availability_method, ping_method, ping_port, ping_timeout, ping_retries, "
				"status, status_event_count, status_fail_date, "
				"status_rec_date, status_last_error, "
				"min_time, max_time, cur_time, avg_time, "
				"total_polls, failed_polls, availability, snmp_sysUptimeInstance, snmp_sysDescr, snmp_sysObjectID, "
                "snmp_sysContact, snmp_sysName, snmp_sysLocation"
			" FROM host"
			" WHERE id=%i", host_id);

		/* data query structure for reindex detection */
		snprintf(query4, BUFSIZE,
			"SELECT data_query_id, action, op, assert_value, arg1"
				" FROM poller_reindex"
				" WHERE host_id=%i", host_id);

		/* multiple polling interval query for items */
		snprintf(query5, BUFSIZE,
			"SELECT action, hostname, snmp_community, "
				"snmp_version, snmp_username, snmp_password, "
				"rrd_name, rrd_path, arg1, arg2, arg3, local_data_id, "
				"rrd_num, snmp_port, snmp_timeout, "
				"snmp_auth_protocol, snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id "
			" FROM poller_item"
			" WHERE host_id=%i AND rrd_next_step <=0"
			" ORDER by snmp_port %s", host_id, limits);

		/* query to setup the next polling interval in cacti */
		snprintf(query6, BUFSIZE,
			"UPDATE poller_item"
			" SET rrd_next_step=IF((rrd_next_step-%i)>=0, (rrd_next_step-%i), (rrd_step-%i))"
			" WHERE host_id=%i", set.poller_interval, set.poller_interval, set.poller_interval, host_id);

		/* query to add output records to the poller output table */
		snprintf(query8, BUFSIZE,
			"INSERT INTO poller_output"
			" (local_data_id, rrd_name, time, output) VALUES");

		/* query suffix to add rows to the poller output table */
		snprintf(posuffix, BUFSIZE,
			" ON DUPLICATE KEY UPDATE output=VALUES(output)");

		/* number of agent's count for single polling interval */
		snprintf(query9, BUFSIZE,
			"SELECT snmp_port, count(snmp_port)"
			" FROM poller_item"
			" WHERE host_id=%i"
			" GROUP BY snmp_port %s", host_id, limits);

		/* number of agent's count for multiple polling intervals */
		snprintf(query10, BUFSIZE,
			"SELECT snmp_port, count(snmp_port)"
			" FROM poller_item"
			" WHERE host_id=%i"
			" AND rrd_next_step <=0"
			" GROUP BY snmp_port %s", host_id, limits);
	} else {
		snprintf(query1, BUFSIZE,
			"SELECT action, hostname, snmp_community, "
				"snmp_version, snmp_username, snmp_password, "
				"rrd_name, rrd_path, arg1, arg2, arg3, local_data_id, "
				"rrd_num, snmp_port, snmp_timeout, "
				"snmp_auth_protocol, snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id "
			" FROM poller_item"
			" WHERE host_id=%i AND poller_id=%i"
			" ORDER BY snmp_port %s", host_id, set.poller_id, limits);

		/* host structure for uptime checks */
		snprintf(query2, BIG_BUFSIZE,
			"SELECT id, hostname, snmp_community, snmp_version, "
				"snmp_username, snmp_password, snmp_auth_protocol, "
				"snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id, snmp_port, snmp_timeout, max_oids, "
				"availability_method, ping_method, ping_port, ping_timeout, ping_retries, "
				"status, status_event_count, status_fail_date, "
				"status_rec_date, status_last_error, "
				"min_time, max_time, cur_time, avg_time, "
				"total_polls, failed_polls, availability, snmp_sysUptimeInstance, snmp_sysDescr, snmp_sysObjectID, "
				"snmp_sysContact, snmp_sysName, snmp_sysLocation"
			" FROM host"
			" WHERE id=%i", host_id);

		/* data query structure for reindex detection */
		snprintf(query4, BUFSIZE,
			"SELECT data_query_id, action, op, assert_value, arg1"
				" FROM poller_reindex"
				" WHERE host_id=%i", host_id);

		/* multiple polling interval query for items */
		snprintf(query5, BUFSIZE,
			"SELECT action, hostname, snmp_community, "
				"snmp_version, snmp_username, snmp_password, "
				"rrd_name, rrd_path, arg1, arg2, arg3, local_data_id, "
				"rrd_num, snmp_port, snmp_timeout, "
				"snmp_auth_protocol, snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id "
			" FROM poller_item"
			" WHERE host_id=%i AND rrd_next_step <=0 AND poller_id=%i"
			" ORDER by snmp_port %s", host_id, set.poller_id, limits);

		/* query to setup the next polling interval in cacti */
		snprintf(query6, BUFSIZE,
			"UPDATE poller_item"
			" SET rrd_next_step=IF((rrd_next_step-%i)>=0, (rrd_next_step-%i), (rrd_step-%i))"
			" WHERE host_id=%i AND poller_id=%i", set.poller_interval, set.poller_interval, set.poller_interval, host_id, set.poller_id);

		/* query to add output records to the poller output table */
		snprintf(query8, BUFSIZE,
			"INSERT INTO poller_output"
			" (local_data_id, rrd_name, time, output) VALUES");

		/* query suffix to add rows to the poller output table */
		snprintf(posuffix, BUFSIZE,
			" ON DUPLICATE KEY UPDATE output=VALUES(output)");

		/* number of agent's count for single polling interval */
		snprintf(query9, BUFSIZE,
			"SELECT snmp_port, count(snmp_port)"
			" FROM poller_item"
			" WHERE host_id=%i"
			" AND poller_id=%i"
			" GROUP BY snmp_port %s", host_id, set.poller_id, limits);

		/* number of agent's count for multiple polling intervals */
		snprintf(query10, BUFSIZE,
			"SELECT snmp_port, count(snmp_port)"
			" FROM poller_item"
			" WHERE host_id=%i"
			" AND rrd_next_step <=0"
			" AND poller_id=%i"
			" GROUP BY snmp_port %s", host_id, set.poller_id, limits);
	}

	/* query to add output records to the poller output table */
	snprintf(query11, BUFSIZE,
		"INSERT INTO poller_output_boost"
		" (local_data_id, rrd_name, time, output) VALUES");

	/* initialize the ping structure variables */
	snprintf(ping->ping_status,   50,            "down");
	snprintf(ping->ping_response, SMALL_BUFSIZE, "Ping not performed due to setting.");
	snprintf(ping->snmp_status,   50,            "down");
	snprintf(ping->snmp_response, SMALL_BUFSIZE, "SNMP not performed due to setting or ping result");

	/* if the host is a real host.  Note host_id=0 is not host based data source */
	if (host_id) {
		/* get data about this host */
		if ((result = db_query(&mysql, query2)) != 0) {
			num_rows = mysql_num_rows(result);

			if (num_rows != 1) {
				mysql_free_result(result);
				mysql_close(&mysql);

				#ifndef OLD_MYSQL
				mysql_thread_end();
				#endif

				return;
			}

			/* fetch the result */
			row = mysql_fetch_row(result);

			if (row) {
				/* initialize variables first */
				host->id                      = 0;					// 0
				host->hostname[0]             = '\0';				// 1
				host->snmp_session            = NULL;              // -
				host->snmp_community[0]       = '\0';              // 2
				host->snmp_version            = 1;                 // 3
				host->snmp_username[0]        = '\0';              // 4
				host->snmp_password[0]        = '\0';              // 5
				host->snmp_auth_protocol[0]   = '\0';              // 6
				host->snmp_priv_passphrase[0] = '\0';              // 7
				host->snmp_priv_protocol[0]   = '\0';              // 8
				host->snmp_context[0]         = '\0';              // 9
				host->snmp_engine_id[0]       = '\0';              // 10
				host->snmp_port               = 161;               // 11
				host->snmp_timeout            = 500;               // 12
				host->snmp_retries            = set.snmp_retries;  // -
				host->max_oids                = 10;                // 13
				host->availability_method     = 0;                 // 14
				host->ping_method             = 0;                 // 15
				host->ping_port               = 23;                // 16
				host->ping_timeout            = 500;               // 17
				host->ping_retries            = 2;                 // 18
				host->status                  = HOST_UP;           // 19
				host->status_event_count      = 0;                 // 20
				host->status_fail_date[0]     = '\0';              // 21
				host->status_rec_date[0]      = '\0';              // 22
				host->status_last_error[0]    = '\0';              // 23
				host->min_time                = 0;                 // 24
				host->max_time                = 0;                 // 25
				host->cur_time                = 0;                 // 26
				host->avg_time                = 0;                 // 27
				host->total_polls             = 0;                 // 28
				host->failed_polls            = 0;                 // 29
				host->availability            = 100;               // 30
				host->snmp_sysUpTimeInstance  = 0;                 // 31
				host->snmp_sysDescr[0]        = '\0';              // 32
				host->snmp_sysObjectID[0]     = '\0';              // 33
				host->snmp_sysContact[0]      = '\0';              // 34
				host->snmp_sysName[0]         = '\0';              // 35
				host->snmp_sysLocation[0]     = '\0';              // 36

				/* populate host structure */
				host->ignore_host = FALSE;
				if (row[0]  != NULL) host->id = atoi(row[0]);

				if (row[1]  != NULL) STRNCOPY(host->hostname,             row[1]);
				if (row[2]  != NULL) STRNCOPY(host->snmp_community,       row[2]);

				if (row[3]  != NULL) host->snmp_version = atoi(row[3]);

				if (row[4]  != NULL) STRNCOPY(host->snmp_username,        row[4]);
				if (row[5]  != NULL) STRNCOPY(host->snmp_password,        row[5]);
				if (row[6]  != NULL) STRNCOPY(host->snmp_auth_protocol,   row[6]);
				if (row[7]  != NULL) STRNCOPY(host->snmp_priv_passphrase, row[7]);
				if (row[8]  != NULL) STRNCOPY(host->snmp_priv_protocol,   row[8]);
				if (row[9]  != NULL) STRNCOPY(host->snmp_context,         row[9]);
				if (row[10]  != NULL) STRNCOPY(host->snmp_engine_id,       row[10]);

				if (row[11] != NULL) host->snmp_port           = atoi(row[11]);
				if (row[12] != NULL) host->snmp_timeout        = atoi(row[12]);
				if (row[13] != NULL) host->max_oids            = atoi(row[13]);

				if (row[14] != NULL) host->availability_method = atoi(row[14]);
				if (row[15] != NULL) host->ping_method         = atoi(row[15]);
				if (row[16] != NULL) host->ping_port           = atoi(row[16]);
				if (row[17] != NULL) host->ping_timeout        = atoi(row[17]);
				if (row[18] != NULL) host->ping_retries        = atoi(row[18]);

				if (row[19] != NULL) host->status              = atoi(row[19]);
				if (row[20] != NULL) host->status_event_count  = atoi(row[20]);

				if (row[21] != NULL) STRNCOPY(host->status_fail_date, row[21]);
				if (row[22] != NULL) STRNCOPY(host->status_rec_date,  row[22]);

				if (row[23] != NULL) STRNCOPY(host->status_last_error, row[23]);

				if (row[24] != NULL) host->min_time     = atof(row[24]);
				if (row[25] != NULL) host->max_time     = atof(row[25]);
				if (row[26] != NULL) host->cur_time     = atof(row[26]);
				if (row[27] != NULL) host->avg_time     = atof(row[27]);
				if (row[28] != NULL) host->total_polls  = atoi(row[28]);
				if (row[29] != NULL) host->failed_polls = atoi(row[29]);
				if (row[30] != NULL) host->availability = atof(row[30]);

				if (row[31] != NULL) host->snmp_sysUpTimeInstance=atoi(row[31]);
				if (row[32] != NULL) STRNCOPY(host->snmp_sysDescr, row[32]);
				if (row[33] != NULL) STRNCOPY(host->snmp_sysObjectID, row[33]);
				if (row[34] != NULL) STRNCOPY(host->snmp_sysContact, row[34]);
				if (row[35] != NULL) STRNCOPY(host->snmp_sysName, row[35]);
				if (row[36] != NULL) STRNCOPY(host->snmp_sysLocation, row[36]);

				/* correct max_oid bounds issues */
				if ((host->max_oids == 0) || (host->max_oids > 100)) {
					SPINE_LOG(("Device[%i] TH[%i] WARNING: Max OIDS is out of range with value of '%i'.  Resetting to default of 5", host_id, host_thread, host->max_oids));
					host->max_oids = 5;
				}

				/* free the host result */
				mysql_free_result(result);

				if (((host->snmp_version >= 1) && (host->snmp_version <= 2) &&
					(strlen(host->snmp_community) > 0)) ||
					(host->snmp_version == 3)) {
					host->snmp_session = snmp_host_init(host->id,
						host->hostname,
						host->snmp_version,
						host->snmp_community,
						host->snmp_username,
						host->snmp_password,
						host->snmp_auth_protocol,
						host->snmp_priv_passphrase,
						host->snmp_priv_protocol,
						host->snmp_context,
						host->snmp_engine_id,
						host->snmp_port,
						host->snmp_timeout);
				} else {
					host->snmp_session = NULL;
				}

				/* perform a check to see if the host is alive by polling it's SysDesc
				 * if the host down from an snmp perspective, don't poll it.
				 * function sets the ignore_host bit */
				if ((host->availability_method == AVAIL_SNMP) &&
					(strlen(host->snmp_community) == 0) &&
					(host->snmp_version < 3)) {
					host->ignore_host = FALSE;
					update_host_status(HOST_UP, host, ping, host->availability_method);

					if (is_debug_device(host->id)) {
						SPINE_LOG(("Device[%i] TH[%i] No host availability check possible for '%s'", host->id, host_thread, host->hostname));
					} else {
						SPINE_LOG_MEDIUM(("Device[%i] TH[%i] No host availability check possible for '%s'", host->id, host_thread, host->hostname));
					}
				} else {
					if (ping_host(host, ping) == HOST_UP) {
						host->ignore_host = FALSE;
						if (host_thread == 1) {
							update_host_status(HOST_UP, host, ping, host->availability_method);

							if ((host->availability_method != AVAIL_PING) && (host->availability_method != AVAIL_NONE)) {
								if (host->snmp_session != NULL) {
									get_system_information(host, &mysql, 1);
									ignore_sysinfo = FALSE;
								}
							}
						}
					} else {
						host->ignore_host = TRUE;
						if (host_thread == 1) {
							update_host_status(HOST_DOWN, host, ping, host->availability_method);
						}
					}
				}

				/* update host table */
				if (host_thread == 1) {
					if (!ignore_sysinfo) {
						if (host->ignore_host != TRUE) {
							snprintf(update_sql, BIG_BUFSIZE, "UPDATE host "
								"SET status='%i', status_event_count='%i', status_fail_date='%s',"
									" status_rec_date='%s', status_last_error='%s', min_time='%f',"
									" max_time='%f', cur_time='%f', avg_time='%f', total_polls='%i',"
									" failed_polls='%i', availability='%.4f', snmp_sysDescr='%s', "
									" snmp_sysObjectID='%s', snmp_sysUpTimeInstance='%u', "
									" snmp_sysContact='%s', snmp_sysName='%s', snmp_sysLocation='%s' "
								"WHERE id='%i'",
								host->status,
								host->status_event_count,
								host->status_fail_date,
								host->status_rec_date,
								host->status_last_error,
								host->min_time,
								host->max_time,
								host->cur_time,
								host->avg_time,
{'fraction_non_alphanumeric': 0.13923498629454273, 'fraction_numerical': 0.016571143782706205, 'mean_word_length': 2.64108574020868, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 289, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 42, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '544108', 'n_tokens_mistral': 18881, 'n_tokens_neox': 16242, 'n_words': 3978}