예제 #1
0
파일: util.c 프로젝트: budisfg/spine
/*! \fn void die(const char *format, ...)
 *  \brief a method to end Spine while returning the fatal error to stderr
 *
 *	Given a printf-style argument list, format it to the standard
 *	error, append a newline, then exit Spine.
 *
 */
void die(const char *format, ...) {
	va_list	args;
	char logmessage[BUFSIZE];
	char flogmessage[BUFSIZE];

	va_start(args, format);
	vsprintf(logmessage, format, args);
	va_end(args);

	if (set.logfile_processed) {
		if (set.parent_fork == SPINE_PARENT) {
			snprintf(flogmessage, BUFSIZE, "%s (Spine parent)", logmessage);
		}else{
			snprintf(flogmessage, BUFSIZE, "%s (Spine thread)", logmessage);
		}
	}else{
		snprintf(flogmessage, BUFSIZE, "%s (Spine init)", logmessage);
	}

	SPINE_LOG(("%s", flogmessage));

	if (set.parent_fork == SPINE_PARENT) {
		if (set.php_initialized) {
			php_close(PHP_INIT);
		}
	}

	exit(set.exit_code);
}
예제 #2
0
/*! \fn char *php_cmd(const char *php_command, int php_process)
 *  \brief calls the script server and executes a script command
 *  \param php_command the formatted php script server command
 *  \param php_process the php script server process to call
 *
 *  This function is called directly by the spine poller when a script server
 *  request has been initiated for a host.  It will place the PHP Script Server
 *  command on it's output pipe and then wait the pre-defined timeout period for
 *  a response on the PHP Script Servers output pipe.
 *
 *  \return pointer to the string results.  Must be freed by the parent.
 *
 */
