Code

use float for time in perf data
[nagiosplug.git] / plugins / check_game.c
1 /******************************************************************************
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 *
17 *****************************************************************************/
19 const char *progname = "check_game";
20 const char *revision = "$Revision$";
21 const char *copyright = "2002-2003";
22 const char *email = "nagiosplug-devel@lists.sourceforge.net";
24 #include "common.h"
25 #include "popen.h"
26 #include "utils.h"
28 int process_arguments (int, char **);
29 int validate_arguments (void);
30 void print_help (void);
31 void print_usage (void);
33 #define QSTAT_DATA_DELIMITER    ","
35 #define QSTAT_HOST_ERROR        "ERROR"
36 #define QSTAT_HOST_DOWN         "DOWN"
37 #define QSTAT_HOST_TIMEOUT      "TIMEOUT"
38 #define QSTAT_MAX_RETURN_ARGS   12
40 char *server_ip;
41 char *game_type;
42 int port = 0;
44 int verbose;
46 int qstat_game_players_max = -1;
47 int qstat_game_players = -1;
48 int qstat_game_field = -1;
49 int qstat_map_field = -1;
50 int qstat_ping_field = -1;
53 int
54 main (int argc, char **argv)
55 {
56         char *command_line;
57         int result;
58         FILE *fp;
59         char input_buffer[MAX_INPUT_BUFFER];
60         char *p, *ret[QSTAT_MAX_RETURN_ARGS];
61         int i;
63         setlocale (LC_ALL, "");
64         bindtextdomain (PACKAGE, LOCALEDIR);
65         textdomain (PACKAGE);
67         result = process_arguments (argc, argv);
69         if (result != OK) {
70                 printf (_("Incorrect arguments supplied\n"));
71                 printf ("\n");
72                 print_revision (progname, revision);
73                 printf (_("Copyright (c) 1999 Ian Cass, Knowledge Matters Limited\n"));
74                 printf (_("License: GPL\n"));
75                 printf ("\n");
76                 return STATE_UNKNOWN;
77         }
79         result = STATE_OK;
81         /* create the command line to execute */
82         asprintf (&command_line, "%s -raw %s -%s %s",
83                                                 PATH_TO_QSTAT, QSTAT_DATA_DELIMITER, game_type, server_ip);
84         
85         if (port)
86                 asprintf (&command_line, "%s:%-d", command_line, port);
88         if (verbose > 0)
89                 printf ("%s\n", command_line);
91         /* run the command */
92         fp = spopen (command_line);
93         if (fp == NULL) {
94                 printf (_("Error - Could not open pipe: %s\n"), command_line);
95                 return STATE_UNKNOWN;
96         }
98         fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp); /* Only interested in the first line */
100         /* strip the newline character from the end of the input */
101         input_buffer[strlen (input_buffer) - 1] = 0;
103         /* sanity check */
104         /* was thinking about running qstat without any options, capturing the
105            -default line, parsing it & making an array of all know server types
106            but thought this would be too much hassle considering this is a tool
107            for intelligent sysadmins (ha). Could put a static array of known 
108            server types in a header file but then we'd be limiting ourselves
110            In the end, I figured I'd simply let an error occur & then trap it
111          */
113         if (!strncmp (input_buffer, "unknown option", 14)) {
114                 printf (_("ERROR: Host type parameter incorrect!\n"));
115                 result = STATE_CRITICAL;
116                 return result;
117         }
119         /* initialize the returned data buffer */
120         for (i = 0; i < QSTAT_MAX_RETURN_ARGS; i++)
121                 ret[i] = strdup("");
123         i = 0;
124         p = (char *) strtok (input_buffer, QSTAT_DATA_DELIMITER);
125         while (p != NULL) {
126                 ret[i] = p;
127                 p = (char *) strtok (NULL, QSTAT_DATA_DELIMITER);
128                 i++;
129                 if (i >= QSTAT_MAX_RETURN_ARGS)
130                         break;
131         }
133         if (strstr (ret[2], QSTAT_HOST_ERROR)) {
134                 printf ("ERROR: Host not found\n");
135                 result = STATE_CRITICAL;
136         }
137         else if (strstr (ret[2], QSTAT_HOST_DOWN)) {
138                 printf ("ERROR: Game server down or unavailable\n");
139                 result = STATE_CRITICAL;
140         }
141         else if (strstr (ret[2], QSTAT_HOST_TIMEOUT)) {
142                 printf ("ERROR: Game server timeout\n");
143                 result = STATE_CRITICAL;
144         }
145         else {
146                 printf ("OK: %s/%s %s (%s), Ping: %s ms|%s %s\n", 
147                         ret[qstat_game_players],
148                         ret[qstat_game_players_max],
149                         ret[qstat_game_field], 
150                         ret[qstat_map_field],
151                         ret[qstat_ping_field],
152                                                 perfdata ("players", atol(ret[qstat_game_players]), "",
153                                   FALSE, 0, FALSE, 0,
154                                   TRUE, 0, TRUE, atol(ret[qstat_game_players_max])),
155                                                 fperfdata ("ping", strtod(ret[qstat_ping_field], NULL), "",
156                                   FALSE, 0, FALSE, 0,
157                                   TRUE, 0, FALSE, 0));
158         }
160         /* close the pipe */
161         spclose (fp);
163         return result;
168 int
169 process_arguments (int argc, char **argv)
171         int c;
173         int opt_index = 0;
174         static struct option long_opts[] = {
175                 {"help", no_argument, 0, 'h'},
176                 {"version", no_argument, 0, 'V'},
177                 {"verbose", no_argument, 0, 'v'},
178                 {"timeout", required_argument, 0, 't'},
179                 {"hostname", required_argument, 0, 'H'},
180                 {"port", required_argument, 0, 'P'},
181                 {"game-type", required_argument, 0, 'G'},
182                 {"map-field", required_argument, 0, 'm'},
183                 {"ping-field", required_argument, 0, 'p'},
184                 {"game-field", required_argument, 0, 'g'},
185                 {"players-field", required_argument, 0, 129},
186                 {"max-players-field", required_argument, 0, 130},
187                 {0, 0, 0, 0}
188         };
190         if (argc < 2)
191                 return ERROR;
193         for (c = 1; c < argc; c++) {
194                 if (strcmp ("-mf", argv[c]) == 0)
195                         strcpy (argv[c], "-m");
196                 else if (strcmp ("-pf", argv[c]) == 0)
197                         strcpy (argv[c], "-p");
198                 else if (strcmp ("-gf", argv[c]) == 0)
199                         strcpy (argv[c], "-g");
200         }
202         while (1) {
203                 c = getopt_long (argc, argv, "hVvt:H:P:G:g:p:m:", long_opts, &opt_index);
205                 if (c == -1 || c == EOF)
206                         break;
208                 switch (c) {
209                 case '?': /* args not parsable */
210                         printf (_("%s: Unknown argument: %s\n\n"), progname, optarg);
211                         print_usage ();
212                         exit (STATE_UNKNOWN);
213                 case 'h': /* help */
214                         print_help ();
215                         exit (STATE_OK);
216                 case 'V': /* version */
217                         print_revision (progname, revision);
218                         exit (STATE_OK);
219                 case 'v': /* version */
220                         verbose = TRUE;
221                         break;
222                 case 't': /* timeout period */
223                         timeout_interval = atoi (optarg);
224                         break;
225                 case 'H': /* hostname */
226                         if (strlen (optarg) >= MAX_HOST_ADDRESS_LENGTH)
227                                 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
228                         server_ip = optarg;
229                         break;
230                 case 'P': /* port */
231                         port = atoi (optarg);
232                         break;
233                 case 'G': /* hostname */
234                         if (strlen (optarg) >= MAX_INPUT_BUFFER)
235                                 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
236                         game_type = optarg;
237                         break;
238                 case 'p': /* index of ping field */
239                         qstat_ping_field = atoi (optarg);
240                         if (qstat_ping_field < 0 || qstat_ping_field > QSTAT_MAX_RETURN_ARGS)
241                                 return ERROR;
242                         break;
243                 case 'm': /* index on map field */
244                         qstat_map_field = atoi (optarg);
245                         if (qstat_map_field < 0 || qstat_map_field > QSTAT_MAX_RETURN_ARGS)
246                                 return ERROR;
247                         break;
248                 case 'g': /* index of game field */
249                         qstat_game_field = atoi (optarg);
250                         if (qstat_game_field < 0 || qstat_game_field > QSTAT_MAX_RETURN_ARGS)
251                                 return ERROR;
252                         break;
253                 case 129: /* index of player count field */
254                         qstat_game_players = atoi (optarg);
255                         if (qstat_game_players_max == 0)
256                                 qstat_game_players_max = qstat_game_players - 1;
257                         if (qstat_game_players < 0 || qstat_game_players > QSTAT_MAX_RETURN_ARGS)
258                                 return ERROR;
259                         break;
260                 case 130: /* index of max players field */
261                         qstat_game_players_max = atoi (optarg);
262                         if (qstat_game_players_max < 0 || qstat_game_players_max > QSTAT_MAX_RETURN_ARGS)
263                                 return ERROR;
264                         break;
265                 }
266         }
268         c = optind;
269         /* first option is the game type */
270         if (!game_type && c<argc)
271                 game_type = strdup (argv[c++]);
273         /* Second option is the server name */
274         if (!server_ip && c<argc)
275                 server_ip = strdup (argv[c++]);
277         return validate_arguments ();
280 int
281 validate_arguments (void)
283         if (qstat_game_players_max < 0)
284                 qstat_game_players_max = 4;
286         if (qstat_game_players < 0)
287                 qstat_game_players = 5;
289         if (qstat_game_field < 0)
290                 qstat_game_field = 2;
292         if (qstat_map_field < 0)
293                 qstat_map_field = 3;
295         if (qstat_ping_field < 0)
296                 qstat_ping_field = 5;
298         return OK;
305 \f
306 void
307 print_help (void)
309         print_revision (progname, revision);
311         printf (_(COPYRIGHT), copyright, email);
313         printf (_("This plugin tests %s connections with the specified host."), progname);
315         print_usage ();
317         printf (_(UT_HELP_VRSN));
319         printf (_("\
320 <game>        = Game type that is recognised by qstat (without the leading dash)\n\
321 <ip_address>  = The IP address of the device you wish to query\n\
322  [port]        = Optional port of which to connect\n\
323  [game_field]  = Field number in raw qstat output that contains game name\n\
324  [map_field]   = Field number in raw qstat output that contains map name\n\
325  [ping_field]  = Field number in raw qstat output that contains ping time\n"));
327         printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
329         printf (_("\n\
330 Notes:\n\
331 - This plugin uses the 'qstat' command, the popular game server status query tool .\n\
332   If you don't have the package installed, you will need to download it from\n\
333   http://www.activesw.com/people/steve/qstat.html before you can use this plugin.\n"));
335         printf (_(UT_SUPPORT));
341 void
342 print_usage (void)
344         printf (_("\
345 Usage: %s <game> <ip_address> [-p port] [-gf game_field] [-mf map_field]\n\
346   [-pf ping_field]\n"), progname);
347         printf (_(UT_HLP_VRS), progname, progname);
350 /******************************************************************************
351  *
352  * Test Cases:
353  *
354  * ./check_game --players 7 -p 8 --map 5 qs 67.20.190.61 26000
355  * 
356  * qstat -raw , -qs 67.20.190.61
357  *  ==> QS,67.20.190.61,Nightmare.fintek.ca,67.20.190.61:26000,3,e2m1,6,0,83,0
358  *
359  * qstat -qs 67.20.190.61
360  *  ==> ADDRESS           PLAYERS      MAP   RESPONSE TIME    NAME
361  *  ==> 67.20.190.61            0/ 6     e2m1     79 / 0   Nightmare.fintek.ca
362  *
363  ******************************************************************************/