Code

ea08f9d93a31e820c2e07a0a5e4e81a072ed2178
[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 * $Id$
18 *****************************************************************************/
20 const char *progname = "check_game";
21 const char *revision = "$Revision$";
22 const char *copyright = "2002-2004";
23 const char *email = "nagiosplug-devel@lists.sourceforge.net";
25 #include "common.h"
26 #include "popen.h"
27 #include "utils.h"
29 int process_arguments (int, char **);
30 int validate_arguments (void);
31 void print_help (void);
32 void print_usage (void);
34 #define QSTAT_DATA_DELIMITER    ","
36 #define QSTAT_HOST_ERROR        "ERROR"
37 #define QSTAT_HOST_DOWN         "DOWN"
38 #define QSTAT_HOST_TIMEOUT      "TIMEOUT"
39 #define QSTAT_MAX_RETURN_ARGS   12
41 char *server_ip;
42 char *game_type;
43 int port = 0;
45 int verbose;
47 int qstat_game_players_max = -1;
48 int qstat_game_players = -1;
49 int qstat_game_field = -1;
50 int qstat_map_field = -1;
51 int qstat_ping_field = -1;
54 int
55 main (int argc, char **argv)
56 {
57         char *command_line;
58         int result = STATE_UNKNOWN;
59         FILE *fp;
60         char input_buffer[MAX_INPUT_BUFFER];
61         char *p, *ret[QSTAT_MAX_RETURN_ARGS];
62         int i;
64         setlocale (LC_ALL, "");
65         bindtextdomain (PACKAGE, LOCALEDIR);
66         textdomain (PACKAGE);
67         
68         if (process_arguments (argc, argv) != TRUE)
69                 usage4 (_("Could not parse arguments"));
71         result = STATE_OK;
73         /* create the command line to execute */
74         asprintf (&command_line, "%s -raw %s -%s %s",
75                                                 PATH_TO_QSTAT, QSTAT_DATA_DELIMITER, game_type, server_ip);
76         
77         if (port)
78                 asprintf (&command_line, "%s:%-d", command_line, port);
80         if (verbose > 0)
81                 printf ("%s\n", command_line);
83         /* run the command */
84         fp = spopen (command_line);
85         if (fp == NULL) {
86                 printf (_("Could not open pipe: %s\n"), command_line);
87                 return STATE_UNKNOWN;
88         }
90         fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp); /* Only interested in the first line */
92         /* strip the newline character from the end of the input */
93         input_buffer[strlen (input_buffer) - 1] = 0;
95         /* sanity check */
96         /* was thinking about running qstat without any options, capturing the
97            -default line, parsing it & making an array of all know server types
98            but thought this would be too much hassle considering this is a tool
99            for intelligent sysadmins (ha). Could put a static array of known 
100            server types in a header file but then we'd be limiting ourselves
102            In the end, I figured I'd simply let an error occur & then trap it
103          */
105         if (!strncmp (input_buffer, "unknown option", 14)) {
106                 printf (_("CRITICAL - Host type parameter incorrect!\n"));
107                 result = STATE_CRITICAL;
108                 return result;
109         }
111         /* initialize the returned data buffer */
112         for (i = 0; i < QSTAT_MAX_RETURN_ARGS; i++)
113                 ret[i] = strdup("");
115         i = 0;
116         p = (char *) strtok (input_buffer, QSTAT_DATA_DELIMITER);
117         while (p != NULL) {
118                 ret[i] = p;
119                 p = (char *) strtok (NULL, QSTAT_DATA_DELIMITER);
120                 i++;
121                 if (i >= QSTAT_MAX_RETURN_ARGS)
122                         break;
123         }
125         if (strstr (ret[2], QSTAT_HOST_ERROR)) {
126                 printf ("CRITICAL - Host not found\n");
127                 result = STATE_CRITICAL;
128         }
129         else if (strstr (ret[2], QSTAT_HOST_DOWN)) {
130                 printf ("CRITICAL - Game server down or unavailable\n");
131                 result = STATE_CRITICAL;
132         }
133         else if (strstr (ret[2], QSTAT_HOST_TIMEOUT)) {
134                 printf ("CRITICAL - Game server timeout\n");
135                 result = STATE_CRITICAL;
136         }
137         else {
138                 printf ("OK: %s/%s %s (%s), Ping: %s ms|%s %s\n", 
139                         ret[qstat_game_players],
140                         ret[qstat_game_players_max],
141                         ret[qstat_game_field], 
142                         ret[qstat_map_field],
143                         ret[qstat_ping_field],
144                                                 perfdata ("players", atol(ret[qstat_game_players]), "",
145                                   FALSE, 0, FALSE, 0,
146                                   TRUE, 0, TRUE, atol(ret[qstat_game_players_max])),
147                                                 fperfdata ("ping", strtod(ret[qstat_ping_field], NULL), "",
148                                   FALSE, 0, FALSE, 0,
149                                   TRUE, 0, FALSE, 0));
150         }
152         /* close the pipe */
153         spclose (fp);
155         return result;
160 int
161 process_arguments (int argc, char **argv)
163         int c;
165         int opt_index = 0;
166         static struct option long_opts[] = {
167                 {"help", no_argument, 0, 'h'},
168                 {"version", no_argument, 0, 'V'},
169                 {"verbose", no_argument, 0, 'v'},
170                 {"timeout", required_argument, 0, 't'},
171                 {"hostname", required_argument, 0, 'H'},
172                 {"port", required_argument, 0, 'P'},
173                 {"game-type", required_argument, 0, 'G'},
174                 {"map-field", required_argument, 0, 'm'},
175                 {"ping-field", required_argument, 0, 'p'},
176                 {"game-field", required_argument, 0, 'g'},
177                 {"players-field", required_argument, 0, 129},
178                 {"max-players-field", required_argument, 0, 130},
179                 {0, 0, 0, 0}
180         };
182         if (argc < 2)
183                 return ERROR;
185         for (c = 1; c < argc; c++) {
186                 if (strcmp ("-mf", argv[c]) == 0)
187                         strcpy (argv[c], "-m");
188                 else if (strcmp ("-pf", argv[c]) == 0)
189                         strcpy (argv[c], "-p");
190                 else if (strcmp ("-gf", argv[c]) == 0)
191                         strcpy (argv[c], "-g");
192         }
194         while (1) {
195                 c = getopt_long (argc, argv, "hVvt:H:P:G:g:p:m:", long_opts, &opt_index);
197                 if (c == -1 || c == EOF)
198                         break;
200                 switch (c) {
201                 case '?': /* args not parsable */
202                         printf (_("%s: Unknown argument: %s\n\n"), progname, optarg);
203                         print_usage ();
204                         exit (STATE_UNKNOWN);
205                 case 'h': /* help */
206                         print_help ();
207                         exit (STATE_OK);
208                 case 'V': /* version */
209                         print_revision (progname, revision);
210                         exit (STATE_OK);
211                 case 'v': /* version */
212                         verbose = TRUE;
213                         break;
214                 case 't': /* timeout period */
215                         timeout_interval = atoi (optarg);
216                         break;
217                 case 'H': /* hostname */
218                         if (strlen (optarg) >= MAX_HOST_ADDRESS_LENGTH)
219                                 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
220                         server_ip = optarg;
221                         break;
222                 case 'P': /* port */
223                         port = atoi (optarg);
224                         break;
225                 case 'G': /* hostname */
226                         if (strlen (optarg) >= MAX_INPUT_BUFFER)
227                                 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
228                         game_type = optarg;
229                         break;
230                 case 'p': /* index of ping field */
231                         qstat_ping_field = atoi (optarg);
232                         if (qstat_ping_field < 0 || qstat_ping_field > QSTAT_MAX_RETURN_ARGS)
233                                 return ERROR;
234                         break;
235                 case 'm': /* index on map field */
236                         qstat_map_field = atoi (optarg);
237                         if (qstat_map_field < 0 || qstat_map_field > QSTAT_MAX_RETURN_ARGS)
238                                 return ERROR;
239                         break;
240                 case 'g': /* index of game field */
241                         qstat_game_field = atoi (optarg);
242                         if (qstat_game_field < 0 || qstat_game_field > QSTAT_MAX_RETURN_ARGS)
243                                 return ERROR;
244                         break;
245                 case 129: /* index of player count field */
246                         qstat_game_players = atoi (optarg);
247                         if (qstat_game_players_max == 0)
248                                 qstat_game_players_max = qstat_game_players - 1;
249                         if (qstat_game_players < 0 || qstat_game_players > QSTAT_MAX_RETURN_ARGS)
250                                 return ERROR;
251                         break;
252                 case 130: /* index of max players field */
253                         qstat_game_players_max = atoi (optarg);
254                         if (qstat_game_players_max < 0 || qstat_game_players_max > QSTAT_MAX_RETURN_ARGS)
255                                 return ERROR;
256                         break;
257                 }
258         }
260         c = optind;
261         /* first option is the game type */
262         if (!game_type && c<argc)
263                 game_type = strdup (argv[c++]);
265         /* Second option is the server name */
266         if (!server_ip && c<argc)
267                 server_ip = strdup (argv[c++]);
269         return validate_arguments ();
272 int
273 validate_arguments (void)
275         if (qstat_game_players_max < 0)
276                 qstat_game_players_max = 4;
278         if (qstat_game_players < 0)
279                 qstat_game_players = 5;
281         if (qstat_game_field < 0)
282                 qstat_game_field = 2;
284         if (qstat_map_field < 0)
285                 qstat_map_field = 3;
287         if (qstat_ping_field < 0)
288                 qstat_ping_field = 5;
290         return OK;
297 void
298 print_help (void)
300         print_revision (progname, revision);
302         printf ("Copyright (c) 1999 Ian Cass, Knowledge Matters Limited\n");
303         printf (_(COPYRIGHT), copyright, email);
305         printf (_("This plugin tests %s connections with the specified host."), progname);
307         print_usage ();
309         printf (_(UT_HELP_VRSN));
311         printf (_("\
312 <game>        = Game type that is recognised by qstat (without the leading dash)\n\
313 <ip_address>  = The IP address of the device you wish to query\n\
314  [port]        = Optional port of which to connect\n\
315  [game_field]  = Field number in raw qstat output that contains game name\n\
316  [map_field]   = Field number in raw qstat output that contains map name\n\
317  [ping_field]  = Field number in raw qstat output that contains ping time\n"));
319         printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
321         printf (_("\n\
322 Notes:\n\
323 - This plugin uses the 'qstat' command, the popular game server status query tool .\n\
324   If you don't have the package installed, you will need to download it from\n\
325   http://www.activesw.com/people/steve/qstat.html before you can use this plugin.\n"));
327         printf (_(UT_SUPPORT));
333 void
334 print_usage (void)
336         printf (_("\
337 Usage: %s <game> <ip_address> [-p port] [-gf game_field] [-mf map_field]\n\
338   [-pf ping_field]\n"), progname);
339         printf (_(UT_HLP_VRS), progname, progname);
342 /******************************************************************************
343  *
344  * Test Cases:
345  *
346  * ./check_game --players 7 -p 8 --map 5 qs 67.20.190.61 26000
347  * 
348  * qstat -raw , -qs 67.20.190.61
349  *  ==> QS,67.20.190.61,Nightmare.fintek.ca,67.20.190.61:26000,3,e2m1,6,0,83,0
350  *
351  * qstat -qs 67.20.190.61
352  *  ==> ADDRESS           PLAYERS      MAP   RESPONSE TIME    NAME
353  *  ==> 67.20.190.61            0/ 6     e2m1     79 / 0   Nightmare.fintek.ca
354  *
355  ******************************************************************************/