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