check_game.c 8.7 KB

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