From ceebd58040b1688749d58dd76963af639cf8c803 Mon Sep 17 00:00:00 2001
From: "M. Sean Finney" <seanius@users.sourceforge.net>
Date: Mon, 24 Oct 2005 11:10:29 +0000
Subject: initial merging of ae's np_runcmd code into selected plugins.

git-svn-id: https://nagiosplug.svn.sourceforge.net/svnroot/nagiosplug/nagiosplug/trunk@1260 f882894a-f735-0410-b71e-b25c423dba1c

diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 9222771..569199d 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -26,7 +26,7 @@ EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_snmp check_hpjd \
 
 EXTRA_DIST = t utils.c netutils.c sslutils.c popen.c utils.h netutils.h \
 	popen.h common.h getaddrinfo.c getaddrinfo.h \
-	gethostbyname.c gethostbyname.h
+	gethostbyname.c gethostbyname.h runcmd.c runcmd.h
 
 PLUGINHDRS = common.h
 
@@ -47,12 +47,12 @@ AM_INSTALL_PROGRAM_FLAGS = @INSTALL_OPTS@
 ##############################################################################
 # the actual targets
 
-check_dig_LDADD = $(NETLIBS) popen.o 
+check_dig_LDADD = $(NETLIBS) runcmd.o 
 check_disk_LDADD = $(BASEOBJS) popen.o
-check_dns_LDADD = $(NETLIBS) popen.o
+check_dns_LDADD = $(NETLIBS) runcmd.o
 check_dummy_LDADD = $(BASEOBJS)
 check_fping_LDADD = $(NETLIBS) popen.o
-check_game_LDADD = $(BASEOBJS) popen.o
+check_game_LDADD = $(BASEOBJS) runcmd.o
 check_http_LDADD = $(SSLOBJS) $(NETLIBS)
 check_hpjd_LDADD = $(NETLIBS) popen.o
 check_ldap_LDADD = $(NETLIBS) $(LDAPLIBS)
@@ -60,7 +60,7 @@ check_load_LDADD = $(BASEOBJS) popen.o
 check_mrtg_LDADD = $(BASEOBJS)
 check_mrtgtraf_LDADD = $(BASEOBJS)
 check_mysql_LDADD = $(NETLIBS) $(MYSQLLIBS)
-check_nagios_LDADD = $(BASEOBJS) popen.o
+check_nagios_LDADD = $(BASEOBJS) runcmd.o
 check_nt_LDADD = $(NETLIBS) 
 check_nwstat_LDADD = $(NETLIBS)
 check_overcr_LDADD = $(NETLIBS)
@@ -78,17 +78,17 @@ check_time_LDADD = $(NETLIBS)
 check_udp_LDADD = $(SSLOBJS) $(NETLIBS)
 check_ups_LDADD = $(NETLIBS)
 check_users_LDADD = $(BASEOBJS) popen.o
-check_by_ssh_LDADD = $(NETLIBS) popen.o
+check_by_ssh_LDADD = $(NETLIBS) runcmd.o
 check_ide_smart_LDADD = $(BASEOBJS)
 negate_LDADD = $(BASEOBJS) popen.o
 urlize_LDADD = $(BASEOBJS) popen.o
 
-check_dig_DEPENDENCIES = check_dig.c $(NETOBJS) popen.o $(DEPLIBS)
+check_dig_DEPENDENCIES = check_dig.c $(NETOBJS) runcmd.o $(DEPLIBS)
 check_disk_DEPENDENCIES = check_disk.c $(BASEOBJS) popen.o $(DEPLIBS)
-check_dns_DEPENDENCIES = check_dns.c $(NETOBJS) popen.o $(DEPLIBS)
+check_dns_DEPENDENCIES = check_dns.c $(NETOBJS) runcmd.o $(DEPLIBS)
 check_dummy_DEPENDENCIES = check_dummy.c $(DEPLIBS)
 check_fping_DEPENDENCIES = check_fping.c $(NETOBJS) popen.o $(DEPLIBS)
-check_game_DEPENDENCIES = check_game.c  $(DEPLIBS)
+check_game_DEPENDENCIES = check_game.c  $(DEPLIBS) runcmd.o
 check_http_DEPENDENCIES = check_http.c $(SSLOBJS) $(NETOBJS) $(DEPLIBS)
 check_hpjd_DEPENDENCIES = check_hpjd.c $(NETOBJS) popen.o $(DEPLIBS)
 check_ide_smart_DEPENDENCIES = check_ide_smart.c $(BASEOBJS) $(DEPLIBS)
@@ -97,7 +97,7 @@ check_load_DEPENDENCIES = check_load.c $(BASEOBJS) popen.o $(DEPLIBS)
 check_mrtg_DEPENDENCIES = check_mrtg.c $(DEPLIBS)
 check_mrtgtraf_DEPENDENCIES = check_mrtgtraf.c $(DEPLIBS)
 check_mysql_DEPENDENCIES = check_mysql.c $(NETOBJS) $(DEPLIBS)
-check_nagios_DEPENDENCIES = check_nagios.c $(BASEOBJS) popen.o $(DEPLIBS)
+check_nagios_DEPENDENCIES = check_nagios.c $(BASEOBJS) runcmd.o $(DEPLIBS)
 check_nt_DEPENDENCIES = check_nt.c $(NETOBJS) $(DEPLIBS)
 check_nwstat_DEPENDENCIES = check_nwstat.c $(NETOBJS) $(DEPLIBS)
 check_overcr_DEPENDENCIES = check_overcr.c $(NETOBJS) $(DEPLIBS)
@@ -115,7 +115,7 @@ check_time_DEPENDENCIES = check_time.c $(NETOBJS) $(DEPLIBS)
 check_udp_DEPENDENCIES = check_udp.c $(SSLOBJS) $(NETOBJS) $(DEPLIBS)
 check_ups_DEPENDENCIES = check_ups.c $(NETOBJS) $(DEPLIBS)
 check_users_DEPENDENCIES = check_users.c $(BASEOBJS) popen.o $(DEPLIBS)
-check_by_ssh_DEPENDENCIES = check_by_ssh.c $(NETOBJS) popen.o $(DEPLIBS)
+check_by_ssh_DEPENDENCIES = check_by_ssh.c $(NETOBJS) runcmd.o $(DEPLIBS)
 negate_DEPENDENCIES = negate.c $(BASEOBJS) popen.o $(DEPLIBS)
 urlize_DEPENDENCIES = urlize.c $(BASEOBJS) popen.o $(DEPLIBS)
 
@@ -124,6 +124,8 @@ urlize_DEPENDENCIES = urlize.c $(BASEOBJS) popen.o $(DEPLIBS)
 
 popen.o: popen.c popen.h $(PLUGINHDRS)
 
+runcmd.o: runcmd.c runcmd.h $(PLUGINHDRS)
+
 utils.o: utils.c utils.h $(PLUGINHDRS)
 
 netutils.o: netutils.c netutils.h $(PLUGINHDRS)
