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 setlocale (LC_ALL, "");
64 bindtextdomain (PACKAGE, LOCALEDIR);
65 textdomain (PACKAGE);
67 result = process_arguments (argc, argv);
69 if (result != OK) {
70 printf (_("Incorrect arguments supplied\n"));
71 printf ("\n");
72 print_revision (progname, revision);
73 printf (_("Copyright (c) 1999 Ian Cass, Knowledge Matters Limited\n"));
74 printf (_("License: GPL\n"));
75 printf ("\n");
76 return STATE_UNKNOWN;
77 }
79 result = STATE_OK;
81 /* create the command line to execute */
82 asprintf (&command_line, "%s -raw %s -%s %s",
83 PATH_TO_QSTAT, QSTAT_DATA_DELIMITER, game_type, server_ip);
85 if (port)
86 asprintf (&command_line, "%s:%-d", command_line, port);
88 if (verbose > 0)
89 printf ("%s\n", command_line);
91 /* run the command */
92 fp = spopen (command_line);
93 if (fp == NULL) {
94 printf (_("Error - Could not open pipe: %s\n"), command_line);
95 return STATE_UNKNOWN;
96 }
98 fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp); /* Only interested in the first line */
100 /* strip the newline character from the end of the input */
101 input_buffer[strlen (input_buffer) - 1] = 0;
103 /* sanity check */
104 /* was thinking about running qstat without any options, capturing the
105 -default line, parsing it & making an array of all know server types
106 but thought this would be too much hassle considering this is a tool
107 for intelligent sysadmins (ha). Could put a static array of known
108 server types in a header file but then we'd be limiting ourselves
110 In the end, I figured I'd simply let an error occur & then trap it
111 */
113 if (!strncmp (input_buffer, "unknown option", 14)) {
114 printf (_("ERROR: Host type parameter incorrect!\n"));
115 result = STATE_CRITICAL;
116 return result;
117 }
119 /* initialize the returned data buffer */
120 for (i = 0; i < QSTAT_MAX_RETURN_ARGS; i++)
121 ret[i] = strdup("");
123 i = 0;
124 p = (char *) strtok (input_buffer, QSTAT_DATA_DELIMITER);
125 while (p != NULL) {
126 ret[i] = p;
127 p = (char *) strtok (NULL, QSTAT_DATA_DELIMITER);
128 i++;
129 if (i >= QSTAT_MAX_RETURN_ARGS)
130 break;
131 }
133 if (strstr (ret[2], QSTAT_HOST_ERROR)) {
134 printf ("ERROR: Host not found\n");
135 result = STATE_CRITICAL;
136 }
137 else if (strstr (ret[2], QSTAT_HOST_DOWN)) {
138 printf ("ERROR: Game server down or unavailable\n");
139 result = STATE_CRITICAL;
140 }
141 else if (strstr (ret[2], QSTAT_HOST_TIMEOUT)) {
142 printf ("ERROR: Game server timeout\n");
143 result = STATE_CRITICAL;
144 }
145 else {
146 printf ("OK: %s/%s %s (%s), Ping: %s ms\n",
147 ret[qstat_game_players],
148 ret[qstat_game_players_max],
149 ret[qstat_game_field],
150 ret[qstat_map_field],
151 ret[qstat_ping_field]);
152 }
154 /* close the pipe */
155 spclose (fp);
157 return result;
158 }
162 int
163 process_arguments (int argc, char **argv)
164 {
165 int c;
167 int opt_index = 0;
168 static struct option long_opts[] = {
169 {"help", no_argument, 0, 'h'},
170 {"version", no_argument, 0, 'V'},
171 {"verbose", no_argument, 0, 'v'},
172 {"timeout", required_argument, 0, 't'},
173 {"hostname", required_argument, 0, 'H'},
174 {"port", required_argument, 0, 'P'},
175 {"game-type", required_argument, 0, 'G'},
176 {"map-field", required_argument, 0, 'm'},
177 {"ping-field", required_argument, 0, 'p'},
178 {"game-field", required_argument, 0, 'g'},
179 {"players-field", required_argument, 0, 129},
180 {"max-players-field", required_argument, 0, 130},
181 {0, 0, 0, 0}
182 };
184 if (argc < 2)
185 return ERROR;
187 for (c = 1; c < argc; c++) {
188 if (strcmp ("-mf", argv[c]) == 0)
189 strcpy (argv[c], "-m");
190 else if (strcmp ("-pf", argv[c]) == 0)
191 strcpy (argv[c], "-p");
192 else if (strcmp ("-gf", argv[c]) == 0)
193 strcpy (argv[c], "-g");
194 }
196 while (1) {
197 c = getopt_long (argc, argv, "hVvt:H:P:G:g:p:m:", long_opts, &opt_index);
199 if (c == -1 || c == EOF)
200 break;
202 switch (c) {
203 case '?': /* args not parsable */
204 printf (_("%s: Unknown argument: %s\n\n"), progname, optarg);
205 print_usage ();
206 exit (STATE_UNKNOWN);
207 case 'h': /* help */
208 print_help ();
209 exit (STATE_OK);
210 case 'V': /* version */
211 print_revision (progname, revision);
212 exit (STATE_OK);
213 case 'v': /* version */
214 verbose = TRUE;
215 break;
216 case 't': /* timeout period */
217 timeout_interval = atoi (optarg);
218 break;
219 case 'H': /* hostname */
220 if (strlen (optarg) >= MAX_HOST_ADDRESS_LENGTH)
221 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
222 server_ip = optarg;
223 break;
224 case 'P': /* port */
225 port = atoi (optarg);
226 break;
227 case 'G': /* hostname */
228 if (strlen (optarg) >= MAX_INPUT_BUFFER)
229 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
230 game_type = optarg;
231 break;
232 case 'p': /* index of ping field */
233 qstat_ping_field = atoi (optarg);
234 if (qstat_ping_field < 0 || qstat_ping_field > QSTAT_MAX_RETURN_ARGS)
235 return ERROR;
236 break;
237 case 'm': /* index on map field */
238 qstat_map_field = atoi (optarg);
239 if (qstat_map_field < 0 || qstat_map_field > QSTAT_MAX_RETURN_ARGS)
240 return ERROR;
241 break;
242 case 'g': /* index of game field */
243 qstat_game_field = atoi (optarg);
244 if (qstat_game_field < 0 || qstat_game_field > QSTAT_MAX_RETURN_ARGS)
245 return ERROR;
246 break;
247 case 129: /* index of player count field */
248 qstat_game_players = atoi (optarg);
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 return OK;
276 }
282 \f
283 void
284 print_help (void)
285 {
286 print_revision (progname, revision);
288 printf (_(COPYRIGHT), copyright, email);
290 printf (_("This plugin tests %s connections with the specified host."), progname);
292 print_usage ();
294 printf (_(UT_HELP_VRSN));
296 printf (_("\
297 <game> = Game type that is recognised by qstat (without the leading dash)\n\
298 <ip_address> = The IP address of the device you wish to query\n\
299 [port] = Optional port of which to connect\n\
300 [game_field] = Field number in raw qstat output that contains game name\n\
301 [map_field] = Field number in raw qstat output that contains map name\n\
302 [ping_field] = Field number in raw qstat output that contains ping time\n"));
304 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
306 printf (_("\n\
307 Notes:\n\
308 - This plugin uses the 'qstat' command, the popular game server status query tool .\n\
309 If you don't have the package installed, you will need to download it from\n\
310 http://www.activesw.com/people/steve/qstat.html before you can use this plugin.\n"));
312 printf (_(UT_SUPPORT));
313 }
318 void
319 print_usage (void)
320 {
321 printf (_("\
322 Usage: %s <game> <ip_address> [-p port] [-gf game_field] [-mf map_field]\n\
323 [-pf ping_field]\n"), progname);
324 printf (_(UT_HLP_VRS), progname, progname);
325 }