Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ bin_PROGRAMS = spine

man_MANS = spine.1

EXTRA_DIST = spine.1
EXTRA_DIST = spine.1 uthash.h

# Docker targets — require Dockerfile and Dockerfile.dev (from PR #401)
.PHONY: docker docker-dev verify cppcheck
Expand Down
2 changes: 2 additions & 0 deletions common.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,4 +159,6 @@
# include <grp.h>
#endif

#include "uthash.h"

#endif /* SPINE_COMMON_H */
130 changes: 56 additions & 74 deletions nft_popen.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@

#include "common.h"
#include "spine.h"
#include <spawn.h>

/* An instance of this struct is created for each popen() fd. */
static struct pid
Expand Down Expand Up @@ -126,7 +127,8 @@ int nft_popen(const char * command, const char * type) {
struct pid *cur;
struct pid *p;
int pdes[2];
int fd, pid, twoway;
int fd, twoway;
pid_t pid;
char *argv[4];
char *command_copy;
char shell_cmd[] = "sh";
Expand Down Expand Up @@ -180,90 +182,70 @@ int nft_popen(const char * command, const char * type) {
*/
pthread_mutex_lock(&ListMutex);

/* Fork. */
retry:
switch (pid = vfork()) {
case -1: /* Error. */
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: SCRIPT: Could not fork. Out of Resources nft_popen.c"));
}
case ENOMEM:
if (retry_count < 3) {
retry_count++;
#ifndef SOLAR_THREAD
/* take a moment */
usleep(50000);
#endif
goto retry;
}else{
SPINE_LOG(("ERROR: SCRIPT Could not fork. Out of Memory nft_popen.c"));
}
default:
SPINE_LOG(("ERROR: SCRIPT Could not fork. Unknown Reason nft_popen.c"));
}

/* Build file actions for posix_spawn to replace vfork+execve. */
posix_spawn_file_actions_t fa;
if (posix_spawn_file_actions_init(&fa) != 0) {
SPINE_LOG(("ERROR: SCRIPT: posix_spawn_file_actions_init failed"));
(void)close(pdes[0]);
(void)close(pdes[1]);
pthread_mutex_unlock(&ListMutex);
free(command_copy);
pthread_setcancelstate(cancel_state, NULL);

return -1;
/* NOTREACHED */
case 0: /* Child. */
if (*type == 'r') {
/* The dup2() to STDIN_FILENO is repeated to avoid
* writing to pdes[1], which might corrupt the
* parent's copy. This isn't good enough in
* general, since the _exit() is no return, so
* the compiler is free to corrupt all the local
* variables.
*/
(void)close(pdes[0]);
if (pdes[1] != STDOUT_FILENO) {
(void)dup2(pdes[1], STDOUT_FILENO);
(void)close(pdes[1]);
if (twoway)
(void)dup2(STDOUT_FILENO, STDIN_FILENO);
}else if (twoway && (pdes[1] != STDIN_FILENO))
(void)dup2(pdes[1], STDIN_FILENO);
}else {
if (pdes[0] != STDIN_FILENO) {
(void)dup2(pdes[0], STDIN_FILENO);
(void)close(pdes[0]);
}
(void)close(pdes[1]);
}

if (*type == 'r') {
posix_spawn_file_actions_addclose(&fa, pdes[0]);
if (pdes[1] != STDOUT_FILENO) {
posix_spawn_file_actions_adddup2(&fa, pdes[1], STDOUT_FILENO);
posix_spawn_file_actions_addclose(&fa, pdes[1]);
if (twoway)
posix_spawn_file_actions_adddup2(&fa, STDOUT_FILENO, STDIN_FILENO);
} else if (twoway && (pdes[1] != STDIN_FILENO)) {
posix_spawn_file_actions_adddup2(&fa, pdes[1], STDIN_FILENO);
}
} else {
if (pdes[0] != STDIN_FILENO) {
posix_spawn_file_actions_adddup2(&fa, pdes[0], STDIN_FILENO);
posix_spawn_file_actions_addclose(&fa, pdes[0]);
}
posix_spawn_file_actions_addclose(&fa, pdes[1]);
}

/* Close all other pipes in the child (Posix.2 requirement). */
for (p = PidList; p; p = p->next)
posix_spawn_file_actions_addclose(&fa, p->fd);

/* Spawn the child process with retry on EAGAIN/ENOMEM. */
#if defined(__CYGWIN__)
const char *spawn_shell = (set.cygwinshloc == 0) ? "sh.exe" : "/bin/sh";
#else
const char *spawn_shell = "/bin/sh";
#endif

/* Close all the other pipes in the child process.
* Posix.2 requires this, tho I don't know why.
*/
for (p = PidList; p; p = p->next)
(void)close(p->fd);

/* Execute the command. */
#if defined(__CYGWIN__)
if (set.cygwinshloc == 0) {
execve("sh.exe", argv, environ);
}else{
execve("/bin/sh", argv, environ);
int spawn_err;
retry:
spawn_err = posix_spawn(&pid, spawn_shell, &fa, NULL, argv, environ);

if (spawn_err != 0) {
if ((spawn_err == EAGAIN || spawn_err == ENOMEM) && retry_count < 3) {
retry_count++;
usleep(50000);
goto retry;
}
#else
execve("/bin/sh", argv, environ);
#endif
_exit(127);
/* NOTREACHED */

SPINE_LOG(("ERROR: SCRIPT: posix_spawn failed: %s", strerror(spawn_err)));
posix_spawn_file_actions_destroy(&fa);
(void)close(pdes[0]);
(void)close(pdes[1]);
pthread_mutex_unlock(&ListMutex);
free(command_copy);
pthread_setcancelstate(cancel_state, NULL);
return -1;
}

posix_spawn_file_actions_destroy(&fa);

/* Parent. */
if (*type == 'r') {
fd = pdes[0];
Expand Down
73 changes: 49 additions & 24 deletions poller.c
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,9 @@ void poll_host(int device_counter, int host_id, int host_thread, int host_thread
limits[0] = '\0';
}

/* optional output_regex column (added in Cacti 1.3.1) */
const char *regex_col = set.has_output_regex ? ", output_regex" : "";

/* single polling interval query for items */
if (set.poller_id == 0) {
if (set.total_snmp_ports == 1) {
Expand All @@ -275,21 +278,23 @@ void poll_host(int device_counter, int host_id, int host_thread, int host_thread
"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 "
"snmp_auth_protocol, snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id"
"%s"
" FROM poller_item"
" WHERE host_id = %i"
" AND deleted = '' %s", host_id, limits);
" AND deleted = '' %s", regex_col, host_id, limits);
} else {
snprintf(query1, BUFSIZE,
"SELECT SQL_NO_CACHE 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 "
"snmp_auth_protocol, snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id"
"%s"
" FROM poller_item"
" WHERE host_id = %i"
" AND deleted = ''"
" ORDER BY snmp_port %s", host_id, limits);
" ORDER BY snmp_port %s", regex_col, host_id, limits);
}

/* host structure for uptime checks */
Expand Down Expand Up @@ -321,22 +326,24 @@ void poll_host(int device_counter, int host_id, int host_thread, int host_thread
"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 "
"snmp_auth_protocol, snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id"
"%s"
" FROM poller_item"
" WHERE host_id = %i"
" AND rrd_next_step <= 0"
" %s", host_id, limits);
" %s", regex_col, host_id, limits);
} else {
snprintf(query5, BUFSIZE,
"SELECT SQL_NO_CACHE 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 "
"snmp_auth_protocol, snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id"
"%s"
" FROM poller_item"
" WHERE host_id = %i"
" AND rrd_next_step <= 0"
" ORDER BY snmp_port %s", host_id, limits);
" ORDER BY snmp_port %s", regex_col, host_id, limits);
}
} else {
if (set.total_snmp_ports == 1) {
Expand All @@ -345,20 +352,22 @@ void poll_host(int device_counter, int host_id, int host_thread, int host_thread
"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 "
"snmp_auth_protocol, snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id"
"%s"
" FROM poller_item"
" WHERE host_id = %i"
" %s", host_id, limits);
" %s", regex_col, host_id, limits);
} else {
snprintf(query5, BUFSIZE,
"SELECT SQL_NO_CACHE 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 "
"snmp_auth_protocol, snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id"
"%s"
" FROM poller_item"
" WHERE host_id = %i"
" ORDER BY snmp_port %s", host_id, limits);
" ORDER BY snmp_port %s", regex_col, host_id, limits);
}
}

