Exemplo n.º 1
0
/*! \fn void snmp_snprint_value(char *obuf, size_t buf_len, const oid *objid, size_t objidlen, struct variable_list *variable)
 *
 *  \brief replacement for the buggy net-snmp.org snprint_value function
 *
 *	This function format an output buffer with the correct string representation
 *  of an snmp OID result fetched with snmp_get_multi.  The buffer pointed to by
 *  the function is modified.
 *
 */
void snmp_snprint_value(char *obuf, size_t buf_len, const oid *objid, size_t objidlen, struct variable_list *variable) {
	u_char *buf    = NULL;
	size_t out_len = 0;

	if ((buf = (u_char *) calloc(buf_len, 1)) != 0) {
		if (sprint_realloc_value(&buf, &buf_len, &out_len, 1,
				objid, objidlen, variable)) {
			snprintf(obuf, buf_len, "%s", buf);
		}else{
			snprintf(obuf, buf_len, "%s [TRUNCATED]", buf);
		}
	}else{
		SET_UNDEFINED(obuf);
	}

	free(buf);
}
Exemplo n.º 2
0
/*! \fn char *snmp_get_multi(host_t *current_host, snmp_oids_t *snmp_oids, int num_oids)
 *  \brief performs multiple OID snmp_get's in a single network call
 *
 *	This function will a group of snmp OID's for a host.  The host snmp
 *  session must already be established.  The function will modify elements of
 *  the snmp_oids array with the results from the snmp api call.
 *
 */
void snmp_get_multi(host_t *current_host, snmp_oids_t *snmp_oids, int num_oids) {
	struct snmp_pdu *pdu       = NULL;
	struct snmp_pdu *response  = NULL;
	struct variable_list *vars = NULL;
	int status;
	int i;
	int max_repetitions = 1;
	int non_repeaters   = 0;
	int array_count;
	int index_count;

	/* get rid of some compiler warnings */
	errstat  = 0;
	errindex = 0;

	struct nameStruct {
	    oid             name[MAX_OID_LEN];
	    size_t          name_len;
	} *name, *namep;

	/* load up oids */
	namep = name = (struct nameStruct *) calloc(num_oids, sizeof(*name));
	pdu = snmp_pdu_create(SNMP_MSG_GET);
	for (i = 0; i < num_oids; i++) {
		namep->name_len = MAX_OID_LEN;

		if (!snmp_parse_oid(snmp_oids[i].oid, namep->name, &namep->name_len)) {
 			SPINE_LOG(("Host[%i] ERROR: Problems parsing Multi SNMP OID! (oid: %s)\n", current_host->id, snmp_oids[i].oid));

 			/* Mark this OID as "bad" */
			SET_UNDEFINED(snmp_oids[i].result);
		}else{
			snmp_add_null_var(pdu, namep->name, namep->name_len);
		}

		namep++;
	}

	status = STAT_DESCRIP_ERROR;

	/* execute the multi-get request */
	retry:
	status = snmp_sess_synch_response(current_host->snmp_session, pdu, &response);

	/* liftoff, successful poll, process it!! */
	if (status == STAT_SUCCESS) {
		if (response == NULL) {
			SPINE_LOG(("ERROR: An internal Net-Snmp error condition detected in Cacti snmp_get_multi\n"));
			status = STAT_ERROR;
		}else{
			if (response->errstat == SNMP_ERR_NOERROR) {
				vars = response->variables;

				for(i = 0; i < num_oids && vars; i++) {
					if (!IS_UNDEFINED(snmp_oids[i].result)) {
						#ifdef USE_NET_SNMP
						snmp_snprint_value(snmp_oids[i].result, RESULTS_BUFFER, vars->name, vars->name_length, vars);
						#else
						sprint_value(snmp_oids[i].result, vars->name, vars->name_length, vars);
						#endif

						vars = vars->next_variable;
					}
				}
			}else{
				if (response->errindex != 0) {
					index_count = 1;
					array_count = 0;

					/* Find our index against errindex */
					while (array_count < num_oids) {
						if (IS_UNDEFINED(snmp_oids[array_count].result) ) {
							array_count++;
						}else{
							/* if we have found our error, exit */
							if (index_count == response->errindex) {
								SET_UNDEFINED(snmp_oids[array_count].result);

								break;
							}
							array_count++;
							index_count++;
						}

					}

					/* remote the invalid OID from the PDU */
					pdu = snmp_fix_pdu(response, SNMP_MSG_GET);

					/* free the previous response */
					snmp_free_pdu(response);

					response = NULL;
					if (pdu != NULL) {
						/* retry the request */
						goto retry;
					}else{
					    /* all OID's errored out so exit cleanly */
						status = STAT_SUCCESS;
					}
				}else{
					status = STAT_DESCRIP_ERROR;
				}
			}
		}
	}

	if (status != STAT_SUCCESS) {
		current_host->ignore_host = 1;
		for (i = 0; i < num_oids; i++) {
			SET_UNDEFINED(snmp_oids[i].result);
		}
	}

	if (response != NULL) {
		snmp_free_pdu(response);
	}
}
Exemplo n.º 3
0
/*! \fn char *snmp_getnext(host_t *current_host, char *snmp_oid)
 *  \brief performs a single snmp_getnext for a specific snmp OID
 *
 *	This function will poll a specific snmp OID for a host.  The host snmp
 *  session must already be established.
 *
 *  \return returns the character representaton of the snmp OID, or "U" if
 *  unsuccessful.
 *
 */