diff --git a/plugins/check_by_ssh.c b/plugins/check_by_ssh.c
index 2ceee28..b777b07 100644
--- a/plugins/check_by_ssh.c
+++ b/plugins/check_by_ssh.c
@@ -26,7 +26,7 @@ const char *email = "nagiosplug-devel@lists.sourceforge.net";
 #include "common.h"
 #include "netutils.h"
 #include "utils.h"
-#include "popen.h"
+#include "runcmd.h"
 
 int process_arguments (int, char **);
 int validate_arguments (void);
@@ -35,7 +35,7 @@ void print_usage (void);
 
 int commands = 0;
 int services = 0;
-int skip_lines = 0;
+int skip = 0;
 char *remotecmd = NULL;
 char *comm = NULL;
 char *hostname = NULL;
@@ -49,19 +49,16 @@ int
 main (int argc, char **argv)
 {
 
-	char input_buffer[MAX_INPUT_BUFFER];
-	char *result_text;
 	char *status_text;
-	char *output;
-	char *eol = NULL;
 	int cresult;
 	int result = STATE_UNKNOWN;
+	int i;
 	time_t local_time;
 	FILE *fp = NULL;
+	struct output chld_out, chld_err;
 
-	remotecmd = strdup ("");
+	remotecmd = "";
 	comm = strdup (SSH_COMMAND);
-	result_text = strdup ("");
 
 	setlocale (LC_ALL, "");
 	bindtextdomain (PACKAGE, LOCALEDIR);
@@ -69,100 +66,62 @@ main (int argc, char **argv)
 
 	/* process arguments */
 	if (process_arguments (argc, argv) == ERROR)
-		usage4 (_("Could not parse arguments"));
+		usage_va(_("Could not parse arguments"));
 
 	/* Set signal handling and alarm timeout */
 	if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
-		usage4 (_("Cannot catch SIGALRM"));
+		usage_va(_("Cannot catch SIGALRM"));
 	}
 	alarm (timeout_interval);
 
 	/* run the command */
-
 	if (verbose)
 		printf ("%s\n", comm);
 
-	child_process = spopen (comm);
-
-	if (child_process == NULL) {
-		printf (_("Could not open pipe: %s\n"), comm);
+	result = np_runcmd(comm, &chld_out, &chld_err, 0);
+	/* UNKNOWN if output found on stderr */
+	if(chld_err.buflen) {
+		printf(_("Remote command execution failed: %s\n"),
+			   chld_err.buflen ? chld_err.buf : _("Unknown error"));
 		return STATE_UNKNOWN;
 	}
 
-
-	/* open STDERR  for spopen */
-	child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
-	if (child_stderr == NULL) {
-		printf (_("Could not open stderr for %s\n"), SSH_COMMAND);
+	/* this is simple if we're not supposed to be passive.
+	 * Wrap up quickly and keep the tricks below */
+	if(!passive) {
+		printf ("%s\n", skip < chld_out.lines ? chld_out.line[skip] : chld_out.buf);
+		return result; 	/* return error status from remote command */
 	}
 
 
-	/* build up results from remote command in result_text */
-	while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process))
-		asprintf (&result_text, "%s%s", result_text, input_buffer);
-
-	/* WARNING if output found on stderr */
-	while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
-		if (skip_lines > 0) {
-			if (input_buffer[strlen(input_buffer)-1] == '\n') {
-				skip_lines--;
-			}
-		} else {
-			printf ("%s", input_buffer);
-			result = STATE_WARNING;
-		}
-	}
-	(void) fclose (child_stderr);
-	if (result == STATE_WARNING)
-		return result;
-
-
-	/* close the pipe */
-	result = spclose (child_process);
-
+	/*
+	 * Passive mode
+	 */
 
 	/* process output */
-	if (passive) {
+	if (!(fp = fopen (outputfile, "a"))) {
+		printf (_("SSH WARNING: could not open %s\n"), outputfile);
+		exit (STATE_UNKNOWN);
+	}
 
-		if (!(fp = fopen (outputfile, "a"))) {
-			printf (_("SSH WARNING: could not open %s\n"), outputfile);
-			exit (STATE_UNKNOWN);
+	local_time = time (NULL);
+	commands = 0;
+	for(i = skip; chld_out.line[i]; i++) {
+		status_text = strstr (chld_out.line[i], "STATUS CODE: ");
+		if (status_text == NULL) {
+			printf ("%s", chld_out.line[i]);
+			return result;
 		}
-
-		local_time = time (NULL);
-		commands = 0;
-		while (result_text && strlen(result_text) > 0) {
-			status_text = strstr (result_text, "STATUS CODE: ");
-			if (status_text == NULL) {
-				printf ("%s", result_text);
-				return result;
-			}
-			asprintf (&output, "%s", result_text);
-			result_text = strnl (status_text);
-			eol = strpbrk (output, "\r\n");
-			if (eol != NULL)
-				eol[0] = 0;
-			if (service[commands] && status_text
-					&& sscanf (status_text, "STATUS CODE: %d", &cresult) == 1) {
-				fprintf (fp, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n",
-								 (int) local_time, host_shortname, service[commands++], cresult,
-								 output);
-			}
+		if (service[commands] && status_text
+			&& sscanf (status_text, "STATUS CODE: %d", &cresult) == 1)
+		{
+			fprintf (fp, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n",
+			         (int) local_time, host_shortname, service[commands++],
+			         cresult, chld_out.line[i]);
 		}
-
-	}
-
-
-	/* print the first line from the remote command */
-	else {
- 		eol = strpbrk (result_text, "\r\n");
- 		if (eol)
- 			eol[0] = 0;
- 		printf ("%s\n", result_text);
 	}
-
-
-	/* return error status from remote command */	
+	
+	/* force an OK state */
 	return result;
 }
 
@@ -206,14 +165,12 @@ process_arguments (int argc, char **argv)
 
 	while (1) {
 		c = getopt_long (argc, argv, "Vvh1246ft:H:O:p:i:u:l:C:S:n:s:", longopts,
-									 &option);
+		                 &option);
 
 		if (c == -1 || c == EOF)
 			break;
 
 		switch (c) {
-		case '?':									/* help */
-			usage2 (_("Unknown argument"), optarg);
 		case 'V':									/* version */
 			print_revision (progname, revision);
 			exit (STATE_OK);
@@ -225,18 +182,17 @@ process_arguments (int argc, char **argv)
 			break;
 		case 't':									/* timeout period */
 			if (!is_integer (optarg))
-				usage2 (_("Timeout interval must be a positive integer"), optarg);
+				usage_va(_("Timeout interval must be a positive integer"));
 			else
 				timeout_interval = atoi (optarg);
 			break;
 		case 'H':									/* host */
-			if (!is_host (optarg))
-				usage2 (_("Invalid hostname/address"), optarg);
+			host_or_die(optarg);
 			hostname = optarg;
 			break;
 		case 'p': /* port number */
 			if (!is_integer (optarg))
-				usage2 (_("Port must be a positive integer"), optarg);
+				usage_va(_("Port must be a positive integer"));
 			asprintf (&comm,"%s -p %s", comm, optarg);
 			break;
 		case 'O':									/* output file */
@@ -244,25 +200,27 @@ process_arguments (int argc, char **argv)
 			passive = TRUE;
 			break;
 		case 's':									/* description of service to check */
-			service = realloc (service, (++services) * sizeof(char *));
 			p1 = optarg;
+			service = realloc (service, (++services) * sizeof(char *));
 			while ((p2 = index (p1, ':'))) {
 				*p2 = '\0';
-				asprintf (&service[services-1], "%s", p1);
+				service[services - 1] = p1;
 				service = realloc (service, (++services) * sizeof(char *));
 				p1 = p2 + 1;
 			}
-			asprintf (&service[services-1], "%s", p1);
+			service[services - 1] = p1;
 			break;
 		case 'n':									/* short name of host in nagios configuration */
 			host_shortname = optarg;
 			break;
+
 		case 'u':
 			c = 'l';
 		case 'l':									/* login name */
 		case 'i':									/* identity */
 			asprintf (&comm, "%s -%c %s", comm, c, optarg);
 			break;
+
 		case '1':									/* Pass these switches directly to ssh */
 		case '2':									/* 1 to force version 1, 2 to force version 2 */
 		case '4':									/* -4 for IPv4 */
@@ -278,10 +236,12 @@ process_arguments (int argc, char **argv)
 			break;
 		case 'S':									/* Skip n lines in the output to ignore system banner */
 			if (!is_integer (optarg))
-				usage2 (_("skip lines must be an integer"), optarg);
+				usage_va(_("skip lines must be an integer"));
 			else
-				skip_lines = atoi (optarg);
+				skip = atoi (optarg);
 			break;
+		default:									/* help */
+			usage_va(_("Unknown argument - %s"), optarg);
 		}
 	}
 
@@ -289,8 +249,8 @@ process_arguments (int argc, char **argv)
 	if (hostname == NULL) {
 		if (c <= argc) {
 			die (STATE_UNKNOWN, _("%s: You must provide a host name\n"), progname);
-		} else if (!is_host (argv[c]))
-			die (STATE_UNKNOWN, "%s: %s %s\n", progname, _("Invalid hostname/address"), argv[c]);
+		}
+		host_or_die(argv[c]);
 		hostname = argv[c++];
 	}
 
