Back to index

nagios-plugins  1.4.16
Defines | Functions | Variables
runcmd.c File Reference
#include "runcmd.h"

Go to the source code of this file.

Defines

#define NAGIOSPLUG_API_C   1
#define WEXITSTATUS(stat_val)   ((unsigned)(stat_val) >> 8)
 includes
#define WIFEXITED(stat_val)   (((stat_val) & 255) == 0)
#define maxfd   256

Functions

static int np_runcmd_open (extern void die(const char *, int *, int *)
 prototypes
static int np_runcmd_open (const char *cmdstring, int *pfd, int *pfderr)
static int np_runcmd_close (int fd)
void popen_timeout_alarm_handler (int signo)
static int np_fetch_output (int fd, output *op, int flags)
int np_runcmd (const char *cmd, output *out, output *err, int flags)
 prototypes

Variables

static pid_t * np_pids = NULL

Define Documentation

#define maxfd   256

Definition at line 79 of file runcmd.c.

#define NAGIOSPLUG_API_C   1

Definition at line 39 of file runcmd.c.

#define WEXITSTATUS (   stat_val)    ((unsigned)(stat_val) >> 8)

includes

macros

Definition at line 49 of file runcmd.c.

#define WIFEXITED (   stat_val)    (((stat_val) & 255) == 0)

Definition at line 53 of file runcmd.c.


Function Documentation

static int np_fetch_output ( int  fd,
output op,
int  flags 
) [static]

Definition at line 275 of file runcmd.c.

{
       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;
       char tmpbuf[4096];

       op->buf = NULL;
       op->buflen = 0;
       while((ret = read(fd, tmpbuf, sizeof(tmpbuf))) > 0) {
              len = (size_t)ret;
              op->buf = realloc(op->buf, op->buflen + len + 1);
              memcpy(op->buf + op->buflen, tmpbuf, len);
              op->buflen += len;
              i++;
       }

       if(ret < 0) {
              printf("read() returned %d: %s\n", ret, strerror(errno));
              return ret;
       }

       /* 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 */
       if(flags & RUNCMD_NO_ASSOC) {
              buf = malloc(op->buflen);
              memcpy(buf, op->buf, op->buflen);
       }
       else buf = op->buf;

       op->line = NULL;
       op->lens = NULL;
       i = 0;
       while(i < op->buflen) {
              /* make sure we have enough memory */
              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[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[lineno] = (size_t)&buf[i] - (size_t)op->line[lineno];

              lineno++;
              i++;
       }

       return lineno;
}

Here is the caller graph for this function:

int np_runcmd ( const char *  cmd,
output out,
output err,
int  flags 
)

prototypes

Definition at line 344 of file runcmd.c.

{
       int fd, pfd_out[2], pfd_err[2];

       /* initialize the structs */
       if(out) memset(out, 0, sizeof(output));
       if(err) memset(err, 0, sizeof(output));

       if((fd = np_runcmd_open(cmd, pfd_out, pfd_err)) == -1)
              die (STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd);

       if(out) out->lines = np_fetch_output(pfd_out[0], out, flags);
       if(err) err->lines = np_fetch_output(pfd_err[0], err, flags);

       return np_runcmd_close(fd);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int np_runcmd_close ( int  fd) [static]

Definition at line 237 of file runcmd.c.

{
       int status;
       pid_t pid;

       /* make sure this fd was opened by popen() */
       if(fd < 0 || fd > maxfd || !np_pids || (pid = np_pids[fd]) == 0)
              return -1;

       np_pids[fd] = 0;
       if (close (fd) == -1) return -1;

       /* EINTR is ok (sort of), everything else is bad */
       while (waitpid (pid, &status, 0) < 0)
              if (errno != EINTR) return -1;

       /* return child's termination status */
       return (WIFEXITED(status)) ? WEXITSTATUS(status) : -1;
}

Here is the caller graph for this function:

static int np_runcmd_open ( extern void die const char *,
int *  ,
int *   
) [static]

prototypes

Definition at line 84 of file runcmd.c.

{
#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

       if(!np_pids) np_pids = calloc(maxfd, sizeof(pid_t));
}

Here is the caller graph for this function:

static int np_runcmd_open ( const char *  cmdstring,
int *  pfd,
int *  pfderr 
) [static]

Definition at line 116 of file runcmd.c.

{
       char *env[2];
       char *cmd = NULL;
       char **argv = NULL;
       char *str;
       int argc;
       size_t cmdlen;
       pid_t pid;
#ifdef RLIMIT_CORE
       struct rlimit limit;
#endif

       int i = 0;

       if(!np_pids) NP_RUNCMD_INIT;

       env[0] = strdup("LC_ALL=C");
       env[1] = '\0';

       /* if no command was passed, return with no error */
       if (cmdstring == NULL)
              return -1;

       /* make copy of command string so strtok() doesn't silently modify it */
       /* (the calling program may want to access it later) */
       cmdlen = strlen(cmdstring);
       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;

       /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */
       if (strstr (cmdstring, " ' ") || strstr (cmdstring, "'''"))
              return -1;

       /* each arg must be whitespace-separated, so args can be a maximum
        * of (len / 2) + 1. We add 1 extra to the mix for NULL termination */
       argc = (cmdlen >> 1) + 2;
       argv = calloc(sizeof(char *), argc);

       if (argv == NULL) {
              printf ("%s\n", _("Could not malloc argv array in popen()"));
              return -1;
       }

       /* get command arguments (stupidly, but fairly quickly) */
       while (cmd) {
              str = cmd;
              str += strspn (str, " \t\r\n"); /* trim any leading whitespace */

              if (strstr (str, "'") == str) {    /* handle SIMPLE quoted strings */
                     str++;
                     if (!strstr (str, "'")) return -1; /* balanced? */
                     cmd = 1 + strstr (str, "'");
                     str[strcspn (str, "'")] = 0;
              }
              else {
                     if (strpbrk (str, " \t\r\n")) {
                            cmd = 1 + strpbrk (str, " \t\r\n");
                            str[strcspn (str, " \t\r\n")] = 0;
                     }
                     else {
                            cmd = NULL;
                     }
              }

              if (cmd && strlen (cmd) == strspn (cmd, " \t\r\n"))
                     cmd = NULL;

              argv[i++] = str;
       }

       if (pipe(pfd) < 0 || pipe(pfderr) < 0 || (pid = fork()) < 0)
              return -1; /* errno set by the failing function */

       /* child runs exceve() and _exit. */
       if (pid == 0) {
#ifdef        RLIMIT_CORE
              /* the program we execve shouldn't leave core files */
              getrlimit (RLIMIT_CORE, &limit);
              limit.rlim_cur = 0;
              setrlimit (RLIMIT_CORE, &limit);
#endif
              close (pfd[0]);
              if (pfd[1] != STDOUT_FILENO) {
                     dup2 (pfd[1], STDOUT_FILENO);
                     close (pfd[1]);
              }
              close (pfderr[0]);
              if (pfderr[1] != STDERR_FILENO) {
                     dup2 (pfderr[1], STDERR_FILENO);
                     close (pfderr[1]);
              }

              /* close all descriptors in np_pids[]
               * This is executed in a separate address space (pure child),
               * so we don't have to worry about async safety */
              for (i = 0; i < maxfd; i++)
                     if(np_pids[i] > 0)
                            close (i);

              execve (argv[0], argv, env);
              _exit (STATE_UNKNOWN);
       }

       /* parent picks up execution here */
       /* close childs descriptors in our address space */
       close(pfd[1]);
       close(pfderr[1]);

       /* tag our file's entry in the pid-list and return it */
       np_pids[pfd[0]] = pid;

       return pfd[0];
}

Here is the call graph for this function:

void popen_timeout_alarm_handler ( int  signo)

Definition at line 259 of file runcmd.c.

{
       size_t i;

       if (signo == SIGALRM)
              puts(_("CRITICAL - Plugin timed out while executing system call\n"));

       if(np_pids) for(i = 0; i < maxfd; i++) {
              if(np_pids[i] != 0) kill(np_pids[i], SIGKILL);
       }

       exit (STATE_CRITICAL);
}

Variable Documentation

pid_t* np_pids = NULL [static]

Definition at line 68 of file runcmd.c.