char *php_cmd(const char *php_command, int php_process) {
	char *result_string;
	char command[BUFSIZE];
	int write_status;

	assert(php_command != 0);

	/* pad command with CR-LF */
	snprintf(command, BUFSIZE, "%s\r\n", php_command);

	/* place lock around mutex */
	switch (php_process) {
	case 0: thread_mutex_lock(LOCK_PHP_PROC_0);	break;
	case 1: thread_mutex_lock(LOCK_PHP_PROC_1);	break;
	case 2: thread_mutex_lock(LOCK_PHP_PROC_2);	break;
	case 3: thread_mutex_lock(LOCK_PHP_PROC_3);	break;
	case 4: thread_mutex_lock(LOCK_PHP_PROC_4);	break;
	case 5: thread_mutex_lock(LOCK_PHP_PROC_5);	break;
	case 6: thread_mutex_lock(LOCK_PHP_PROC_6);	break;
	case 7: thread_mutex_lock(LOCK_PHP_PROC_7);	break;
	case 8: thread_mutex_lock(LOCK_PHP_PROC_8);	break;
	case 9: thread_mutex_lock(LOCK_PHP_PROC_9);	break;
	}

	/* send command to the script server */
	write_status = write(php_processes[php_process].php_write_fd, command, strlen(command));

	/* if write status is <= 0 then the script server may be hung */
	if (write_status <= 0) {
		result_string = strdup("U");
		SPINE_LOG(("ERROR: SS[%i] PHP Script Server communications lost.\n", php_process));
		php_close(php_process);
	}else{
		/* read the result from the php_command */
		result_string = php_readpipe(php_process);
	}

	/* unlock around php process */
	switch (php_process) {
	case 0: thread_mutex_unlock(LOCK_PHP_PROC_0); break;
	case 1: thread_mutex_unlock(LOCK_PHP_PROC_1); break;
	case 2: thread_mutex_unlock(LOCK_PHP_PROC_2); break;
	case 3: thread_mutex_unlock(LOCK_PHP_PROC_3); break;
	case 4: thread_mutex_unlock(LOCK_PHP_PROC_4); break;
	case 5: thread_mutex_unlock(LOCK_PHP_PROC_5); break;
	case 6: thread_mutex_unlock(LOCK_PHP_PROC_6); break;
	case 7: thread_mutex_unlock(LOCK_PHP_PROC_7); break;
	case 8: thread_mutex_unlock(LOCK_PHP_PROC_8); break;
	case 9: thread_mutex_unlock(LOCK_PHP_PROC_9); break;
	}

	return result_string;
}
예제 #3
0
int main(int argc, char *argv[]) {
	struct timeval now;
	char *conf_file = NULL;
	double begin_time, end_time;
	int num_rows;
	int device_counter = 0;
	int last_active_threads = 0;
	long int THREAD_SLEEP = 100000;
	time_t nowbin;
	const struct tm *nowstruct;

	pthread_t* threads = NULL;
	pthread_attr_t attr;
	pthread_mutexattr_t mutexattr;

	int* ids = NULL;
	MYSQL mysql;
	MYSQL_RES *result = NULL;
	MYSQL_ROW mysql_row;
	int canexit = 0;
	int host_id;
	int i;
	int mutex_status = 0;
	int thread_status = 0;
	char result_string[BUFSIZE] = "";
	char logmessage[LOGSIZE];

	/* set start time for cacti */
	gettimeofday(&now, NULL);
	begin_time = (double) now.tv_usec / 1000000 + now.tv_sec;

	/* get time for poller_output table */
	if (time(&nowbin) == (time_t) - 1)
		printf("ERROR: Could not get time of day from time()\n");

	nowstruct = localtime(&nowbin);

	if (strftime(start_datetime, sizeof(start_datetime), "%Y-%m-%d %H:%M:%S", nowstruct) == (size_t) 0)
		printf("ERROR: Could not get string from strftime()\n");

	set.verbose = POLLER_VERBOSITY_HIGH;

	/* get static defaults for system */
	config_defaults(&set);

	/* scan arguments for errors */
	if ((argc != 1) && (argc != 3)) {
		printf("ERROR: Cactid requires either 0 or 2 input parameters\n");
		printf("USAGE: <cactidpath>/cactid [start_id end_id]\n");
		exit(-1);
	}

	/* return error if the first arg is greater than the second */
	if (argc == 3) {
		if (atol(argv[1]) > atol(argv[2])) {
			printf("ERROR: Invalid row specifications.  First row must be less than the second row\n");
			exit(-2);
		}
	}

	/* read configuration file to establish local environment */
	if (conf_file) {
		if ((read_cactid_config(conf_file, &set)) < 0) {
			printf("ERROR: Could not read config file: %s\n", conf_file);
			exit(-3);
		}
	}else{
		conf_file = malloc(BUFSIZE);

		if (!conf_file) {
			printf("ERROR: Fatal malloc error!\n");
			exit(-1);
		}

		for(i=0;i<CONFIG_PATHS;i++) {
			snprintf(conf_file, BUFSIZE, "%s%s", config_paths[i], DEFAULT_CONF_FILE);

			if (read_cactid_config(conf_file, &set) >= 0) {
				break;
			}

			if (i == CONFIG_PATHS-1) {
				snprintf(conf_file, BUFSIZE, "%s%s", config_paths[0], DEFAULT_CONF_FILE);
			}
		}
	}

	/* read settings table from the database to further establish environment */
	read_config_options(&set);

	/* set the poller ID, stub for next version */
	set.poller_id = 0;

	if (set.verbose == POLLER_VERBOSITY_DEBUG) {
		snprintf(logmessage, LOGSIZE, "CACTID: Version %s starting\n", VERSION);
		cacti_log(logmessage);
	} else {
		printf("CACTID: Version %s starting\n", VERSION);
	}

	/* connect to database */
	db_connect(set.dbdb, &mysql);

	/* initialize SNMP */
	init_snmp("cactid");

	/* initialize PHP */
	php_init();

	/* get the id's to poll */
	switch (argc) {
		case 1:
			result = db_query(&mysql, "SELECT id FROM host WHERE disabled='' ORDER BY id");

			break;
		case 3:
			snprintf(result_string, sizeof(result_string), "SELECT id FROM host WHERE (disabled='' and (id >= %s and id <= %s)) ORDER BY id\0", argv[1], argv[2]);
			result = db_query(&mysql, result_string);

			break;
		default:
			break;
	}

	num_rows = mysql_num_rows(result);
	threads = (pthread_t *)malloc(num_rows * sizeof(pthread_t));
	ids = (int *)malloc(num_rows * sizeof(int));

	/* initialize threads and mutexes */
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

	init_mutexes();

	if (set.verbose == POLLER_VERBOSITY_DEBUG) {
		snprintf(logmessage, LOGSIZE, "DEBUG: Initial Value of Active Threads is %i\n", active_threads);
		cacti_log(logmessage);
	}

	/* loop through devices until done */
	while (device_counter < num_rows) {
		mutex_status = thread_mutex_trylock(LOCK_THREAD);

		switch (mutex_status) {
		case 0:
			if (last_active_threads != active_threads) {
				last_active_threads = active_threads;
			}

			while ((active_threads < set.threads) && (device_counter < num_rows)) {
				mysql_row = mysql_fetch_row(result);
				host_id = atoi(mysql_row[0]);
				ids[device_counter] = host_id;

				/* create child process */
				thread_status = pthread_create(&threads[device_counter], &attr, child, &ids[device_counter]);

				switch (thread_status) {
					case 0:
						if (set.verbose == POLLER_VERBOSITY_DEBUG) {
							snprintf(logmessage, LOGSIZE, "DEBUG: Valid Thread to be Created\n");
							cacti_log(logmessage);
						}

						device_counter++;
						active_threads++;

						if (set.verbose == POLLER_VERBOSITY_DEBUG) {
							snprintf(logmessage, LOGSIZE, "DEBUG: The Value of Active Threads is %i\n", active_threads);
							cacti_log(logmessage);
						}

						break;
					case EAGAIN:
						snprintf(logmessage, LOGSIZE, "ERROR: The System Lacked the Resources to Create a Thread\n");
						cacti_log(logmessage);
						break;
					case EFAULT:
						snprintf(logmessage, LOGSIZE, "ERROR: The Thread or Attribute Was Invalid\n");
						cacti_log(logmessage);
						break;
					case EINVAL:
						snprintf(logmessage, LOGSIZE, "ERROR: The Thread Attribute is Not Initialized\n");
						cacti_log(logmessage);
						break;
					default:
						snprintf(logmessage, LOGSIZE, "ERROR: Unknown Thread Creation Error\n");
						cacti_log(logmessage);
						break;
				}
				usleep(THREAD_SLEEP);
			}

			thread_mutex_unlock(LOCK_THREAD);

			break;
		case EBUSY:
			snprintf(logmessage, LOGSIZE, "ERROR: Deadlock Occured\n");
			cacti_log(logmessage);
			break;
		case EINVAL:
			snprintf(logmessage, LOGSIZE, "ERROR: Attempt to Unlock an Uninitialized Mutex\n");
			cacti_log(logmessage);
			break;
		case EFAULT:
			snprintf(logmessage, LOGSIZE, "ERROR: Attempt to Unlock an Invalid Mutex\n");
			cacti_log(logmessage);
			break;
		default:
			snprintf(logmessage, LOGSIZE, "ERROR: Unknown Mutex Lock Error Code Returned\n");
			cacti_log(logmessage);
			break;
		}

		usleep(THREAD_SLEEP);
	}

	/* wait for all threads to complete */
	while (canexit == 0) {
		if (thread_mutex_trylock(LOCK_THREAD) != EBUSY) {
			if (last_active_threads != active_threads) {
				last_active_threads = active_threads;
			}

			if (active_threads == 0) {
				canexit = 1;
			}

			thread_mutex_unlock(LOCK_THREAD);
		}

		usleep(THREAD_SLEEP);
	}

	/* print out stats */
	gettimeofday(&now, NULL);

	/* update the db for |data_time| on graphs */
	db_insert(&mysql, "replace into settings (name,value) values ('date',NOW())");
	db_insert(&mysql, "insert into poller_time (poller_id, start_time, end_time) values (0, NOW(), NOW())");

	/* cleanup and exit program */
	pthread_attr_destroy(&attr);
	pthread_mutexattr_destroy(&mutexattr);

	if (set.verbose == POLLER_VERBOSITY_DEBUG) {
		cacti_log("DEBUG: Thread Cleanup Complete\n");
	}

	/* close the php script server */
	php_close();

	if (set.verbose == POLLER_VERBOSITY_DEBUG) {
		cacti_log("DEBUG: PHP Script Server Pipes Closed\n");
	}

	/* free malloc'd variables */
	free(threads);
	free(ids);
	free(conf_file);

	if (set.verbose == POLLER_VERBOSITY_DEBUG) {
		cacti_log("DEBUG: Allocated Variable Memory Freed\n");
	}

	/* close mysql */
	mysql_free_result(result);
	mysql_close(&mysql);

	if (set.verbose == POLLER_VERBOSITY_DEBUG) {
		cacti_log("DEBUG: MYSQL Free & Close Completed\n");
	}

	/* finally add some statistics to the log and exit */
	end_time = (double) now.tv_usec / 1000000 + now.tv_sec;

	if ((set.verbose >= POLLER_VERBOSITY_MEDIUM) && (argc != 1)) {
		snprintf(logmessage, LOGSIZE, "Time: %.4f s, Threads: %i, Hosts: %i\n", (end_time - begin_time), set.threads, num_rows);
		cacti_log(logmessage);
	} else {
		printf("CACTID: Execution Time: %.4f s, Threads: %i, Hosts: %i\n", (end_time - begin_time), set.threads, num_rows);
	}

	exit(0);
}
예제 #4
0
/*! \fn main(int argc, char *argv[])
 *  \brief The Cactid program entry point
 *  \param argc The number of arguments passed to the function plus one (+1)
 *  \param argv An array of the command line arguments
 *
 *  The Cactid entry point.  This function performs the following tasks.
 *  1) Processes command line input parameters
 *  2) Processes the Cactid configuration file to obtain database access information
 *  3) Process runtime parameters from the settings table
 *  4) Initialize the runtime threads and mutexes for the threaded environment
 *  5) Initialize Net-SNMP, MySQL, and the PHP Script Server (if required)
 *  6) Spawns X threads in order to process hosts
 *  7) Loop until either all hosts have been processed or until the poller runtime
 *     has been exceeded
 *  8) Close database and free variables
 *  9) Log poller process statistics if required
 *  10) Exit
 *
 *  Note: Command line runtime parameters override any database settings.
 *
 *  \return 0 if SUCCESS, or -1 if FAILED
 *
 */