@@ -306,7 +266,7 @@ process_arguments (int argc, char **argv)
 		asprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd);
 
 	if (remotecmd == NULL || strlen (remotecmd) <= 1)
-		usage4 (_("No remotecmd"));
+		usage_va(_("No remotecmd"));
 
 	asprintf (&comm, "%s %s '%s'", comm, hostname, remotecmd);
 
diff --git a/plugins/check_dig.c b/plugins/check_dig.c
index 4394490..bc4dcd5 100644
--- a/plugins/check_dig.c
+++ b/plugins/check_dig.c
@@ -18,6 +18,12 @@
  
 *****************************************************************************/
 
+/* Hackers note:
+ *  There are typecasts to (char *) from _("foo bar") in this file.
+ *  They prevent compiler warnings. Never (ever), permute strings obtained
+ *  that are typecast from (const char *) (which happens when --disable-nls)
+ *  because on some architectures those strings are in non-writable memory */
+
 const char *progname = "check_dig";
 const char *revision = "$Revision$";
 const char *copyright = "2002-2004";
@@ -26,17 +32,15 @@ const char *email = "nagiosplug-devel@lists.sourceforge.net";
 #include "common.h"
 #include "netutils.h"
 #include "utils.h"
-#include "popen.h"
+#include "runcmd.h"
 
 int process_arguments (int, char **);
 int validate_arguments (void);
 void print_help (void);
 void print_usage (void);
 
-enum {
-	UNDEFINED = 0,
-	DEFAULT_PORT = 53
-};
+#define UNDEFINED 0
+#define DEFAULT_PORT 53
 
 char *query_address = NULL;
 char *record_type = "A";
@@ -51,26 +55,25 @@ struct timeval tv;
 int
 main (int argc, char **argv)
 {
-	char input_buffer[MAX_INPUT_BUFFER];
 	char *command_line;
-	char *output;
+	output chld_out, chld_err;
+	char *msg = NULL;
+	size_t i;
 	char *t;
 	long microsec;
 	double elapsed_time;
 	int result = STATE_UNKNOWN;
 
-	output = strdup ("");
-
 	setlocale (LC_ALL, "");
 	bindtextdomain (PACKAGE, LOCALEDIR);
 	textdomain (PACKAGE);
 
 	/* Set signal handling and alarm */
 	if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR)
-		usage4 (_("Cannot catch SIGALRM"));
+		usage_va(_("Cannot catch SIGALRM"));
 
 	if (process_arguments (argc, argv) == ERROR)
-		usage4 (_("Could not parse arguments"));
+		usage_va(_("Could not parse arguments"));
 
 	/* get the command to run */
 	asprintf (&command_line, "%s @%s -p %d %s -t %s",
@@ -89,100 +92,75 @@ main (int argc, char **argv)
 	}
 
 	/* run the command */
-	child_process = spopen (command_line);
-	if (child_process == NULL) {
-		printf (_("Could not open pipe: %s\n"), command_line);
-		return STATE_UNKNOWN;
+	if(np_runcmd(command_line, &chld_out, &chld_err, 0) != 0) {
+		result = STATE_WARNING;
+		msg = (char *)_("dig returned an error status");
 	}
 
-	child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
-	if (child_stderr == NULL)
-		printf (_("Could not open stderr for %s\n"), command_line);
-
-	while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
-
+	for(i = 0; i < chld_out.lines; i++) {
 		/* the server is responding, we just got the host name... */
-		if (strstr (input_buffer, ";; ANSWER SECTION:")) {
+		if (strstr (chld_out.line[i], ";; ANSWER SECTION:")) {
 
 			/* loop through the whole 'ANSWER SECTION' */
-			do {
+			for(; i < chld_out.lines; i++) {
 				/* get the host address */
-				if (!fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process))
-					break;
-
-				if (strpbrk (input_buffer, "\r\n"))
-					input_buffer[strcspn (input_buffer, "\r\n")] = '\0';
+				if (verbose)
+					printf ("%s\n", chld_out.line[i]);
 
-				if (verbose && !strstr (input_buffer, ";; ")) 
-					printf ("%s\n", input_buffer); 
-
-				if (expected_address==NULL && strstr (input_buffer, query_address) != NULL) {
-					output = strdup(input_buffer);
+				if (strstr (chld_out.line[i], (expected_address == NULL ? query_address : expected_address)) != NULL) {
+					msg = chld_out.line[i];
 					result = STATE_OK;
-				}
-				else if (expected_address != NULL && strstr (input_buffer, expected_address) != NULL) {
-					output = strdup(input_buffer);
-                        	        result = STATE_OK;
-				}
-
-				/* Translate output TAB -> SPACE */
-				t = output;
-				while ((t = index(t, '\t')) != NULL) 
-					*t = ' ';
 
-			} while (!strstr (input_buffer, ";; "));
+					/* Translate output TAB -> SPACE */
+					t = msg;
+					while ((t = strchr(t, '\t')) != NULL) *t = ' ';
+					break;
+				}
+			}
 
 			if (result == STATE_UNKNOWN) {
-		        	asprintf (&output, _("Server not found in ANSWER SECTION"));
-	                        result = STATE_WARNING;
-                        }
-		}
-
-	}
-
-	if (result == STATE_UNKNOWN) {
-		asprintf (&output, _("No ANSWER SECTION found"));
-	}
+				msg = (char *)_("Server not found in ANSWER SECTION");
+				result = STATE_WARNING;
+			}
 
