Пример #1
0
/*! \fn void snmp_spine_init()
 *  \brief wrapper function for init_snmp
 *
 *	Initializes snmp for the given application ID
 *
 */
void snmp_spine_init(void) {
#ifdef USE_NET_SNMP
	/* Only do numeric output */
	#ifdef NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM
		netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM, 1);
	#endif

	/* Prevent update of the snmpapp.conf file */
	#ifdef NETSNMP_DS_LIB_DONT_PERSIST_STATE
		netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_PERSIST_STATE, 1);
	#endif

	/* Prevent update of the snmpapp.conf file */
	#ifdef NETSNMP_DS_LIB_DISABLE_PERSISTENT_LOAD
		netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DISABLE_PERSISTENT_LOAD, 1);
	#endif

	#ifdef NETSNMP_DS_LIB_DONT_PRINT_UNITS
		netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_PRINT_UNITS, 1);
	#endif

	netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT, 1);
	netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT, 1);
	netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_BARE_VALUE, 1);
	netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NUMERIC_TIMETICKS, 1);

	#ifdef PACKAGE_VERSION
		/* check that the headers we compiled with match the library we linked with -
		   apparently not defined in UCD-SNMP...
		*/
		SPINE_LOG_DEBUG(("DEBUG: SNMP Header Version is %s\n", PACKAGE_VERSION));
		SPINE_LOG_DEBUG(("DEBUG: SNMP Library Version is %s\n", netsnmp_get_version()));

		if(STRMATCH(PACKAGE_VERSION,netsnmp_get_version())) {
			init_snmp("spine");
		}else{
			/* report the error and quit spine */
			die("ERROR: SNMP Library Version Mismatch (%s vs %s)",PACKAGE_VERSION,netsnmp_get_version());
		}
	#else
		SPINE_LOG_DEBUG(("DEBUG: Issues with SNMP Header Version information, assuming old version of Net-SNMP.\n"));
		init_snmp("spine");
	#endif
#else
	ds_set_boolean(DS_LIBRARY_ID, DS_LIB_QUICK_PRINT, 1);
	ds_set_boolean(DS_LIBRARY_ID, DS_LIB_PRINT_BARE_VALUE, 1);
	ds_set_boolean(DS_LIBRARY_ID, DS_LIB_NUMERIC_TIMETICKS, 1);

	init_snmp("spine");
#endif
}
Пример #2
0
/*! \fn void php_close(int php_process)
 *  \brief close the php script server process
 *  \param php_process the process to close or PHP_INIT
 *
 *  This function will take an input parameter of either a specially coded
 *  PHP_INIT parameter or an integer stating the process number.  With that
 *  information is will close and/or terminate the child PHP Script Server
 *  process and then return to the calling function.
 *
 *  TODO: Make ending of the child process not be reliant on SIG_TERM in cases
 *  where the child process is hung for one reason or another.
 *
 */
void php_close(int php_process) {
    int i;
    int num_processes;
    ssize_t bytes;

    if (php_process == PHP_INIT) {
        num_processes = set.php_servers;
    } else {
        num_processes = 1;
    }

    for(i = 0; i < num_processes; i++) {
        php_t *phpp;

        SPINE_LOG_DEBUG(("DEBUG: SS[%i] Script Server Shutdown Started", i));

        /* tell the script server to close */
        if (php_process == PHP_INIT) {
            phpp = &php_processes[i];
        } else {
            phpp = &php_processes[php_process];
        }

        /* If we still have a valid write pipe, tell PHP to close down
         * by sending a "quit" message, then closing the input channel
         * so it gets an EOF.
         *
         * Then we wait a moment before actually killing it to allow for
         * a clean shutdown.
         */
        if (phpp->php_write_fd >= 0) {
            static const char quit[] = "quit\r\n";

            bytes = write(phpp->php_write_fd, quit, strlen(quit));

            close(phpp->php_write_fd);
            phpp->php_write_fd = -1;

            /* wait before killing php */
#ifndef SOLAR_THREAD
            usleep(50000);			/* 50 msec */
#endif
        }

        /* only try to kill the process if the PID looks valid.
         * Trying to kill a negative number is bad news (it's
         * a process group leader), and PID 1 is "init".
         */
        if (phpp->php_pid > 1) {
            /* end the php script server process */
            kill(phpp->php_pid, SIGTERM);

            /* reset this PID variable? */
        }

        /* close file descriptors */
        close(phpp->php_read_fd);
        phpp->php_read_fd  = -1;
    }
}
Пример #3
0
/*! \fn MYSQL_RES *db_query(MYSQL *mysql, const char *query)
 *  \brief executes a query and returns a pointer to the result set.
 *  \param mysql the database connection object
 *  \param query the database query to execute
 *
 *	This function will execute the SQL statement specified in the query variable.
 *
 *  \return MYSQL_RES a MySQL result structure
 *
 */
