1 /******************************************************************************
2 *
3 * CHECK_GAME.C
4 *
5 * Program: GAME plugin for Nagios
6 * License: GPL
7 * Copyright (c) 1999 Ian Cass (ian@knowledge.com)
8 *
9 * Last Modified: $Date$
10 *
11 * Mod History
12 *
13 * 25-8-99 Ethan Galstad <nagios@nagios.org>
14 * Integrated with common plugin code, minor cleanup stuff
15 *
16 * 17-8-99 version 1.1b
17 *
18 * 17-8-99 make port a separate argument so we can use something like
19 * check_game q2s!27910 with the probe set up as
20 * check_game $ARG1$ $HOSTADDRESS$ $ARG2$
21 *
22 * 17-8-99 Put in sanity check for ppl who enter the wrong server type
23 *
24 * 17-8-99 Release version 1.0b
25 *
26 * Command line: CHECK_GAME <server type> <ip_address> [port]
27 *
28 * server type = a server type that qstat understands (type qstat & look at the -default line)
29 * ip_address = either a dotted address or a FQD name
30 * port = defaults game default port
31 *
32 *
33 * Description:
34 *
35 * Needed to explore writing my own probes for nagios. It looked
36 * pretty simple so I thought I'd write one for monitoring the status
37 * of game servers. It uses qstat to do the actual monitoring and
38 * analyses the result. Doing it this way means I can support all the
39 * servers that qstat does and will do in the future.
40 *
41 *
42 * Dependencies:
43 *
44 * This plugin uses the 'qstat' command If you don't
45 * have the package installed you will need to download it from
46 * http://www.activesw.com/people/steve/qstat.html or any popular files archive
47 * before you can use this plugin.
48 *
49 * License Information:
50 *
51 * This program is free software; you can redistribute it and/or modify
52 * it under the terms of the GNU General Public License as published by
53 * the Free Software Foundation; either version 2 of the License, or
54 * (at your option) any later version.
55 *
56 * This program is distributed in the hope that it will be useful,
57 * but WITHOUT ANY WARRANTY; without even the implied warranty of
58 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
59 * GNU General Public License for more details.
60 *
61 * You should have received a copy of the GNU General Public License
62 * along with this program; if not, write to the Free Software
63 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
64 *
65 *****************************************************************************/
67 #include "config.h"
68 #include "common.h"
69 #include "utils.h"
71 int process_arguments (int, char **);
72 const char *progname = "check_game";
74 #define QSTAT_DATA_DELIMITER ","
76 #define QSTAT_HOST_ERROR "ERROR"
77 #define QSTAT_HOST_DOWN "DOWN"
78 #define QSTAT_HOST_TIMEOUT "TIMEOUT"
79 #define QSTAT_MAX_RETURN_ARGS 12
81 char server_ip[MAX_HOST_ADDRESS_LENGTH];
82 char game_type[MAX_INPUT_BUFFER];
83 char port[MAX_INPUT_BUFFER];
85 int qstat_game_players_max = 4;
86 int qstat_game_players = 5;
87 int qstat_game_field = 2;
88 int qstat_map_field = 3;
89 int qstat_ping_field = 5;
92 int
93 main (int argc, char **argv)
94 {
95 char command_line[MAX_INPUT_BUFFER];
96 int result;
97 FILE *fp;
98 char input_buffer[MAX_INPUT_BUFFER];
99 char response[MAX_INPUT_BUFFER];
100 char *temp_ptr;
101 int found;
102 char *p, *ret[QSTAT_MAX_RETURN_ARGS];
103 int i;
105 result = process_arguments (argc, argv);
107 if (result != OK) {
108 printf ("Incorrect arguments supplied\n");
109 printf ("\n");
110 print_revision (argv[0], "$Revision$");
111 printf ("Copyright (c) 1999 Ian Cass, Knowledge Matters Limited\n");
112 printf ("License: GPL\n");
113 printf ("\n");
114 printf
115 ("Usage: %s <game> <ip_address> [-p port] [-gf game_field] [-mf map_field] [-pf ping_field]\n",
116 argv[0]);
117 printf ("\n");
118 printf ("Options:\n");
119 printf
120 (" <game> = Game type that is recognised by qstat (without the leading dash)\n");
121 printf
122 (" <ip_address> = The IP address of the device you wish to query\n");
123 printf (" [port] = Optional port of which to connect\n");
124 printf
125 (" [game_field] = Field number in raw qstat output that contains game name\n");
126 printf
127 (" [map_field] = Field number in raw qstat output that contains map name\n");
128 printf
129 (" [ping_field] = Field number in raw qstat output that contains ping time\n");
130 printf ("\n");
131 printf ("Notes:\n");
132 printf
133 ("- This plugin uses the 'qstat' command, the popular game server status query tool .\n");
134 printf
135 (" If you don't have the package installed, you will need to download it from\n");
136 printf
137 (" http://www.activesw.com/people/steve/qstat.html before you can use this plugin.\n");
138 printf ("\n");
139 return STATE_UNKNOWN;
140 }
142 result = STATE_OK;
144 /* create the command line to execute */
145 snprintf (command_line, sizeof (command_line) - 1, "%s -raw %s -%s %s%s",
146 PATH_TO_QSTAT, QSTAT_DATA_DELIMITER, game_type, server_ip, port);
147 command_line[sizeof (command_line) - 1] = 0;
149 /* run the command */
150 fp = popen (command_line, "r");
151 if (fp == NULL) {
152 printf ("Error - Could not open pipe: %s\n", command_line);
153 return STATE_UNKNOWN;
154 }
156 found = 0;
157 fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp); /* Only interested in the first line */
159 /* strip the newline character from the end of the input */
160 input_buffer[strlen (input_buffer) - 1] = 0;
162 /* sanity check */
163 /* was thinking about running qstat without any options, capturing the
164 -default line, parsing it & making an array of all know server types
165 but thought this would be too much hassle considering this is a tool
166 for intelligent sysadmins (ha). Could put a static array of known
167 server types in a header file but then we'd be limiting ourselves
169 In the end, I figured I'd simply let an error occur & then trap it
170 */
172 if (!strncmp (input_buffer, "unknown option", 14)) {
173 printf ("ERROR: Host type parameter incorrect!\n");
174 result = STATE_CRITICAL;
175 return result;
176 }
178 /* initialize the returned data buffer */
179 for (i = 0; i < QSTAT_MAX_RETURN_ARGS; i++)
180 ret[i] = "";
182 i = 0;
183 p = (char *) strtok (input_buffer, QSTAT_DATA_DELIMITER);
184 while (p != NULL) {
185 ret[i] = p;
186 p = (char *) strtok (NULL, QSTAT_DATA_DELIMITER);
187 i++;
188 if (i >= QSTAT_MAX_RETURN_ARGS)
189 break;
190 }
192 if (strstr (ret[2], QSTAT_HOST_ERROR)) {
193 printf ("ERROR: Host not found\n");
194 result = STATE_CRITICAL;
195 }
196 else if (strstr (ret[2], QSTAT_HOST_DOWN)) {
197 printf ("ERROR: Game server down or unavailable\n");
198 result = STATE_CRITICAL;
199 }
200 else if (strstr (ret[2], QSTAT_HOST_TIMEOUT)) {
201 printf ("ERROR: Game server timeout\n");
202 result = STATE_CRITICAL;
203 }
204 else {
205 printf ("OK: %s/%s %s (%s), Ping: %s ms\n",
206 ret[qstat_game_players_max],
207 ret[qstat_game_players],
208 ret[qstat_game_field],
209 ret[qstat_map_field],
210 ret[qstat_ping_field]);
211 }
213 /* close the pipe */
214 pclose (fp);
216 return result;
217 }
221 int
222 process_arguments (int argc, char **argv)
223 {
224 int x;
226 /* not enough options were supplied */
227 if (argc < 3)
228 return ERROR;
230 /* first option is always the game type */
231 strncpy (game_type, argv[1], sizeof (game_type) - 1);
232 game_type[sizeof (game_type) - 1] = 0;
234 /* Second option is always the server name */
235 strncpy (server_ip, argv[2], sizeof (server_ip) - 1);
236 server_ip[sizeof (server_ip) - 1] = 0;
238 /* process all remaining arguments */
239 for (x = 4; x <= argc; x++) {
241 /* we got the port number to connect to */
242 if (!strcmp (argv[x - 1], "-p")) {
243 if (x < argc) {
244 snprintf (port, sizeof (port) - 2, ":%s", argv[x]);
245 port[sizeof (port) - 1] = 0;
246 x++;
247 }
248 else
249 return ERROR;
250 }
252 /* we got the game field */
253 else if (!strcmp (argv[x - 1], "-gf")) {
254 if (x < argc) {
255 qstat_game_field = atoi (argv[x]);
256 if (qstat_game_field < 0 || qstat_game_field > QSTAT_MAX_RETURN_ARGS)
257 return ERROR;
258 x++;
259 }
260 else
261 return ERROR;
262 }
264 /* we got the map field */
265 else if (!strcmp (argv[x - 1], "-mf")) {
266 if (x < argc) {
267 qstat_map_field = atoi (argv[x]);
268 if (qstat_map_field < 0 || qstat_map_field > QSTAT_MAX_RETURN_ARGS)
269 return ERROR;
270 x++;
271 }
272 else
273 return ERROR;
274 }
276 /* we got the ping field */
277 else if (!strcmp (argv[x - 1], "-pf")) {
278 if (x < argc) {
279 qstat_ping_field = atoi (argv[x]);
280 if (qstat_ping_field < 0 || qstat_ping_field > QSTAT_MAX_RETURN_ARGS)
281 return ERROR;
282 x++;
283 }
284 else
285 return ERROR;
286 }
288 /* else we got something else... */
289 else
290 return ERROR;
291 }
293 return OK;
294 }
296 void print_usage (void)
297 {
298 return STATE_OK;
299 }