-	while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
-		/* If we get anything on STDERR, at least set warning */
-		result = max_state (result, STATE_WARNING);
-		printf ("%s", input_buffer);
-		if (strlen (output) == 0)
-			output = strdup (1 + index (input_buffer, ':'));
+			/* we found the answer section, so break out of the loop */
+			break;
+		}
 	}
 
-	(void) fclose (child_stderr);
-
-	/* close the pipe */
-	if (spclose (child_process)) {
-		result = max_state (result, STATE_WARNING);
-		if (strlen (output) == 0)
-			asprintf (&output, _("dig returned an error status"));
+	if (result == STATE_UNKNOWN)
+		msg = (char *)_("No ANSWER SECTION found");
+
+	/* If we get anything on STDERR, at least set warning */
+	if(chld_err.buflen > 0) {
+		result = max_state(result, STATE_WARNING);
+		if(!msg) for(i = 0; i < chld_err.lines; i++) {
+			msg = strchr(chld_err.line[0], ':');
+			if(msg) {
+				msg++;
+				break;
+			}
+		}
 	}
 
 	microsec = deltime (tv);
 	elapsed_time = (double)microsec / 1.0e6;
 
-	if (output == NULL || strlen (output) == 0)
-		asprintf (&output, _(" Probably a non-existent host/domain"));
-
 	if (critical_interval > UNDEFINED && elapsed_time > critical_interval)
 		result = STATE_CRITICAL;
 
 	else if (warning_interval > UNDEFINED && elapsed_time > warning_interval)
 		result = STATE_WARNING;
 
-	asprintf (&output, _("%.3f seconds response time (%s)"), elapsed_time, output);
-
-	printf ("DNS %s - %s|%s\n",
-	        state_text (result), output,
+	printf ("DNS %s - %.3f seconds response time (%s)|%s\n",
+	        state_text (result), elapsed_time,
+	        msg ? msg : _("Probably a non-existent host/domain"),
 	        fperfdata("time", elapsed_time, "s",
-	                 (warning_interval>UNDEFINED?TRUE:FALSE),
-	                 warning_interval,
-	                 (critical_interval>UNDEFINED?TRUE:FALSE),
-	                 critical_interval,
-									 TRUE, 0, FALSE, 0));
+	                  (warning_interval>UNDEFINED?TRUE:FALSE),
+	                  warning_interval,
+	                  (critical_interval>UNDEFINED?TRUE:FALSE),
+					  critical_interval,
+					  TRUE, 0, FALSE, 0));
 	return result;
 }
 
@@ -219,8 +197,6 @@ process_arguments (int argc, char **argv)
 			break;
 
 		switch (c) {
-		case '?':									/* help */
-			usage2 (_("Unknown argument"), optarg);
 		case 'h':									/* help */
 			print_help ();
 			exit (STATE_OK);
@@ -228,19 +204,15 @@ process_arguments (int argc, char **argv)
 			print_revision (progname, revision);
 			exit (STATE_OK);
 		case 'H':									/* hostname */
-			if (is_host (optarg)) {
-				dns_server = optarg;
-			}
-			else {
-				usage2 (_("Invalid hostname/address"), optarg);
-			}
+			host_or_die(optarg);
+			dns_server = optarg;
 			break;
 		case 'p':                 /* server port */
 			if (is_intpos (optarg)) {
 				server_port = atoi (optarg);
 			}
 			else {
-				usage2 (_("Port must be a positive integer"), optarg);
+				usage_va(_("Port must be a positive integer - %s"), optarg);
 			}
 			break;
 		case 'l':									/* address to lookup */
@@ -251,7 +223,7 @@ process_arguments (int argc, char **argv)
 				warning_interval = strtod (optarg, NULL);
 			}
 			else {
-				usage2 (_("Warning interval must be a positive integer"), optarg);
+				usage_va(_("Warning interval must be a positive integer - %s"), optarg);
 			}
 			break;
 		case 'c':									/* critical */
@@ -259,7 +231,7 @@ process_arguments (int argc, char **argv)
 				critical_interval = strtod (optarg, NULL);
 			}
 			else {
-				usage2 (_("Critical interval must be a positive integer"), optarg);
+				usage_va(_("Critical interval must be a positive integer - %s"), optarg);
 			}
 			break;
 		case 't':									/* timeout */
@@ -267,7 +239,7 @@ process_arguments (int argc, char **argv)
 				timeout_interval = atoi (optarg);
 			}
 			else {
-				usage2 (_("Timeout interval must be a positive integer"), optarg);
+				usage_va(_("Timeout interval must be a positive integer - %s"), optarg);
 			}
 			break;
 		case 'v':									/* verbose */
@@ -279,18 +251,16 @@ process_arguments (int argc, char **argv)
 		case 'a':
 			expected_address = optarg;
 			break;
