Module: monitoring-plugins
 Branch: master
 Commit: 7cafb0e84550035fe671662c293122be975065ca
 Author: Sven Nierlein <s...@nierlein.de>
   Date: Fri Feb 15 10:36:28 2019 +0100
    URL: 
https://www.monitoring-plugins.org/repositories/monitoring-plugins/commit/?id=7cafb0e

check_by_ssh: fix child process leak on timeouts

When check_by_ssh runs into a timeout it simply exits keeping all child 
processes running.
Simply adopting the kill loop from runcmd_timeout_alarm_handler() fixes this.

Signed-off-by: Sven Nierlein <s...@nierlein.de>

---

 lib/utils_base.c      | 19 +++++++++++++++++++
 lib/utils_base.h      |  5 +++++
 lib/utils_cmd.c       | 42 +++++++++++++++++-------------------------
 lib/utils_cmd.h       | 13 +++++++++++++
 plugins/check_dbi.c   |  1 +
 plugins/check_pgsql.c |  1 +
 plugins/common.h      | 14 ++++++++++++++
 plugins/popen.c       | 29 -----------------------------
 plugins/runcmd.c      | 13 -------------
 plugins/utils.c       | 31 -------------------------------
 plugins/utils.h       |  9 ---------
 11 files changed, 70 insertions(+), 107 deletions(-)

diff --git a/lib/utils_base.c b/lib/utils_base.c
index 19a531f..fd7058d 100644
--- a/lib/utils_base.c
+++ b/lib/utils_base.c
@@ -37,6 +37,9 @@
 
 monitoring_plugin *this_monitoring_plugin=NULL;
 
+unsigned int timeout_state = STATE_CRITICAL;
+unsigned int timeout_interval = DEFAULT_SOCKET_TIMEOUT;
+
 int _np_state_read_file(FILE *);
 
 void np_init( char *plugin_name, int argc, char **argv ) {
@@ -359,6 +362,22 @@ char *np_extract_value(const char *varlist, const char 
*name, char sep) {
        return value;
 }
 
+const char *
+state_text (int result)
+{
+       switch (result) {
+       case STATE_OK:
+               return "OK";
+       case STATE_WARNING:
+               return "WARNING";
+       case STATE_CRITICAL:
+               return "CRITICAL";
+       case STATE_DEPENDENT:
+               return "DEPENDENT";
+       default:
+               return "UNKNOWN";
+       }
+}
 
 /*
  * Read a string representing a state (ok, warning... or numeric: 0, 1) and
diff --git a/lib/utils_base.h b/lib/utils_base.h
index 42ae0c0..d7e7dff 100644
--- a/lib/utils_base.h
+++ b/lib/utils_base.h
@@ -61,6 +61,10 @@ void print_thresholds(const char *, thresholds *);
 int check_range(double, range *);
 int get_status(double, thresholds *);
 
+/* Handle timeouts */
+extern unsigned int timeout_state;
+extern unsigned int timeout_interval;
+
 /* All possible characters in a threshold range */
 #define NP_THRESHOLDS_CHARS "-0123456789.:@~"
 
@@ -107,5 +111,6 @@ void np_state_write_string(time_t, char *);
 void np_init(char *, int argc, char **argv);
 void np_set_args(int argc, char **argv);
 void np_cleanup();
+const char *state_text (int);
 
 #endif /* _UTILS_BASE_ */
diff --git a/lib/utils_cmd.c b/lib/utils_cmd.c
index 7eb9a3a..795840d 100644
--- a/lib/utils_cmd.c
+++ b/lib/utils_cmd.c
@@ -40,6 +40,7 @@
 
 /** includes **/
 #include "common.h"
+#include "utils.h"
 #include "utils_cmd.h"
 #include "utils_base.h"
 #include <fcntl.h>
@@ -65,31 +66,6 @@ extern char **environ;
 # define SIG_ERR ((Sigfunc *)-1)
 #endif
 
-/* This variable must be global, since there's no way the caller
- * can forcibly slay a dead or ungainly running program otherwise.
- * Multithreading apps and plugins can initialize it (via CMD_INIT)
- * in an async safe manner PRIOR to calling cmd_run() or cmd_run_array()
- * for the first time.
- *
- * The check for initialized values is atomic and can
- * occur in any number of threads simultaneously. */
-static pid_t *_cmd_pids = NULL;
-
-/* Try sysconf(_SC_OPEN_MAX) first, as it can be higher than OPEN_MAX.
- * If that fails and the macro isn't defined, we fall back to an educated
- * guess. There's no guarantee that our guess is adequate and the program
- * will die with SIGSEGV if it isn't and the upper boundary is breached. */
-#define DEFAULT_MAXFD  256   /* fallback value if no max open files value is 
set */
-#define MAXFD_LIMIT   8192   /* upper limit of open files */
-#ifdef _SC_OPEN_MAX
-static long maxfd = 0;
-#elif defined(OPEN_MAX)
-# define maxfd OPEN_MAX
-#else  /* sysconf macro unavailable, so guess (may be wildly inaccurate) */
-# define maxfd DEFAULT_MAXFD
-#endif
-
-
 /** prototypes **/
 static int _cmd_open (char *const *, int *, int *)
        __attribute__ ((__nonnull__ (1, 2, 3)));
@@ -406,3 +382,19 @@ cmd_file_read ( char *filename, output *out, int flags)
 
        return 0;
 }
