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