+		default:									/* usage_va */
+			usage_va(_("Unknown argument - %s"), optarg);
 		}
 	}
 
 	c = optind;
 	if (dns_server == NULL) {
 		if (c < argc) {
-			if (is_host (argv[c])) {
-				dns_server = argv[c];
-			}
-			else {
-				usage2 (_("Invalid hostname/address"), argv[c]);
-			}
+			host_or_die(argv[c]);
+			dns_server = argv[c];
 		}
 		else {
 			dns_server = strdup ("127.0.0.1");
@@ -359,6 +329,6 @@ print_usage (void)
 {
 	printf ("\
 Usage: %s -H host -l lookup [-p <server port>] [-T <query type>]\n\
-                  [-w <warning interval>] [-c <critical interval>] [-t <timeout>]\n\
-                  [-a <expected answer address>] [-v]\n", progname);
+              [-w <warning interval>] [-c <critical interval>] [-t <timeout>]\n\
+              [-a <expected answer address>] [-v]\n", progname);
 }
diff --git a/plugins/check_dns.c b/plugins/check_dns.c
index 94d4300..d6e8ca2 100644
--- a/plugins/check_dns.c
+++ b/plugins/check_dns.c
@@ -27,9 +27,9 @@ const char *copyright = "2000-2004";
 const char *email = "nagiosplug-devel@lists.sourceforge.net";
 
 #include "common.h"
-#include "popen.h"
 #include "utils.h"
 #include "netutils.h"
+#include "runcmd.h"
 
 int process_arguments (int, char **);
 int validate_arguments (void);
@@ -51,8 +51,8 @@ main (int argc, char **argv)
 {
 	char *command_line = NULL;
 	char input_buffer[MAX_INPUT_BUFFER];
-	char *output = NULL;
 	char *address = NULL;
+	char *msg = NULL;
 	char *temp_buffer = NULL;
 	int non_authoritative = FALSE;
 	int result = STATE_UNKNOWN;
@@ -61,6 +61,8 @@ main (int argc, char **argv)
 	struct timeval tv;
 	int multi_address;
 	int parse_address = FALSE; /* This flag scans for Address: but only after Name: */
+	output chld_out, chld_err;
+	size_t i;
 
 	setlocale (LC_ALL, "");
 	bindtextdomain (PACKAGE, LOCALEDIR);
@@ -68,11 +70,11 @@ main (int argc, char **argv)
 
 	/* Set signal handling and alarm */
 	if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
-		usage4 (_("Cannot catch SIGALRM"));
+		usage_va(_("Cannot catch SIGALRM"));
 	}
 
 	if (process_arguments (argc, argv) == ERROR) {
-		usage4 (_("Could not parse arguments"));
+		usage_va(_("Could not parse arguments"));
 	}
 
 	/* get the command to run */
@@ -85,37 +87,31 @@ main (int argc, char **argv)
 		printf ("%s\n", command_line);
 
 	/* run the command */
-	child_process = spopen (command_line);
-	if (child_process == NULL) {
-		printf (_("Could not open pipe: %s\n"), command_line);
-		return STATE_UNKNOWN;
+	if((np_runcmd(command_line, &chld_out, &chld_err, 0)) != 0) {
+		msg = (char *)_("nslookup returned error status");
+		result = STATE_WARNING;
 	}
 
-	child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
-	if (child_stderr == NULL)
-		printf (_("Could not open stderr for %s\n"), command_line);
-
 	/* scan stdout */
-	while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
-
+	for(i = 0; i < chld_out.lines; i++) {
 		if (verbose)
-			printf ("%s", input_buffer);
+			puts(chld_out.line[i]);
 
-		if (strstr (input_buffer, ".in-addr.arpa")) {
-			if ((temp_buffer = strstr (input_buffer, "name = ")))
+		if (strstr (chld_out.line[i], ".in-addr.arpa")) {
+			if ((temp_buffer = strstr (chld_out.line[i], "name = ")))
 				address = strdup (temp_buffer + 7);
 			else {
-				output = strdup (_("Warning plugin error"));
+				msg = (char *)_("Warning plugin error");
 				result = STATE_WARNING;
 			}
 		}
 
 		/* the server is responding, we just got the host name... */
-		if (strstr (input_buffer, "Name:"))
+		if (strstr (chld_out.line[i], "Name:"))
 			parse_address = TRUE;
-		else if (parse_address == TRUE && (strstr (input_buffer, "Address:") ||
-		         strstr (input_buffer, "Addresses:"))) {
-			temp_buffer = index (input_buffer, ':');
+		else if (parse_address == TRUE && (strstr (chld_out.line[i], "Address:") ||
+		         strstr (chld_out.line[i], "Addresses:"))) {
+			temp_buffer = index (chld_out.line[i], ':');
 			temp_buffer++;
 
 			/* Strip leading spaces */
@@ -135,59 +131,47 @@ main (int argc, char **argv)
 				asprintf(&address, "%s,%s", address, temp_buffer);
 		}
 
-		else if (strstr (input_buffer, _("Non-authoritative answer:"))) {
+		else if (strstr (chld_out.line[i], _("Non-authoritative answer:"))) {
 			non_authoritative = TRUE;
 		}
 
-		result = error_scan (input_buffer);
+		result = error_scan (chld_out.line[i]);
 		if (result != STATE_OK) {
-			output = strdup (1 + index (input_buffer, ':'));
-			strip (output);
+			msg = strchr (chld_out.line[i], ':');
+			if(msg) msg++;
 			break;
 		}
-
 	}
 
 	/* scan stderr */
-	while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
-
+	for(i = 0; i < chld_err.lines; i++) {
 		if (verbose)
-			printf ("%s", input_buffer);
+			puts(chld_err.line[i]);
 
-		if (error_scan (input_buffer) != STATE_OK) {
-			result = max_state (result, error_scan (input_buffer));
-			output = strdup (1 + index (input_buffer, ':'));
-			strip (output);
+		if (error_scan (chld_err.line[i]) != STATE_OK) {
+			result = max_state (result, error_scan (chld_err.line[i]));
+			msg = strchr(input_buffer, ':');
+			if(msg) msg++;
 		}
 	}
 
-	/* close stderr */
-	(void) fclose (child_stderr);
-
-	/* close stdout */
-	if (spclose (child_process)) {
-		result = max_state (result, STATE_WARNING);
-		if (output == NULL || !strcmp (output, ""))
-			output = strdup (_("nslookup returned error status"));
-	}
-
-	/* If we got here, we should have an address string, 
-		 and we can segfault if we do not */
+	/* If we got here, we should have an address string,
+	 * and we can segfault if we do not */
 	if (address==NULL || strlen(address)==0)
 		die (STATE_CRITICAL,
-		     _("DNS CRITICAL - '%s' output parsing exited with no address\n"),
+		     _("DNS CRITICAL - '%s' msg parsing exited with no address\n"),
 		     NSLOOKUP_COMMAND);
 
 	/* compare to expected address */
 	if (result == STATE_OK && match_expected_address && strcmp(address, expected_address)) {
 		result = STATE_CRITICAL;
-		asprintf(&output, _("expected %s but got %s"), expected_address, address);
+		asprintf(&msg, _("expected %s but got %s"), expected_address, address);
 	}
 
 	/* check if authoritative */
 	if (result == STATE_OK && expect_authority && non_authoritative) {
 		result = STATE_CRITICAL;
-		asprintf(&output, _("server %s is not authoritative for %s"), dns_server, query_address);
+		asprintf(&msg, _("server %s is not authoritative for %s"), dns_server, query_address);
 	}
 
 	microsec = deltime (tv);
@@ -200,19 +184,19 @@ main (int argc, char **argv)
 			multi_address = TRUE;
 
 		printf ("DNS %s: ", _("OK"));
-		printf (ngettext("%.3f second response time ", "%.3f seconds response time ", elapsed_time), elapsed_time);
-		printf (_("%s returns %s"), query_address, address);
+		printf (ngettext("%.3f second response time", "%.3f seconds response time", elapsed_time), elapsed_time);
+		printf (_(". %s returns %s"), query_address, address);
 		printf ("|%s\n", fperfdata ("time", elapsed_time, "s", FALSE, 0, FALSE, 0, TRUE, 0, FALSE, 0));
 	}
 	else if (result == STATE_WARNING)
 		printf (_("DNS WARNING - %s\n"),
-		        !strcmp (output, "") ? _(" Probably a non-existent host/domain") : output);
+		        !strcmp (msg, "") ? _(" Probably a non-existent host/domain") : msg);
 	else if (result == STATE_CRITICAL)
 		printf (_("DNS CRITICAL - %s\n"),
-		        !strcmp (output, "") ? _(" Probably a non-existent host/domain") : output);
+		        !strcmp (msg, "") ? _(" Probably a non-existent host/domain") : msg);
 	else
 		printf (_("DNS UNKNOW - %s\n"),
-		        !strcmp (output, "") ? _(" Probably a non-existent host/domain") : output);
+		        !strcmp (msg, "") ? _(" Probably a non-existent host/domain") : msg);
 
 	return result;
 }
@@ -311,8 +295,6 @@ process_arguments (int argc, char **argv)
 			break;
 
 		switch (c) {
-		case '?': /* args not parsable */
-			usage2 (_("Unknown argument"), optarg);
 		case 'h': /* help */
 			print_help ();
 			exit (STATE_OK);
@@ -331,20 +313,16 @@ process_arguments (int argc, char **argv)
 			strcpy (query_address, optarg);
 			break;
 		case 's': /* server name */
-			/* TODO: this is_host check is probably unnecessary. */
-			/* Better to confirm nslookup response matches */
-			if (is_host (optarg) == FALSE) {
-				usage2 (_("Invalid hostname/address"), optarg);
-			}
+			/* TODO: this host_or_die check is probably unnecessary.
+			 * Better to confirm nslookup response matches */
+			host_or_die(optarg);
 			if (strlen (optarg) >= ADDRESS_LENGTH)
 				die (STATE_UNKNOWN, _("Input buffer overflow\n"));
 			strcpy (dns_server, optarg);
 			break;
 		case 'r': /* reverse server name */
-			/* TODO: Is this is_host necessary? */
-			if (is_host (optarg) == FALSE) {
-				usage2 (_("Invalid hostname/address"), optarg);
-			}
+			/* TODO: Is this host_or_die necessary? */
+			host_or_die(optarg);
 			if (strlen (optarg) >= ADDRESS_LENGTH)
 				die (STATE_UNKNOWN, _("Input buffer overflow\n"));
 			strcpy (ptr_server, optarg);
@@ -358,6 +336,8 @@ process_arguments (int argc, char **argv)
 		case 'A': /* expect authority */
 			expect_authority = TRUE;
 			break;
+		default: /* args not parsable */
+			usage_va(_("Unknown argument - %s"), optarg);
 		}
 	}
 
@@ -370,10 +350,7 @@ process_arguments (int argc, char **argv)
 
 	if (strlen(dns_server)==0 && c<argc) {
 		/* TODO: See -s option */
-		if (is_host(argv[c]) == FALSE) {
-			printf (_("Invalid hostname/address: %s\n\n"), argv[c]);
-			return ERROR;
-		}
+		host_or_die(argv[c]);
 		if (strlen(argv[c]) >= ADDRESS_LENGTH)
 			die (STATE_UNKNOWN, _("Input buffer overflow\n"));
 		strcpy (dns_server, argv[c++]);
@@ -388,8 +365,8 @@ validate_arguments ()
 {
 	if (query_address[0] == 0)
 		return ERROR;
-	else
-		return OK;
+
+	return OK;
 }
 
 
diff --git a/plugins/check_game.c b/plugins/check_game.c
index 08b04d6..912072c 100644
--- a/plugins/check_game.c
+++ b/plugins/check_game.c
@@ -23,8 +23,8 @@ const char *copyright = "2002-2004";
 const char *email = "nagiosplug-devel@lists.sourceforge.net";
 
 #include "common.h"
-#include "popen.h"
 #include "utils.h"
+#include "runcmd.h"
 
 int process_arguments (int, char **);
 int validate_arguments (void);
@@ -57,16 +57,16 @@ main (int argc, char **argv)
 	char *command_line;
 	int result = STATE_UNKNOWN;
 	FILE *fp;
-	char input_buffer[MAX_INPUT_BUFFER];
 	char *p, *ret[QSTAT_MAX_RETURN_ARGS];
-	int i;
+	size_t i = 0;
+	output chld_out;
 
 	setlocale (LC_ALL, "");
 	bindtextdomain (PACKAGE, LOCALEDIR);
 	textdomain (PACKAGE);
 	
 	if (process_arguments (argc, argv) == ERROR)
-		usage4 (_("Could not parse arguments"));
+		usage_va(_("Could not parse arguments"));
 
 	result = STATE_OK;
 
@@ -80,17 +80,9 @@ main (int argc, char **argv)
 	if (verbose > 0)
 		printf ("%s\n", command_line);
 
-	/* run the command */
-	fp = spopen (command_line);
-	if (fp == NULL) {
-		printf (_("Could not open pipe: %s\n"), command_line);
-		return STATE_UNKNOWN;
-	}
-
-	fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp);	/* Only interested in the first line */
-
-	/* strip the newline character from the end of the input */
-	input_buffer[strlen (input_buffer) - 1] = 0;
+	/* run the command. historically, this plugin ignores output on stderr,
+	 * as well as return status of the qstat program */
+	(void)np_runcmd(command_line, &chld_out, NULL, 0);
 
 	/* sanity check */
 	/* was thinking about running qstat without any options, capturing the
@@ -102,18 +94,13 @@ main (int argc, char **argv)
 	   In the end, I figured I'd simply let an error occur & then trap it
 	 */
 
-	if (!strncmp (input_buffer, "unknown option", 14)) {
+	if (!strncmp (chld_out.line[0], "unknown option", 14)) {
 		printf (_("CRITICAL - Host type parameter incorrect!\n"));
 		result = STATE_CRITICAL;
 		return result;
 	}
 
-	/* initialize the returned data buffer */
-	for (i = 0; i < QSTAT_MAX_RETURN_ARGS; i++)
-		ret[i] = strdup("");
-
-	i = 0;
-	p = (char *) strtok (input_buffer, QSTAT_DATA_DELIMITER);
+	p = (char *) strtok (chld_out.line[0], QSTAT_DATA_DELIMITER);
 	while (p != NULL) {
 		ret[i] = p;
 		p = (char *) strtok (NULL, QSTAT_DATA_DELIMITER);
@@ -141,17 +128,14 @@ main (int argc, char **argv)
 		        ret[qstat_game_field], 
 		        ret[qstat_map_field],
 		        ret[qstat_ping_field],
-						perfdata ("players", atol(ret[qstat_game_players]), "",
+		        perfdata ("players", atol(ret[qstat_game_players]), "",
 		                  FALSE, 0, FALSE, 0,
 		                  TRUE, 0, TRUE, atol(ret[qstat_game_players_max])),
-						fperfdata ("ping", strtod(ret[qstat_ping_field], NULL), "",
+		        fperfdata ("ping", strtod(ret[qstat_ping_field], NULL), "",
 		                  FALSE, 0, FALSE, 0,
 		                  TRUE, 0, FALSE, 0));
 	}
 
-	/* close the pipe */
-	spclose (fp);
-
 	return result;
 }
 
@@ -197,8 +181,6 @@ process_arguments (int argc, char **argv)
 			break;
 
 		switch (c) {
-		case '?': /* args not parsable */
-			usage2 (_("Unknown argument"), optarg);
 		case 'h': /* help */
 			print_help ();
 			exit (STATE_OK);
@@ -251,6 +233,8 @@ process_arguments (int argc, char **argv)
 			if (qstat_game_players_max < 0 || qstat_game_players_max > QSTAT_MAX_RETURN_ARGS)
 				return ERROR;
 			break;
+		default: /* args not parsable */
+			usage_va(_("Unknown argument - %s"), optarg);
 		}
 	}
 
@@ -328,8 +312,8 @@ void
 print_usage (void)
 {
 	printf ("\
-Usage: %s [-hvV] [-P port] [-t timeout] [-g game_field] [-m map_field]\n\
-                  [-p ping_field] [-G game-time] [-H hostname] <game> <ip_address>\n", progname);
+Usage: %s <game> <ip_address> [-p port] [-gf game_field] [-mf map_field]\n\
+                  [-pf ping_field]\n", progname);
 }
 
 /******************************************************************************
diff --git a/plugins/check_nagios.c b/plugins/check_nagios.c
index 089ff66..0ae488f 100644
--- a/plugins/check_nagios.c
+++ b/plugins/check_nagios.c
@@ -24,7 +24,7 @@ const char *copyright = "1999-2004";
 const char *email = "nagiosplug-devel@lists.sourceforge.net";
 
 #include "common.h"
-#include "popen.h"
+#include "runcmd.h"
 #include "utils.h"
 
 int process_arguments (int, char **);
@@ -55,6 +55,8 @@ main (int argc, char **argv)
 	int procrss = 0;
 	float procpcpu = 0;
 	char procstat[8];
+	/* procetime is unused in most configurations, but may be in PS_VAR_LIST
+	 * so it must be here in spite of it producing compiler warnings */
 	char procetime[MAX_INPUT_BUFFER];
 	char procprog[MAX_INPUT_BUFFER];
 	char *procargs;
@@ -62,17 +64,19 @@ main (int argc, char **argv)
 	int expected_cols = PS_COLS - 1;
 	const char *zombie = "Z";
 	char *temp_string;
+	output chld_out, chld_err;
+	size_t i;
 
 	setlocale (LC_ALL, "");
 	bindtextdomain (PACKAGE, LOCALEDIR);
 	textdomain (PACKAGE);
 
 	if (process_arguments (argc, argv) == ERROR)
-		usage4 (_("Could not parse arguments"));
+		usage_va(_("Could not parse arguments"));
 
 	/* Set signal handling and alarm timeout */
 	if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) {
-		usage4 (_("Cannot catch SIGALRM"));
+		usage_va(_("Cannot catch SIGALRM"));
 	}
 
 	/* handle timeouts gracefully... */