int main(int argc, char *argv[]) {
	struct timeval now;
	char *conf_file = NULL;
	double begin_time, end_time, current_time;
	int poller_interval;
	int num_rows;
	int device_counter = 0;
	int poller_counter = 0;
	int last_active_threads = 0;
	long int EXTERNAL_THREAD_SLEEP = 100000;
	long int internal_thread_sleep;
	time_t nowbin;
	struct tm now_time;
	struct tm *now_ptr;

	pthread_t* threads = NULL;
	pthread_attr_t attr;

	int* ids = NULL;
	MYSQL mysql;
	MYSQL_RES *result = NULL;
	MYSQL_ROW mysql_row;
	int canexit = 0;
	int host_id;
	int i;
	int mutex_status = 0;
	int thread_status = 0;

	UNUSED_PARAMETER(argc);		/* we operate strictly with argv */

	/* establish php processes and initialize space */
	php_processes = (php_t*) calloc(MAX_PHP_SERVERS, sizeof(php_t));
	for (i = 0; i < MAX_PHP_SERVERS; i++) {
		php_processes[i].php_state = PHP_BUSY;
	}

	/* set start time for cacti */
	begin_time = get_time_as_double();

	/* get time for poller_output table */
	if (time(&nowbin) == (time_t) - 1) {
		die("ERROR: Could not get time of day from time()\n");
	}
	localtime_r(&nowbin,&now_time);
	now_ptr = &now_time;

	if (strftime(start_datetime, sizeof(start_datetime), "%Y-%m-%d %H:%M:%S", now_ptr) == (size_t) 0) {
		die("ERROR: Could not get string from strftime()\n");
	}

	/* set default verbosity */
	set.log_level = POLLER_VERBOSITY_LOW;

	/* get static defaults for system */
	config_defaults();

	/*! ----------------------------------------------------------------
	 * PROCESS COMMAND LINE
	 *
	 * Run through the list of ARGV words looking for parameters we
	 * know about. Most have two flavors (-C + --conf), and many
	 * themselves take a parameter.
	 *
	 * These parameters can be structured in two ways:
	 *
	 *	--conf=FILE		both parts in one argv[] string
	 *	--conf FILE		two separate argv[] strings
	 *
	 * We set "arg" to point to "--conf", and "opt" to point to FILE.
	 * The helper routine
	 *
	 * In each loop we set "arg" to next argv[] string, then look
	 * to see if it has an equal sign. If so, we split it in half
	 * and point to the option separately.
	 *
	 * NOTE: most direction to the program is given with dash-type
	 * parameters, but we also allow standalone numeric device IDs
	 * in "first last" format: this is how poller.php calls this
	 * program.
	 */

	/* initialize some global variables */
	set.start_host_id = -1;
	set.end_host_id   = -1;
	set.php_initialized = FALSE;
	set.logfile_processed = FALSE;
	set.parent_fork = CACTID_PARENT;

	for (argv++; *argv; argv++) {
		char	*arg = *argv;
		char	*opt = strchr(arg, '=');	/* pick off the =VALUE part */

		if (opt) *opt++ = '\0';

		if (STRIMATCH(arg, "-f") ||
			STRIMATCH(arg, "--first")) {
			if (HOSTID_DEFINED(set.start_host_id)) {
				die("ERROR: %s can only be used once", arg);
			}

			set.start_host_id = atoi(opt = getarg(opt, &argv));

			if (!HOSTID_DEFINED(set.start_host_id)) {
				die("ERROR: '%s=%s' is invalid first-host ID", arg, opt);
			}
		}

		else if (STRIMATCH(arg, "-l") ||
				 STRIMATCH(arg, "--last")) {
			if (HOSTID_DEFINED(set.end_host_id)) {
				die("ERROR: %s can only be used once", arg);
			}

			set.end_host_id = atoi(opt = getarg(opt, &argv));

			if (!HOSTID_DEFINED(set.end_host_id)) {
				die("ERROR: '%s=%s' is invalid last-host ID", arg, opt);
			}
		}

		else if (STRIMATCH(arg, "-p") ||
				 STRIMATCH(arg, "--poller")) {
			set.poller_id = atoi(getarg(opt, &argv));
		}

		else if (STRIMATCH(arg, "-h") ||
				 STRIMATCH(arg, "-v") ||
				 STRIMATCH(arg, "--help") ||
				 STRIMATCH(arg, "--version")) {
			display_help();

			exit(EXIT_SUCCESS);
		}

		else if (STRIMATCH(arg, "-O") ||
				 STRIMATCH(arg, "--option")) {
			char	*setting = getarg(opt, &argv);
			char	*value   = strchr(setting, ':');

			if (*value) {
				*value++ = '\0';
			}else{
				die("ERROR: -O requires setting:value");
			}

			set_option(setting, value);
		}

		else if (STRIMATCH(arg, "-R") ||
				 STRIMATCH(arg, "--readonly") ||
				 STRIMATCH(arg, "--read-only")) {
			set.SQL_readonly = TRUE;
		}

		else if (STRIMATCH(arg, "-C") ||
				 STRIMATCH(arg, "--conf")) {
			conf_file = strdup(getarg(opt, &argv));
		}

		else if (STRIMATCH(arg, "-S") ||
				 STRIMATCH(arg, "--stdout")) {
			set_option("log_destination", "STDOUT");
		}

		else if (STRIMATCH(arg, "-L") ||
				 STRIMATCH(arg, "--log")) {
			set_option("log_destination", getarg(opt, &argv));
		}

		else if (STRIMATCH(arg, "-V") ||
				 STRIMATCH(arg, "--verbosity")) {
			set_option("log_verbosity", getarg(opt, &argv));
		}

		else if (STRIMATCH(arg, "--snmponly") ||
				 STRIMATCH(arg, "--snmp-only")) {
			set.snmponly = TRUE;
		}

		else if (!HOSTID_DEFINED(set.start_host_id) && all_digits(arg)) {
			set.start_host_id = atoi(arg);
		}

		else if (!HOSTID_DEFINED(set.end_host_id) && all_digits(arg)) {
			set.end_host_id = atoi(arg);
		}

		else {
			die("ERROR: %s is an unknown command-line parameter", arg);
		}
	}

	/* we require either both the first and last hosts, or niether host */
	if (HOSTID_DEFINED(set.start_host_id) != HOSTID_DEFINED(set.end_host_id)) {
		die("ERROR: must provide both -f/-l, or neither");
	}

	if (set.start_host_id > set.end_host_id) {
		die("ERROR: Invalid row spec; first host_id must be less than the second");
	}

	/* read configuration file to establish local environment */
	if (conf_file) {
		if ((read_cactid_config(conf_file)) < 0) {
			die("ERROR: Could not read config file: %s\n", conf_file);
		}
	}else{
		if (!(conf_file = calloc(1, BUFSIZE))) {
			die("ERROR: Fatal malloc error: cactid.c conf_file!\n");
		}

		for (i=0; i<CONFIG_PATHS; i++) {
			snprintf(conf_file, BUFSIZE-1, "%s%s", config_paths[i], DEFAULT_CONF_FILE);

			if (read_cactid_config(conf_file) >= 0) {
				break;
			}

			if (i == CONFIG_PATHS-1) {
				snprintf(conf_file, BUFSIZE-1, "%s%s", config_paths[0], DEFAULT_CONF_FILE);
			}
		}
	}

	/* read settings table from the database to further establish environment */
	read_config_options();

	/* set the poller interval for those who use less than 5 minute intervals */
	if (set.poller_interval == 0) {
		poller_interval = 300;
	}else {
		poller_interval = set.poller_interval;
	}

	/* calculate the external_tread_sleep value */
	internal_thread_sleep = EXTERNAL_THREAD_SLEEP * set.num_parent_processes / 2;

	if (set.log_level == POLLER_VERBOSITY_DEBUG) {
		CACTID_LOG_DEBUG(("CACTID: Version %s starting\n", VERSION));
	}else{
		printf("CACTID: Version %s starting\n", VERSION);
	}

	/* connect to database */
	db_connect(set.dbdb, &mysql);

	/* initialize SNMP */
	CACTID_LOG_DEBUG(("CACTID: Initializing Net-SNMP API\n"));
	snmp_cactid_init();

	/* initialize PHP if required */
	CACTID_LOG_DEBUG(("CACTID: Initializing PHP Script Server\n"));

	/* tell cactid that it is parent, and set the poller id */
	set.parent_fork = CACTID_PARENT;
	set.poller_id = 0;

	/* initialize the script server */
	if (set.php_required) {
		php_init(PHP_INIT);
		set.php_initialized = TRUE;
		set.php_current_server = 0;
	}

	/* obtain the list of hosts to poll */
	{
	char querybuf[256], *qp = querybuf;

	qp += sprintf(qp, "SELECT id FROM host");
	qp += sprintf(qp, " WHERE disabled=''");
	qp += append_hostrange(qp, "id");	/* AND id BETWEEN a AND b */
	qp += sprintf(qp, " ORDER BY id");

	result = db_query(&mysql, querybuf);
	}

	num_rows = mysql_num_rows(result) + 1; /* add 1 for host = 0 */

	if (!(threads = (pthread_t *)malloc(num_rows * sizeof(pthread_t)))) {
		die("ERROR: Fatal malloc error: cactid.c threads!\n");
	}

	if (!(ids = (int *)malloc(num_rows * sizeof(int)))) {
		die("ERROR: Fatal malloc error: cactid.c host id's!\n");
	}

	/* initialize threads and mutexes */
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

	init_mutexes();

	CACTID_LOG_DEBUG(("DEBUG: Initial Value of Active Threads is %i\n", active_threads));

	/* tell fork processes that they are now active */
	set.parent_fork = CACTID_FORK;

	/* loop through devices until done */
	while ((device_counter < num_rows) && (canexit == 0)) {
		mutex_status = thread_mutex_trylock(LOCK_THREAD);

		switch (mutex_status) {
		case 0:
			if (last_active_threads != active_threads) {
				last_active_threads = active_threads;
			}

			while ((active_threads < set.threads) && (device_counter < num_rows)) {
				if (device_counter > 0) {
					mysql_row = mysql_fetch_row(result);
					host_id = atoi(mysql_row[0]);
					ids[device_counter] = host_id;
				}else{
					ids[device_counter] = 0;
				}

				/* create child process */
				thread_status = pthread_create(&threads[device_counter], &attr, child, &ids[device_counter]);

				switch (thread_status) {
					case 0:
						CACTID_LOG_DEBUG(("DEBUG: Valid Thread to be Created\n"));

						device_counter++;
						active_threads++;

						CACTID_LOG_DEBUG(("DEBUG: The Value of Active Threads is %i\n", active_threads));

						break;
					case EAGAIN:
						CACTID_LOG(("ERROR: The System Lacked the Resources to Create a Thread\n"));
						break;
					case EFAULT:
						CACTID_LOG(("ERROR: The Thread or Attribute Was Invalid\n"));
						break;
					case EINVAL:
						CACTID_LOG(("ERROR: The Thread Attribute is Not Initialized\n"));
						break;
					default:
						CACTID_LOG(("ERROR: Unknown Thread Creation Error\n"));
						break;
				}
				usleep(internal_thread_sleep);

				/* get current time and exit program if time limit exceeded */
				if (poller_counter >= 20) {
					current_time = get_time_as_double();

					if ((current_time - begin_time + 6) > poller_interval) {
						CACTID_LOG(("ERROR: Cactid Timed Out While Processing Hosts Internal\n"));
						canexit = 1;
						break;
					}

					poller_counter = 0;
				}else{
					poller_counter++;
				}
			}

			thread_mutex_unlock(LOCK_THREAD);

			break;
		case EDEADLK:
			CACTID_LOG(("ERROR: Deadlock Occured\n"));
			break;
		case EBUSY:
			break;
		case EINVAL:
			CACTID_LOG(("ERROR: Attempt to Unlock an Uninitialized Mutex\n"));
			break;
		case EFAULT:
			CACTID_LOG(("ERROR: Attempt to Unlock an Invalid Mutex\n"));
			break;
		default:
			CACTID_LOG(("ERROR: Unknown Mutex Lock Error Code Returned\n"));
			break;
		}

		usleep(internal_thread_sleep);

		/* get current time and exit program if time limit exceeded */
		if (poller_counter >= 20) {
			current_time = get_time_as_double();

			if ((current_time - begin_time + 6) > poller_interval) {
				CACTID_LOG(("ERROR: Cactid Timed Out While Processing Hosts Internal\n"));
				canexit = 1;
				break;
			}

			poller_counter = 0;
		}else{
			poller_counter++;
		}
	}

	/* wait for all threads to complete */
	while (canexit == 0) {
		if (thread_mutex_trylock(LOCK_THREAD) == 0) {
			if (last_active_threads != active_threads) {
				last_active_threads = active_threads;
			}

			if (active_threads == 0) {
				canexit = 1;
			}

			thread_mutex_unlock(LOCK_THREAD);
		}

		usleep(EXTERNAL_THREAD_SLEEP);

		/* get current time and exit program if time limit exceeded */
		if (poller_counter >= 20) {
			current_time = get_time_as_double();

			if ((current_time - begin_time + 6) > poller_interval) {
				CACTID_LOG(("ERROR: Cactid Timed Out While Processing Hosts Internal\n"));
				canexit = 1;
				break;
			}

			poller_counter = 0;
		}else{
			poller_counter++;
		}
	}

	/* tell Cactid that it is now parent */
	set.parent_fork = CACTID_PARENT;

	/* print out stats */
	gettimeofday(&now, NULL);

	/* update the db for |data_time| on graphs */
	db_insert(&mysql, "replace into settings (name,value) values ('date',NOW())");
	db_insert(&mysql, "insert into poller_time (poller_id, start_time, end_time) values (0, NOW(), NOW())");

	/* cleanup and exit program */
	pthread_attr_destroy(&attr);

	CACTID_LOG_DEBUG(("DEBUG: Thread Cleanup Complete\n"));

	/* close the php script server */
	if (set.php_required) {
		php_close(PHP_INIT);
	}

	CACTID_LOG_DEBUG(("DEBUG: PHP Script Server Pipes Closed\n"));

	/* free malloc'd variables */
	free(threads);
	free(ids);
	free(conf_file);

	CACTID_LOG_DEBUG(("DEBUG: Allocated Variable Memory Freed\n"));

	/* shutdown SNMP */
	snmp_cactid_close();

	CACTID_LOG_DEBUG(("CACTID: Net-SNMP API Shutdown Completed\n"));

	/* close mysql */
	mysql_free_result(result);
	mysql_close(&mysql);

	CACTID_LOG_DEBUG(("DEBUG: MYSQL Free & Close Completed\n"));

	/* finally add some statistics to the log and exit */
	end_time = TIMEVAL_TO_DOUBLE(now);

	CACTID_LOG_MEDIUM(("Time: %.4f s, Threads: %i, Hosts: %i\n", (end_time - begin_time), set.threads, num_rows));

	exit(EXIT_SUCCESS);
}
예제 #5
0
/*! \fn char *php_readpipe(int php_process)
 *  \brief read a line from a PHP Script Server process
 *  \param php_process the PHP Script Server process to obtain output from
 *
 *  This function will read the output pipe from the PHP Script Server process
 *  and return that string to the Spine thread requesting the output.  If for
 *  some reason the PHP Script Server process does not respond in time, it will
 *  be closed using the php_close function, then restarted.
 *
 *  \return a string pointer to the PHP Script Server response
 */