+
+void
+timeout_alarm_handler (int signo)
+{
+       size_t i;
+       if (signo == SIGALRM) {
+               printf (_("%s - Plugin timed out after %d seconds\n"),
+                                               state_text(timeout_state), 
timeout_interval);
+
+               if(_cmd_pids) for(i = 0; i < maxfd; i++) {
+                       if(_cmd_pids[i] != 0) kill(_cmd_pids[i], SIGKILL);
+               }
+
+               exit (timeout_state);
+       }
+}
diff --git a/lib/utils_cmd.h b/lib/utils_cmd.h
index ebaf15b..6f3aeb8 100644
--- a/lib/utils_cmd.h
+++ b/lib/utils_cmd.h
@@ -32,4 +32,17 @@ void cmd_init (void);
 #define CMD_NO_ARRAYS 0x01   /* don't populate arrays at all */
 #define CMD_NO_ASSOC 0x02    /* output.line won't point to buf */
 
+/* This variable must be global, since there's no way the caller
+ * can forcibly slay a dead or ungainly running program otherwise.
+ * Multithreading apps and plugins can initialize it (via CMD_INIT)
+ * in an async safe manner PRIOR to calling cmd_run() or cmd_run_array()
+ * for the first time.
+ *
+ * The check for initialized values is atomic and can
+ * occur in any number of threads simultaneously. */
+static pid_t *_cmd_pids = NULL;
+
+RETSIGTYPE timeout_alarm_handler (int);
+
+
 #endif /* _UTILS_CMD_ */
diff --git a/plugins/check_dbi.c b/plugins/check_dbi.c
index 826eb8d..ced13d0 100644
--- a/plugins/check_dbi.c
+++ b/plugins/check_dbi.c
@@ -35,6 +35,7 @@ const char *email = "devel@monitoring-plugins.org";
 
 #include "common.h"
 #include "utils.h"
+#include "utils_cmd.h"
 
 #include "netutils.h"
 
diff --git a/plugins/check_pgsql.c b/plugins/check_pgsql.c
index 5cd4709..11ce691 100644
--- a/plugins/check_pgsql.c
+++ b/plugins/check_pgsql.c
@@ -34,6 +34,7 @@ const char *email = "devel@monitoring-plugins.org";
 
 #include "common.h"
 #include "utils.h"
+#include "utils_cmd.h"
 
 #include "netutils.h"
 #include <libpq-fe.h>
diff --git a/plugins/common.h b/plugins/common.h
index 6bf4fca..0f08e2f 100644
--- a/plugins/common.h
+++ b/plugins/common.h
@@ -225,4 +225,18 @@ enum {
 # define __attribute__(x) /* do nothing */
 #endif
 
+/* Try sysconf(_SC_OPEN_MAX) first, as it can be higher than OPEN_MAX.
+ * If that fails and the macro isn't defined, we fall back to an educated
+ * guess. There's no guarantee that our guess is adequate and the program
+ * will die with SIGSEGV if it isn't and the upper boundary is breached. */
+#define DEFAULT_MAXFD  256   /* fallback value if no max open files value is 
set */
+#define MAXFD_LIMIT   8192   /* upper limit of open files */
+#ifdef _SC_OPEN_MAX
+static long maxfd = 0;
+#elif defined(OPEN_MAX)
+# define maxfd OPEN_MAX
+#else  /* sysconf macro unavailable, so guess (may be wildly inaccurate) */
+# define maxfd DEFAULT_MAXFD
+#endif
+
 #endif /* _COMMON_H_ */
diff --git a/plugins/popen.c b/plugins/popen.c
index 592263f..116d168 100644
--- a/plugins/popen.c
+++ b/plugins/popen.c
@@ -78,7 +78,6 @@ RETSIGTYPE popen_timeout_alarm_handler (int);
 
 #define        min(a,b)        ((a) < (b) ? (a) : (b))
 #define        max(a,b)        ((a) > (b) ? (a) : (b))
-int open_max (void);                                           /* {Prog 
openmax} */
 static void err_sys (const char *, ...) __attribute__((noreturn,format(printf, 
1, 2)));
 char *rtrim (char *, const char *);
 
@@ -86,7 +85,6 @@ char *pname = NULL;                                           
        /* caller can set this from argv[0] */
 
 /*int *childerr = NULL;*//* ptr to array allocated at run-time */
 /*extern pid_t *childpid = NULL; *//* ptr to array allocated at run-time */
-static int maxfd;                                                              
/* from our open_max(), {Prog openmax} */
 
 #ifdef REDHAT_SPOPEN_ERROR
 static volatile int childtermd = 0;
@@ -187,13 +185,11 @@ spopen (const char *cmdstring)
        argv[i] = NULL;
 
        if (childpid == NULL) {                         /* first time through */
-               maxfd = open_max ();                            /* allocate 
zeroed out array for child pids */
                if ((childpid = calloc ((size_t)maxfd, sizeof (pid_t))) == NULL)
                        return (NULL);
        }
 
        if (child_stderr_array == NULL) {       /* first time through */
-               maxfd = open_max ();                            /* allocate 
zeroed out array for child pids */
                if ((child_stderr_array = calloc ((size_t)maxfd, sizeof (int))) 
== NULL)
                        return (NULL);
        }
@@ -273,15 +269,6 @@ spclose (FILE * fp)
        return (1);
 }
 