@@ -99,40 +103,30 @@ main (int argc, char **argv)
 		printf(_("command: %s\n"), PS_COMMAND);
 
 	/* run the command to check for the Nagios process.. */
-	child_process = spopen (PS_COMMAND);
-	if (child_process == NULL) {
-		printf (_("Could not open pipe: %s\n"), PS_COMMAND);
-		return STATE_UNKNOWN;
-	}
-
-	child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
-	if (child_stderr == NULL) {
-		printf (_("Could not open stderr for %s\n"), PS_COMMAND);
-	}
-
-	fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
+	if((result = np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0)) != 0)
+		result = STATE_WARNING;
 
 	/* count the number of matching Nagios processes... */
-	while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
-		cols = sscanf (input_buffer, PS_FORMAT, PS_VARLIST);
-                /* Zombie processes do not give a procprog command */
-                if ( cols == (expected_cols - 1) && strstr(procstat, zombie) ) {
-                        cols = expected_cols;
-                        /* Set some value for procargs for the strip command further below
-                        Seen to be a problem on some Solaris 7 and 8 systems */
-                        input_buffer[pos] = '\n';
-                        input_buffer[pos+1] = 0x0;
-                }
+	for(i = 0; i < chld_out.lines; i++) {
+		cols = sscanf (chld_out.line[i], PS_FORMAT, PS_VARLIST);
+		/* Zombie processes do not give a procprog command */
+		if ( cols == (expected_cols - 1) && strstr(procstat, zombie) ) {
+			cols = expected_cols;
+			/* Set some value for procargs for the strip command further below
+			 * Seen to be a problem on some Solaris 7 and 8 systems */
+			chld_out.line[i][pos] = '\n';
+			chld_out.line[i][pos+1] = 0x0;
+		}
 		if ( cols >= expected_cols ) {
-			asprintf (&procargs, "%s", input_buffer + pos);
+			asprintf (&procargs, "%s", chld_out.line[i] + pos);
 			strip (procargs);
-			
+
 			/* Some ps return full pathname for command. This removes path */
-                        temp_string = strtok ((char *)procprog, "/");
-                        while (temp_string) {
-                                strcpy(procprog, temp_string);
-                                temp_string = strtok (NULL, "/");
-                        }
+			temp_string = strtok ((char *)procprog, "/");
+			while (temp_string) {
+				strcpy(procprog, temp_string);
+				temp_string = strtok (NULL, "/");
+			}
 
 			/* May get empty procargs */
 			if (!strstr(procargs, argv[0]) && strstr(procargs, process_string) && strcmp(procargs,"")) {
@@ -145,14 +139,7 @@ main (int argc, char **argv)
 	}
 
 	/* If we get anything on stderr, at least set warning */
-	while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr))
-		result = max_state (result, STATE_WARNING);
-
-	/* close stderr */
-	(void) fclose (child_stderr);
-
-	/* close the pipe */
-	if (spclose (child_process))
+	if(chld_err.buflen)
 		result = max_state (result, STATE_WARNING);
 
 	/* reset the alarm handler */
