2 * Check-Plugin for Nagios to check status of an APC-UPS
5 * Written by Christian Masopust, November 2005
7 * Build it with: cc check_apcupsd.c ../lib/libapc.a -o check_apcupsd
9 * Execute: ./check_apcupsd [host[:port]]
17 /* Default values, can be changed on command line */
18 #define SERV_TCP_PORT 3551
19 #define SERV_HOST_ADDR "127.0.0.1"
26 #define NAGIOS_WARNING 1
27 #define NAGIOS_CRITICAL 2
28 #define NAGIOS_UNKNOWN 3
29 #define S_NAGIOS_OK "OK: "
30 #define S_NAGIOS_WARNING "WARNING: "
31 #define S_NAGIOS_CRITICAL "CRITICAL: "
32 #define S_NAGIOS_UNKNOWN "UNKNOWN: "
35 /* List of variables that can be read by getupsvar()
36 * First field is that name given to getupsvar(),
37 * Second field is our internal name as produced by the STATUS
38 * output from apcupsd.
39 * Third field, if 0 returns everything to the end of the
40 * line, and if 1 returns only to first space (e.g. integers,
41 * and floating point values.
48 {"model", "MODEL", 0},
49 {"upsmodel", "UPSMODEL", 0},
51 {"battcap", "BCHARGE", 1},
52 {"mbattchg", "MBATTCHG", 1},
53 {"battvolt", "BATTV", 1},
54 {"nombattv", "NOMBATTV", 1},
55 {"utility", "LINEV", 1},
56 {"upsload", "LOADPCT", 1},
57 {"loadpct", "LOADPCT", 1},
58 {"outputv", "OUTPUTV", 1},
59 {"status", "STATFLAG", 1},
60 {"linemin", "MINLINEV", 1},
61 {"linemax", "MAXLINEV", 1},
62 {"upstemp", "ITEMP", 1},
63 {"outputfreq", "LINEFREQ", 1},
64 {"translo", "LOTRANS", 1},
65 {"transhi", "HITRANS", 1},
66 {"runtime", "TIMELEFT", 1},
67 {"mintimel", "MINTIMEL", 1},
68 {"retpct", "RETPCT", 1}, /* min batt to turn on UPS */
69 {"sense", "SENSE", 1},
70 {"hostname", "HOSTNAME", 1},
71 {"battdate", "BATTDATE", 1},
72 {"serialno", "SERIALNO", 1},
73 {"lastxfer", "LASTXFER", 0}, /* reason for last xfer to batteries */
74 {"selftest", "SELFTEST", 1}, /* results of last self test */
75 {"laststest", "LASTSTEST", 0},
76 {"version", "VERSION", 1},
77 {"upsname", "UPSNAME", 1},
78 {"lowbatt", "DLOWBATT", 1}, /* low battery power off delay */
79 {"battpct", "BCHARGE", 1},
80 {"highxfer", "HITRANS", 1},
81 {"lowxfer", "LOTRANS", 1},
82 {"cable", "CABLE", 0},
83 {"firmware", "FIRMWARE", 0},
87 int fetch_data(char *host
, int port
);
88 int getupsvar(char *host
, int port
, char *request
, char *answer
, int anslen
);
89 int fill_buffer(int sockfd
);
93 struct sockaddr_in tcp_serv_addr
;
95 void error_abort(char *msg
)
98 exit(NAGIOS_CRITICAL
);
101 int main(int argc
, char *argv
[])
116 retVal
= NAGIOS_UNKNOWN
;
117 strcpy (sStatus
, S_NAGIOS_UNKNOWN
);
119 strcpy(host
, SERV_HOST_ADDR
);
120 port
= SERV_TCP_PORT
;
123 strcpy(host
, argv
[1]); /* get host from command line */
124 p
= strchr(host
, ':');
131 if (getupsvar(host
, port
, "hostname", msg
, sizeof(msg
)) <= 0) {
132 printf("%scannot get hostname from UPS-Server\n", S_NAGIOS_CRITICAL
);
133 exit(NAGIOS_CRITICAL
);
135 strcpy(hostname
, msg
);
137 if (getupsvar(host
, port
, "model", msg
, sizeof(msg
)) <= 0) {
138 printf("%scannot get model from UPS-Server\n", S_NAGIOS_CRITICAL
);
139 exit(NAGIOS_CRITICAL
);
143 if (getupsvar(host
, port
, "upsname", msg
, sizeof(msg
)) <= 0) {
144 printf("%scannot get upsname from UPS-Server\n", S_NAGIOS_CRITICAL
);
145 exit(NAGIOS_CRITICAL
);
147 strcpy(upsname
, msg
);
149 if (getupsvar(host
, port
, "status", msg
, sizeof(msg
)) <= 0) {
150 printf("%scannot get status from UPS-Server\n", S_NAGIOS_CRITICAL
);
151 exit(NAGIOS_CRITICAL
);
153 iStatus
= strtol(msg
, 0, 16);
155 if (iStatus
& UPS_calibration
) {
156 strcat(status
, "CALIBRATION ");
158 strcpy(sStatus
, S_NAGIOS_OK
);
160 if (iStatus
& UPS_trim
) {
161 strcat(status
, "SMART TRIM ");
163 strcpy(sStatus
, S_NAGIOS_OK
);
165 if (iStatus
& UPS_boost
) {
166 strcat(status
, "SMART BOOST ");
168 strcpy(sStatus
, S_NAGIOS_OK
);
170 if (iStatus
& UPS_online
) {
171 strcat(status
, "ONLINE ");
173 strcpy(sStatus
, S_NAGIOS_OK
);
175 if (iStatus
& UPS_onbatt
) {
176 strcat(status
, "ON BATTERY ");
177 retVal
= NAGIOS_WARNING
;
178 strcpy(sStatus
, S_NAGIOS_WARNING
);
180 if (iStatus
& UPS_overload
) {
181 strcat(status
, "OVERLOADED ");
182 retVal
= NAGIOS_CRITICAL
;
183 strcpy(sStatus
, S_NAGIOS_CRITICAL
);
185 if (iStatus
& UPS_battlow
) {
186 strcat(status
, "BATTERY LOW ");
187 retVal
= NAGIOS_CRITICAL
;
188 strcpy(sStatus
, S_NAGIOS_CRITICAL
);
190 if (iStatus
& UPS_replacebatt
) {
191 strcat(status
, "REPLACE BATTERY ");
192 retVal
= NAGIOS_WARNING
;
193 strcpy(sStatus
, S_NAGIOS_WARNING
);
195 if (iStatus
& UPS_commlost
) {
196 strcat(status
, "COMMUNICATION LOST ");
197 retVal
= NAGIOS_CRITICAL
;
198 strcpy(sStatus
, S_NAGIOS_CRITICAL
);
200 if (iStatus
& UPS_shutdown
) {
201 strcat(status
, "SHUTDOWN ");
203 strcpy(sStatus
, S_NAGIOS_OK
);
205 if (iStatus
& UPS_slave
) {
206 strcat(status
, "SLAVE ");
208 strcpy(sStatus
, S_NAGIOS_OK
);
211 if (strlen(status
) > 0) {
212 status
[strlen(status
) - 1] = '\0';
215 if (getupsvar(host
, port
, "loadpct", msg
, sizeof(msg
)) <= 0) {
216 printf("%scannot get loadpct from UPS-Server\n", S_NAGIOS_CRITICAL
);
217 exit(NAGIOS_CRITICAL
);
219 strcpy(loadpct
, msg
);
221 if (getupsvar(host
, port
, "runtime", msg
, sizeof(msg
)) <= 0) {
222 printf("%scannot get runtime from UPS-Server\n", S_NAGIOS_CRITICAL
);
223 exit(NAGIOS_CRITICAL
);
225 strcpy(runtime
, msg
);
227 printf ("%sUPS: %s, Load: %s%%, Runtime: %smin, Status: %s\n", sStatus
, model
, loadpct
, runtime
, status
);
228 /* printf("For host=%s ups=%s model=%s, the Status=%s, loadpct=%s, runtime=%s\n",
229 hostname, upsname, model, status, loadpct, runtime); */
236 * Read data into memory buffer to be used by getupsvar()
238 * Returns 1 if data fetched
240 int fetch_data(char *host
, int port
)
245 if ((sockfd
= net_open(host
, NULL
, port
)) < 0) {
246 printf("fetch_data: tcp_open failed for %s port %d", host
, port
);
250 stat
= fill_buffer(sockfd
); /* fill statbuf */
258 * Returns 1 if var found
260 * Returns 0 if variable name not found
261 * answer has "Not found" is variable name not found
262 * answer may have "N/A" if the UPS does not support this
264 * Returns -1 if network problem
265 * answer has "N/A" if host is not available or network error
267 int getupsvar(char *host
, int port
, char *request
, char *answer
, int anslen
)
270 char *stat_match
= NULL
;
274 if (!fetch_data(host
, port
)) {
275 strcpy(answer
, "N/A");
279 for (i
=0; cmdtrans
[i
].request
; i
++)
280 if (!(strcmp(cmdtrans
[i
].request
, request
))) {
281 stat_match
= cmdtrans
[i
].upskeyword
;
282 nfields
= cmdtrans
[i
].nfields
;
285 if (stat_match
!= NULL
) {
286 if ((find
=strstr(statbuf
, stat_match
)) != NULL
) {
287 if (nfields
== 1) /* get one field */
288 sscanf (find
, "%*s %*s %s", answer
);
289 else { /* get everything to eol */
291 find
+= 11; /* skip label */
292 while (*find
!= '\n')
293 answer
[i
++] = *find
++;
296 if (strcmp(answer
, "N/A") == 0)
302 strcpy(answer
, "Not found");
308 /* Fill buffer with data from UPS network daemon
312 int fill_buffer(int sockfd
)
319 if (net_send(sockfd
, "status", 6) != 6) {
320 printf("fill_buffer: write error on socket\n");
324 while ((n
= net_recv(sockfd
, buf
, sizeof(buf
)-1)) > 0) {
326 strcat(statbuf
, buf
);
331 statlen
= strlen(statbuf
);
336 #else /* HAVE_NISLIB */
338 int main(int argc
, char *argv
[]) {
339 printf("Sorry, NIS code is not compiled in apcupsd.\n");
343 #endif /* HAVE_NISLIB */