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