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 void
29 print_usage (void)
30 {
31 printf (_("\
32 Usage: %s <game> <ip_address> [-p port] [-gf game_field] [-mf map_field]\n\
33 [-pf ping_field]\n"), progname);
34 printf (_(UT_HLP_VRS), progname, progname);
35 }
37 void
38 print_help (void)
39 {
40 print_revision (progname, revision);
42 printf (_(COPYRIGHT), copyright, email);
44 printf (_("This plugin tests %s connections with the specified host."), progname);
46 print_usage ();
48 printf (_(UT_HELP_VRSN));
50 printf (_("\
51 <game> = Game type that is recognised by qstat (without the leading dash)\n\
52 <ip_address> = The IP address of the device you wish to query\n\
53 [port] = Optional port of which to connect\n\
54 [game_field] = Field number in raw qstat output that contains game name\n\
55 [map_field] = Field number in raw qstat output that contains map name\n\
56 [ping_field] = Field number in raw qstat output that contains ping time\n"),
57 DEFAULT_SOCKET_TIMEOUT);
59 printf (_("\n\
60 Notes:\n\
61 - This plugin uses the 'qstat' command, the popular game server status query tool .\n\
62 If you don't have the package installed, you will need to download it from\n\
63 http://www.activesw.com/people/steve/qstat.html before you can use this plugin.\n"));
65 printf (_(UT_SUPPORT));
66 }
67 \f
68 int process_arguments (int, char **);
69 int validate_arguments (void);
71 #define QSTAT_DATA_DELIMITER ","
73 #define QSTAT_HOST_ERROR "ERROR"
74 #define QSTAT_HOST_DOWN "DOWN"
75 #define QSTAT_HOST_TIMEOUT "TIMEOUT"
76 #define QSTAT_MAX_RETURN_ARGS 12
78 char *server_ip;
79 char *game_type;
80 int port = 0;
82 int verbose;
84 int qstat_game_players_max = 4;
85 int qstat_game_players = 5;
86 int qstat_game_field = 2;
87 int qstat_map_field = 3;
88 int qstat_ping_field = 5;
91 int
92 main (int argc, char **argv)
93 {
94 char *command_line;
95 int result;
96 FILE *fp;
97 char input_buffer[MAX_INPUT_BUFFER];
98 char *p, *ret[QSTAT_MAX_RETURN_ARGS];
99 int i;
101 result = process_arguments (argc, argv);
103 if (result != OK) {
104 printf (_("Incorrect arguments supplied\n"));
105 printf ("\n");
106 print_revision (progname, revision);
107 printf (_("Copyright (c) 1999 Ian Cass, Knowledge Matters Limited\n"));
108 printf (_("License: GPL\n"));
109 printf ("\n");
110 return STATE_UNKNOWN;
111 }
113 result = STATE_OK;
115 /* create the command line to execute */
116 asprintf (&command_line, "%s -raw %s -%s %s",
117 PATH_TO_QSTAT, QSTAT_DATA_DELIMITER, game_type, server_ip);
119 if (port)
120 asprintf (&command_line, "%s:%-d", command_line, port);
122 if (verbose > 0)
123 printf ("%s\n", command_line);
125 /* run the command */
126 fp = spopen (command_line);
127 if (fp == NULL) {
128 printf (_("Error - Could not open pipe: %s\n"), command_line);
129 return STATE_UNKNOWN;
130 }
132 fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp); /* Only interested in the first line */
134 /* strip the newline character from the end of the input */
135 input_buffer[strlen (input_buffer) - 1] = 0;
137 /* sanity check */
138 /* was thinking about running qstat without any options, capturing the
139 -default line, parsing it & making an array of all know server types
140 but thought this would be too much hassle considering this is a tool
141 for intelligent sysadmins (ha). Could put a static array of known
142 server types in a header file but then we'd be limiting ourselves
144 In the end, I figured I'd simply let an error occur & then trap it
145 */
147 if (!strncmp (input_buffer, "unknown option", 14)) {
148 printf (_("ERROR: Host type parameter incorrect!\n"));
149 result = STATE_CRITICAL;
150 return result;
151 }
153 /* initialize the returned data buffer */
154 for (i = 0; i < QSTAT_MAX_RETURN_ARGS; i++)
155 ret[i] = "";
157 i = 0;
158 p = (char *) strtok (input_buffer, QSTAT_DATA_DELIMITER);
159 while (p != NULL) {
160 ret[i] = p;
161 p = (char *) strtok (NULL, QSTAT_DATA_DELIMITER);
162 i++;
163 if (i >= QSTAT_MAX_RETURN_ARGS)
164 break;
165 }
167 if (strstr (ret[2], QSTAT_HOST_ERROR)) {
168 printf ("ERROR: Host not found\n");
169 result = STATE_CRITICAL;
170 }
171 else if (strstr (ret[2], QSTAT_HOST_DOWN)) {
172 printf ("ERROR: Game server down or unavailable\n");
173 result = STATE_CRITICAL;
174 }
175 else if (strstr (ret[2], QSTAT_HOST_TIMEOUT)) {
176 printf ("ERROR: Game server timeout\n");
177 result = STATE_CRITICAL;
178 }
179 else {
180 printf ("OK: %s/%s %s (%s), Ping: %s ms\n",
181 ret[qstat_game_players],
182 ret[qstat_game_players_max],
183 ret[qstat_game_field],
184 ret[qstat_map_field],
185 ret[qstat_ping_field]);
186 }
188 /* close the pipe */
189 spclose (fp);
191 return result;
192 }
196 int
197 process_arguments (int argc, char **argv)
198 {
199 int c;
201 int opt_index = 0;
202 static struct option long_opts[] = {
203 {"help", no_argument, 0, 'h'},
204 {"version", no_argument, 0, 'V'},
205 {"verbose", no_argument, 0, 'v'},
206 {"timeout", required_argument, 0, 't'},
207 {"hostname", required_argument, 0, 'H'},
208 {"port", required_argument, 0, 'P'},
209 {"game-type", required_argument, 0, 'G'},
210 {"map-field", required_argument, 0, 'm'},
211 {"ping-field", required_argument, 0, 'p'},
212 {"game-field", required_argument, 0, 'g'},
213 {"players-field", required_argument, 0, 129},
214 {"max-players-field", required_argument, 0, 130},
215 {0, 0, 0, 0}
216 };
218 if (argc < 2)
219 return ERROR;
221 for (c = 1; c < argc; c++) {
222 if (strcmp ("-mf", argv[c]) == 0)
223 strcpy (argv[c], "-m");
224 else if (strcmp ("-pf", argv[c]) == 0)
225 strcpy (argv[c], "-p");
226 else if (strcmp ("-gf", argv[c]) == 0)
227 strcpy (argv[c], "-g");
228 }
230 while (1) {
231 c = getopt_long (argc, argv, "hVvt:H:P:G:g:p:m:", long_opts, &opt_index);
233 if (c == -1 || c == EOF)
234 break;
236 switch (c) {
237 case '?': /* args not parsable */
238 printf (_("%s: Unknown argument: %s\n\n"), progname, optarg);
239 print_usage ();
240 exit (STATE_UNKNOWN);
241 case 'h': /* help */
242 print_help ();
243 exit (STATE_OK);
244 case 'V': /* version */
245 print_revision (progname, revision);
246 exit (STATE_OK);
247 case 'v': /* version */
248 verbose = TRUE;
249 break;
250 case 't': /* timeout period */
251 timeout_interval = atoi (optarg);
252 break;
253 case 'H': /* hostname */
254 if (strlen (optarg) >= MAX_HOST_ADDRESS_LENGTH)
255 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
256 server_ip = strdup (optarg);
257 break;
258 case 'P': /* port */
259 port = atoi (optarg);
260 break;
261 case 'G': /* hostname */
262 if (strlen (optarg) >= MAX_INPUT_BUFFER)
263 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
264 game_type = strdup (optarg);
265 break;
266 case 'p': /* index of ping field */
267 qstat_ping_field = atoi (optarg);
268 if (qstat_ping_field < 0 || qstat_ping_field > QSTAT_MAX_RETURN_ARGS)
269 return ERROR;
270 break;
271 case 'm': /* index on map field */
272 qstat_map_field = atoi (optarg);
273 if (qstat_map_field < 0 || qstat_map_field > QSTAT_MAX_RETURN_ARGS)
274 return ERROR;
275 break;
276 case 'g': /* index of game field */
277 qstat_game_field = atoi (optarg);
278 if (qstat_game_field < 0 || qstat_game_field > QSTAT_MAX_RETURN_ARGS)
279 return ERROR;
280 break;
281 case 129: /* index of player count field */
282 qstat_game_players = atoi (optarg);
283 if (qstat_game_players < 0 || qstat_game_players > QSTAT_MAX_RETURN_ARGS)
284 return ERROR;
285 break;
286 case 130: /* index of max players field */
287 qstat_game_players_max = atoi (optarg);
288 if (qstat_game_players_max < 0 || qstat_game_players_max > QSTAT_MAX_RETURN_ARGS)
289 return ERROR;
290 break;
291 }
292 }
294 c = optind;
295 /* first option is the game type */
296 if (!game_type && c<argc)
297 game_type = strdup (argv[c++]);
299 /* Second option is the server name */
300 if (!server_ip && c<argc)
301 server_ip = strdup (argv[c++]);
303 return validate_arguments ();
304 }
306 int
307 validate_arguments (void)
308 {
309 return OK;
310 }