ea08f9d93a31e820c2e07a0a5e4e81a072ed2178
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);
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);
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;
156 }
160 int
161 process_arguments (int argc, char **argv)
162 {
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 ();
270 }
272 int
273 validate_arguments (void)
274 {
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;
291 }
297 void
298 print_help (void)
299 {
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));
328 }
333 void
334 print_usage (void)
335 {
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);
340 }
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 ******************************************************************************/