Code

Initial revision
[nagiosplug.git] / plugins / check_game.c
1 /******************************************************************************
2  *
3  * CHECK_GAME.C
4  *
5  * Program: GAME plugin for Nagios
6  * License: GPL
7  * Copyright (c) 1999 Ian Cass (ian@knowledge.com)
8  *
9  * Last Modified: $Date$
10  *
11  * Mod History
12  *
13  * 25-8-99 Ethan Galstad <nagios@nagios.org>
14  *         Integrated with common plugin code, minor cleanup stuff
15  *
16  * 17-8-99 version 1.1b
17  *
18  * 17-8-99 make port a separate argument so we can use something like
19  *         check_game q2s!27910 with the probe set up as
20  *         check_game $ARG1$ $HOSTADDRESS$ $ARG2$
21  *
22  * 17-8-99 Put in sanity check for ppl who enter the wrong server type
23  *
24  * 17-8-99 Release version 1.0b
25  *
26  * Command line: CHECK_GAME <server type> <ip_address> [port]
27  *
28  * server type = a server type that qstat understands (type qstat & look at the -default line)
29  * ip_address  = either a dotted address or a FQD name
30  * port        = defaults game default port
31  *                        
32  *
33  * Description:
34  * 
35  * Needed to explore writing my own probes for nagios. It looked
36  * pretty simple so I thought I'd write one for monitoring the status
37  * of game servers. It uses qstat to do the actual monitoring and
38  * analyses the result. Doing it this way means I can support all the
39  * servers that qstat does and will do in the future.
40  *
41  *
42  * Dependencies:
43  *
44  * This plugin uses the 'qstat' command If you don't
45  * have the package installed you will need to download it from 
46  * http://www.activesw.com/people/steve/qstat.html or any popular files archive
47  * before you can use this plugin.
48  *
49  * License Information:
50  *
51  * This program is free software; you can redistribute it and/or modify
52  * it under the terms of the GNU General Public License as published by
53  * the Free Software Foundation; either version 2 of the License, or
54  * (at your option) any later version.
55  *
56  * This program is distributed in the hope that it will be useful,
57  * but WITHOUT ANY WARRANTY; without even the implied warranty of
58  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
59  * GNU General Public License for more details.
60  *
61  * You should have received a copy of the GNU General Public License
62  * along with this program; if not, write to the Free Software
63  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
64  *
65  *****************************************************************************/
67 #include "config.h"
68 #include "common.h"
69 #include "utils.h"
71 int process_arguments (int, char **);
73 #define QSTAT_DATA_DELIMITER    ","
75 #define QSTAT_HOST_ERROR        "ERROR"
76 #define QSTAT_HOST_DOWN         "DOWN"
77 #define QSTAT_HOST_TIMEOUT      "TIMEOUT"
78 #define QSTAT_MAX_RETURN_ARGS   12
80 char server_ip[MAX_HOST_ADDRESS_LENGTH];
81 char game_type[MAX_INPUT_BUFFER];
82 char port[MAX_INPUT_BUFFER];
84 int qstat_game_field = 2;
85 int qstat_map_field = 3;
86 int qstat_ping_field = 5;
89 int
90 main (int argc, char **argv)
91 {
92         char command_line[MAX_INPUT_BUFFER];
93         int result;
94         FILE *fp;
95         char input_buffer[MAX_INPUT_BUFFER];
96         char response[MAX_INPUT_BUFFER];
97         char *temp_ptr;
98         int found;
99         char *p, *ret[QSTAT_MAX_RETURN_ARGS];
100         int i;
102         result = process_arguments (argc, argv);
104         if (result != OK) {
105                 printf ("Incorrect arguments supplied\n");
106                 printf ("\n");
107                 print_revision (argv[0], "$Revision$");
108                 printf ("Copyright (c) 1999 Ian Cass, Knowledge Matters Limited\n");
109                 printf ("License: GPL\n");
110                 printf ("\n");
111                 printf
112                         ("Usage: %s <game> <ip_address> [-p port] [-gf game_field] [-mf map_field] [-pf ping_field]\n",
113                          argv[0]);
114                 printf ("\n");
115                 printf ("Options:\n");
116                 printf
117                         (" <game>        = Game type that is recognised by qstat (without the leading dash)\n");
118                 printf
119                         (" <ip_address>  = The IP address of the device you wish to query\n");
120                 printf (" [port]        = Optional port of which to connect\n");
121                 printf
122                         (" [game_field]  = Field number in raw qstat output that contains game name\n");
123                 printf
124                         (" [map_field]   = Field number in raw qstat output that contains map name\n");
125                 printf
126                         (" [ping_field]  = Field number in raw qstat output that contains ping time\n");
127                 printf ("\n");
128                 printf ("Notes:\n");
129                 printf
130                         ("- This plugin uses the 'qstat' command, the popular game server status query tool .\n");
131                 printf
132                         ("  If you don't have the package installed, you will need to download it from\n");
133                 printf
134                         ("  http://www.activesw.com/people/steve/qstat.html before you can use this plugin.\n");
135                 printf ("\n");
136                 return STATE_UNKNOWN;
137         }
139         result = STATE_OK;
141         /* create the command line to execute */
142         snprintf (command_line, sizeof (command_line) - 1, "%s -raw %s -%s %s%s",
143                                                 PATH_TO_QSTAT, QSTAT_DATA_DELIMITER, game_type, server_ip, port);
144         command_line[sizeof (command_line) - 1] = 0;
146         /* run the command */
147         fp = popen (command_line, "r");
148         if (fp == NULL) {
149                 printf ("Error - Could not open pipe: %s\n", command_line);
150                 return STATE_UNKNOWN;
151         }
153         found = 0;
154         fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp); /* Only interested in the first line */
156         /* strip the newline character from the end of the input */
157         input_buffer[strlen (input_buffer) - 1] = 0;
159         /* sanity check */
160         /* was thinking about running qstat without any options, capturing the
161            -default line, parsing it & making an array of all know server types
162            but thought this would be too much hassle considering this is a tool
163            for intelligent sysadmins (ha). Could put a static array of known 
164            server types in a header file but then we'd be limiting ourselves
166            In the end, I figured I'd simply let an error occur & then trap it
167          */
169         if (!strncmp (input_buffer, "unknown option", 14)) {
170                 printf ("ERROR: Host type parameter incorrect!\n");
171                 result = STATE_CRITICAL;
172                 return result;
173         }
175         /* initialize the returned data buffer */
176         for (i = 0; i < QSTAT_MAX_RETURN_ARGS; i++)
177                 ret[i] = "";
179         i = 0;
180         p = (char *) strtok (input_buffer, QSTAT_DATA_DELIMITER);
181         while (p != NULL) {
182                 ret[i] = p;
183                 p = (char *) strtok (NULL, QSTAT_DATA_DELIMITER);
184                 i++;
185                 if (i >= QSTAT_MAX_RETURN_ARGS)
186                         break;
187         }
189         if (strstr (ret[2], QSTAT_HOST_ERROR)) {
190                 printf ("ERROR: Host not found\n");
191                 result = STATE_CRITICAL;
192         }
193         else if (strstr (ret[2], QSTAT_HOST_DOWN)) {
194                 printf ("ERROR: Game server down or unavailable\n");
195                 result = STATE_CRITICAL;
196         }
197         else if (strstr (ret[2], QSTAT_HOST_TIMEOUT)) {
198                 printf ("ERROR: Game server timeout\n");
199                 result = STATE_CRITICAL;
200         }
201         else {
202                 printf ("OK: %s (%s), Ping: %s ms\n", ret[qstat_game_field],
203                                                 ret[qstat_map_field], ret[qstat_ping_field]);
204         }
206         /* close the pipe */
207         pclose (fp);
209         return result;
214 int
215 process_arguments (int argc, char **argv)
217         int x;
219         /* not enough options were supplied */
220         if (argc < 3)
221                 return ERROR;
223         /* first option is always the game type */
224         strncpy (game_type, argv[1], sizeof (game_type) - 1);
225         game_type[sizeof (game_type) - 1] = 0;
227         /* Second option is always the server name */
228         strncpy (server_ip, argv[2], sizeof (server_ip) - 1);
229         server_ip[sizeof (server_ip) - 1] = 0;
231         /* process all remaining arguments */
232         for (x = 4; x <= argc; x++) {
234                 /* we got the port number to connect to */
235                 if (!strcmp (argv[x - 1], "-p")) {
236                         if (x < argc) {
237                                 snprintf (port, sizeof (port) - 2, ":%s", argv[x]);
238                                 port[sizeof (port) - 1] = 0;
239                                 x++;
240                         }
241                         else
242                                 return ERROR;
243                 }
245                 /* we got the game field */
246                 else if (!strcmp (argv[x - 1], "-gf")) {
247                         if (x < argc) {
248                                 qstat_game_field = atoi (argv[x]);
249                                 if (qstat_game_field < 0 || qstat_game_field > QSTAT_MAX_RETURN_ARGS)
250                                         return ERROR;
251                                 x++;
252                         }
253                         else
254                                 return ERROR;
255                 }
257                 /* we got the map field */
258                 else if (!strcmp (argv[x - 1], "-mf")) {
259                         if (x < argc) {
260                                 qstat_map_field = atoi (argv[x]);
261                                 if (qstat_map_field < 0 || qstat_map_field > QSTAT_MAX_RETURN_ARGS)
262                                         return ERROR;
263                                 x++;
264                         }
265                         else
266                                 return ERROR;
267                 }
269                 /* we got the ping field */
270                 else if (!strcmp (argv[x - 1], "-pf")) {
271                         if (x < argc) {
272                                 qstat_ping_field = atoi (argv[x]);
273                                 if (qstat_ping_field < 0 || qstat_ping_field > QSTAT_MAX_RETURN_ARGS)
274                                         return ERROR;
275                                 x++;
276                         }
277                         else
278                                 return ERROR;
279                 }
281                 /* else we got something else... */
282                 else
283                         return ERROR;
284         }
286         return OK;