check_ups.c 16 KB

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