3a8b9f57e6927b7f1272d6ebb67084021f386b7a
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-2003";
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;
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);
68 // result = process_arguments (argc, argv);
70 if (process_arguments (argc, argv) != OK)
71 usage (_("check_game: could not parse arguments\n"));
73 /* if (result != OK) {
74 printf (_("Incorrect arguments supplied\n"));
75 printf ("\n");
76 print_revision (progname, revision);
77 printf ("Copyright (c) 1999 Ian Cass, Knowledge Matters Limited\n");
78 printf (_("License: GPL\n"));
79 printf ("\n");
80 return STATE_UNKNOWN;
81 }
82 */
84 result = STATE_OK;
86 /* create the command line to execute */
87 asprintf (&command_line, "%s -raw %s -%s %s",
88 PATH_TO_QSTAT, QSTAT_DATA_DELIMITER, game_type, server_ip);
90 if (port)
91 asprintf (&command_line, "%s:%-d", command_line, port);
93 if (verbose > 0)
94 printf ("%s\n", command_line);
96 /* run the command */
97 fp = spopen (command_line);
98 if (fp == NULL) {
99 printf (_("Could not open pipe: %s\n"), command_line);
100 return STATE_UNKNOWN;
101 }
103 fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp); /* Only interested in the first line */
105 /* strip the newline character from the end of the input */
106 input_buffer[strlen (input_buffer) - 1] = 0;
108 /* sanity check */
109 /* was thinking about running qstat without any options, capturing the
110 -default line, parsing it & making an array of all know server types
111 but thought this would be too much hassle considering this is a tool
112 for intelligent sysadmins (ha). Could put a static array of known
113 server types in a header file but then we'd be limiting ourselves
115 In the end, I figured I'd simply let an error occur & then trap it
116 */
118 if (!strncmp (input_buffer, "unknown option", 14)) {
119 printf (_("CRITICAL - Host type parameter incorrect!\n"));
120 result = STATE_CRITICAL;
121 return result;
122 }
124 /* initialize the returned data buffer */
125 for (i = 0; i < QSTAT_MAX_RETURN_ARGS; i++)
126 ret[i] = strdup("");
128 i = 0;
129 p = (char *) strtok (input_buffer, QSTAT_DATA_DELIMITER);
130 while (p != NULL) {
131 ret[i] = p;
132 p = (char *) strtok (NULL, QSTAT_DATA_DELIMITER);
133 i++;
134 if (i >= QSTAT_MAX_RETURN_ARGS)
135 break;
136 }
138 if (strstr (ret[2], QSTAT_HOST_ERROR)) {
139 printf ("CRITICAL - Host not found\n");
140 result = STATE_CRITICAL;
141 }
142 else if (strstr (ret[2], QSTAT_HOST_DOWN)) {
143 printf ("CRITICAL - Game server down or unavailable\n");
144 result = STATE_CRITICAL;
145 }
146 else if (strstr (ret[2], QSTAT_HOST_TIMEOUT)) {
147 printf ("CRITICAL - Game server timeout\n");
148 result = STATE_CRITICAL;
149 }
150 else {
151 printf ("OK: %s/%s %s (%s), Ping: %s ms|%s %s\n",
152 ret[qstat_game_players],
153 ret[qstat_game_players_max],
154 ret[qstat_game_field],
155 ret[qstat_map_field],
156 ret[qstat_ping_field],
157 perfdata ("players", atol(ret[qstat_game_players]), "",
158 FALSE, 0, FALSE, 0,
159 TRUE, 0, TRUE, atol(ret[qstat_game_players_max])),
160 fperfdata ("ping", strtod(ret[qstat_ping_field], NULL), "",
161 FALSE, 0, FALSE, 0,
162 TRUE, 0, FALSE, 0));
163 }
165 /* close the pipe */
166 spclose (fp);
168 return result;
169 }
173 int
174 process_arguments (int argc, char **argv)
175 {
176 int c;
178 int opt_index = 0;
179 static struct option long_opts[] = {
180 {"help", no_argument, 0, 'h'},
181 {"version", no_argument, 0, 'V'},
182 {"verbose", no_argument, 0, 'v'},
183 {"timeout", required_argument, 0, 't'},
184 {"hostname", required_argument, 0, 'H'},
185 {"port", required_argument, 0, 'P'},
186 {"game-type", required_argument, 0, 'G'},
187 {"map-field", required_argument, 0, 'm'},
188 {"ping-field", required_argument, 0, 'p'},
189 {"game-field", required_argument, 0, 'g'},
190 {"players-field", required_argument, 0, 129},
191 {"max-players-field", required_argument, 0, 130},
192 {0, 0, 0, 0}
193 };
195 if (argc < 2)
196 return ERROR;
198 for (c = 1; c < argc; c++) {
199 if (strcmp ("-mf", argv[c]) == 0)
200 strcpy (argv[c], "-m");
201 else if (strcmp ("-pf", argv[c]) == 0)
202 strcpy (argv[c], "-p");
203 else if (strcmp ("-gf", argv[c]) == 0)
204 strcpy (argv[c], "-g");
205 }
207 while (1) {
208 c = getopt_long (argc, argv, "hVvt:H:P:G:g:p:m:", long_opts, &opt_index);
210 if (c == -1 || c == EOF)
211 break;
213 switch (c) {
214 case '?': /* args not parsable */
215 printf (_("%s: Unknown argument: %s\n\n"), progname, optarg);
216 print_usage ();
217 exit (STATE_UNKNOWN);
218 case 'h': /* help */
219 print_help ();
220 exit (STATE_OK);
221 case 'V': /* version */
222 print_revision (progname, revision);
223 exit (STATE_OK);
224 case 'v': /* version */
225 verbose = TRUE;
226 break;
227 case 't': /* timeout period */
228 timeout_interval = atoi (optarg);
229 break;
230 case 'H': /* hostname */
231 if (strlen (optarg) >= MAX_HOST_ADDRESS_LENGTH)
232 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
233 server_ip = optarg;
234 break;
235 case 'P': /* port */
236 port = atoi (optarg);
237 break;
238 case 'G': /* hostname */
239 if (strlen (optarg) >= MAX_INPUT_BUFFER)
240 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
241 game_type = optarg;
242 break;
243 case 'p': /* index of ping field */
244 qstat_ping_field = atoi (optarg);
245 if (qstat_ping_field < 0 || qstat_ping_field > QSTAT_MAX_RETURN_ARGS)
246 return ERROR;
247 break;
248 case 'm': /* index on map field */
249 qstat_map_field = atoi (optarg);
250 if (qstat_map_field < 0 || qstat_map_field > QSTAT_MAX_RETURN_ARGS)
251 return ERROR;
252 break;
253 case 'g': /* index of game field */
254 qstat_game_field = atoi (optarg);
255 if (qstat_game_field < 0 || qstat_game_field > QSTAT_MAX_RETURN_ARGS)
256 return ERROR;
257 break;
258 case 129: /* index of player count field */
259 qstat_game_players = atoi (optarg);
260 if (qstat_game_players_max == 0)
261 qstat_game_players_max = qstat_game_players - 1;
262 if (qstat_game_players < 0 || qstat_game_players > QSTAT_MAX_RETURN_ARGS)
263 return ERROR;
264 break;
265 case 130: /* index of max players field */
266 qstat_game_players_max = atoi (optarg);
267 if (qstat_game_players_max < 0 || qstat_game_players_max > QSTAT_MAX_RETURN_ARGS)
268 return ERROR;
269 break;
270 }
271 }
273 c = optind;
274 /* first option is the game type */
275 if (!game_type && c<argc)
276 game_type = strdup (argv[c++]);
278 /* Second option is the server name */
279 if (!server_ip && c<argc)
280 server_ip = strdup (argv[c++]);
282 return validate_arguments ();
283 }
285 int
286 validate_arguments (void)
287 {
288 if (qstat_game_players_max < 0)
289 qstat_game_players_max = 4;
291 if (qstat_game_players < 0)
292 qstat_game_players = 5;
294 if (qstat_game_field < 0)
295 qstat_game_field = 2;
297 if (qstat_map_field < 0)
298 qstat_map_field = 3;
300 if (qstat_ping_field < 0)
301 qstat_ping_field = 5;
303 return OK;
304 }
310 void
311 print_help (void)
312 {
313 print_revision (progname, revision);
315 printf (_(COPYRIGHT), copyright, email);
317 printf (_("This plugin tests %s connections with the specified host."), progname);
319 print_usage ();
321 printf (_(UT_HELP_VRSN));
323 printf (_("\
324 <game> = Game type that is recognised by qstat (without the leading dash)\n\
325 <ip_address> = The IP address of the device you wish to query\n\
326 [port] = Optional port of which to connect\n\
327 [game_field] = Field number in raw qstat output that contains game name\n\
328 [map_field] = Field number in raw qstat output that contains map name\n\
329 [ping_field] = Field number in raw qstat output that contains ping time\n"));
331 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
333 printf (_("\n\
334 Notes:\n\
335 - This plugin uses the 'qstat' command, the popular game server status query tool .\n\
336 If you don't have the package installed, you will need to download it from\n\
337 http://www.activesw.com/people/steve/qstat.html before you can use this plugin.\n"));
339 printf (_(UT_SUPPORT));
340 }
345 void
346 print_usage (void)
347 {
348 printf (_("\
349 Usage: %s <game> <ip_address> [-p port] [-gf game_field] [-mf map_field]\n\
350 [-pf ping_field]\n"), progname);
351 printf (_(UT_HLP_VRS), progname, progname);
352 }
354 /******************************************************************************
355 *
356 * Test Cases:
357 *
358 * ./check_game --players 7 -p 8 --map 5 qs 67.20.190.61 26000
359 *
360 * qstat -raw , -qs 67.20.190.61
361 * ==> QS,67.20.190.61,Nightmare.fintek.ca,67.20.190.61:26000,3,e2m1,6,0,83,0
362 *
363 * qstat -qs 67.20.190.61
364 * ==> ADDRESS PLAYERS MAP RESPONSE TIME NAME
365 * ==> 67.20.190.61 0/ 6 e2m1 79 / 0 Nightmare.fintek.ca
366 *
367 ******************************************************************************/