Code

code cleanups, largely resulting from turning on -Wall. mostly
[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 "utils.h"
27 #include "runcmd.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         char *p, *ret[QSTAT_MAX_RETURN_ARGS];
60         size_t i = 0;
61         output chld_out;
63         setlocale (LC_ALL, "");
64         bindtextdomain (PACKAGE, LOCALEDIR);
65         textdomain (PACKAGE);
66         
67         if (process_arguments (argc, argv) == ERROR)
68                 usage_va(_("Could not parse arguments"));
70         result = STATE_OK;
72         /* create the command line to execute */
73         asprintf (&command_line, "%s -raw %s -%s %s",
74                                                 PATH_TO_QSTAT, QSTAT_DATA_DELIMITER, game_type, server_ip);
75         
76         if (port)
77                 asprintf (&command_line, "%s:%-d", command_line, port);
79         if (verbose > 0)
80                 printf ("%s\n", command_line);
82         /* run the command. historically, this plugin ignores output on stderr,
83          * as well as return status of the qstat program */
84         (void)np_runcmd(command_line, &chld_out, NULL, 0);
86         /* sanity check */
87         /* was thinking about running qstat without any options, capturing the
88            -default line, parsing it & making an array of all know server types
89            but thought this would be too much hassle considering this is a tool
90            for intelligent sysadmins (ha). Could put a static array of known 
91            server types in a header file but then we'd be limiting ourselves
93            In the end, I figured I'd simply let an error occur & then trap it
94          */
96         if (!strncmp (chld_out.line[0], "unknown option", 14)) {
97                 printf (_("CRITICAL - Host type parameter incorrect!\n"));
98                 result = STATE_CRITICAL;
99                 return result;
100         }
102         p = (char *) strtok (chld_out.line[0], QSTAT_DATA_DELIMITER);
103         while (p != NULL) {
104                 ret[i] = p;
105                 p = (char *) strtok (NULL, QSTAT_DATA_DELIMITER);
106                 i++;
107                 if (i >= QSTAT_MAX_RETURN_ARGS)
108                         break;
109         }
111         if (strstr (ret[2], QSTAT_HOST_ERROR)) {
112                 printf (_("CRITICAL - Host not found\n"));
113                 result = STATE_CRITICAL;
114         }
115         else if (strstr (ret[2], QSTAT_HOST_DOWN)) {
116                 printf (_("CRITICAL - Game server down or unavailable\n"));
117                 result = STATE_CRITICAL;
118         }
119         else if (strstr (ret[2], QSTAT_HOST_TIMEOUT)) {
120                 printf (_("CRITICAL - Game server timeout\n"));
121                 result = STATE_CRITICAL;
122         }
123         else {
124                 printf ("OK: %s/%s %s (%s), Ping: %s ms|%s %s\n", 
125                         ret[qstat_game_players],
126                         ret[qstat_game_players_max],
127                         ret[qstat_game_field], 
128                         ret[qstat_map_field],
129                         ret[qstat_ping_field],
130                         perfdata ("players", atol(ret[qstat_game_players]), "",
131                                   FALSE, 0, FALSE, 0,
132                                   TRUE, 0, TRUE, atol(ret[qstat_game_players_max])),
133                         fperfdata ("ping", strtod(ret[qstat_ping_field], NULL), "",
134                                   FALSE, 0, FALSE, 0,
135                                   TRUE, 0, FALSE, 0));
136         }
138         return result;
142 int
143 process_arguments (int argc, char **argv)
145         int c;
147         int opt_index = 0;
148         static struct option long_opts[] = {
149                 {"help", no_argument, 0, 'h'},
150                 {"version", no_argument, 0, 'V'},
151                 {"verbose", no_argument, 0, 'v'},
152                 {"timeout", required_argument, 0, 't'},
153                 {"hostname", required_argument, 0, 'H'},
154                 {"port", required_argument, 0, 'P'},
155                 {"game-type", required_argument, 0, 'G'},
156                 {"map-field", required_argument, 0, 'm'},
157                 {"ping-field", required_argument, 0, 'p'},
158                 {"game-field", required_argument, 0, 'g'},
159                 {"players-field", required_argument, 0, 129},
160                 {"max-players-field", required_argument, 0, 130},
161                 {0, 0, 0, 0}
162         };
164         if (argc < 2)
165                 return ERROR;
167         for (c = 1; c < argc; c++) {
168                 if (strcmp ("-mf", argv[c]) == 0)
169                         strcpy (argv[c], "-m");
170                 else if (strcmp ("-pf", argv[c]) == 0)
171                         strcpy (argv[c], "-p");
172                 else if (strcmp ("-gf", argv[c]) == 0)
173                         strcpy (argv[c], "-g");
174         }
176         while (1) {
177                 c = getopt_long (argc, argv, "hVvt:H:P:G:g:p:m:", long_opts, &opt_index);
179                 if (c == -1 || c == EOF)
180                         break;
182                 switch (c) {
183                 case 'h': /* help */
184                         print_help ();
185                         exit (STATE_OK);
186                 case 'V': /* version */
187                         print_revision (progname, revision);
188                         exit (STATE_OK);
189                 case 'v': /* version */
190                         verbose = TRUE;
191                         break;
192                 case 't': /* timeout period */
193                         timeout_interval = atoi (optarg);
194                         break;
195                 case 'H': /* hostname */
196                         if (strlen (optarg) >= MAX_HOST_ADDRESS_LENGTH)
197                                 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
198                         server_ip = optarg;
199                         break;
200                 case 'P': /* port */
201                         port = atoi (optarg);
202                         break;
203                 case 'G': /* hostname */
204                         if (strlen (optarg) >= MAX_INPUT_BUFFER)
205                                 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
206                         game_type = optarg;
207                         break;
208                 case 'p': /* index of ping field */
209                         qstat_ping_field = atoi (optarg);
210                         if (qstat_ping_field < 0 || qstat_ping_field > QSTAT_MAX_RETURN_ARGS)
211                                 return ERROR;
212                         break;
213                 case 'm': /* index on map field */
214                         qstat_map_field = atoi (optarg);
215                         if (qstat_map_field < 0 || qstat_map_field > QSTAT_MAX_RETURN_ARGS)
216                                 return ERROR;
217                         break;
218                 case 'g': /* index of game field */
219                         qstat_game_field = atoi (optarg);
220                         if (qstat_game_field < 0 || qstat_game_field > QSTAT_MAX_RETURN_ARGS)
221                                 return ERROR;
222                         break;
223                 case 129: /* index of player count field */
224                         qstat_game_players = atoi (optarg);
225                         if (qstat_game_players_max == 0)
226                                 qstat_game_players_max = qstat_game_players - 1;
227                         if (qstat_game_players < 0 || qstat_game_players > QSTAT_MAX_RETURN_ARGS)
228                                 return ERROR;
229                         break;
230                 case 130: /* index of max players field */
231                         qstat_game_players_max = atoi (optarg);
232                         if (qstat_game_players_max < 0 || qstat_game_players_max > QSTAT_MAX_RETURN_ARGS)
233                                 return ERROR;
234                         break;
235                 default: /* args not parsable */
236                         usage_va(_("Unknown argument - %s"), optarg);
237                 }
238         }
240         c = optind;
241         /* first option is the game type */
242         if (!game_type && c<argc)
243                 game_type = strdup (argv[c++]);
245         /* Second option is the server name */
246         if (!server_ip && c<argc)
247                 server_ip = strdup (argv[c++]);
249         return validate_arguments ();
253 int
254 validate_arguments (void)
256         if (qstat_game_players_max < 0)
257                 qstat_game_players_max = 4;
259         if (qstat_game_players < 0)
260                 qstat_game_players = 5;
262         if (qstat_game_field < 0)
263                 qstat_game_field = 2;
265         if (qstat_map_field < 0)
266                 qstat_map_field = 3;
268         if (qstat_ping_field < 0)
269                 qstat_ping_field = 5;
271         return OK;
275 void
276 print_help (void)
278         print_revision (progname, revision);
280         printf ("Copyright (c) 1999 Ian Cass, Knowledge Matters Limited\n");
281         printf (COPYRIGHT, copyright, email);
283         printf (_("This plugin tests game server connections with the specified host."));
285         print_usage ();
287         printf (_(UT_HELP_VRSN));
289         printf (_("\
290 <game>        = Game type that is recognised by qstat (without the leading dash)\n\
291 <ip_address>  = The IP address of the device you wish to query\n\
292  [port]        = Optional port of which to connect\n\
293  [game_field]  = Field number in raw qstat output that contains game name\n\
294  [map_field]   = Field number in raw qstat output that contains map name\n\
295  [ping_field]  = Field number in raw qstat output that contains ping time\n"));
297         printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
299         printf (_("\n\
300 Notes:\n\
301 - This plugin uses the 'qstat' command, the popular game server status query tool .\n\
302   If you don't have the package installed, you will need to download it from\n\
303   http://www.activesw.com/people/steve/qstat.html before you can use this plugin.\n"));
305         printf (_(UT_SUPPORT));
310 void
311 print_usage (void)
313         printf ("\
314 Usage: %s <game> <ip_address> [-p port] [-gf game_field] [-mf map_field]\n\
315                   [-pf ping_field]\n", progname);
318 /******************************************************************************
319  *
320  * Test Cases:
321  *
322  * ./check_game --players 7 -p 8 --map 5 qs 67.20.190.61 26000
323  * 
324  * qstat -raw , -qs 67.20.190.61
325  *  ==> QS,67.20.190.61,Nightmare.fintek.ca,67.20.190.61:26000,3,e2m1,6,0,83,0
326  *
327  * qstat -qs 67.20.190.61
328  *  ==> ADDRESS           PLAYERS      MAP   RESPONSE TIME    NAME
329  *  ==> 67.20.190.61            0/ 6     e2m1     79 / 0   Nightmare.fintek.ca
330  *
331  ******************************************************************************/