MYSQL_RES *db_query(MYSQL *mysql, const char *query) {
	MYSQL_RES  *mysql_res = 0;

	int    error       = 0;
	int    error_count = 0;

	char   query_frag[BUFSIZE];

	/* save a fragment just in case */
	snprintf(query_frag, BUFSIZE, "%s", query);

	/* show the sql query */
	SPINE_LOG_DEBUG(("DEBUG: SQL:'%s'", query_frag));

	while (1) {
		if (mysql_query(mysql, query)) {
			error = mysql_errno(mysql);

			if ((error == 1213) || (error == 1205)) {
				#ifndef SOLAR_THREAD
				usleep(50000);
				#endif
				error_count++;

				if (error_count > 30) {
					die("FATAL: Too many Lock/Deadlock errors occurred!, SQL Fragment:'%s'\n", query_frag);
				}

				continue;
			}else{
				die("FATAL: MySQL Error:'%i', Message:'%s'", error, mysql_error(mysql));
			}
		}else{
			mysql_res = mysql_store_result(mysql);

			break;
		}
	}

	return mysql_res;
}
Пример #4
0
/*! \fn int db_insert(MYSQL *mysql, const char *query)
 *  \brief inserts a row or rows in a database table.
 *  \param mysql the database connection object
 *  \param query the database query to execute
 *
 *	Unless the SQL_readonly boolean is set to TRUE, the function will execute
 *	the SQL statement specified in the query variable.
 *
 *  \return TRUE if successful, or FALSE if not.
 *
 */
int db_insert(MYSQL *mysql, const char *query) {
	int    error;
	int    error_count = 0;
	char   query_frag[BUFSIZE];

	/* save a fragment just in case */
	snprintf(query_frag, BUFSIZE, "%s", query);

	/* show the sql query */
	if (set.log_level == 5) {
		SPINE_LOG_DEBUG(("DEBUG: SQL:'%s'", query_frag));
	}

	while(1) {
		if (set.SQL_readonly == FALSE) {
			if (mysql_query(mysql, query)) {
				error = mysql_errno(mysql);

				if ((error == 1213) || (error == 1205)) {
					usleep(50000);
					error_count++;

					if (error_count > 30) {
						SPINE_LOG(("ERROR: Too many Lock/Deadlock errors occurred!, SQL Fragment:'%s'\n", query_frag));
						return FALSE;
					}

					continue;
				}else{
					SPINE_LOG(("ERROR: SQL Failed! Error:'%i', Message:'%s', SQL Fragment:'%s'\n", error, mysql_error(mysql), query_frag));
					return FALSE;
				}
			}else{
				return TRUE;
			}
		}else{
			return TRUE;
		}
	}
}
Пример #5
0
int hasCaps() {
	#ifdef HAVE_LCAP
	cap_t caps;
	cap_value_t capval;
	cap_flag_value_t capflag;

	caps = cap_from_text("cap_net_raw=eip");
	if (caps == NULL) {
		SPINE_LOG_DEBUG(("WARNING: cap_from_text failed."));
		return FALSE;
	}

	for (capval=0; ;capval++) {
		if (cap_get_flag(caps, capval, CAP_EFFECTIVE, &capflag))
			break;
		if (capflag != CAP_SET)
			return FALSE;
	}
	return TRUE;
	#else
	return FALSE;
	#endif
}
Пример #6
0
/*! \fn void read_config_options(void)
 *  \brief Reads the default Spine runtime parameters from the database and set's the global array
 *
 *  load default values from the database for poller processing
 *
 */