char *php_readpipe(int php_process) {
	fd_set fds;
	struct timeval timeout;
	double begin_time = 0;
	double end_time = 0;
	char *result_string;

	int  i;
	char *cp;
	char *bptr;

	if (!(result_string = (char *)malloc(BUFSIZE))) {
		die("ERROR: Fatal malloc error: php.c php_readpipe!");
	}
	result_string[0] = '\0';

	/* record start time */
	begin_time = get_time_as_double();

	/* initialize file descriptors to review for input/output */
	FD_ZERO(&fds);
	FD_SET(php_processes[php_process].php_read_fd,&fds);

	/* establish timeout value for the PHP script server to respond */
	timeout.tv_sec = set.script_timeout;
	timeout.tv_usec = 0;

	/* check to see which pipe talked and take action
	 * should only be the READ pipe */
	retry:
	switch (select(FD_SETSIZE, &fds, NULL, NULL, &timeout)) {
	case -1:
		switch (errno) {
			case EBADF:
				SPINE_LOG(("ERROR: SS[%i] An invalid file descriptor was given in one of the sets.\n", php_process));
				break;
			case EAGAIN:
			case EINTR:
				#ifndef SOLAR_THREAD
				/* take a moment */
				usleep(2000);
				#endif

				/* record end time */
				end_time = get_time_as_double();

				/* re-establish new timeout value */
				timeout.tv_sec = rint(floor(set.script_timeout-(end_time-begin_time)));
				timeout.tv_usec = rint((set.script_timeout-(end_time-begin_time)-timeout.tv_sec)*1000000);

				if ((end_time - begin_time) < set.script_timeout) {
					goto retry;
				}else{
					SPINE_LOG(("WARNING: SS[%i] The Script Server script timed out while processing EINTR's.\n", php_process));
				}
				break;
			case EINVAL:
				SPINE_LOG(("ERROR: SS[%i] N is negative or the value contained within timeout is invalid.\n", php_process));
				break;
			case ENOMEM:
				SPINE_LOG(("ERROR: SS[%i] Select was unable to allocate memory for internal tables.\n", php_process));
				break;
			default:
				SPINE_LOG(("ERROR: SS[%i] Unknown fatal select() error\n", php_process));
				break;
		}

		SET_UNDEFINED(result_string);

		/* kill script server because it is misbehaving */
		php_close(php_process);
		php_init(php_process);
		break;
	case 0:
		SPINE_LOG(("WARNING: SS[%i] The PHP Script Server did not respond in time and will therefore be restarted\n", php_process));
		SET_UNDEFINED(result_string);

		/* kill script server because it is misbehaving */
		php_close(php_process);
		php_init(php_process);
		break;
	default:
		bptr = result_string;

		while (1) {
			i = read(php_processes[php_process].php_read_fd,bptr,BUFSIZE-(bptr-result_string));

			if (i <= 0) {
				SET_UNDEFINED(result_string);
				break;
			}

			bptr += i;
			*bptr = '\0';	/* make what we've got into a string */

			if ((cp = strstr(result_string,"\n")) > 0) {
				*cp = '\0';

				if ((cp = strstr(result_string,"\r")) > 0) {
					*cp = '\0';
				}

				break;
			}

			if (bptr >= result_string+BUFSIZE) {
				SPINE_LOG(("ERROR: SS[%i] The Script Server result was longer than the acceptable range\n", php_process));
				SET_UNDEFINED(result_string);
			}
		}

		php_processes[php_process].php_state = PHP_READY;
	}

	return result_string;
}
예제 #6
0
파일: php.c 프로젝트: budisfg/spine
/*! \fn char *php_cmd(const char *php_command, int php_process)
 *  \brief calls the script server and executes a script command
 *  \param php_command the formatted php script server command
 *  \param php_process the php script server process to call
 *
 *  This function is called directly by the spine poller when a script server
 *  request has been initiated for a host.  It will place the PHP Script Server
 *  command on it's output pipe and then wait the pre-defined timeout period for
 *  a response on the PHP Script Servers output pipe.
 *
 *  \return pointer to the string results.  Must be freed by the parent.
 *
 */
