check_game.c 9.2 KB

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