void read_config_options() {
	MYSQL      mysql;
	MYSQL_RES  *result;
	int        num_rows;
	char       web_root[BUFSIZE];
	char       sqlbuf[SMALL_BUFSIZE], *sqlp = sqlbuf;
	const char *res;

	db_connect(set.dbdb, &mysql);

	/* get the mysql server version */
	set.dbversion = 0;
	if ((res = getglobalvariable(&mysql, "version")) != 0 ) {
		set.dbversion = atoi(res);
	}

	/* get logging level from database - overrides spine.conf */
	if ((res = getsetting(&mysql, "log_verbosity")) != 0 ) {
		const int n = atoi(res);
		if (n != 0) set.log_level = n;
	}

	/* determine script server path operation and default log file processing */
	if ((res = getsetting(&mysql, "path_webroot")) != 0 ) {
		snprintf(set.path_php_server, SMALL_BUFSIZE, "%s/script_server.php", res);
		snprintf(web_root, BUFSIZE, "%s", res);
	}

	/* determine logfile path */
	if ((res = getsetting(&mysql, "path_cactilog")) != 0 ) {
		if (strlen(res) != 0) {
			snprintf(set.path_logfile, SMALL_BUFSIZE, "%s", res);
		}else{
			if (strlen(web_root) != 0) {
				snprintf(set.path_logfile, SMALL_BUFSIZE, "%s/log/cacti.log", web_root);
			}else{
				set.path_logfile[0] ='\0';
			}
		}
	}else{
		snprintf(set.path_logfile, SMALL_BUFSIZE, "%s/log/cacti.log", web_root);
 	}

	/* log the path_webroot variable */
	SPINE_LOG_DEBUG(("DEBUG: The path_php_server variable is %s", set.path_php_server));

	/* log the path_cactilog variable */
	SPINE_LOG_DEBUG(("DEBUG: The path_cactilog variable is %s", set.path_logfile));

	/* determine log file, syslog or both, default is 1 or log file only */
	if ((res = getsetting(&mysql, "log_destination")) != 0 ) {
		set.log_destination = parse_logdest(res, LOGDEST_FILE);
	}else{
		set.log_destination = LOGDEST_FILE;
	}

	/* log the log_destination variable */
	SPINE_LOG_DEBUG(("DEBUG: The log_destination variable is %i (%s)",
			set.log_destination,
			printable_logdest(set.log_destination)));
	set.logfile_processed = TRUE;

	/* get PHP Path Information for Scripting */
	if ((res = getsetting(&mysql, "path_php_binary")) != 0 ) {
		STRNCOPY(set.path_php, res);
	}

	/* log the path_php variable */
	SPINE_LOG_DEBUG(("DEBUG: The path_php variable is %s", set.path_php));

	/* set availability_method */
	if ((res = getsetting(&mysql, "availability_method")) != 0 ) {
		set.availability_method = atoi(res);
	}

	/* log the availability_method variable */
	SPINE_LOG_DEBUG(("DEBUG: The availability_method variable is %i", set.availability_method));

	/* set ping_recovery_count */
	if ((res = getsetting(&mysql, "ping_recovery_count")) != 0 ) {
		set.ping_recovery_count = atoi(res);
	}

	/* log the ping_recovery_count variable */
	SPINE_LOG_DEBUG(("DEBUG: The ping_recovery_count variable is %i", set.ping_recovery_count));

	/* set ping_failure_count */
	if ((res = getsetting(&mysql, "ping_failure_count")) != 0) {
		set.ping_failure_count = atoi(res);
	}

	/* log the ping_failure_count variable */
	SPINE_LOG_DEBUG(("DEBUG: The ping_failure_count variable is %i", set.ping_failure_count));

	/* set ping_method */
	if ((res = getsetting(&mysql, "ping_method")) != 0 ) {
		set.ping_method = atoi(res);
	}

	/* log the ping_method variable */
	SPINE_LOG_DEBUG(("DEBUG: The ping_method variable is %i", set.ping_method));

	/* set ping_retries */
	if ((res = getsetting(&mysql, "ping_retries")) != 0 ) {
		set.ping_retries = atoi(res);
	}

	/* log the ping_retries variable */
	SPINE_LOG_DEBUG(("DEBUG: The ping_retries variable is %i", set.ping_retries));

	/* set ping_timeout */
	if ( (res = getsetting(&mysql, "ping_timeout")) != 0 ) {
		set.ping_timeout = atoi(res);
	}

	/* log the ping_timeout variable */
	SPINE_LOG_DEBUG(("DEBUG: The ping_timeout variable is %i", set.ping_timeout));

	/* set snmp_retries */
	if ( (res = getsetting(&mysql, "snmp_retries")) != 0 ) {
		set.snmp_retries = atoi(res);
	}

	/* log the snmp_retries variable */
	SPINE_LOG_DEBUG(("DEBUG: The snmp_retries variable is %i", set.snmp_retries));

	/* set logging option for errors */
	set.log_perror = getboolsetting(&mysql, "log_perror", FALSE);

	/* log the log_perror variable */
	SPINE_LOG_DEBUG(("DEBUG: The log_perror variable is %i", set.log_perror));

	/* set logging option for errors */
	set.log_pwarn = getboolsetting(&mysql, "log_pwarn", FALSE);

	/* log the log_pwarn variable */
	SPINE_LOG_DEBUG(("DEBUG: The log_pwarn variable is %i", set.log_pwarn));

	/* set logging option for errors */
	set.boost_redirect = getboolsetting(&mysql, "boost_redirect", FALSE);

	/* log the log_pwarn variable */
	SPINE_LOG_DEBUG(("DEBUG: The boost_redirect variable is %i", set.boost_redirect));

	/* set logging option for statistics */
	set.log_pstats = getboolsetting(&mysql, "log_pstats", FALSE);

	/* log the log_pstats variable */
	SPINE_LOG_DEBUG(("DEBUG: The log_pstats variable is %i", set.log_pstats));

	/* get Cacti defined max threads override spine.conf */
	if ((res = getsetting(&mysql, "max_threads")) != 0 ) {
		set.threads = atoi(res);
		if (set.threads > MAX_THREADS) {
			set.threads = MAX_THREADS;
		}
	}

	/* log the threads variable */
	SPINE_LOG_DEBUG(("DEBUG: The threads variable is %i", set.threads));

	/* get the poller_interval for those who have elected to go with a 1 minute polling interval */
	if ((res = getsetting(&mysql, "poller_interval")) != 0 ) {
		set.poller_interval = atoi(res);
	}else{
		set.poller_interval = 0;
	}

	/* log the poller_interval variable */
	if (set.poller_interval == 0) {
		SPINE_LOG_DEBUG(("DEBUG: The polling interval is the system default"));
	}else{
		SPINE_LOG_DEBUG(("DEBUG: The polling interval is %i seconds", set.poller_interval));
	}

	/* get the concurrent_processes variable to determine thread sleep values */
	if ((res = getsetting(&mysql, "concurrent_processes")) != 0 ) {
		set.num_parent_processes = atoi(res);
	}else{
		set.num_parent_processes = 1;
	}

	/* log the concurrent processes variable */
	SPINE_LOG_DEBUG(("DEBUG: The number of concurrent processes is %i", set.num_parent_processes));

	/* get the script timeout to establish timeouts */
	if ((res = getsetting(&mysql, "script_timeout")) != 0 ) {
		set.script_timeout = atoi(res);
		if (set.script_timeout < 5) {
			set.script_timeout = 5;
		}
	}else{
		set.script_timeout = 25;
	}

	/* log the script timeout value */
	SPINE_LOG_DEBUG(("DEBUG: The script timeout is %i", set.script_timeout));

	/* get the number of script server processes to run */
	if ((res = getsetting(&mysql, "php_servers")) != 0 ) {
		set.php_servers = atoi(res);

		if (set.php_servers > MAX_PHP_SERVERS) {
			set.php_servers = MAX_PHP_SERVERS;
		}

		if (set.php_servers <= 0) {
			set.php_servers = 1;
		}
	}else{
		set.php_servers = 2;
	}

	/* log the script timeout value */
	SPINE_LOG_DEBUG(("DEBUG: The number of php script servers to run is %i", set.php_servers));

	/*----------------------------------------------------------------
	 * determine if the php script server is required by searching for
	 * all the host records for an action of POLLER_ACTION_PHP_SCRIPT_SERVER.
	 * If we get even one, it means we have to deal with the PHP script
	 * server.
	 *
	 */
	set.php_required = FALSE;		/* assume no */

	/* log the requirement for the script server */
	if (!strlen(set.host_id_list)) {
		sqlp = sqlbuf;
		sqlp += sprintf(sqlp, "SELECT action FROM poller_item");
		sqlp += sprintf(sqlp, " WHERE action=%d", POLLER_ACTION_PHP_SCRIPT_SERVER);
		sqlp += append_hostrange(sqlp, "host_id");
		if (set.poller_id_exists) {
			sqlp += sprintf(sqlp, " AND poller_id=%i", set.poller_id);
		}
		sqlp += sprintf(sqlp, " LIMIT 1");

		result = db_query(&mysql, sqlbuf);
		num_rows = mysql_num_rows(result);

		if (num_rows > 0) set.php_required = TRUE;

		SPINE_LOG_DEBUG(("DEBUG: StartHost='%i', EndHost='%i', TotalPHPScripts='%i'",
			set.start_host_id,
			set.end_host_id,
			num_rows));
	}else{
		sqlp = sqlbuf;
		sqlp += sprintf(sqlp, "SELECT action FROM poller_item");
		sqlp += sprintf(sqlp, " WHERE action=%d", POLLER_ACTION_PHP_SCRIPT_SERVER);
		sqlp += sprintf(sqlp, " AND host_id IN(%s)", set.host_id_list);
		if (set.poller_id_exists) {
			sqlp += sprintf(sqlp, " AND poller_id=%i", set.poller_id);
		}
		sqlp += sprintf(sqlp, " LIMIT 1");

		result = db_query(&mysql, sqlbuf);
		num_rows = mysql_num_rows(result);

		if (num_rows > 0) set.php_required = TRUE;

		SPINE_LOG_DEBUG(("DEBUG: Host List to be polled='%s', TotalPHPScripts='%i'",
			set.host_id_list,
			num_rows));
	}

	SPINE_LOG_DEBUG(("DEBUG: The PHP Script Server is %sRequired",
		set.php_required
		? ""
		: "Not "));

	/* determine the maximum oid's to obtain in a single get request */
	if ((res = getsetting(&mysql, "max_get_size")) != 0 ) {
		set.snmp_max_get_size = atoi(res);

		if (set.snmp_max_get_size > 128) {
			set.snmp_max_get_size = 128;
		}
	}else{
		set.snmp_max_get_size = 25;
	}

	/* log the snmp_max_get_size variable */
	SPINE_LOG_DEBUG(("DEBUG: The Maximum SNMP OID Get Size is %i", set.snmp_max_get_size));

	mysql_free_result(result);
	db_disconnect(&mysql);
}
Пример #7
0
void checkAsRoot() {
	#ifndef __CYGWIN__
	#ifdef SOLAR_PRIV
	priv_set_t *privset;
	char *p;

	/* Get the basic set */
	privset = priv_str_to_set("basic", ",", NULL);
	if (privset == NULL) {
		die("ERROR: Could not get basic privset from priv_str_to_set().");
	} else {
		p = priv_set_to_str(privset, ',', 0);
		SPINE_LOG_DEBUG(("DEBUG: Basic privset is: '%s'.", p != NULL ? p : "Unknown"));
	}

	/* Add priviledge to send/receive ICMP packets */
	if (priv_addset(privset, PRIV_NET_ICMPACCESS) < 0 ) {
		SPINE_LOG_DEBUG(("Warning: Addition of PRIV_NET_ICMPACCESS to privset failed: '%s'.", strerror(errno)));
	}

	/* Compute the set of privileges that are never needed */
	priv_inverse(privset);

	/* Remove the set of unneeded privs from Permitted (and by
	 * implication from Effective) */
	if (setppriv(PRIV_OFF, PRIV_PERMITTED, privset) < 0) {
		SPINE_LOG_DEBUG(("Warning: Dropping privileges from PRIV_PERMITTED failed: '%s'.", strerror(errno)));
	}

	/* Remove unneeded priv set from Limit to be safe */
	if (setppriv(PRIV_OFF, PRIV_LIMIT, privset) < 0) {
		SPINE_LOG_DEBUG(("Warning: Dropping privileges from PRIV_LIMIT failed: '%s'.", strerror(errno)));
	}

	boolean_t pe = priv_ineffect(PRIV_NET_ICMPACCESS);
	SPINE_LOG_DEBUG(("DEBUG: Privilege PRIV_NET_ICMPACCESS is: '%s'.", pe != 0 ? "Enabled" : "Disabled"));

	set.icmp_avail = pe;

	/* Free the privset */
	priv_freeset(privset);
	free(p);
	#else
	if (hasCaps() != TRUE) {
		seteuid(0);
	
		if (geteuid() != 0) {
			SPINE_LOG_DEBUG(("WARNING: Spine NOT running asroot.  This is required if using ICMP.  Please run \"chmod +s;chown root:root spine\" to resolve."));
			set.icmp_avail = FALSE;
		}else{
			SPINE_LOG_DEBUG(("DEBUG: Spine is running asroot."));
			set.icmp_avail = TRUE;
			seteuid(getuid());
		}
	} else {
		SPINE_LOG_DEBUG(("DEBUG: Spine has cap_net_raw capability."));
		set.icmp_avail = TRUE;
	}
	#endif
	#endif
}
Пример #8
0
/*! \fn int php_init(int php_process)
 *  \brief initialize either a specific PHP Script Server or all of them.
 *  \param php_process the process number to start or PHP_INIT
 *
 *  This function will either start an individual PHP Script Server process
 *  or all of them if the input parameter is the PHP_INIT constant.  The function
 *  will check the status of the process to verify that it is ready to process
 *  scripts as well.
 *
 *  \return TRUE if the PHP Script Server is know running or FALSE otherwise
 */
