summaryrefslogtreecommitdiffstats
path: root/plugins/runcmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/runcmd.c')
-rw-r--r--plugins/runcmd.c78
1 files changed, 52 insertions, 26 deletions
diff --git a/plugins/runcmd.c b/plugins/runcmd.c
index 74843149..7c583b85 100644
--- a/plugins/runcmd.c
+++ b/plugins/runcmd.c
@@ -40,6 +40,7 @@
40 40
41/** includes **/ 41/** includes **/
42#include "runcmd.h" 42#include "runcmd.h"
43#include "../lib/monitoringplug.h"
43#ifdef HAVE_SYS_WAIT_H 44#ifdef HAVE_SYS_WAIT_H
44# include <sys/wait.h> 45# include <sys/wait.h>
45#endif 46#endif
@@ -52,7 +53,7 @@
52#endif 53#endif
53 54
54#ifndef WIFEXITED 55#ifndef WIFEXITED
55# define WIFEXITED(stat_val) (((stat_val)&255) == 0) 56# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
56#endif 57#endif
57 58
58/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */ 59/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */
@@ -86,8 +87,9 @@ extern void die(int, const char *, ...) __attribute__((__noreturn__, __format__(
86 * through this api and thus achieve async-safeness throughout the api */ 87 * through this api and thus achieve async-safeness throughout the api */
87void np_runcmd_init(void) { 88void np_runcmd_init(void) {
88 long maxfd = mp_open_max(); 89 long maxfd = mp_open_max();
89 if (!np_pids) 90 if (!np_pids) {
90 np_pids = calloc(maxfd, sizeof(pid_t)); 91 np_pids = calloc(maxfd, sizeof(pid_t));
92 }
91} 93}
92 94
93/* Start running a command */ 95/* Start running a command */
@@ -105,8 +107,9 @@ static int np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr) {
105 107
106 int i = 0; 108 int i = 0;
107 109
108 if (!np_pids) 110 if (!np_pids) {
109 NP_RUNCMD_INIT; 111 NP_RUNCMD_INIT;
112 }
110 113
111 env[0] = strdup("LC_ALL=C"); 114 env[0] = strdup("LC_ALL=C");
112 env[1] = NULL; 115 env[1] = NULL;
@@ -114,18 +117,21 @@ static int np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr) {
114 /* make copy of command string so strtok() doesn't silently modify it */ 117 /* make copy of command string so strtok() doesn't silently modify it */
115 /* (the calling program may want to access it later) */ 118 /* (the calling program may want to access it later) */
116 cmdlen = strlen(cmdstring); 119 cmdlen = strlen(cmdstring);
117 if ((cmd = malloc(cmdlen + 1)) == NULL) 120 if ((cmd = malloc(cmdlen + 1)) == NULL) {
118 return -1; 121 return -1;
122 }
119 memcpy(cmd, cmdstring, cmdlen); 123 memcpy(cmd, cmdstring, cmdlen);
120 cmd[cmdlen] = '\0'; 124 cmd[cmdlen] = '\0';
121 125
122 /* This is not a shell, so we don't handle "???" */ 126 /* This is not a shell, so we don't handle "???" */
123 if (strstr(cmdstring, "\"")) 127 if (strstr(cmdstring, "\"")) {
124 return -1; 128 return -1;
129 }
125 130
126 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */ 131 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */
127 if (strstr(cmdstring, " ' ") || strstr(cmdstring, "'''")) 132 if (strstr(cmdstring, " ' ") || strstr(cmdstring, "'''")) {
128 return -1; 133 return -1;
134 }
129 135
130 /* each arg must be whitespace-separated, so args can be a maximum 136 /* each arg must be whitespace-separated, so args can be a maximum
131 * of (len / 2) + 1. We add 1 extra to the mix for NULL termination */ 137 * of (len / 2) + 1. We add 1 extra to the mix for NULL termination */
@@ -144,8 +150,9 @@ static int np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr) {
144 150
145 if (strstr(str, "'") == str) { /* handle SIMPLE quoted strings */ 151 if (strstr(str, "'") == str) { /* handle SIMPLE quoted strings */
146 str++; 152 str++;
147 if (!strstr(str, "'")) 153 if (!strstr(str, "'")) {
148 return -1; /* balanced? */ 154 return -1; /* balanced? */
155 }
149 cmd = 1 + strstr(str, "'"); 156 cmd = 1 + strstr(str, "'");
150 str[strcspn(str, "'")] = 0; 157 str[strcspn(str, "'")] = 0;
151 } else { 158 } else {
@@ -157,14 +164,16 @@ static int np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr) {
157 } 164 }
158 } 165 }
159 166
160 if (cmd && strlen(cmd) == strspn(cmd, " \t\r\n")) 167 if (cmd && strlen(cmd) == strspn(cmd, " \t\r\n")) {
161 cmd = NULL; 168 cmd = NULL;
169 }
162 170
163 argv[i++] = str; 171 argv[i++] = str;
164 } 172 }
165 173
166 if (pipe(pfd) < 0 || pipe(pfderr) < 0 || (pid = fork()) < 0) 174 if (pipe(pfd) < 0 || pipe(pfderr) < 0 || (pid = fork()) < 0) {
167 return -1; /* errno set by the failing function */ 175 return -1; /* errno set by the failing function */
176 }
168 177
169 /* child runs exceve() and _exit. */ 178 /* child runs exceve() and _exit. */
170 if (pid == 0) { 179 if (pid == 0) {
@@ -189,9 +198,11 @@ static int np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr) {
189 * This is executed in a separate address space (pure child), 198 * This is executed in a separate address space (pure child),
190 * so we don't have to worry about async safety */ 199 * so we don't have to worry about async safety */
191 long maxfd = mp_open_max(); 200 long maxfd = mp_open_max();
192 for (i = 0; i < maxfd; i++) 201 for (i = 0; i < maxfd; i++) {
193 if (np_pids[i] > 0) 202 if (np_pids[i] > 0) {
194 close(i); 203 close(i);
204 }
205 }
195 206
196 execve(argv[0], argv, env); 207 execve(argv[0], argv, env);
197 _exit(STATE_UNKNOWN); 208 _exit(STATE_UNKNOWN);
@@ -214,17 +225,21 @@ static int np_runcmd_close(int fd) {
214 225
215 /* make sure this fd was opened by popen() */ 226 /* make sure this fd was opened by popen() */
216 long maxfd = mp_open_max(); 227 long maxfd = mp_open_max();
217 if (fd < 0 || fd > maxfd || !np_pids || (pid = np_pids[fd]) == 0) 228 if (fd < 0 || fd > maxfd || !np_pids || (pid = np_pids[fd]) == 0) {
218 return -1; 229 return -1;
230 }
219 231
220 np_pids[fd] = 0; 232 np_pids[fd] = 0;
221 if (close(fd) == -1) 233 if (close(fd) == -1) {
222 return -1; 234 return -1;
235 }
223 236
224 /* EINTR is ok (sort of), everything else is bad */ 237 /* EINTR is ok (sort of), everything else is bad */
225 while (waitpid(pid, &status, 0) < 0) 238 while (waitpid(pid, &status, 0) < 0) {
226 if (errno != EINTR) 239 if (errno != EINTR) {
227 return -1; 240 return -1;
241 }
242 }
228 243
229 /* return child's termination status */ 244 /* return child's termination status */
230 return (WIFEXITED(status)) ? WEXITSTATUS(status) : -1; 245 return (WIFEXITED(status)) ? WEXITSTATUS(status) : -1;
@@ -232,15 +247,18 @@ static int np_runcmd_close(int fd) {
232 247
233void runcmd_timeout_alarm_handler(int signo) { 248void runcmd_timeout_alarm_handler(int signo) {
234 249
235 if (signo == SIGALRM) 250 if (signo == SIGALRM) {
236 puts(_("CRITICAL - Plugin timed out while executing system call")); 251 puts(_("CRITICAL - Plugin timed out while executing system call"));
252 }
237 253
238 long maxfd = mp_open_max(); 254 long maxfd = mp_open_max();
239 if (np_pids) 255 if (np_pids) {
240 for (long int i = 0; i < maxfd; i++) { 256 for (long int i = 0; i < maxfd; i++) {
241 if (np_pids[i] != 0) 257 if (np_pids[i] != 0) {
242 kill(np_pids[i], SIGKILL); 258 kill(np_pids[i], SIGKILL);
259 }
243 } 260 }
261 }
244 262
245 exit(STATE_CRITICAL); 263 exit(STATE_CRITICAL);
246} 264}
@@ -269,15 +287,17 @@ static int np_fetch_output(int fd, output *op, int flags) {
269 287
270 /* some plugins may want to keep output unbroken, and some commands 288 /* some plugins may want to keep output unbroken, and some commands
271 * will yield no output, so return here for those */ 289 * will yield no output, so return here for those */
272 if (flags & RUNCMD_NO_ARRAYS || !op->buf || !op->buflen) 290 if (flags & RUNCMD_NO_ARRAYS || !op->buf || !op->buflen) {
273 return op->buflen; 291 return op->buflen;
292 }
274 293
275 /* and some may want both */ 294 /* and some may want both */
276 if (flags & RUNCMD_NO_ASSOC) { 295 if (flags & RUNCMD_NO_ASSOC) {
277 buf = malloc(op->buflen); 296 buf = malloc(op->buflen);
278 memcpy(buf, op->buf, op->buflen); 297 memcpy(buf, op->buf, op->buflen);
279 } else 298 } else {
280 buf = op->buf; 299 buf = op->buf;
300 }
281 301
282 op->line = NULL; 302 op->line = NULL;
283 op->lens = NULL; 303 op->lens = NULL;
@@ -298,8 +318,9 @@ static int np_fetch_output(int fd, output *op, int flags) {
298 op->line[lineno] = &buf[i]; 318 op->line[lineno] = &buf[i];
299 319
300 /* hop to next newline or end of buffer */ 320 /* hop to next newline or end of buffer */
301 while (buf[i] != '\n' && i < op->buflen) 321 while (buf[i] != '\n' && i < op->buflen) {
302 i++; 322 i++;
323 }
303 buf[i] = '\0'; 324 buf[i] = '\0';
304 325
305 /* calculate the string length using pointer difference */ 326 /* calculate the string length using pointer difference */
@@ -316,18 +337,23 @@ int np_runcmd(const char *cmd, output *out, output *err, int flags) {
316 int fd, pfd_out[2], pfd_err[2]; 337 int fd, pfd_out[2], pfd_err[2];
317 338
318 /* initialize the structs */ 339 /* initialize the structs */
319 if (out) 340 if (out) {
320 memset(out, 0, sizeof(output)); 341 memset(out, 0, sizeof(output));
321 if (err) 342 }
343 if (err) {
322 memset(err, 0, sizeof(output)); 344 memset(err, 0, sizeof(output));
345 }
323 346
324 if ((fd = np_runcmd_open(cmd, pfd_out, pfd_err)) == -1) 347 if ((fd = np_runcmd_open(cmd, pfd_out, pfd_err)) == -1) {
325 die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd); 348 die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd);
349 }
326 350
327 if (out) 351 if (out) {
328 out->lines = np_fetch_output(pfd_out[0], out, flags); 352 out->lines = np_fetch_output(pfd_out[0], out, flags);
329 if (err) 353 }
354 if (err) {
330 err->lines = np_fetch_output(pfd_err[0], err, flags); 355 err->lines = np_fetch_output(pfd_err[0], err, flags);
356 }
331 357
332 return np_runcmd_close(fd); 358 return np_runcmd_close(fd);
333} 359}