check_ups.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  1. /******************************************************************************
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation; either version 2 of the License, or (at
  5. your option) any later version.
  6. This program is distributed in the hope that it will be useful, but
  7. WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  9. General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program; if not, write to the Free Software
  12. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  13. ******************************************************************************/
  14. const char *progname = "check_ups";
  15. const char *revision = "$Revision$";
  16. const char *copyright = "2000-2002";
  17. const char *email = "nagiosplug-devel@lists.sourceforge.net";
  18. #include "common.h"
  19. #include "netutils.h"
  20. #include "utils.h"
  21. enum {
  22. PORT = 3493
  23. };
  24. #define CHECK_NONE 0
  25. #define UPS_NONE 0 /* no supported options */
  26. #define UPS_UTILITY 1 /* supports utility line voltage */
  27. #define UPS_BATTPCT 2 /* supports percent battery remaining */
  28. #define UPS_STATUS 4 /* supports UPS status */
  29. #define UPS_TEMP 8 /* supports UPS temperature */
  30. #define UPS_LOADPCT 16 /* supports load percent */
  31. #define UPSSTATUS_NONE 0
  32. #define UPSSTATUS_OFF 1
  33. #define UPSSTATUS_OL 2
  34. #define UPSSTATUS_OB 4
  35. #define UPSSTATUS_LB 8
  36. #define UPSSTATUS_CAL 16
  37. #define UPSSTATUS_RB 32 /*Replace Battery */
  38. #define UPSSTATUS_UNKOWN 64
  39. int server_port = PORT;
  40. char *server_address;
  41. char *ups_name = NULL;
  42. double warning_value = 0.0;
  43. double critical_value = 0.0;
  44. int check_warning_value = FALSE;
  45. int check_critical_value = FALSE;
  46. int check_variable = UPS_NONE;
  47. int supported_options = UPS_NONE;
  48. int status = UPSSTATUS_NONE;
  49. double ups_utility_voltage = 0.0;
  50. double ups_battery_percent = 0.0;
  51. double ups_load_percent = 0.0;
  52. double ups_temperature = 0.0;
  53. char *ups_status;
  54. int determine_status (void);
  55. int determine_supported_vars (void);
  56. int get_ups_variable (const char *, char *, size_t);
  57. int process_arguments (int, char **);
  58. int validate_arguments (void);
  59. void print_help (void);
  60. void print_usage (void);
  61. int
  62. main (int argc, char **argv)
  63. {
  64. int result = STATE_OK;
  65. char *message;
  66. char temp_buffer[MAX_INPUT_BUFFER];
  67. double ups_utility_deviation = 0.0;
  68. setlocale (LC_ALL, "");
  69. bindtextdomain (PACKAGE, LOCALEDIR);
  70. textdomain (PACKAGE);
  71. ups_status = strdup ("N/A");
  72. if (process_arguments (argc, argv) != OK)
  73. usage ("Invalid command arguments supplied\n");
  74. /* initialize alarm signal handling */
  75. signal (SIGALRM, socket_timeout_alarm_handler);
  76. /* set socket timeout */
  77. alarm (socket_timeout);
  78. /* determine what variables the UPS supports */
  79. if (determine_supported_vars () != OK)
  80. return STATE_CRITICAL;
  81. /* get the ups status if possible */
  82. if (supported_options & UPS_STATUS) {
  83. if (determine_status () != OK)
  84. return STATE_CRITICAL;
  85. ups_status = strdup ("");
  86. result = STATE_OK;
  87. if (status & UPSSTATUS_OFF) {
  88. asprintf (&ups_status, "Off");
  89. result = STATE_CRITICAL;
  90. }
  91. else if ((status & (UPSSTATUS_OB | UPSSTATUS_LB)) ==
  92. (UPSSTATUS_OB | UPSSTATUS_LB)) {
  93. asprintf (&ups_status, "On Battery, Low Battery");
  94. result = STATE_CRITICAL;
  95. }
  96. else {
  97. if (status & UPSSTATUS_OL) {
  98. asprintf (&ups_status, "%s%s", ups_status, "Online");
  99. }
  100. if (status & UPSSTATUS_OB) {
  101. asprintf (&ups_status, "%s%s", ups_status, "On Battery");
  102. result = STATE_WARNING;
  103. }
  104. if (status & UPSSTATUS_LB) {
  105. asprintf (&ups_status, "%s%s", ups_status, ", Low Battery");
  106. result = STATE_WARNING;
  107. }
  108. if (status & UPSSTATUS_CAL) {
  109. asprintf (&ups_status, "%s%s", ups_status, ", Calibrating");
  110. }
  111. if (status & UPSSTATUS_RB) {
  112. asprintf (&ups_status, "%s%s", ups_status, ", Replace Battery");
  113. result = STATE_WARNING;
  114. }
  115. if (status & UPSSTATUS_UNKOWN) {
  116. asprintf (&ups_status, "%s%s", ups_status, ", Unknown");
  117. }
  118. }
  119. }
  120. /* get the ups utility voltage if possible */
  121. if (supported_options & UPS_UTILITY) {
  122. if (get_ups_variable ("UTILITY", temp_buffer, sizeof (temp_buffer)) != OK)
  123. return STATE_CRITICAL;
  124. ups_utility_voltage = atof (temp_buffer);
  125. if (ups_utility_voltage > 120.0)
  126. ups_utility_deviation = 120.0 - ups_utility_voltage;
  127. else
  128. ups_utility_deviation = ups_utility_voltage - 120.0;
  129. if (check_variable == UPS_UTILITY) {
  130. if (check_critical_value == TRUE
  131. && ups_utility_deviation >= critical_value) result = STATE_CRITICAL;
  132. else if (check_warning_value == TRUE
  133. && ups_utility_deviation >= warning_value
  134. && result < STATE_WARNING) result = STATE_WARNING;
  135. }
  136. }
  137. /* get the ups battery percent if possible */
  138. if (supported_options & UPS_BATTPCT) {
  139. if (get_ups_variable ("BATTPCT", temp_buffer, sizeof (temp_buffer)) != OK)
  140. return STATE_CRITICAL;
  141. ups_battery_percent = atof (temp_buffer);
  142. if (check_variable == UPS_BATTPCT) {
  143. if (check_critical_value == TRUE
  144. && ups_battery_percent <= critical_value) result = STATE_CRITICAL;
  145. else if (check_warning_value == TRUE
  146. && ups_battery_percent <= warning_value
  147. && result < STATE_WARNING) result = STATE_WARNING;
  148. }
  149. }
  150. /* get the ups load percent if possible */
  151. if (supported_options & UPS_LOADPCT) {
  152. if (get_ups_variable ("LOADPCT", temp_buffer, sizeof (temp_buffer)) != OK)
  153. return STATE_CRITICAL;
  154. ups_load_percent = atof (temp_buffer);
  155. if (check_variable == UPS_LOADPCT) {
  156. if (check_critical_value == TRUE && ups_load_percent >= critical_value)
  157. result = STATE_CRITICAL;
  158. else if (check_warning_value == TRUE
  159. && ups_load_percent >= warning_value && result < STATE_WARNING)
  160. result = STATE_WARNING;
  161. }
  162. }
  163. /* get the ups temperature if possible */
  164. if (supported_options & UPS_TEMP) {
  165. if (get_ups_variable ("UPSTEMP", temp_buffer, sizeof (temp_buffer)) != OK)
  166. return STATE_CRITICAL;
  167. ups_temperature = (atof (temp_buffer) * 1.8) + 32;
  168. if (check_variable == UPS_TEMP) {
  169. if (check_critical_value == TRUE && ups_temperature >= critical_value)
  170. result = STATE_CRITICAL;
  171. else if (check_warning_value == TRUE && ups_temperature >= warning_value
  172. && result < STATE_WARNING)
  173. result = STATE_WARNING;
  174. }
  175. }
  176. /* if the UPS does not support any options we are looking for, report an error */
  177. if (supported_options == UPS_NONE)
  178. result = STATE_CRITICAL;
  179. /* reset timeout */
  180. alarm (0);
  181. asprintf (&message, "UPS %s - ", (result == STATE_OK) ? "ok" : "problem");
  182. if (supported_options & UPS_STATUS)
  183. asprintf (&message, "%sStatus=%s ", message, ups_status);
  184. if (supported_options & UPS_UTILITY)
  185. asprintf (&message, "%sUtility=%3.1fV ", message, ups_utility_voltage);
  186. if (supported_options & UPS_BATTPCT)
  187. asprintf (&message, "%sBatt=%3.1f%% ", message, ups_battery_percent);
  188. if (supported_options & UPS_LOADPCT)
  189. asprintf (&message, "%sLoad=%3.1f%% ", message, ups_load_percent);
  190. if (supported_options & UPS_TEMP)
  191. asprintf (&message, "%sTemp=%3.1fF", message, ups_temperature);
  192. if (supported_options == UPS_NONE)
  193. asprintf (&message, "UPS does not support any available options\n");
  194. printf ("%s\n", message);
  195. return result;
  196. }
  197. /* determines what options are supported by the UPS */
  198. int
  199. determine_status (void)
  200. {
  201. char recv_buffer[MAX_INPUT_BUFFER];
  202. char temp_buffer[MAX_INPUT_BUFFER];
  203. char *ptr;
  204. if (get_ups_variable ("STATUS", recv_buffer, sizeof (recv_buffer)) !=
  205. STATE_OK) {
  206. printf ("Invalid response received from hostn");
  207. return ERROR;
  208. }
  209. recv_buffer[strlen (recv_buffer) - 1] = 0;
  210. strcpy (temp_buffer, recv_buffer);
  211. for (ptr = (char *) strtok (temp_buffer, " "); ptr != NULL;
  212. ptr = (char *) strtok (NULL, " ")) {
  213. if (!strcmp (ptr, "OFF"))
  214. status |= UPSSTATUS_OFF;
  215. else if (!strcmp (ptr, "OL"))
  216. status |= UPSSTATUS_OL;
  217. else if (!strcmp (ptr, "OB"))
  218. status |= UPSSTATUS_OB;
  219. else if (!strcmp (ptr, "LB"))
  220. status |= UPSSTATUS_LB;
  221. else if (!strcmp (ptr, "CAL"))
  222. status |= UPSSTATUS_CAL;
  223. else if (!strcmp (ptr, "RB"))
  224. status |= UPSSTATUS_RB;
  225. else
  226. status |= UPSSTATUS_UNKOWN;
  227. }
  228. return OK;
  229. }
  230. /* determines what options are supported by the UPS */
  231. int
  232. determine_supported_vars (void)
  233. {
  234. char send_buffer[MAX_INPUT_BUFFER];
  235. char recv_buffer[MAX_INPUT_BUFFER];
  236. char temp_buffer[MAX_INPUT_BUFFER];
  237. char *ptr;
  238. /* get the list of variables that this UPS supports */
  239. if (ups_name)
  240. sprintf (send_buffer, "LISTVARS %s\r\n", ups_name);
  241. else
  242. sprintf (send_buffer, "LISTVARS\r\n");
  243. if (process_tcp_request
  244. (server_address, server_port, send_buffer, recv_buffer,
  245. sizeof (recv_buffer)) != STATE_OK) {
  246. printf ("Invalid response received from host\n");
  247. return ERROR;
  248. }
  249. recv_buffer[strlen (recv_buffer) - 1] = 0;
  250. if (ups_name)
  251. ptr = recv_buffer + 5 + strlen (ups_name) + 2;
  252. else
  253. ptr = recv_buffer + 5;
  254. strcpy (temp_buffer, recv_buffer);
  255. for (ptr = (char *) strtok (temp_buffer, " "); ptr != NULL;
  256. ptr = (char *) strtok (NULL, " ")) {
  257. if (!strcmp (ptr, "UTILITY"))
  258. supported_options |= UPS_UTILITY;
  259. else if (!strcmp (ptr, "BATTPCT"))
  260. supported_options |= UPS_BATTPCT;
  261. else if (!strcmp (ptr, "LOADPCT"))
  262. supported_options |= UPS_LOADPCT;
  263. else if (!strcmp (ptr, "STATUS"))
  264. supported_options |= UPS_STATUS;
  265. else if (!strcmp (ptr, "UPSTEMP"))
  266. supported_options |= UPS_TEMP;
  267. }
  268. return OK;
  269. }
  270. /* gets a variable value for a specific UPS */
  271. int
  272. get_ups_variable (const char *varname, char *buf, size_t buflen)
  273. {
  274. /* char command[MAX_INPUT_BUFFER]; */
  275. char temp_buffer[MAX_INPUT_BUFFER];
  276. char send_buffer[MAX_INPUT_BUFFER];
  277. char *ptr;
  278. /* create the command string to send to the UPS daemon */
  279. if (ups_name)
  280. sprintf (send_buffer, "REQ %s@%s\n", varname, ups_name);
  281. else
  282. sprintf (send_buffer, "REQ %s\n", varname);
  283. /* send the command to the daemon and get a response back */
  284. if (process_tcp_request
  285. (server_address, server_port, send_buffer, temp_buffer,
  286. sizeof (temp_buffer)) != STATE_OK) {
  287. printf ("Invalid response received from host\n");
  288. return ERROR;
  289. }
  290. if (ups_name)
  291. ptr = temp_buffer + strlen (varname) + 5 + strlen (ups_name) + 1;
  292. else
  293. ptr = temp_buffer + strlen (varname) + 5;
  294. if (!strcmp (ptr, "NOT-SUPPORTED")) {
  295. printf ("Error: Variable '%s' is not supported\n", varname);
  296. return ERROR;
  297. }
  298. if (!strcmp (ptr, "DATA-STALE")) {
  299. printf ("Error: UPS data is stale\n");
  300. return ERROR;
  301. }
  302. if (!strcmp (ptr, "UNKNOWN-UPS")) {
  303. if (ups_name)
  304. printf ("Error: UPS '%s' is unknown\n", ups_name);
  305. else
  306. printf ("Error: UPS is unknown\n");
  307. return ERROR;
  308. }
  309. strncpy (buf, ptr, buflen - 1);
  310. buf[buflen - 1] = 0;
  311. return OK;
  312. }
  313. /* Command line: CHECK_UPS <host_address> [-u ups] [-p port] [-v variable]
  314. [-wv warn_value] [-cv crit_value] [-to to_sec] */
  315. /* process command-line arguments */
  316. int
  317. process_arguments (int argc, char **argv)
  318. {
  319. int c;
  320. int option = 0;
  321. static struct option longopts[] = {
  322. {"hostname", required_argument, 0, 'H'},
  323. {"ups", required_argument, 0, 'u'},
  324. {"port", required_argument, 0, 'p'},
  325. {"critical", required_argument, 0, 'c'},
  326. {"warning", required_argument, 0, 'w'},
  327. {"timeout", required_argument, 0, 't'},
  328. {"variable", required_argument, 0, 'v'},
  329. {"version", no_argument, 0, 'V'},
  330. {"help", no_argument, 0, 'h'},
  331. {0, 0, 0, 0}
  332. };
  333. if (argc < 2)
  334. return ERROR;
  335. for (c = 1; c < argc; c++) {
  336. if (strcmp ("-to", argv[c]) == 0)
  337. strcpy (argv[c], "-t");
  338. else if (strcmp ("-wt", argv[c]) == 0)
  339. strcpy (argv[c], "-w");
  340. else if (strcmp ("-ct", argv[c]) == 0)
  341. strcpy (argv[c], "-c");
  342. }
  343. while (1) {
  344. c = getopt_long (argc, argv, "hVH:u:p:v:c:w:t:", longopts,
  345. &option);
  346. if (c == -1 || c == EOF)
  347. break;
  348. switch (c) {
  349. case '?': /* help */
  350. usage3 ("Unknown option", optopt);
  351. case 'H': /* hostname */
  352. if (is_host (optarg)) {
  353. server_address = optarg;
  354. }
  355. else {
  356. usage2 ("Invalid host name", optarg);
  357. }
  358. break;
  359. case 'u': /* ups name */
  360. ups_name = optarg;
  361. break;
  362. case 'p': /* port */
  363. if (is_intpos (optarg)) {
  364. server_port = atoi (optarg);
  365. }
  366. else {
  367. usage2 ("Server port must be a positive integer", optarg);
  368. }
  369. break;
  370. case 'c': /* critical time threshold */
  371. if (is_intnonneg (optarg)) {
  372. critical_value = atoi (optarg);
  373. check_critical_value = TRUE;
  374. }
  375. else {
  376. usage2 ("Critical time must be a nonnegative integer", optarg);
  377. }
  378. break;
  379. case 'w': /* warning time threshold */
  380. if (is_intnonneg (optarg)) {
  381. warning_value = atoi (optarg);
  382. check_warning_value = TRUE;
  383. }
  384. else {
  385. usage2 ("Warning time must be a nonnegative integer", optarg);
  386. }
  387. break;
  388. case 'v': /* variable */
  389. if (!strcmp (optarg, "LINE"))
  390. check_variable = UPS_UTILITY;
  391. else if (!strcmp (optarg, "TEMP"))
  392. check_variable = UPS_TEMP;
  393. else if (!strcmp (optarg, "BATTPCT"))
  394. check_variable = UPS_BATTPCT;
  395. else if (!strcmp (optarg, "LOADPCT"))
  396. check_variable = UPS_LOADPCT;
  397. else
  398. usage2 ("Unrecognized UPS variable", optarg);
  399. break;
  400. case 't': /* timeout */
  401. if (is_intnonneg (optarg)) {
  402. socket_timeout = atoi (optarg);
  403. }
  404. else {
  405. usage ("Time interval must be a nonnegative integer\n");
  406. }
  407. break;
  408. case 'V': /* version */
  409. print_revision (progname, "$Revision$");
  410. exit (STATE_OK);
  411. case 'h': /* help */
  412. print_help ();
  413. exit (STATE_OK);
  414. }
  415. }
  416. if (server_address == NULL && argc > optind) {
  417. if (is_host (argv[optind]))
  418. server_address = argv[optind++];
  419. else
  420. usage ("Invalid host name");
  421. }
  422. if (server_address == NULL)
  423. server_address = strdup("127.0.0.1");
  424. return validate_arguments();
  425. }
  426. int
  427. validate_arguments (void)
  428. {
  429. return OK;
  430. }
  431. void
  432. print_help (void)
  433. {
  434. char *myport;
  435. asprintf (&myport, "%d", PORT);
  436. print_revision (progname, revision);
  437. printf (_("Copyright (c) 2000 Tom Shields"));
  438. printf (_(COPYRIGHT), copyright, email);
  439. printf (_("This plugin tests the UPS service on the specified host.\n\
  440. Network UPS Tools from www.exploits.org must be running for this plugin to\n\
  441. work.\n\n"));
  442. print_usage ();
  443. printf (_(UT_HELP_VRSN));
  444. printf (_(UT_HOST_PORT), 'p', myport);
  445. printf (_("\
  446. -u, --ups=STRING\n\
  447. Name of UPS\n"));
  448. printf (_(UT_WARN_CRIT));
  449. printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
  450. printf (_(UT_VERBOSE));
  451. printf (_("\
  452. This plugin attempts to determine the status of a UPS (Uninterruptible Power\n\
  453. Supply) on a local or remote host. If the UPS is online or calibrating, the\n\
  454. plugin will return an OK state. If the battery is on it will return a WARNING\n\
  455. state. If the UPS is off or has a low battery the plugin will return a CRITICAL\n\
  456. state.\n\n"));
  457. printf (_("\
  458. You may also specify a variable to check [such as temperature, utility voltage,\n\
  459. battery load, etc.] as well as warning and critical thresholds for the value of\n\
  460. that variable. If the remote host has multiple UPS that are being monitored you\n\
  461. will have to use the [ups] option to specify which UPS to check.\n\n"));
  462. printf (_("Notes:\n\n\
  463. This plugin requires that the UPSD daemon distributed with Russel Kroll's\n\
  464. Smart UPS Tools be installed on the remote host. If you do not have the\n\
  465. package installed on your system, you can download it from\n\
  466. http://www.exploits.org/nut\n\n"));
  467. printf (_(UT_SUPPORT));
  468. }
  469. void
  470. print_usage (void)
  471. {
  472. printf (_("\
  473. Usage: %s -H host [-e expect] [-p port] [-w warn] [-c crit]\n\
  474. [-t timeout] [-v]\n"), progname);
  475. printf (_(UT_HLP_VRS), progname, progname);
  476. }