int php_init(int php_process) {
	int  cacti2php_pdes[2];
	int  php2cacti_pdes[2];
	pid_t  pid;
	char poller_id[TINY_BUFSIZE];
	char *argv[6];
	int  cancel_state;
	char *result_string = 0;
	int num_processes;
	int i;
	int retry_count = 0;

	/* special code to start all PHP Servers */
	if (php_process == PHP_INIT) {
		num_processes = set.php_servers;
	}else{
		num_processes = 1;
	}

	for (i=0; i < num_processes; i++) {
		SPINE_LOG_DEBUG(("DEBUG: SS[%i] PHP Script Server Routine Starting\n", i));

		/* create the output pipes from Spine to php*/
		if (pipe(cacti2php_pdes) < 0) {
			SPINE_LOG(("ERROR: SS[%i] Could not allocate php server pipes\n", i));
			return FALSE;
		}

		/* create the input pipes from php to Spine */
		if (pipe(php2cacti_pdes) < 0) {
			SPINE_LOG(("ERROR: SS[%i] Could not allocate php server pipes\n", i));
			return FALSE;
		}

		/* disable thread cancellation from this point forward. */
		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);

		/* establish arguments for script server execution */
		argv[0] = set.path_php;
		argv[1] = "-q";
		argv[2] = set.path_php_server;
		argv[3] = "spine";
		snprintf(poller_id, TINY_BUFSIZE, "%d", set.poller_id);
		argv[4] = poller_id;
		argv[5] = NULL;

		/* fork a child process */
		SPINE_LOG_DEBUG(("DEBUG: SS[%i] PHP Script Server About to FORK Child Process\n", i));

		retry:

		pid = vfork();

		/* check the pid status and process as required */
		switch (pid) {
			case -1: /* ERROR: Could not fork() */
				switch (errno) {
				case EAGAIN:
					if (retry_count < 3) {
						retry_count++;
						#ifndef SOLAR_THREAD
						/* take a moment */
						usleep(50000);
						#endif
						goto retry;
					}else{
						SPINE_LOG(("ERROR: SS[%i] Cound not fork PHP Script Server Out of Resources\n", i));
					}
				case ENOMEM:
					if (retry_count < 3) {
						retry_count++;
						#ifndef SOLAR_THREAD
						/* take a moment */
						usleep(50000);
						#endif
						goto retry;
					}else{
						SPINE_LOG(("ERROR: SS[%i] Cound not fork PHP Script Server Out of Memory\n", i));
					}
				default:
					SPINE_LOG(("ERROR: SS[%i] Cound not fork PHP Script Server Unknown Reason\n", i));
				}

				close(php2cacti_pdes[0]);
				close(php2cacti_pdes[1]);
				close(cacti2php_pdes[0]);
				close(cacti2php_pdes[1]);

				SPINE_LOG(("ERROR: SS[%i] Cound not fork PHP Script Server\n", i));
				pthread_setcancelstate(cancel_state, NULL);

				return FALSE;
				/* NOTREACHED */
			case 0:	/* SUCCESS: I am now the child */
				/* set the standard input/output channels of the new process.  */
				dup2(cacti2php_pdes[0], STDIN_FILENO);
				dup2(php2cacti_pdes[1], STDOUT_FILENO);

				/* close unneeded Pipes */
				(void)close(php2cacti_pdes[0]);
				(void)close(php2cacti_pdes[1]);
				(void)close(cacti2php_pdes[0]);
				(void)close(cacti2php_pdes[1]);

				/* start the php script server process */
				execv(argv[0], argv);
				_exit(127);
				/* NOTREACHED */
			default: /* I am the parent process */
				SPINE_LOG_DEBUG(("DEBUG: SS[%i] PHP Script Server Child FORK Success\n", i));
		}

		/* Parent */
		/* close unneeded pipes */
		close(cacti2php_pdes[0]);
		close(php2cacti_pdes[1]);

		if (php_process == PHP_INIT) {
			php_processes[i].php_pid = pid;
			php_processes[i].php_write_fd = cacti2php_pdes[1];
			php_processes[i].php_read_fd = php2cacti_pdes[0];
		}else{
			php_processes[php_process].php_pid = pid;
			php_processes[php_process].php_write_fd = cacti2php_pdes[1];
			php_processes[php_process].php_read_fd = php2cacti_pdes[0];
		}

		/* restore caller's cancellation state. */
		pthread_setcancelstate(cancel_state, NULL);

		/* check pipe to insure startup took place */
		if (php_process == PHP_INIT) {
			result_string = php_readpipe(i);
		}else{
			result_string = php_readpipe(php_process);
		}

		if (strstr(result_string, "Started")) {
			if (php_process == PHP_INIT) {
				SPINE_LOG_DEBUG(("DEBUG: SS[%i] Confirmed PHP Script Server running\n", i));

				php_processes[i].php_state = PHP_READY;
			}else{
				SPINE_LOG_DEBUG(("DEBUG: SS[%i] Confirmed PHP Script Server running\n", php_process));

				php_processes[php_process].php_state = PHP_READY;
			}
		}else{
			SPINE_LOG(("ERROR: SS[%i] Script Server did not start properly return message was: '%s'\n", php_process, result_string));

			if (php_process == PHP_INIT) {
				php_processes[i].php_state = PHP_BUSY;
			}else{
				php_processes[php_process].php_state = PHP_BUSY;
			}
		}
	}

	free(result_string);

	return TRUE;
}