@@ -219,8 +206,6 @@ process_arguments (int argc, char **argv)
 			break;
 
 		switch (c) {
-		case '?':									/* print short usage statement if args not parsable */
-			usage2 (_("Unknown argument"), optarg);
 		case 'h':									/* help */
 			print_help ();
 			exit (STATE_OK);
@@ -243,16 +228,17 @@ process_arguments (int argc, char **argv)
 		case 'v':
 			verbose++;
 			break;
+		default:									/* print short usage_va statement if args not parsable */
+			usage_va(_("Unknown argument - %s"), optarg);
 		}
 	}
 
 
 	if (status_log == NULL)
-		die (STATE_UNKNOWN,
-		     _("You must provide the status_log\n"));
-	else if (process_string == NULL)
-		die (STATE_UNKNOWN,
-							 _("You must provide a process string\n"));
+		die (STATE_UNKNOWN, _("You must provide the status_log\n"));
+
+	if (process_string == NULL)
+		die (STATE_UNKNOWN, _("You must provide a process string\n"));
 
 	return OK;
 }
diff --git a/plugins/netutils.c b/plugins/netutils.c
index db64ef0..0824527 100644
--- a/plugins/netutils.c
+++ b/plugins/netutils.c
@@ -291,6 +291,13 @@ is_host (const char *address)
 	return (FALSE);
 }
 