char *php_cmd(const char *php_command, int php_process) {
    char *result_string;
    char command[BUFSIZE];
    ssize_t bytes;
    int retries = 0;

    assert(php_command != 0);

    /* pad command with CR-LF */
    snprintf(command, BUFSIZE, "%s\r\n", php_command);

    /* place lock around mutex */
    switch (php_process) {
    case 0:
        thread_mutex_lock(LOCK_PHP_PROC_0);
        break;
    case 1:
        thread_mutex_lock(LOCK_PHP_PROC_1);
        break;
    case 2:
        thread_mutex_lock(LOCK_PHP_PROC_2);
        break;
    case 3:
        thread_mutex_lock(LOCK_PHP_PROC_3);
        break;
    case 4:
        thread_mutex_lock(LOCK_PHP_PROC_4);
        break;
    case 5:
        thread_mutex_lock(LOCK_PHP_PROC_5);
        break;
    case 6:
        thread_mutex_lock(LOCK_PHP_PROC_6);
        break;
    case 7:
        thread_mutex_lock(LOCK_PHP_PROC_7);
        break;
    case 8:
        thread_mutex_lock(LOCK_PHP_PROC_8);
        break;
    case 9:
        thread_mutex_lock(LOCK_PHP_PROC_9);
        break;
    }

    /* send command to the script server */
retry:
    bytes = write(php_processes[php_process].php_write_fd, command, strlen(command));

    /* if write status is <= 0 then the script server may be hung */
    if (bytes <= 0) {
        result_string = strdup("U");
        SPINE_LOG(("ERROR: SS[%i] PHP Script Server communications lost.  Restarting PHP Script Server", php_process));
        php_close(php_process);
        php_init(php_process);
        /* increment and retry a few times on the next item */
        retries++;
        if (retries < 3) {
            goto retry;
        }
    } else {
        /* read the result from the php_command */
        result_string = php_readpipe(php_process);

        /* check for a null */
        if (!strlen(result_string)) {
            SET_UNDEFINED(result_string);
        }
    }

    /* unlock around php process */
    switch (php_process) {
    case 0:
        thread_mutex_unlock(LOCK_PHP_PROC_0);
        break;
    case 1:
        thread_mutex_unlock(LOCK_PHP_PROC_1);
        break;
    case 2:
        thread_mutex_unlock(LOCK_PHP_PROC_2);
        break;
    case 3:
        thread_mutex_unlock(LOCK_PHP_PROC_3);
        break;
    case 4:
        thread_mutex_unlock(LOCK_PHP_PROC_4);
        break;
    case 5:
        thread_mutex_unlock(LOCK_PHP_PROC_5);
        break;
    case 6:
        thread_mutex_unlock(LOCK_PHP_PROC_6);
        break;
    case 7:
        thread_mutex_unlock(LOCK_PHP_PROC_7);
        break;
    case 8:
        thread_mutex_unlock(LOCK_PHP_PROC_8);
        break;
    case 9:
        thread_mutex_unlock(LOCK_PHP_PROC_9);
        break;
    }

    return result_string;
}