17
17
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
/* default host - only used if you don't specify one in the URL */
21
#define MONHOST "127.0.0.1"
23
20
#include "common.h"
21
#include "upsclient.h"
25
22
#include "status.h"
26
23
#include "cgilib.h"
24
#include "parseconf.h"
27
25
#include "timehead.h"
31
static char monhost[SMALLBUF];
27
#include "upsimagearg.h"
29
#define MAX_CGI_STRLEN 64
31
static char *monhost = NULL;
32
32
static int use_celsius = 1, refreshdelay = -1;
34
/* from cgilib's checkhost() */
35
static char *monhostdesc = NULL;
38
static char *upsname, *hostname;
42
static long forofs = 0;
44
static ulist_t *ulhead = NULL, *currups = NULL;
46
static int skip_to_endif = 0;
34
48
void parsearg(char *var, char *value)
36
if (!strcmp(var, "host"))
37
strlcpy(monhost, value, sizeof(monhost));
39
if (!strcmp(var, "use_celsius"))
40
use_celsius = (int) strtol(value, (char **) NULL, 10);
50
/* avoid bogus junk from evil people */
51
if ((strlen(var) > MAX_CGI_STRLEN) || (strlen(value) > MAX_CGI_STRLEN))
54
if (!strcmp(var, "host")) {
58
monhost = xstrdup(value);
42
62
if (!strcmp(var, "refresh"))
43
63
refreshdelay = (int) strtol(value, (char **) NULL, 10);
46
const char *my_getdate()
66
static void report_error(void)
68
if (upscli_upserror(&ups) == UPSCLI_ERR_VARNOTSUPP)
69
printf("Not supported\n");
71
printf("[error: %s]\n", upscli_strerror(&ups));
74
/* make sure we're actually connected to upsd */
75
static int check_ups_fd(int do_report)
77
if (upscli_fd(&ups) == -1) {
84
/* also check for insanity in currups */
88
printf("No UPS specified for monitoring\n");
97
static void parse_var(const char *buf)
101
if (!check_ups_fd(1))
104
if (upscli_getvar(&ups, upsname, buf, ans, sizeof(ans)) < 0) {
112
static void do_status(void)
115
char stat[SMALLBUF], *sp, *ptr;
117
if (!check_ups_fd(1))
120
if (upscli_getvar(&ups, upsname, "status", stat, sizeof(stat)) < 0) {
128
ptr = strchr(sp, ' ');
132
/* expand from table in status.h */
133
for (i = 0; stattab[i].name != NULL; i++)
134
if (!strcmp(stattab[i].name, sp))
135
printf("%s<BR>", stattab[i].desc);
141
static int do_date(const char *buf)
143
char datebuf[SMALLBUF];
49
static char timestr[255];
52
if (strftime (timestr, sizeof(timestr), "%a %b %d %X %Z %Y", localtime(&tod)) == 0)
60
printf ("Error: %s\n", upsstrerror(upserror));
67
char model[64], status[64], battpct[64], utility[64], loadpct[64],
68
upstemp[64], acfreq[64], *stat, *ptr;
147
if (strftime(datebuf, sizeof(datebuf), buf, localtime(&tod))) {
148
printf("%s\n", datebuf);
155
static int get_img_val(const char *var, const char *desc, const char *imgargs)
159
if (!check_ups_fd(1))
162
if (upscli_getvar(&ups, upsname, var, temp, sizeof(temp)) < 0) {
167
printf("<IMG SRC=\"upsimage.cgi?host=%s&display=%s",
170
if ((imgargs) && (strlen(imgargs) > 0))
171
printf("&%s", imgargs);
173
printf("\" WIDTH=\"100\" HEIGHT=\"350\" ALT=\"%s: %s\">\n",
179
/* see if <arg> is valid - table from upsimagearg.h */
180
static void check_imgarg(char *arg, char *out, size_t outlen)
71
strcpy (monhost, MONHOST); /* default host */
185
ep = strchr(arg, '=');
192
/* if it's allowed, append it so it can become part of the URL */
193
for (i = 0; imgarg[i].name != NULL; i++) {
194
if (!strcmp(imgarg[i].name, arg)) {
196
if (strlen(out) == 0)
197
snprintf(out, outlen, "%s=%s", arg, ep);
199
snprintfcat(out, outlen, "&%s=%s", arg, ep);
205
/* split out the var=val commands from the IMG line */
206
static void split_imgarg(char *in, char *out, size_t outlen)
215
sp = strchr(ptr, ' ');
217
/* split by spaces, then check each one (can't use parseconf...) */
220
check_imgarg(ptr, out, outlen);
223
sp = strchr(ptr, ' ');
226
check_imgarg(ptr, out, outlen);
229
/* IMG <type> [<var>=<val] [<var>=<val>] ... */
230
static int do_img(char *buf)
232
char *type, *ptr, imgargs[SMALLBUF];
234
memset(imgargs, '\0', sizeof(imgargs));
238
ptr = strchr(buf, ' ');
242
split_imgarg(ptr, imgargs, sizeof(imgargs));
245
if (!strcmp(type, "BATTVOLT"))
246
return get_img_val("battvolt", "Battery Voltage", imgargs);
248
if (!strcmp(type, "BATTPCT"))
249
return get_img_val("battpct", "Battery Charge", imgargs);
251
if (!strcmp(type, "UTILITY"))
252
return get_img_val("utility", "Utility", imgargs);
254
if (!strcmp(type, "OUTVOLT"))
255
return get_img_val("outvolt", "Output Voltage", imgargs);
257
if (!strcmp(type, "LOADPCT"))
258
return get_img_val("loadpct", "UPS Load", imgargs);
260
if (!strcmp(type, "ACFREQ"))
261
return get_img_val("acfreq", "AC Freq", imgargs);
263
if (!strcmp(type, "OUT_FREQ"))
264
return get_img_val("out_freq", "Out Freq", imgargs);
269
static void ups_connect(void)
271
static ulist_t *lastups = NULL;
272
char *newups, *newhost;
275
/* try to minimize reconnects */
278
/* don't reconnect if these are both the same UPS */
279
if (!strcmp(lastups->sys, currups->sys)) {
284
/* see if it's just on the same host */
285
upscli_splitname(currups->sys, &newups, &newhost, &newport);
287
if ((!strcmp(newhost, hostname)) && (port == newport)) {
296
/* not the same upsd, so disconnect */
301
upscli_disconnect(&ups);
308
upscli_splitname(currups->sys, &upsname, &hostname, &port);
310
if (upscli_connect(&ups, hostname, port, 0) < 0)
311
fprintf(stderr, "UPS [%s]: can't connect to server: %s\n",
312
currups->sys, upscli_strerror(&ups));
317
static void do_hostlink(void)
322
printf("<a href=\"upsstats.cgi?host=%s\">%s</a>\n",
323
currups->sys, currups->desc);
326
/* see if the UPS supports this variable - skip to the next ENDIF if not */
327
static void do_ifsupp(char *var)
331
/* if not connected, assume it's not supported to skip more */
332
if (!check_ups_fd(0)) {
337
if (upscli_getvar(&ups, upsname, var, ans, sizeof(ans)) < 0)
341
static void do_temp(char *var)
343
char tempc[SMALLBUF];
346
if (!check_ups_fd(1))
349
if (upscli_getvar(&ups, upsname, var, tempc, sizeof(tempc)) < 0) {
355
printf("%s\n", tempc);
359
tempf = (strtod(tempc, (char **) NULL) * 1.8) + 32;
360
printf("%.1f\n", tempf);
363
static void do_degrees(void)
373
/* plug in the right color string (like #FF0000) for the UPS status */
374
static void do_statuscolor(void)
377
char stat[SMALLBUF], *sp, *ptr;
379
if (!check_ups_fd(0)) {
381
/* can't print the warning here - give a red error condition */
386
if (upscli_getvar(&ups, upsname, "status", stat, sizeof(stat)) < 0) {
388
/* status not available - give yellow as a warning */
397
ptr = strchr(sp, ' ');
401
/* expand from table in status.h */
402
for (i = 0; stattab[i].name != NULL; i++)
403
if (!strcmp(stattab[i].name, sp))
404
if (stattab[i].severity > severity)
405
severity = stattab[i].severity;
411
case 0: printf("#00FF00\n"); break; /* green : OK */
412
case 1: printf("#FFFF00\n"); break; /* yellow : warning */
414
default: printf("#FF0000\n"); break; /* red : error */
418
/* use red if utility is outside lowxfer+highxfer bounds, else green */
419
static void do_utilitycolor(void)
422
int lowxfer, highxfer, utility;
424
if (!check_ups_fd(0)) {
426
/* can't print the warning here - give a red error condition */
431
if (upscli_getvar(&ups, upsname, "utility", tmp, sizeof(tmp)) < 0) {
433
/* nothing available - default is green */
438
utility = strtol(tmp, (char **) NULL, 10);
440
if (upscli_getvar(&ups, upsname, "lowxfer", tmp, sizeof(tmp)) < 0) {
442
/* no lowxfer? default to green */
447
lowxfer = strtol(tmp, (char **) NULL, 10);
449
if (upscli_getvar(&ups, upsname, "highxfer", tmp, sizeof(tmp)) < 0) {
451
/* same idea for highxfer */
456
highxfer = strtol(tmp, (char **) NULL, 10);
458
if ((utility < lowxfer) || (utility > highxfer))
464
/* look for lines starting and ending with @ containing valid commands */
465
static int parse_line(const char *buf)
467
static char *cmd = NULL;
469
/* deal with extremely short lines as a special case */
470
if (strlen(buf) < 3) {
472
if (skip_to_endif == 1)
480
/* if skipping a section, act like we parsed the line */
481
if (skip_to_endif == 1)
484
/* otherwise pass it through for normal printing */
488
if (buf[strlen(buf) - 1] != '@')
494
cmd = xstrdup(&buf[1]);
496
/* strip off final @ */
497
cmd[strlen(cmd) - 1] = '\0';
499
/* ending an if block? */
500
if (!strcmp(cmd, "ENDIF")) {
505
/* don't do any commands if skipping a section */
506
if (skip_to_endif == 1)
509
if (!strncmp(cmd, "VAR ", 4)) {
514
if (!strcmp(cmd, "HOST")) {
515
printf("%s\n", currups->sys);
519
if (!strcmp(cmd, "HOSTDESC")) {
520
printf("%s\n", currups->desc);
524
if (!strcmp(cmd, "STATUS")) {
529
if (!strcmp(cmd, "STATUSCOLOR")) {
534
if (!strcmp(cmd, "UTILITYCOLOR")) {
539
if (!strcmp(cmd, "TEMPF")) {
544
if (!strcmp(cmd, "TEMPC")) {
549
if (!strncmp(cmd, "DATE ", 5))
550
return do_date(&cmd[5]);
552
if (!strncmp(cmd, "IMG ", 4))
553
return do_img(&cmd[4]);
555
if (!strcmp(cmd, "VERSION")) {
556
printf("%s\n", UPS_VERSION);
560
if (!strcmp(cmd, "REFRESH")) {
561
if (refreshdelay > 0)
562
printf("<META HTTP-EQUIV=\"Refresh\" CONTENT=\"%d\">\n",
568
if (!strcmp(cmd, "FOREACHUPS")) {
576
if (!strcmp(cmd, "ENDFOR")) {
578
/* if not in a for, ignore this */
582
currups = currups->next;
585
fseek(tf, forofs, SEEK_SET);
592
if (!strcmp(cmd, "HOSTLINK")) {
597
if (!strncmp(cmd, "IFSUPP ", 7)) {
602
if (!strcmp(cmd, "UPSTEMP")) {
607
if (!strcmp(cmd, "AMBTEMP")) {
612
if (!strcmp(cmd, "DEGREES")) {
620
static void display_template(const char *tfn)
622
char fn[SMALLBUF], buf[LARGEBUF];
624
snprintf(fn, sizeof(fn), "%s/%s", confpath(), tfn);
629
fprintf(stderr, "upsstats: Can't open %s: %s\n",
630
fn, strerror(errno));
632
printf("Error: can't open template file (%s)\n", tfn);
637
while (fgets(buf, sizeof(buf), tf)) {
638
buf[strlen(buf) - 1] = '\0';
640
if (!parse_line(buf))
647
static void add_ups(char *sys, char *desc)
658
tmp = xmalloc(sizeof(ulist_t));
660
tmp->sys = xstrdup(sys);
661
tmp->desc = xstrdup(desc);
670
/* called for fatal errors in parseconf like malloc failures */
671
void upsstats_hosts_err(const char *errmsg)
673
upslogx(LOG_ERR, "Fatal error in parseconf(hosts.conf): %s", errmsg);
676
static void load_hosts_conf(void)
681
snprintf(fn, sizeof(fn), "%s/hosts.conf", CONFPATH);
683
pconf_init(&ctx, upsstats_hosts_err);
685
if (!pconf_file_begin(&ctx, fn)) {
688
printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"\n");
689
printf(" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n");
690
printf("<HTML><HEAD>\n");
691
printf("<TITLE>Error: can't open hosts.conf</TITLE>\n");
692
printf("</HEAD><BODY>\n");
693
printf("Error: can't open hosts.conf\n");
694
printf("</BODY></HTML>\n");
696
/* leave something for the admin */
697
fprintf(stderr, "upsstats: %s\n", ctx.errmsg);
701
while (pconf_file_next(&ctx)) {
702
if (pconf_parse_error(&ctx)) {
703
upslogx(LOG_ERR, "Parse error: %s:%d: %s",
704
fn, ctx.linenum, ctx.errmsg);
711
/* MONITOR <host> <desc> */
712
if (!strcmp(ctx.arglist[0], "MONITOR"))
713
add_ups(ctx.arglist[1], ctx.arglist[2]);
720
static void display_single(void)
722
if (!checkhost(monhost, &monhostdesc)) {
723
printf("Access to that host [%s] is not authorized.\n",
728
add_ups(monhost, monhostdesc);
733
display_template("upsstats-single.html");
735
upscli_disconnect(&ups);
738
int main(int argc, char **argv)
75
printf ("Content-type: text/html\n");
76
printf ("Pragma: no-cache\n");
79
if (!checkhost (monhost, NULL)) {
80
printf ("Access to that host is not authorized.\n");
84
if (getupsvar(monhost, "model", model, sizeof(model)) < 0)
85
snprintf (model, sizeof(model), "Unknown - %s", upsstrerror(upserror));
87
printf ("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"\n");
88
printf (" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n");
90
printf ("<HTML><HEAD>\n");
92
printf ("<META HTTP-EQUIV=\"Refresh\" CONTENT=\"%d\">\n", refreshdelay);
94
printf ("<TITLE>%s on %s</TITLE></HEAD>\n", model, monhost);
95
printf ("<BODY BGCOLOR=\"#C8C8C8\" TEXT=\"#000000\" LINK=\"#0000EE\" VLINK=\"#551A8B\">\n");
96
printf ("<CENTER><TABLE BORDER CELLSPACING=10 CELLPADDING=5>\n");
97
printf ("<TR><TH>%s</TH>\n", my_getdate());
98
printf ("<TH>Batt Chg</TH><TH>Utility</TH><TH>UPS Load</TH></TR>\n");
99
printf ("<TR><TD BGCOLOR=\"#FFFFFF\"><PRE>\n");
100
printf ("Monitoring: %s\n", monhost);
101
printf (" UPS Model: %s\n", model);
103
getupsvar (monhost, "status", status, sizeof(status));
104
printf (" Status: ");
107
while (stat != NULL) {
108
ptr = strchr (stat, ' ');
112
for (i = 0; stattab[i].name != NULL; i++) {
113
if (!strcmp(stattab[i].name, stat))
114
printf ("%s ", stattab[i].desc);
121
printf ("</PRE></TD>\n");
123
if (getupsvar (monhost, "battpct", battpct, sizeof(battpct)) > 0)
124
printf ("<TD ROWSPAN=3><IMG SRC=\"upsimage.cgi?host=%s&display=battpct\" WIDTH=130 HEIGHT=350 ALT=\"Battery charge: %s %%\">\n", monhost, battpct);
126
printf ("<TD ROWSPAN=3 VALIGN=TOP>Not supported\n");
129
if (getupsvar (monhost, "utility", utility, sizeof(utility)) > 0)
130
printf ("<TD ROWSPAN=3><IMG SRC=\"upsimage.cgi?host=%s&display=utility\" WIDTH=130 HEIGHT=350 ALT=\"Utility: %s VAC\">\n", monhost, utility);
132
printf ("<TD ROWSPAN=3 VALIGN=TOP>Not supported\n");
133
strcpy (utility, "");
137
if (getupsvar (monhost, "loadpct", loadpct, sizeof(loadpct)) > 0)
138
printf ("<TD ROWSPAN=3><IMG SRC=\"upsimage.cgi?host=%s&display=loadpct\" WIDTH=130 HEIGHT=350 ALT=\"UPS Load: %s %%\">\n", monhost, loadpct);
140
printf ("<TD ROWSPAN=3 VALIGN=TOP>Not supported\n");
145
printf ("<TR><TD BGCOLOR=\"#FFFFFF\"><PRE>\n");
147
/* TODO: handle self tests */
149
/* printf ("Last UPS Self Test: Not Available\n"); */
150
/* printf (" Last Test Date: Not Available\n"); */
151
printf ("</PRE></TD></TR>\n");
153
printf ("<TR><TD BGCOLOR=\"#FFFFFF\"><PRE>\n");
155
if (strlen(utility) != 0)
156
printf (" UPS Input: %s VAC\n", utility);
158
if (getupsvar (monhost, "upstemp", upstemp, sizeof(upstemp)) > 0) {
160
printf (" UPS Temp: %s °C\n", upstemp);
162
tempf = (strtod (upstemp, 0) * 1.8) + 32;
163
printf (" UPS Temp: %.1f °F\n", tempf);
167
if (getupsvar (monhost, "acfreq", acfreq, sizeof(acfreq)) > 0)
168
printf (" Output Freq: %s Hz\n", acfreq);
170
printf ("</PRE><P>\n");
171
printf ("<CENTER>Network UPS Tools upsstats %s</CENTER>\n", UPS_VERSION);
173
printf ("</TD></TR>\n");
174
printf ("</TABLE></CENTER>\n");
742
printf("Content-type: text/html\n");
743
printf("Pragma: no-cache\n");
746
/* if a host is specified, use upsstats-single.html instead */
752
/* default: multimon replacement mode */
758
display_template("upsstats.html");
760
upscli_disconnect(&ups);