-#ifdef OPEN_MAX
-static int openmax = OPEN_MAX;
-#else
-static int openmax = 0;
-#endif
-
-#define        OPEN_MAX_GUESS  256                     /* if OPEN_MAX is 
indeterminate */
-                               /* no guarantee this is adequate */
-
 #ifdef REDHAT_SPOPEN_ERROR
 RETSIGTYPE
 popen_sigchld_handler (int signo)
@@ -311,22 +298,6 @@ popen_timeout_alarm_handler (int signo)
 }
 
 
-int
-open_max (void)
-{
-       if (openmax == 0) {                                             /* 
first time through */
-               errno = 0;
-               if ((openmax = sysconf (_SC_OPEN_MAX)) < 0) {
-                       if (errno == 0)
-                               openmax = OPEN_MAX_GUESS;       /* it's 
indeterminate */
-                       else
-                               err_sys (_("sysconf error for _SC_OPEN_MAX"));
-               }
-       }
-       return (openmax);
-}
-
-
 /* Fatal error related to a system call.
  * Print a message and die. */
 
diff --git a/plugins/runcmd.c b/plugins/runcmd.c
index 1a7c904..c382867 100644
--- a/plugins/runcmd.c
+++ b/plugins/runcmd.c
@@ -67,19 +67,6 @@
  * occur in any number of threads simultaneously. */
 static pid_t *np_pids = NULL;
 
-/* Try sysconf(_SC_OPEN_MAX) first, as it can be higher than OPEN_MAX.
- * If that fails and the macro isn't defined, we fall back to an educated
- * guess. There's no guarantee that our guess is adequate and the program
- * will die with SIGSEGV if it isn't and the upper boundary is breached. */
-#ifdef _SC_OPEN_MAX
-static long maxfd = 0;
-#elif defined(OPEN_MAX)
-# define maxfd OPEN_MAX
-#else /* sysconf macro unavailable, so guess (may be wildly inaccurate) */
-# define maxfd 256
-#endif
-
-
 /** prototypes **/
 static int np_runcmd_open(const char *, int *, int *)
        __attribute__((__nonnull__(1, 2, 3)));
diff --git a/plugins/utils.c b/plugins/utils.c
index 231af92..ee62013 100644
--- a/plugins/utils.c
+++ b/plugins/utils.c
@@ -36,9 +36,6 @@ extern const char *progname;
 #define STRLEN 64
 #define TXTBLK 128
 
-unsigned int timeout_state = STATE_CRITICAL;
-unsigned int timeout_interval = DEFAULT_SOCKET_TIMEOUT;
-
 time_t start_time, end_time;
 
 /* **************************************************************************
@@ -148,33 +145,6 @@ print_revision (const char *command_name, const char 
*revision)
                 command_name, revision, PACKAGE, VERSION);
 }
 
-const char *
-state_text (int result)
-{
-       switch (result) {
-       case STATE_OK:
-               return "OK";
-       case STATE_WARNING:
-               return "WARNING";
-       case STATE_CRITICAL:
-               return "CRITICAL";
-       case STATE_DEPENDENT:
-               return "DEPENDENT";
-       default:
-               return "UNKNOWN";
-       }
-}
-
-void
-timeout_alarm_handler (int signo)
-{
-       if (signo == SIGALRM) {
-               printf (_("%s - Plugin timed out after %d seconds\n"),
-                                               state_text(timeout_state), 
timeout_interval);
-               exit (timeout_state);
-       }
-}
-
 int
 is_numeric (char *number)
 {
@@ -708,4 +678,3 @@ char *sperfdata_int (const char *label,
 
        return data;
 }
-
diff --git a/plugins/utils.h b/plugins/utils.h
index a436e1c..6aa316f 100644
--- a/plugins/utils.h
+++ b/plugins/utils.h
@@ -29,13 +29,6 @@ suite of plugins. */
 void support (void);
 void print_revision (const char *, const char *);
 
-/* Handle timeouts */
-
-extern unsigned int timeout_state;
-extern unsigned int timeout_interval;
-
-RETSIGTYPE timeout_alarm_handler (int);
-
 extern time_t start_time, end_time;
 
 /* Test input types */
@@ -89,8 +82,6 @@ void usage4(const char *) __attribute__((noreturn));
 void usage5(void) __attribute__((noreturn));
 void usage_va(const char *fmt, ...) __attribute__((noreturn));
 
-const char *state_text (int);
-
 #define max(a,b) (((a)>(b))?(a):(b))
 #define min(a,b) (((a)<(b))?(a):(b))
 

Reply via email to