Code

test GNU_SOURCE and include features.h if present to clear warning about asprintf...
[nagiosplug.git] / plugins / check_by_ssh.c
index 5aee5343d634ab4023ba9a7b17f7e0ed6b912093..7328f5ac66d0016cabae9b4c8adc78abdb021c17 100644 (file)
@@ -22,7 +22,7 @@
  *
  *****************************************************************************/
  
-#define PROGRAM check_by_ssh
+const char *progname = "check_by_ssh";
 #define DESCRIPTION "Run checks on a remote system using ssh, wrapping the proper timeout around the ssh invocation."
 #define AUTHOR "Karl DeBisschop"
 #define EMAIL "karl@debisschop.net"
 #include "utils.h"
 #include <time.h>
 
-#define PROGNAME "check_by_ssh"
-
 int process_arguments (int, char **);
-int call_getopt (int, char **);
 int validate_arguments (void);
-void print_help (char *command_name);
+void print_help (const char *command_name);
 void print_usage (void);
 
 
-int commands;
-char *remotecmd = NULL;
-char *comm = NULL;
+int commands = 0;
+int services = 0;
+char *remotecmd = "";
+char *comm = SSH_COMMAND;
 char *hostname = NULL;
 char *outputfile = NULL;
 char *host_shortname = NULL;
-char *servicelist = NULL;
+char **service;
 int passive = FALSE;
 int verbose = FALSE;
 
@@ -59,9 +57,10 @@ main (int argc, char **argv)
 {
 
        char input_buffer[MAX_INPUT_BUFFER] = "";
-       char *result_text = NULL;
+       char *result_text = "";
        char *status_text;
-       char *output = NULL;
+       char *output = "";
+       char *summary = "";
        char *eol = NULL;
        char *srvc_desc = NULL;
        int cresult;
@@ -104,10 +103,8 @@ main (int argc, char **argv)
 
 
        /* get results from remote command */
-       result_text = realloc (result_text, 1);
-       result_text[0] = 0;
        while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process))
-               result_text = strscat (result_text, input_buffer);
+               asprintf (&result_text, "%s%s", result_text, input_buffer);
 
 
        /* WARNING if output found on stderr */
@@ -131,24 +128,23 @@ main (int argc, char **argv)
                }
 
                time (&local_time);
-               srvc_desc = strtok (servicelist, ":");
-               while (result_text != 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;
                        }
-                       output = result_text;
+                       asprintf (&output, "%s", result_text);
                        result_text = strnl (status_text);
                        eol = strpbrk (output, "\r\n");
                        if (eol != NULL)
                                eol[0] = 0;
-                       if (srvc_desc && status_text
+                       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, srvc_desc, cresult,
+                               fprintf (fp, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n",
+                                                                (int) local_time, host_shortname, service[commands++], cresult,
                                                                 output);
-                               srvc_desc = strtok (NULL, ":");
                        }
                }
 
@@ -156,14 +152,12 @@ main (int argc, char **argv)
 
        /* 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);
-
+               eol = strpbrk (result_text, "\r\n");
+               if (eol)
+                       eol[0] = 0;
+               printf ("%s\n", result_text);
        }
 
-
        /* return error status from remote command */
        return result;
 }