char *snmp_getnext(host_t *current_host, char *snmp_oid) {
	struct snmp_pdu *pdu       = NULL;
	struct snmp_pdu *response  = NULL;
	struct variable_list *vars = NULL;
	size_t anOID_len           = MAX_OID_LEN;
	oid    anOID[MAX_OID_LEN];
	int    status;
	char   *result_string;

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

	status           = STAT_DESCRIP_ERROR;

	if (current_host->snmp_session != NULL) {
		anOID_len = MAX_OID_LEN;
		pdu       = snmp_pdu_create(SNMP_MSG_GETNEXT);

		if (!snmp_parse_oid(snmp_oid, anOID, &anOID_len)) {
			SPINE_LOG(("ERROR: Problems parsing SNMP OID\n"));
			SET_UNDEFINED(result_string);
			return result_string;
		}else{
			snmp_add_null_var(pdu, anOID, anOID_len);
		}

		/* poll host */
		status = snmp_sess_synch_response(current_host->snmp_session, pdu, &response);

		/* liftoff, successful poll, process it!! */
		if (status == STAT_SUCCESS) {
			if (response == NULL) {
				SPINE_LOG(("ERROR: An internal Net-Snmp error condition detected in Cacti snmp_get\n"));

				SET_UNDEFINED(result_string);
				status = STAT_ERROR;
			}else{
				if (response->errstat == SNMP_ERR_NOERROR) {
					vars = response->variables;

					#ifdef USE_NET_SNMP
					snprint_value(result_string, RESULTS_BUFFER, anOID, anOID_len, vars);
					#else
					sprint_value(result_string, anOID, anOID_len, vars);
					#endif
				}
			}
		}

		if (response) {
			snmp_free_pdu(response);
			response = NULL;
		}
	}else{
		status = STAT_DESCRIP_ERROR;
	}

	if (status != STAT_SUCCESS) {
		current_host->ignore_host = TRUE;

		SET_UNDEFINED(result_string);
	}

	return result_string;
}
Exemplo n.º 4
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;
}
Exemplo n.º 5
0
Arquivo: php.c Projeto: 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;
}
Exemplo n.º 6
0
/*! \fn char *snmp_get_multi(host_t *current_host, snmp_oids_t *snmp_oids, int num_oids)
 *  \brief performs multiple OID snmp_get's in a single network call
 * 
 *	This function will a group of snmp OID's for a host.  The host snmp
 *  session must already be established.  The function will modify elements of
 *  the snmp_oids array with the results from the snmp api call.
 *
 */
void snmp_get_multi(host_t *current_host, snmp_oids_t *snmp_oids, int num_oids) {
	struct snmp_pdu *pdu = NULL;
	struct snmp_pdu *response = NULL;
	struct variable_list *vars = NULL;
	int status;
	int i;
	int max_repetitions = 1;
	int non_repeaters   = 0;

	struct nameStruct {
	    oid             name[MAX_OID_LEN];
	    size_t          name_len;
	} *name, *namep;

	/* load up oids */
	namep = name = (struct nameStruct *) calloc(num_oids, sizeof(*name));
	pdu = snmp_pdu_create(SNMP_MSG_GET);
	for (i = 0; i < num_oids; i++) {
		namep->name_len = MAX_OID_LEN;

		if (!snmp_parse_oid(snmp_oids[i].oid, namep->name, &namep->name_len)) {
 			CACTID_LOG(("Host[%i] ERROR: Problems parsing Multi SNMP OID! (oid: %s)\n", current_host->id, snmp_oids[i].oid));

 			/* Mark this OID as "bad" */
			SET_UNDEFINED(snmp_oids[i].result);
		}else{
			snmp_add_null_var(pdu, namep->name, namep->name_len);
		}

		namep++;
	}

	status = STAT_DESCRIP_ERROR;

	/* execute the multi-get request */
	retry:
	status = snmp_sess_synch_response(current_host->snmp_session, pdu, &response);

	/* liftoff, successful poll, process it!! */
	if (status == STAT_SUCCESS) {
		if (response == NULL) {
			CACTID_LOG(("ERROR: An internal Net-Snmp error condition detected in Cacti snmp_get_multi\n"));
			status = STAT_ERROR;
		}else{
			if (response->errstat == SNMP_ERR_NOERROR) {
				vars = response->variables;
				for(i = 0; i < num_oids && vars; i++) {
					if (!IS_UNDEFINED(snmp_oids[i].result)) {
						#ifdef USE_NET_SNMP
						snmp_snprint_value(snmp_oids[i].result, sizeof(snmp_oids[i].result), vars->name, vars->name_length, vars);
						#else
						sprint_value(snmp_oids[i].result, vars->name, vars->name_length, vars);
						#endif
						vars = vars->next_variable;
					}
				}
			}else{
				if (response->errindex != 0) {
					/* removed errored OID and then retry */
					int count;

					/* Find our index against errindex */
					count = 0;
					for(i = 0; i < num_oids && count < response->errindex; i++) {
						if ( ! IS_UNDEFINED(snmp_oids[i].result) ) {
							count++;
						}
					}
					i--;
					SET_UNDEFINED(snmp_oids[i].result);

					for (count = 1, vars = response->variables;
						vars && count != response->errindex;
						vars = vars->next_variable, count++) {
					}

					pdu = snmp_fix_pdu(response, SNMP_MSG_GET);
					snmp_free_pdu(response);
					response = NULL;
					if (pdu != NULL) {
						goto retry;
					}else{
						status = STAT_DESCRIP_ERROR;
					}
				}else{
					status = STAT_DESCRIP_ERROR;
				}
			}
		}
	}

	if (status != STAT_SUCCESS) {
		current_host->ignore_host = 1;
		for (i = 0; i < num_oids; i++) {
			SET_UNDEFINED(snmp_oids[i].result);
		}
	}

	if (response != NULL) {
		snmp_free_pdu(response);
	}
}