Branch data Line data Source code
1 : : /*
2 : : *****************************************************************************
3 : : *
4 : : * File: extcmd.c
5 : : *
6 : : * Purpose: Routines for executing and processing external commands.
7 : : *
8 : : * Fwknop is developed primarily by the people listed in the file 'AUTHORS'.
9 : : * Copyright (C) 2009-2014 fwknop developers and contributors. For a full
10 : : * list of contributors, see the file 'CREDITS'.
11 : : *
12 : : * License (GNU General Public License):
13 : : *
14 : : * This program is free software; you can redistribute it and/or
15 : : * modify it under the terms of the GNU General Public License
16 : : * as published by the Free Software Foundation; either version 2
17 : : * of the License, or (at your option) any later version.
18 : : *
19 : : * This program is distributed in the hope that it will be useful,
20 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 : : * GNU General Public License for more details.
23 : : *
24 : : * You should have received a copy of the GNU General Public License
25 : : * along with this program; if not, write to the Free Software
26 : : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
27 : : * USA
28 : : *
29 : : *****************************************************************************
30 : : */
31 : : #include "fwknopd_common.h"
32 : : #include "extcmd.h"
33 : : #include "log_msg.h"
34 : : #include "utils.h"
35 : :
36 : : #include <errno.h>
37 : : #include <signal.h>
38 : :
39 : : #if HAVE_SYS_WAIT_H
40 : : #include <sys/wait.h>
41 : : #endif
42 : :
43 : : /*
44 : : static sig_atomic_t got_sigalrm;
45 : : */
46 : :
47 : : /* Takes a file descriptor and makes it non-blocking.
48 : : static int
49 : : set_nonblock(int fd)
50 : : {
51 : : int val;
52 : :
53 : : if((val = fcntl(fd, F_GETFL, 0)) < 0)
54 : : {
55 : : perror("fcntl F_GETFL error:");
56 : : return(-1);
57 : : }
58 : :
59 : : val |= O_NONBLOCK;
60 : :
61 : : if(fcntl(fd, F_SETFL, val) < 0)
62 : : {
63 : : perror("fcntl F_SETFL error setting O_NONBLOCK");
64 : : return(-1);
65 : : }
66 : :
67 : : return(0);
68 : : }
69 : :
70 : : static void
71 : : alarm_handler(int sig)
72 : : {
73 : : got_sigalrm = 1;
74 : : }
75 : : */
76 : :
77 : : /* Run an external command returning exit status, and optionally filling
78 : : * provided buffer with STDOUT output up to the size provided.
79 : : *
80 : : * Note: XXX: We are not using the timeout parameter at present. We still need
81 : : * to implement a reliable timeout mechanism.
82 : : */
83 : : static int
84 : 10865 : _run_extcmd(uid_t uid, gid_t gid, const char *cmd, char *so_buf,
85 : : const size_t so_buf_sz, const int want_stderr, const int timeout,
86 : : const char *substr_search, int *pid_status,
87 : : const fko_srv_options_t * const opts)
88 : : {
89 : 10865 : char so_read_buf[IO_READ_BUF_LEN] = {0};
90 : 10865 : pid_t pid=0;
91 : : FILE *output;
92 : 10865 : int retval = EXTCMD_SUCCESS_ALL_OUTPUT;
93 : 10865 : int line_ctr = 0, found_str = 0;
94 : :
95 : : char *argv_new[MAX_CMDLINE_ARGS]; /* for validation and/or execvpe() */
96 : 10865 : int argc_new=0;
97 : :
98 : : #if HAVE_EXECVPE
99 : : int pipe_fd[2];
100 : : #endif
101 : :
102 : 10865 : *pid_status = 0;
103 : :
104 : : /* Even without execvpe() we examine the command for basic validity
105 : : * in term of number of args
106 : : */
107 : : memset(argv_new, 0x0, sizeof(argv_new));
108 : :
109 [ + + ]: 10865 : if(strtoargv(cmd, argv_new, &argc_new, opts) != 1)
110 : : {
111 : 2 : log_msg(LOG_ERR,
112 : : "run_extcmd(): Error converting cmd str to argv via strtoargv()");
113 : : return EXTCMD_ARGV_ERROR;
114 : : }
115 : :
116 : : #if !HAVE_EXECVPE
117 : : /* if we are not using execvpe() then free up argv_new unconditionally
118 : : * since was used only for validation
119 : : */
120 : : free_argv(argv_new, &argc_new);
121 : : #endif
122 : :
123 : : #if HAVE_EXECVPE
124 [ + + ]: 10863 : if(opts->verbose > 1)
125 : 9631 : log_msg(LOG_INFO, "run_extcmd() (with execvpe()): running CMD: %s", cmd);
126 : :
127 [ + + ]: 10863 : if(so_buf != NULL || substr_search != NULL)
128 : : {
129 [ - + ]: 9800 : if(pipe(pipe_fd) < 0)
130 : : {
131 : 0 : log_msg(LOG_ERR, "run_extcmd(): pipe() failed: %s", strerror(errno));
132 : 0 : free_argv(argv_new, &argc_new);
133 : : return EXTCMD_PIPE_ERROR;
134 : : }
135 : : }
136 : :
137 : 10863 : pid = fork();
138 [ - + ]: 10863 : if (pid == 0)
139 : : {
140 [ # # ]: 0 : if(chdir("/") != 0)
141 : 0 : exit(EXTCMD_CHDIR_ERROR);
142 : :
143 [ # # ]: 0 : if(so_buf != NULL || substr_search != NULL)
144 : : {
145 : 0 : close(pipe_fd[0]);
146 : 0 : dup2(pipe_fd[1], STDOUT_FILENO);
147 [ # # ]: 0 : if(want_stderr)
148 : 0 : dup2(pipe_fd[1], STDERR_FILENO);
149 : : else
150 : 0 : close(STDERR_FILENO);
151 : : }
152 : :
153 : : /* Take care of gid/uid settings before running the command.
154 : : */
155 [ # # ]: 0 : if(gid > 0)
156 [ # # ]: 0 : if(setgid(gid) < 0)
157 : 0 : exit(EXTCMD_SETGID_ERROR);
158 : :
159 [ # # ]: 0 : if(uid > 0)
160 [ # # ]: 0 : if(setuid(uid) < 0)
161 : 0 : exit(EXTCMD_SETUID_ERROR);
162 : :
163 : : /* don't use env
164 : : */
165 : 0 : execvpe(argv_new[0], argv_new, (char * const *)NULL);
166 : : }
167 [ - + ]: 10863 : else if(pid == -1)
168 : : {
169 : 0 : log_msg(LOG_ERR, "run_extcmd(): fork() failed: %s", strerror(errno));
170 : 0 : free_argv(argv_new, &argc_new);
171 : : return EXTCMD_FORK_ERROR;
172 : : }
173 : :
174 : : /* Only the parent process makes it here
175 : : */
176 [ + + ]: 10863 : if(so_buf != NULL || substr_search != NULL)
177 : : {
178 : 9800 : close(pipe_fd[1]);
179 [ + - ]: 9800 : if ((output = fdopen(pipe_fd[0], "r")) != NULL)
180 : : {
181 [ + + ]: 9800 : if(so_buf != NULL)
182 : : memset(so_buf, 0x0, so_buf_sz);
183 : :
184 [ + + ]: 17145 : while((fgets(so_read_buf, IO_READ_BUF_LEN, output)) != NULL)
185 : : {
186 : 7354 : line_ctr++;
187 : :
188 [ + + ]: 7354 : if(so_buf != NULL)
189 : : {
190 : 7284 : strlcat(so_buf, so_read_buf, so_buf_sz);
191 : :
192 [ + - ]: 7284 : if(strlen(so_buf) >= so_buf_sz-1)
193 : : break;
194 : : }
195 : : else /* we are looking for a substring */
196 : : {
197 : : /* Get past comments and empty lines (note: we only look at the
198 : : * first character).
199 : : */
200 [ + - ][ + - ]: 70 : if(IS_EMPTY_LINE(so_read_buf[0]))
[ + - ][ - + ]
201 : 0 : continue;
202 : :
203 [ + + ]: 7354 : if(strstr(so_read_buf, substr_search) != NULL)
204 : : {
205 : : found_str = 1;
206 : : break;
207 : : }
208 : : }
209 : : }
210 : 9800 : fclose(output);
211 : : }
212 : : else
213 : : {
214 : 0 : log_msg(LOG_ERR,
215 : : "run_extcmd(): could not fdopen() pipe output file descriptor.");
216 : 0 : free_argv(argv_new, &argc_new);
217 : : return EXTCMD_OPEN_ERROR;
218 : : }
219 : : }
220 : :
221 : 10863 : free_argv(argv_new, &argc_new);
222 : :
223 : 10863 : waitpid(pid, pid_status, 0);
224 : :
225 : : #else
226 : :
227 : : if(opts->verbose > 1)
228 : : log_msg(LOG_INFO, "run_extcmd() (without execvpe()): running CMD: %s", cmd);
229 : :
230 : : if(so_buf == NULL && substr_search == NULL)
231 : : {
232 : : /* Since we do not have to capture output, we will fork here (which we
233 : : * * would have to do anyway if we are running as another user as well).
234 : : * */
235 : : pid = fork();
236 : : if(pid == -1)
237 : : {
238 : : log_msg(LOG_ERR, "run_extcmd: fork failed: %s", strerror(errno));
239 : : return(EXTCMD_FORK_ERROR);
240 : : }
241 : : else if (pid == 0)
242 : : {
243 : : /* We are the child */
244 : :
245 : : if(chdir("/") != 0)
246 : : exit(EXTCMD_CHDIR_ERROR);
247 : :
248 : : /* Take care of gid/uid settings before running the command.
249 : : */
250 : : if(gid > 0)
251 : : if(setgid(gid) < 0)
252 : : exit(EXTCMD_SETGID_ERROR);
253 : :
254 : : if(uid > 0)
255 : : if(setuid(uid) < 0)
256 : : exit(EXTCMD_SETUID_ERROR);
257 : :
258 : : *pid_status = system(cmd);
259 : : exit(*pid_status);
260 : : }
261 : : /* Retval is forced to 0 as we don't care about the exit status of
262 : : * the child (for now)
263 : : */
264 : : retval = EXTCMD_SUCCESS_ALL_OUTPUT;
265 : : }
266 : : else
267 : : {
268 : : /* Looking for output use popen and fill the buffer to its limit.
269 : : */
270 : : output = popen(cmd, "r");
271 : : if(output == NULL)
272 : : {
273 : : log_msg(LOG_ERR, "Got popen error %i: %s", errno, strerror(errno));
274 : : retval = EXTCMD_OPEN_ERROR;
275 : : }
276 : : else
277 : : {
278 : : if(so_buf != NULL)
279 : : memset(so_buf, 0x0, so_buf_sz);
280 : :
281 : : while((fgets(so_read_buf, IO_READ_BUF_LEN, output)) != NULL)
282 : : {
283 : : line_ctr++;
284 : : if(so_buf != NULL)
285 : : {
286 : : strlcat(so_buf, so_read_buf, so_buf_sz);
287 : : if(strlen(so_buf) >= so_buf_sz-1)
288 : : break;
289 : : }
290 : : else /* we are looking for a substring */
291 : : {
292 : : /* Get past comments and empty lines (note: we only look at the
293 : : * first character).
294 : : */
295 : : if(IS_EMPTY_LINE(so_read_buf[0]))
296 : : continue;
297 : :
298 : : if(strstr(so_read_buf, substr_search) != NULL)
299 : : {
300 : : found_str = 1;
301 : : break;
302 : : }
303 : : }
304 : : }
305 : : pclose(output);
306 : : }
307 : : }
308 : :
309 : : #endif
310 : :
311 [ + + ]: 10863 : if(substr_search != NULL)
312 : : {
313 : : /* The semantics of the return value changes in search mode to the line
314 : : * number where the substring match was found, or zero if it wasn't found
315 : : */
316 [ + + ]: 32 : if(found_str)
317 : 9 : retval = line_ctr;
318 : : else
319 : : retval = 0;
320 : : }
321 : : else
322 : : {
323 [ - + ]: 10831 : if(WIFEXITED(*pid_status))
324 : : {
325 : : /* Even if the child exited with an error condition, if we make it here
326 : : * then the child exited normally as far as the OS is concerned (i.e. didn't
327 : : * crash or get hit with a signal)
328 : : */
329 : : retval = EXTCMD_SUCCESS_ALL_OUTPUT;
330 : : }
331 : : else
332 : 0 : retval = EXTCMD_EXECUTION_ERROR;
333 : : }
334 : :
335 [ + + ]: 10863 : if(opts->verbose > 1)
336 [ + - ]: 10863 : log_msg(LOG_INFO,
337 : : "run_extcmd(): returning %d, pid_status: %d",
338 : 19262 : retval, WIFEXITED(*pid_status) ? WEXITSTATUS(*pid_status) : *pid_status);
339 : :
340 : : return(retval);
341 : : }
342 : :
343 : :
344 : : #if 0 /* --DSS the original method that did not work on some systems */
345 : :
346 : : /* Create the pipes we will use for getting stdout and stderr
347 : : * from the child process.
348 : : */
349 : : if(pipe(so) != 0)
350 : : return(EXTCMD_PIPE_ERROR);
351 : :
352 : : if(pipe(se) != 0)
353 : : return(EXTCMD_PIPE_ERROR);
354 : :
355 : : /* Fork off a child process to run the command and provide its outputs.
356 : : */
357 : : pid = fork();
358 : : if(pid == -1)
359 : : {
360 : : return(EXTCMD_FORK_ERROR);
361 : : }
362 : : else if (pid == 0)
363 : : {
364 : : /* We are the child, so we dup stdout and stderr to our respective
365 : : * write-end of the pipes, close stdin and the read-end of the pipes
366 : : * (since we don't need them here). Then use system() to run the
367 : : * command and exit with the exit status of that command so we can
368 : : * grab it from the waitpid call in the parent.
369 : : */
370 : : close(fileno(stdin));
371 : : dup2(so[1], fileno(stdout));
372 : : dup2(se[1], fileno(stderr));
373 : : close(so[0]);
374 : : close(se[0]);
375 : :
376 : : /* If user is not null, then we setuid to that user before running the
377 : : * command.
378 : : */
379 : : if(uid > 0)
380 : : {
381 : : if(setuid(uid) < 0)
382 : : {
383 : : exit(EXTCMD_SETUID_ERROR);
384 : : }
385 : : }
386 : :
387 : : /* --DSS XXX: Would it be more efficient to use one of the exec()
388 : : * calls (i.e. 'return(execvp(ext_cmd, &argv[1]));')?
389 : : * For now, we use system() and exit with the external
390 : : * command exit status.
391 : : */
392 : : exit(WEXITSTATUS(system(cmd)));
393 : : }
394 : :
395 : : /* Parent from here */
396 : :
397 : : /* Give the exit status an initial value of -1.
398 : : */
399 : : *status = -1;
400 : :
401 : : /* Close the write-end of the pipes (we are only reading).
402 : : */
403 : : close(so[1]);
404 : : close(se[1]);
405 : :
406 : : /* Set our pipes to non-blocking
407 : : */
408 : : set_nonblock(so[0]);
409 : : set_nonblock(se[0]);
410 : :
411 : : tv.tv_sec = EXTCMD_DEF_TIMEOUT;
412 : : tv.tv_usec = 0;
413 : :
414 : : /* Initialize and setup our file descriptor sets for select.
415 : : */
416 : : FD_ZERO(&rfds);
417 : : FD_ZERO(&efds);
418 : : FD_SET(so[0], &rfds);
419 : : FD_SET(se[0], &rfds);
420 : : FD_SET(so[0], &efds);
421 : : FD_SET(se[0], &efds);
422 : :
423 : : /* Start with fully clear buffers.
424 : : */
425 : : memset(so_buf, 0x0, so_buf_sz);
426 : : memset(se_buf, 0x0, se_buf_sz);
427 : :
428 : : /* Read both stdout and stderr piped from the child until we get eof,
429 : : * fill the buffers, or error out.
430 : : */
431 : : while(so_buf_remaining > 0 || se_buf_remaining > 0)
432 : : {
433 : : selval = select(8, &rfds, NULL, &efds, &tv);
434 : :
435 : : if(selval == -1)
436 : : {
437 : : /* Select error - so kill the child and bail.
438 : : */
439 : : kill(pid, SIGTERM);
440 : : retval |= EXTCMD_SELECT_ERROR;
441 : : break;
442 : : }
443 : :
444 : : if(selval == 0)
445 : : {
446 : : /* Timeout - so kill the child and bail
447 : : */
448 : : kill(pid, SIGTERM);
449 : : retval |= EXTCMD_EXECUTION_TIMEOUT;
450 : : break;
451 : : }
452 : :
453 : : /* The stdout pipe...
454 : : */
455 : : bytes_read = read(so[0], so_read_buf, IO_READ_BUF_LEN);
456 : : if(so_buf_remaining > 0)
457 : : {
458 : : if(bytes_read > 0)
459 : : {
460 : : /* We have data, so process it...
461 : : */
462 : : if(bytes_read > so_buf_remaining)
463 : : {
464 : : bytes_read = so_buf_remaining;
465 : : retval |= EXTCMD_SUCCESS_PARTIAL_STDOUT;
466 : : }
467 : :
468 : : memcpy(so_buf, so_read_buf, bytes_read);
469 : : so_buf += bytes_read;
470 : : so_buf_remaining -= bytes_read;
471 : : }
472 : : else if(bytes_read < 0)
473 : : {
474 : : /* Anything other than EAGAIN or EWOULDBLOCK is conisdered
475 : : * error enough to bail. We are done here so we force the
476 : : * buf_remaining value to 0.
477 : : */
478 : : if(errno != EAGAIN && errno != EWOULDBLOCK)
479 : : {
480 : : retval |= EXTCMD_STDOUT_READ_ERROR;
481 : : so_buf_remaining = 0;
482 : : }
483 : : }
484 : : else
485 : : {
486 : : /* Bytes read was 0 which indicate end of file. So we are
487 : : * done.
488 : : */
489 : : so_buf_remaining = 0;
490 : : }
491 : : }
492 : : else
493 : : break;
494 : :
495 : : /* The stderr pipe...
496 : : */
497 : : bytes_read = read(se[0], se_read_buf, IO_READ_BUF_LEN);
498 : : if(se_buf_remaining > 0)
499 : : {
500 : : if(bytes_read > 0)
501 : : {
502 : : /* We have data, so process it...
503 : : */
504 : : if(bytes_read > se_buf_remaining)
505 : : {
506 : : bytes_read = se_buf_remaining;
507 : : retval |= EXTCMD_SUCCESS_PARTIAL_STDERR;
508 : : }
509 : :
510 : : memcpy(se_buf, se_read_buf, bytes_read);
511 : : se_buf += bytes_read;
512 : : se_buf_remaining -= bytes_read;
513 : : }
514 : : else if(bytes_read < 0)
515 : : {
516 : : /* Anything other than EAGAIN or EWOULDBLOCK is conisdered
517 : : * error enough to bail. We are done here so we force the
518 : : * buf_remaining value to 0.
519 : : */
520 : : if(errno != EAGAIN && errno != EWOULDBLOCK)
521 : : {
522 : : retval |= EXTCMD_STDERR_READ_ERROR;
523 : : se_buf_remaining = 0;
524 : : }
525 : : }
526 : : else
527 : : {
528 : : /* Bytes read was 0 which indicate end of file. So we are
529 : : * done.
530 : : */
531 : : se_buf_remaining = 0;
532 : : }
533 : : }
534 : : else
535 : : break;
536 : : }
537 : :
538 : : close(so[0]);
539 : : close(se[0]);
540 : :
541 : : /* Wait for the external command to finish and capture its exit status.
542 : : */
543 : : waitpid(pid, status, 0);
544 : :
545 : : if(*status != 0)
546 : : retval != EXTCMD_EXECUTION_ERROR;
547 : :
548 : : /* Return the our status of this operation command.
549 : : */
550 : : return(retval);
551 : : }
552 : : #endif
553 : :
554 : 5 : int _run_extcmd_write(const char *cmd, const char *cmd_write, int *pid_status,
555 : : const fko_srv_options_t * const opts)
556 : : {
557 : 5 : int retval = EXTCMD_SUCCESS_ALL_OUTPUT;
558 : : char *argv_new[MAX_CMDLINE_ARGS]; /* for validation and/or execvpe() */
559 : 5 : int argc_new=0;
560 : :
561 : : #if HAVE_EXECVPE
562 : : int pipe_fd[2];
563 : 5 : pid_t pid=0;
564 : : #else
565 : : FILE *fd = NULL;
566 : : #endif
567 : :
568 : 5 : *pid_status = 0;
569 : :
570 : : /* Even without execvpe() we examine the command for basic validity
571 : : * in term of number of args
572 : : */
573 : : memset(argv_new, 0x0, sizeof(argv_new));
574 : :
575 [ - + ]: 5 : if(strtoargv(cmd, argv_new, &argc_new, opts) != 1)
576 : : {
577 : 0 : log_msg(LOG_ERR,
578 : : "run_extcmd_write(): Error converting cmd str to argv via strtoargv()");
579 : 0 : return EXTCMD_ARGV_ERROR;
580 : : }
581 : :
582 : : #if !HAVE_EXECVPE
583 : : /* if we are not using execvpe() then free up argv_new unconditionally
584 : : * since was used only for validation
585 : : */
586 : : free_argv(argv_new, &argc_new);
587 : : #endif
588 : :
589 : : #if HAVE_EXECVPE
590 [ + - ]: 5 : if(opts->verbose > 1)
591 : 5 : log_msg(LOG_INFO, "run_extcmd_write() (with execvpe()): running CMD: %s | %s",
592 : : cmd_write, cmd);
593 : :
594 [ - + ]: 5 : if(pipe(pipe_fd) < 0)
595 : : {
596 : 0 : log_msg(LOG_ERR, "run_extcmd_write(): pipe() failed: %s", strerror(errno));
597 : 0 : free_argv(argv_new, &argc_new);
598 : 0 : return EXTCMD_PIPE_ERROR;
599 : : }
600 : :
601 : 5 : pid = fork();
602 [ - + ]: 5 : if (pid == 0)
603 : : {
604 [ # # ]: 0 : if(chdir("/") != 0)
605 : 0 : exit(EXTCMD_CHDIR_ERROR);
606 : :
607 : 0 : close(pipe_fd[1]);
608 : 0 : dup2(pipe_fd[0], STDIN_FILENO);
609 : :
610 : : /* don't use env
611 : : */
612 : 0 : execvpe(argv_new[0], argv_new, (char * const *)NULL);
613 : : }
614 [ - + ]: 5 : else if(pid == -1)
615 : : {
616 : 0 : log_msg(LOG_ERR, "run_extcmd_write(): fork() failed: %s", strerror(errno));
617 : 0 : free_argv(argv_new, &argc_new);
618 : 0 : return EXTCMD_FORK_ERROR;
619 : : }
620 : :
621 : 5 : close(pipe_fd[0]);
622 [ - + ]: 5 : if(write(pipe_fd[1], cmd_write, strlen(cmd_write)) < 0)
623 : 0 : retval = EXTCMD_WRITE_ERROR;
624 : 5 : close(pipe_fd[1]);
625 : :
626 : 5 : free_argv(argv_new, &argc_new);
627 : :
628 : 5 : waitpid(pid, pid_status, 0);
629 : :
630 : : #else
631 : : if(opts->verbose > 1)
632 : : log_msg(LOG_INFO, "run_extcmd_write() (without execvpe()): running CMD: %s | %s",
633 : : cmd_write, cmd);
634 : :
635 : : if ((fd = popen(cmd, "w")) == NULL)
636 : : {
637 : : log_msg(LOG_ERR, "Got popen error %i: %s", errno, strerror(errno));
638 : : retval = EXTCMD_OPEN_ERROR;
639 : : }
640 : : else
641 : : {
642 : : if (fwrite(cmd_write, strlen(cmd_write), 1, fd) != 1)
643 : : {
644 : : log_msg(LOG_ERR, "Could not write to cmd stdin");
645 : : retval = -1;
646 : : }
647 : : pclose(fd);
648 : : }
649 : :
650 : : #endif
651 : 5 : return retval;
652 : : }
653 : :
654 : : /* _run_extcmd() wrapper, run an external command.
655 : : */
656 : : int
657 : 10829 : run_extcmd(const char *cmd, char *so_buf, const size_t so_buf_sz,
658 : : const int want_stderr, const int timeout, int *pid_status,
659 : : const fko_srv_options_t * const opts)
660 : : {
661 : 10829 : return _run_extcmd(0, 0, cmd, so_buf, so_buf_sz, want_stderr,
662 : : timeout, NULL, pid_status, opts);
663 : : }
664 : :
665 : : /* _run_extcmd() wrapper, run an external command as the specified user.
666 : : */
667 : : int
668 : 4 : run_extcmd_as(uid_t uid, gid_t gid, const char *cmd,char *so_buf,
669 : : const size_t so_buf_sz, const int want_stderr, const int timeout,
670 : : int *pid_status, const fko_srv_options_t * const opts)
671 : : {
672 : 4 : return _run_extcmd(uid, gid, cmd, so_buf, so_buf_sz,
673 : : want_stderr, timeout, NULL, pid_status, opts);
674 : : }
675 : :
676 : : /* _run_extcmd() wrapper, search command output for a substring.
677 : : */
678 : : int
679 : 32 : search_extcmd(const char *cmd, const int want_stderr, const int timeout,
680 : : const char *substr_search, int *pid_status,
681 : : const fko_srv_options_t * const opts)
682 : : {
683 : 32 : return _run_extcmd(0, 0, cmd, NULL, 0, want_stderr, timeout,
684 : : substr_search, pid_status, opts);
685 : : }
686 : :
687 : : /* _run_extcmd_write() wrapper, run a command which is expecting input via stdin
688 : : */
689 : 5 : int run_extcmd_write(const char *cmd, const char *cmd_write, int *pid_status,
690 : : const fko_srv_options_t * const opts)
691 : : {
692 : 5 : return _run_extcmd_write(cmd, cmd_write, pid_status, opts);
693 : : }
|