@@ -176,62 +170,10 @@ main (int argc, char **argv)
 int
 process_arguments (int argc, char **argv)
 {
-       int c;
-
-       if (argc < 2)
-               return ERROR;
-
-       remotecmd = realloc (remotecmd, 1);
-       remotecmd[0] = 0;
-
-       for (c = 1; c < argc; c++)
-               if (strcmp ("-to", argv[c]) == 0)
-                       strcpy (argv[c], "-t");
-
-       comm = strscpy (comm, SSH_COMMAND);
-
-       c = 0;
-       while (c += (call_getopt (argc - c, &argv[c]))) {
-
-               if (argc <= c)
-                       break;
-
-               if (hostname == NULL) {
-                       if (!is_host (argv[c]))
-                               terminate (STATE_UNKNOWN, "%s: Invalid host name %s\n", PROGNAME,
-                                                                        argv[c]);
-                       hostname = argv[c];
-               }
-               else if (remotecmd == NULL) {
-                       remotecmd = strscpy (remotecmd, argv[c++]);
-                       for (; c < argc; c++)
-                               remotecmd = ssprintf (remotecmd, "%s %s", remotecmd, argv[c]);
-               }
+       int c, i;
+       char *p1, *p2;
+       size_t len;
 
-       }
-
-       if (commands > 1)
-               remotecmd = strscat (remotecmd, ";echo STATUS CODE: $?;");
-
-       if (remotecmd == NULL || strlen (remotecmd) <= 1)
-               usage ("No remotecmd\n");
-
-       comm = ssprintf (comm, "%s %s '%s'", comm, hostname, remotecmd);
-
-       return validate_arguments ();
-}
-
-
-
-
-
-/* Call getopt */
-int
-call_getopt (int argc, char **argv)
-{
-       int c, i = 1;
-
-#ifdef HAVE_GETOPT_H
        int option_index = 0;
        static struct option long_options[] = {
                {"version", no_argument, 0, 'V'},
@@ -248,54 +190,40 @@ call_getopt (int argc, char **argv)
                {"user", required_argument, 0, 'u'},
                {"logname", required_argument, 0, 'l'},
                {"command", required_argument, 0, 'C'},
+               {"proto1", no_argument, 0, '1'},
+               {"proto2", no_argument, 0, '2'},
                {"use-ipv4", no_argument, 0, '4'},
                {"use-ipv6", no_argument, 0, '6'},
                {0, 0, 0, 0}
        };
-#endif
+
+       if (argc < 2)
+               return ERROR;
+
+       for (c = 1; c < argc; c++)
+               if (strcmp ("-to", argv[c]) == 0)
+                       strcpy (argv[c], "-t");
 
        while (1) {
-#ifdef HAVE_GETOPT_H
-               c =
-                       getopt_long (argc, argv, "+?Vvhft46:H:O:p:i:u:l:C:n:s:", long_options,
+               c = getopt_long (argc, argv, "Vvh1246ft:H:O:p:i:u:l:C:n:s:", long_options,
                                                                         &option_index);
-#else
-               c = getopt (argc, argv, "+?Vvhft46:H:O:p:i:u:l:C:n:s:");
-#endif
 
                if (c == -1 || c == EOF)
                        break;
 
-               i++;
-               switch (c) {
-               case 't':
-               case 'H':
-               case 'O':
-               case 'p':
-               case 'i':
-               case 'u':
-               case 'l':
-               case 'n':
-               case 's':
-                       i++;
-               }
-
                switch (c) {
                case '?':                                                                       /* help */
                        print_usage ();
                        exit (STATE_UNKNOWN);
                case 'V':                                                                       /* version */
-                       print_revision (PROGNAME, "$Revision$");
+                       print_revision (progname, "$Revision$");
                        exit (STATE_OK);
                case 'h':                                                                       /* help */
-                       print_help (PROGNAME);
+                       print_help (progname);
                        exit (STATE_OK);
                case 'v':                                                                       /* help */
                        verbose = TRUE;
                        break;
-               case 'f':                                                                       /* fork to background */
-                       comm = ssprintf (comm, "%s -f", comm);
-                       break;
                case 't':                                                                       /* timeout period */
                        if (!is_integer (optarg))
                                usage2 ("timeout interval must be an integer", optarg);
@@ -309,14 +237,22 @@ call_getopt (int argc, char **argv)
                case 'p': /* port number */
                        if (!is_integer (optarg))
                                usage2 ("port must be an integer", optarg);
-                       comm = ssprintf (comm,"%s -p %s", comm, optarg);
+                       asprintf (&comm,"%s -p %s", comm, optarg);
                        break;
                case 'O':                                                                       /* output file */
                        outputfile = optarg;
                        passive = TRUE;
                        break;
                case 's':                                                                       /* description of service to check */
-                       servicelist = optarg;
+                       service = realloc (service, (++services) * sizeof(char *));
+                       p1 = optarg;
+                       while (p2 = index (p1, ':')) {
+                               *p2 = '\0';
+                               asprintf (&service[services-1], "%s", p1);
+                               service = realloc (service, (++services) * sizeof(char *));
+                               p1 = p2 + 1;
+                       }
+                       asprintf (&service[services-1], "%s", p1);
                        break;
                case 'n':                                                                       /* short name of host in nagios configuration */
                        host_shortname = optarg;
@@ -325,22 +261,49 @@ call_getopt (int argc, char **argv)
                        c = 'l';
                case 'l':                                                                       /* login name */
                case 'i':                                                                       /* identity */
-                       comm = ssprintf (comm, "%s -%c %s", comm, c, optarg);
-                       break;
-               case '4':                                                                       /* IPv4 */
-                       comm = ssprintf (comm, "%s -4", comm);
+                       asprintf (&comm, "%s -%c %s", comm, c, optarg);
                        break;
-               case '6':                                                                       /* IPv6 */
-                       comm = ssprintf (comm, "%s -4", comm);
+               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 */
+               case '6':                                                               /* -6 for IPv6 */
+               case 'f':                                                                       /* fork to background */
+                       asprintf (&comm, "%s -%c", comm, c);
                        break;
                case 'C':                                                                       /* Command for remote machine */
                        commands++;
                        if (commands > 1)
-                               remotecmd = strscat (remotecmd, ";echo STATUS CODE: $?;");
-                       remotecmd = strscat (remotecmd, optarg);
+                               asprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd);
+                       asprintf (&remotecmd, "%s%s", remotecmd, optarg);
                }
        }
-       return i;
+
+       c = optind;
+       if (hostname == NULL) {
+               if (c <= argc) {
+                       terminate (STATE_UNKNOWN, "%s: You must provide a host name\n", progname);
+               } else if (!is_host (argv[c]))
+                       terminate (STATE_UNKNOWN, "%s: Invalid host name %s\n", progname, argv[c]);
+               hostname = argv[c++];
+       }
+
+       if (strlen(remotecmd) == 0) {
+               for (; c < argc; c++)
+                       if (strlen(remotecmd) > 0)
+                               asprintf (&remotecmd, "%s %s", remotecmd, argv[c]);
+                       else
+                               asprintf (&remotecmd, "%s", argv[c]);
+       }
+
+       if (commands > 1)
+               remotecmd = strscat (remotecmd, ";echo STATUS CODE: $?;");
+
+       if (remotecmd == NULL || strlen (remotecmd) <= 1)
+               usage ("No remotecmd\n");
+
+       asprintf (&comm, "%s %s '%s'", comm, hostname, remotecmd);
+
+       return validate_arguments ();
 }
 
 
@@ -352,6 +315,13 @@ validate_arguments (void)
 {
        if (remotecmd == NULL || hostname == NULL)
                return ERROR;
+
+       if (passive && commands != services)
+               terminate (STATE_UNKNOWN, "%s: In passive mode, you must provide a service name for each command.\n", progname);
+
+       if (passive && host_shortname == NULL)
+               terminate (STATE_UNKNOWN, "%s: In passive mode, you must provide the host short name from the nagios configs.\n", progname);
+
        return OK;
 }
 
@@ -360,7 +330,7 @@ validate_arguments (void)
 
 
 void
-print_help (char *cmd)
+print_help (const char *cmd)
 {
        print_revision (cmd, "$Revision$");
 
@@ -391,6 +361,10 @@ print_help (char *cmd)
                 "   list of nagios service names, separated by ':' [optional]\n"
                 "-n, --name=NAME\n"
                 "   short name of host in nagios configuration [optional]\n"
+                "-1, --proto1\n"
+                "   tell ssh to use Protocol 1\n"
+                "-2, --proto2\n"
+                "   tell ssh to use Protocol 2\n"
                 "-4, --use-ipv4\n"
                 "   tell ssh to use IPv4\n"
                 "-6, --use-ipv6\n"