Expand Down Expand Up @@ -411,21 +420,23 @@ void poll_host(int device_counter, int host_id, int host_thread, int host_thread
"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 "
"snmp_auth_protocol, snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id"
"%s"
" FROM poller_item"
" WHERE host_id = %i"
" AND poller_id=%i %s", host_id, set.poller_id, limits);
" AND poller_id=%i %s", regex_col, host_id, set.poller_id, limits);
} else {
snprintf(query1, BUFSIZE,
"SELECT SQL_NO_CACHE 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 "
"snmp_auth_protocol, snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id"
"%s"
" FROM poller_item"
" WHERE host_id = %i"
" AND poller_id=%i"
" ORDER BY snmp_port %s", host_id, set.poller_id, limits);
" ORDER BY snmp_port %s", regex_col, host_id, set.poller_id, limits);
}

/* host structure for uptime checks */
Expand Down Expand Up @@ -457,23 +468,25 @@ void poll_host(int device_counter, int host_id, int host_thread, int host_thread
"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 "
"snmp_auth_protocol, snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id"
"%s"
" FROM poller_item"
" WHERE host_id = %i"
" AND rrd_next_step <= 0"
" AND poller_id = %i %s", host_id, set.poller_id, limits);
" AND poller_id = %i %s", regex_col, host_id, set.poller_id, limits);
} else {
snprintf(query5, BUFSIZE,
"SELECT SQL_NO_CACHE 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 "
"snmp_auth_protocol, snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id"
"%s"
" 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);
" ORDER BY snmp_port %s", regex_col, host_id, set.poller_id, limits);
}
} else {
if (set.total_snmp_ports == 1) {
Expand All @@ -482,21 +495,23 @@ void poll_host(int device_counter, int host_id, int host_thread, int host_thread
"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 "
"snmp_auth_protocol, snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id"
"%s"
" FROM poller_item"
" WHERE host_id = %i"
" AND poller_id = %i %s", host_id, set.poller_id, limits);
" AND poller_id = %i %s", regex_col, host_id, set.poller_id, limits);
} else {
snprintf(query5, BUFSIZE,
"SELECT SQL_NO_CACHE 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 "
"snmp_auth_protocol, snmp_priv_passphrase, snmp_priv_protocol, snmp_context, snmp_engine_id"
"%s"
" FROM poller_item"
" WHERE host_id = %i"
" AND poller_id = %i"
" ORDER BY snmp_port %s", host_id, set.poller_id, limits);
" ORDER BY snmp_port %s", regex_col, host_id, set.poller_id, limits);
}
}

