Code

various fixes for localization
[nagiosplug.git] / plugins / check_game.c
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 * $Id$
18 *****************************************************************************/
20 const char *progname = "check_game";
21 const char *revision = "$Revision$";
22 const char *copyright = "2002-2004";
23 const char *email = "nagiosplug-devel@lists.sourceforge.net";
25 #include "common.h"
26 #include "popen.h"
27 #include "utils.h"
29 int process_arguments (int, char **);
30 int validate_arguments (void);
31 void print_help (void);
32 void print_usage (void);
34 #define QSTAT_DATA_DELIMITER    ","
36 #define QSTAT_HOST_ERROR        "ERROR"
37 #define QSTAT_HOST_DOWN         "DOWN"
38 #define QSTAT_HOST_TIMEOUT      "TIMEOUT"
39 #define QSTAT_MAX_RETURN_ARGS   12
41 char *server_ip;
42 char *game_type;
43 int port = 0;
45 int verbose;
47 int qstat_game_players_max = -1;
48 int qstat_game_players = -1;
49 int qstat_game_field = -1;
50 int qstat_map_field = -1;
51 int qstat_ping_field = -1;
54 int
55 main (int argc, char **argv)
56 {
57         char *command_line;
58         int result = STATE_UNKNOWN;
59         FILE *fp;
60         char input_buffer[MAX_INPUT_BUFFER];
61         char *p, *ret[QSTAT_MAX_RETURN_ARGS];
62         int i;
64         setlocale (LC_ALL, "");
65         bindtextdomain (PACKAGE, LOCALEDIR);
66         textdomain (PACKAGE);
67         
68         if (process_arguments (argc, argv) == ERROR)
69                 usage4 (_("Could not parse arguments"));
71         result = STATE_OK;
73         /* create the command line to execute */
74         asprintf (&command_line, "%s -raw %s -%s %s",
75                                                 PATH_TO_QSTAT, QSTAT_DATA_DELIMITER, game_type, server_ip);
76         
77         if (port)
78                 asprintf (&command_line, "%s:%-d", command_line, port);
80         if (verbose > 0)
81                 printf ("%s\n", command_line);
83         /* run the command */
84         fp = spopen (command_line);
85         if (fp == NULL) {
86                 printf (_("Could not open pipe: %s\n"), command_line);
87                 return STATE_UNKNOWN;
88         }
90         fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp); /* Only interested in the first line */
92         /* strip the newline character from the end of the input */
93         input_buffer[strlen (input_buffer) - 1] = 0;
95         /* sanity check */
96         /* was thinking about running qstat without any options, capturing the
97            -default line, parsing it & making an array of all know server types
98            but thought this would be too much hassle considering this is a tool
99            for intelligent sysadmins (ha). Could put a static array of known 
100            server types in a header file but then we'd be limiting ourselves
102            In the end, I figured I'd simply let an error occur & then trap it
103          */
105         if (!strncmp (input_buffer, "unknown option", 14)) {
106                 printf (_("CRITICAL - Host type parameter incorrect!\n"));
107                 result = STATE_CRITICAL;
108                 return result;
109         }
111         /* initialize the returned data buffer */
112         for (i = 0; i < QSTAT_MAX_RETURN_ARGS; i++)
113                 ret[i] = strdup("");
115         i = 0;
116         p = (char *) strtok (input_buffer, QSTAT_DATA_DELIMITER);
117         while (p != NULL) {
118                 ret[i] = p;
119                 p = (char *) strtok (NULL, QSTAT_DATA_DELIMITER);
120                 i++;
121                 if (i >= QSTAT_MAX_RETURN_ARGS)
122                         break;
123         }
125         if (strstr (ret[2], QSTAT_HOST_ERROR)) {
126                 printf (_("CRITICAL - Host not found\n"));
127                 result = STATE_CRITICAL;
128         }
129         else if (strstr (ret[2], QSTAT_HOST_DOWN)) {
130                 printf (_("CRITICAL - Game server down or unavailable\n"));
131                 result = STATE_CRITICAL;
132         }
133         else if (strstr (ret[2], QSTAT_HOST_TIMEOUT)) {
134                 printf (_("CRITICAL - Game server timeout\n"));
135                 result = STATE_CRITICAL;
136         }
137         else {
138                 printf ("OK: %s/%s %s (%s), Ping: %s ms|%s %s\n", 
139                         ret[qstat_game_players],
140                         ret[qstat_game_players_max],
141                         ret[qstat_game_field], 
142                         ret[qstat_map_field],
143                         ret[qstat_ping_field],
144                                                 perfdata ("players", atol(ret[qstat_game_players]), "",
145                                   FALSE, 0, FALSE, 0,
146                                   TRUE, 0, TRUE, atol(ret[qstat_game_players_max])),
147                                                 fperfdata ("ping", strtod(ret[qstat_ping_field], NULL), "",
148                                   FALSE, 0, FALSE, 0,
149                                   TRUE, 0, FALSE, 0));
150         }
152         /* close the pipe */
153         spclose (fp);
155         return result;
159 int
160 process_arguments (int argc, char **argv)
162         int c;
164         int opt_index = 0;
165         static struct option long_opts[] = {
166                 {"help", no_argument, 0, 'h'},
167                 {"version", no_argument, 0, 'V'},
168                 {"verbose", no_argument, 0, 'v'},
169                 {"timeout", required_argument, 0, 't'},
170                 {"hostname", required_argument, 0, 'H'},
171                 {"port", required_argument, 0, 'P'},
172                 {"game-type", required_argument, 0, 'G'},
173                 {"map-field", required_argument, 0, 'm'},
174                 {"ping-field", required_argument, 0, 'p'},
175                 {"game-field", required_argument, 0, 'g'},
176                 {"players-field", required_argument, 0, 129},
177                 {"max-players-field", required_argument, 0, 130},
178                 {0, 0, 0, 0}
179         };
181         if (argc < 2)
182                 return ERROR;
184         for (c = 1; c < argc; c++) {
185                 if (strcmp ("-mf", argv[c]) == 0)
186                         strcpy (argv[c], "-m");
187                 else if (strcmp ("-pf", argv[c]) == 0)
188                         strcpy (argv[c], "-p");
189                 else if (strcmp ("-gf", argv[c]) == 0)
190                         strcpy (argv[c], "-g");
191         }
193         while (1) {
194                 c = getopt_long (argc, argv, "hVvt:H:P:G:g:p:m:", long_opts, &opt_index);
196                 if (c == -1 || c == EOF)
197                         break;
199                 switch (c) {
200                 case '?': /* args not parsable */
201                         usage2 (_("Unknown argument"), optarg);
202                 case 'h': /* help */
203                         print_help ();
204                         exit (STATE_OK);
205                 case 'V': /* version */
206                         print_revision (progname, revision);
207                         exit (STATE_OK);
208                 case 'v': /* version */
209                         verbose = TRUE;
210                         break;
211                 case 't': /* timeout period */
212                         timeout_interval = atoi (optarg);
213                         break;
214                 case 'H': /* hostname */
215                         if (strlen (optarg) >= MAX_HOST_ADDRESS_LENGTH)
216                                 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
217                         server_ip = optarg;
218                         break;
219                 case 'P': /* port */
220                         port = atoi (optarg);
221                         break;
222                 case 'G': /* hostname */
223                         if (strlen (optarg) >= MAX_INPUT_BUFFER)
224                                 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
225                         game_type = optarg;
226                         break;
227                 case 'p': /* index of ping field */
228                         qstat_ping_field = atoi (optarg);
229                         if (qstat_ping_field < 0 || qstat_ping_field > QSTAT_MAX_RETURN_ARGS)
230                                 return ERROR;
231                         break;
232                 case 'm': /* index on map field */
233                         qstat_map_field = atoi (optarg);
234                         if (qstat_map_field < 0 || qstat_map_field > QSTAT_MAX_RETURN_ARGS)
235                                 return ERROR;
236                         break;
237                 case 'g': /* index of game field */
238                         qstat_game_field = atoi (optarg);
239                         if (qstat_game_field < 0 || qstat_game_field > QSTAT_MAX_RETURN_ARGS)
240                                 return ERROR;
241                         break;
242                 case 129: /* index of player count field */
243                         qstat_game_players = atoi (optarg);
244                         if (qstat_game_players_max == 0)
245                                 qstat_game_players_max = qstat_game_players - 1;
246                         if (qstat_game_players < 0 || qstat_game_players > QSTAT_MAX_RETURN_ARGS)
247                                 return ERROR;
248                         break;
249                 case 130: /* index of max players field */
250                         qstat_game_players_max = atoi (optarg);
251                         if (qstat_game_players_max < 0 || qstat_game_players_max > QSTAT_MAX_RETURN_ARGS)
252                                 return ERROR;
253                         break;
254                 }
255         }
257         c = optind;
258         /* first option is the game type */
259         if (!game_type && c<argc)
260                 game_type = strdup (argv[c++]);
262         /* Second option is the server name */
263         if (!server_ip && c<argc)
264                 server_ip = strdup (argv[c++]);
266         return validate_arguments ();
270 int
271 validate_arguments (void)
273         if (qstat_game_players_max < 0)
274                 qstat_game_players_max = 4;
276         if (qstat_game_players < 0)
277                 qstat_game_players = 5;
279         if (qstat_game_field < 0)
280                 qstat_game_field = 2;
282         if (qstat_map_field < 0)
283                 qstat_map_field = 3;
285         if (qstat_ping_field < 0)
286                 qstat_ping_field = 5;
288         return OK;
292 void
293 print_help (void)
295         print_revision (progname, revision);
297         printf ("Copyright (c) 1999 Ian Cass, Knowledge Matters Limited\n");
298         printf (COPYRIGHT, copyright, email);
300         printf (_("This plugin tests game server connections with the specified host."));
302         print_usage ();
304         printf (_(UT_HELP_VRSN));
306         printf (_("\
307 <game>        = Game type that is recognised by qstat (without the leading dash)\n\
308 <ip_address>  = The IP address of the device you wish to query\n\
309  [port]        = Optional port of which to connect\n\
310  [game_field]  = Field number in raw qstat output that contains game name\n\
311  [map_field]   = Field number in raw qstat output that contains map name\n\
312  [ping_field]  = Field number in raw qstat output that contains ping time\n"));
314         printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
316         printf (_("\n\
317 Notes:\n\
318 - This plugin uses the 'qstat' command, the popular game server status query tool .\n\
319   If you don't have the package installed, you will need to download it from\n\
320   http://www.activesw.com/people/steve/qstat.html before you can use this plugin.\n"));
322         printf (_(UT_SUPPORT));
327 void
328 print_usage (void)
330         printf ("\
331 Usage: %s <game> <ip_address> [-p port] [-gf game_field] [-mf map_field]\n\
332                   [-pf ping_field]\n", progname);
335 /******************************************************************************
336  *
337  * Test Cases:
338  *
339  * ./check_game --players 7 -p 8 --map 5 qs 67.20.190.61 26000
340  * 
341  * qstat -raw , -qs 67.20.190.61
342  *  ==> QS,67.20.190.61,Nightmare.fintek.ca,67.20.190.61:26000,3,e2m1,6,0,83,0
343  *
344  * qstat -qs 67.20.190.61
345  *  ==> ADDRESS           PLAYERS      MAP   RESPONSE TIME    NAME
346  *  ==> 67.20.190.61            0/ 6     e2m1     79 / 0   Nightmare.fintek.ca
347  *
348  ******************************************************************************/