+void
+host_or_die(const char *str)
+{
+	if(!str || (!is_addr(str) && !is_hostname(str)))
+		usage_va(_("Invalid hostname/address - %s"), str);
+}
+
 int
 is_addr (const char *address)
 {
diff --git a/plugins/runcmd.c b/plugins/runcmd.c
index 14300ee..4155796 100644
--- a/plugins/runcmd.c
+++ b/plugins/runcmd.c
@@ -16,6 +16,8 @@
  *
  */
 
+#define NAGIOSPLUG_API_C 1
+
 /** includes **/
 #include "runcmd.h"
 #ifdef HAVE_SYS_WAIT_H
@@ -45,20 +47,17 @@
  * occur in any number of threads simultaneously. */
 static pid_t *np_pids = NULL;
 
-/* If OPEN_MAX isn't defined, we try the sysconf syscall first.
- * If that fails, we fall back to an educated guess which is accurate
- * on Linux and some other systems. 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 OPEN_MAX
+/* 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
-# ifndef _SC_OPEN_MAX /* sysconf macro unavailable, so guess */
-#  define maxfd 256
-# else
-static int maxfd = 0;
-# endif /* _SC_OPEN_MAX */
-#endif /* OPEN_MAX */
+#else /* sysconf macro unavailable, so guess (may be wildly inaccurate) */
+# define maxfd 256
+#endif
 
 
 /** prototypes **/
@@ -70,7 +69,7 @@ static int np_fetch_output(int, output *, int)
 
 static int np_runcmd_close(int);
 
-/* imported from utils.h */
+/* prototype imported from utils.h */
 extern void die (int, const char *, ...)
 	__attribute__((__noreturn__,__format__(__printf__, 2, 3)));
 
@@ -80,13 +79,11 @@ extern void die (int, const char *, ...)
  * through this api and thus achieve async-safeness throughout the api */
 void np_runcmd_init(void)
 {
-#if !defined(OPEN_MAX) && defined(_SC_OPEN_MAX)
-	if(!maxfd) {
-		if((maxfd = sysconf(_SC_OPEN_MAX)) < 0) {
-			/* possibly log or emit a warning here, since there's no
-			 * guarantee that our guess at maxfd will be adequate */
-			maxfd = 256;
-		}
+#ifndef maxfd
+	if(!maxfd && (maxfd = sysconf(_SC_OPEN_MAX)) < 0) {
+		/* possibly log or emit a warning here, since there's no
+		 * guarantee that our guess at maxfd will be adequate */
+		maxfd = 256;
 	}
 #endif
 
@@ -123,9 +120,9 @@ np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr)
 	/* make copy of command string so strtok() doesn't silently modify it */
 	/* (the calling program may want to access it later) */
 	cmdlen = strlen(cmdstring);
-	cmd = malloc(cmdlen + 1);
-	if (cmd == NULL) return -1;
+	if((cmd = malloc(cmdlen + 1)) == NULL) return -1;
 	memcpy(cmd, cmdstring, cmdlen);
+	cmd[cmdlen] = '\0';
 
 	/* This is not a shell, so we don't handle "???" */
 	if (strstr (cmdstring, "\"")) return -1;
@@ -257,7 +254,7 @@ popen_timeout_alarm_handler (int signo)
 static int
 np_fetch_output(int fd, output *op, int flags)
 {
-	size_t len = 0, i = 0;
+	size_t len = 0, i = 0, lineno = 0;
 	size_t rsf = 6, ary_size = 0; /* rsf = right shift factor, dec'ed uncond once */
 	char *buf = NULL;
 	int ret;
@@ -278,13 +275,12 @@ np_fetch_output(int fd, output *op, int flags)
 		return ret;
 	}
 
-	if(!op->buf || !op->buflen) return 0;
-
-	/* some plugins may want to keep output unbroken */
-	if(flags & RUNCMD_NO_ARRAYS)
+	/* some plugins may want to keep output unbroken, and some commands
+	 * will yield no output, so return here for those */
+	if(flags & RUNCMD_NO_ARRAYS || !op->buf || !op->buflen)
 		return op->buflen;
 
-	/* and some may want both (*sigh*) */
+	/* and some may want both */
 	if(flags & RUNCMD_NO_ASSOC) {
 		buf = malloc(op->buflen);
 		memcpy(buf, op->buf, op->buflen);
@@ -293,30 +289,34 @@ np_fetch_output(int fd, output *op, int flags)
 
 	op->line = NULL;
 	op->lens = NULL;
-	len = i = 0;
+	i = 0;
 	while(i < op->buflen) {
 		/* make sure we have enough memory */
-		if(len >= ary_size) {
-			ary_size = op->buflen >> --rsf;
+		if(lineno >= ary_size) {
+			/* ary_size must never be zero */
+			do {
+				ary_size = op->buflen >> --rsf;
+			} while(!ary_size);
+
 			op->line = realloc(op->line, ary_size * sizeof(char *));
 			op->lens = realloc(op->lens, ary_size * sizeof(size_t));
 		}
 
 		/* set the pointer to the string */
-		op->line[len] = &buf[i];
+		op->line[lineno] = &buf[i];
 
 		/* hop to next newline or end of buffer */
 		while(buf[i] != '\n' && i < op->buflen) i++;
 		buf[i] = '\0';
 
 		/* calculate the string length using pointer difference */
-		op->lens[len] = (size_t)&buf[i] - (size_t)op->line[len];
-		
-		len++;
+		op->lens[lineno] = (size_t)&buf[i] - (size_t)op->line[lineno];
+
+		lineno++;
 		i++;
 	}
 
-	return len;
+	return lineno;
 }
 
 
diff --git a/plugins/utils.c b/plugins/utils.c
index b9a19d3..8b31c5a 100644
--- a/plugins/utils.c
+++ b/plugins/utils.c
@@ -58,6 +58,17 @@ void usage (const char *msg)
 	exit (STATE_UNKNOWN);
 }
 
+void usage_va (const char *fmt, ...)
+{
+	va_list ap;
+	printf("%s: ", progname);
+	va_start(ap, fmt);
+	vprintf(fmt, ap);
+	va_end(ap);
+	printf("\n");
+	exit (STATE_UNKNOWN);
+}
+
 void usage2(const char *msg, const char *arg)
 {
 	printf ("%s: %s - %s\n",progname,msg,arg);
diff --git a/plugins/utils.h b/plugins/utils.h
index bdf1ee1..ffdb545 100644
--- a/plugins/utils.h
+++ b/plugins/utils.h
@@ -1,3 +1,5 @@
+#ifndef NP_UTILS_H
+#define NP_UTILS_H
 /* Header file for nagios plugins utils.c */
 
 /* This file should be included in all plugins */
@@ -77,6 +79,7 @@ void usage (const char *) __attribute__((noreturn));
 void usage2(const char *, const char *) __attribute__((noreturn));
 void usage3(const char *, int) __attribute__((noreturn));
 void usage4(const char *);
+void usage_va(const char *fmt, ...);
 
 const char *state_text (int);
 
@@ -169,3 +172,5 @@ send email to nagiosplug-devel@lists.sourceforge.net\n"
 The nagios plugins come with ABSOLUTELY NO WARRANTY. You may redistribute\n\
 copies of the plugins under the terms of the GNU General Public License.\n\
 For more information about these matters, see the file named COPYING.\n"
+
+#endif /* NP_UTILS_H */
-- 
cgit v0.10-9-g596f