Expand Down Expand Up @@ -1280,6 +1295,7 @@ void poll_host(int device_counter, int host_id, int host_thread, int host_thread
poller_items[i].arg3[0] = '\0';
poller_items[i].local_data_id = 0;
poller_items[i].rrd_num = 0;
poller_items[i].output_regex[0] = '\0';

if (row[0] != NULL) poller_items[i].action = atoi(row[0]);

Expand Down Expand Up @@ -1314,6 +1330,10 @@ void poll_host(int device_counter, int host_id, int host_thread, int host_thread
if (row[19] != NULL) snprintf(poller_items[i].snmp_engine_id,
sizeof(poller_items[i].snmp_engine_id), "%s", row[19]);

if (set.has_output_regex && row[20] != NULL)
snprintf(poller_items[i].output_regex,
sizeof(poller_items[i].output_regex), "%s", row[20]);

SET_UNDEFINED(poller_items[i].result);

i++;
Expand Down Expand Up @@ -1544,6 +1564,11 @@ void poll_host(int device_counter, int host_id, int host_thread, int host_thread
}
}

if (strlen(poller_items[snmp_oids[j].array_position].output_regex)) {
snprintf(temp_result, RESULTS_BUFFER, "%s", regex_replace(poller_items[snmp_oids[j].array_position].output_regex, snmp_oids[j].result));
snprintf(snmp_oids[j].result, RESULTS_BUFFER, "%s", temp_result);
}

snprintf(poller_items[snmp_oids[j].array_position].result, RESULTS_BUFFER, "%s", snmp_oids[j].result);

thread_end = get_time_as_double();
Expand Down
2 changes: 2 additions & 0 deletions snmp.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
+-------------------------------------------------------------------------+
*/

#define SNMP_SESSION_FREE(s) { if (s != NULL) { snmp_host_cleanup(s); s = NULL; } }

extern void snmp_spine_init(void);
extern void snmp_spine_close(void);
extern void *snmp_host_init(int host_id, char *hostname, int snmp_version, char *snmp_community, char *snmp_username, char *snmp_password, char *snmp_auth_protocol, char *snmp_priv_passphrase, char *snmp_priv_protocol, char *snmp_context, char *snmp_engine_id, int snmp_port, int snmp_timeout);
Expand Down
Loading
Loading