~iheino+ub/+junk/nut-upsconf-docfix

« back to all changes in this revision

Viewing changes to clients/upsstats.c

  • Committer: Tuomas Heino
  • Author(s): Laurent Bigonville
  • Date: 2014-04-22 20:46:12 UTC
  • Revision ID: iheino+ub@cc.hut.fi-20140422204612-1x2gh3nkezfsdao4
Tags: upstream-2.7.2
ImportĀ upstreamĀ versionĀ 2.7.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* upsstats - cgi program to generate the main ups info page
 
2
 
 
3
   Copyright (C) 1998  Russell Kroll <rkroll@exploits.org>
 
4
   Copyright (C) 2005  Arnaud Quette <http://arnaud.quette.free.fr/contact.html>
 
5
 
 
6
   This program is free software; you can redistribute it and/or modify
 
7
   it under the terms of the GNU General Public License as published by
 
8
   the Free Software Foundation; either version 2 of the License, or
 
9
   (at your option) any later version.
 
10
 
 
11
   This program is distributed in the hope that it will be useful,
 
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
   GNU General Public License for more details.
 
15
 
 
16
   You should have received a copy of the GNU General Public License
 
17
   along with this program; if not, write to the Free Software
 
18
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
19
 */
 
20
 
 
21
#include "common.h"
 
22
#include "upsclient.h"
 
23
#include "status.h"
 
24
#include "cgilib.h"
 
25
#include "parseconf.h"
 
26
#include "timehead.h"
 
27
#include "upsstats.h"
 
28
#include "upsimagearg.h"
 
29
 
 
30
#define MAX_CGI_STRLEN 128
 
31
#define MAX_PARSE_ARGS 16
 
32
 
 
33
static char     *monhost = NULL;
 
34
static int      use_celsius = 1, refreshdelay = -1, treemode = 0;
 
35
 
 
36
        /* from cgilib's checkhost() */
 
37
static char     *monhostdesc = NULL;
 
38
 
 
39
static int      port;
 
40
static char     *upsname, *hostname;
 
41
static char     *upsimgpath="upsimage.cgi", *upsstatpath="upsstats.cgi";
 
42
static UPSCONN_t        ups;
 
43
 
 
44
static FILE     *tf;
 
45
static long     forofs = 0;
 
46
 
 
47
static ulist_t  *ulhead = NULL, *currups = NULL;
 
48
 
 
49
static int      skip_clause = 0, skip_block = 0;
 
50
 
 
51
void parsearg(char *var, char *value)
 
52
{
 
53
        /* avoid bogus junk from evil people */
 
54
        if ((strlen(var) > MAX_CGI_STRLEN) || (strlen(value) > MAX_CGI_STRLEN))
 
55
                return;
 
56
 
 
57
        if (!strcmp(var, "host")) {
 
58
                free(monhost);
 
59
                monhost = xstrdup(value);
 
60
                return;
 
61
        }
 
62
 
 
63
        if (!strcmp(var, "refresh"))
 
64
                refreshdelay = (int) strtol(value, (char **) NULL, 10);
 
65
 
 
66
        if (!strcmp(var, "treemode")) {
 
67
                /* FIXME: Validate that treemode is allowed */
 
68
                treemode = 1;
 
69
        }
 
70
}
 
71
 
 
72
static void report_error(void)
 
73
{
 
74
        if (upscli_upserror(&ups) == UPSCLI_ERR_VARNOTSUPP)
 
75
                printf("Not supported\n");
 
76
        else
 
77
                printf("[error: %s]\n", upscli_strerror(&ups));
 
78
}
 
79
 
 
80
/* make sure we're actually connected to upsd */
 
81
static int check_ups_fd(int do_report)
 
82
{
 
83
        if (upscli_fd(&ups) == -1) {
 
84
                if (do_report)
 
85
                        report_error();
 
86
 
 
87
                return 0;
 
88
        }
 
89
 
 
90
        /* also check for insanity in currups */
 
91
 
 
92
        if (!currups) {
 
93
                if (do_report)
 
94
                        printf("No UPS specified for monitoring\n");
 
95
 
 
96
                return 0;
 
97
        }
 
98
 
 
99
        /* must be OK */
 
100
        return 1;
 
101
}
 
102
 
 
103
static int get_var(const char *var, char *buf, size_t buflen, int verbose)
 
104
{
 
105
        int     ret;
 
106
        unsigned int    numq, numa;
 
107
        const   char    *query[4];
 
108
        char    **answer;
 
109
 
 
110
        if (!check_ups_fd(1))
 
111
                return 0;
 
112
 
 
113
        if (!upsname) {
 
114
                if (verbose)
 
115
                        printf("[No UPS name specified]\n");
 
116
 
 
117
                return 0;
 
118
        }
 
119
 
 
120
        query[0] = "VAR";
 
121
        query[1] = upsname;
 
122
        query[2] = var;
 
123
 
 
124
        numq = 3;
 
125
 
 
126
        ret = upscli_get(&ups, numq, query, &numa, &answer);
 
127
 
 
128
        if (ret < 0) {
 
129
                if (verbose)
 
130
                        report_error();
 
131
                return 0;
 
132
        }
 
133
 
 
134
        if (numa < numq) {
 
135
                if (verbose)
 
136
                        printf("[Invalid response]\n");
 
137
                
 
138
                return 0;
 
139
        }
 
140
 
 
141
        snprintf(buf, buflen, "%s", answer[3]);
 
142
        return 1;
 
143
}
 
144
 
 
145
static void parse_var(const char *var)
 
146
{
 
147
        char    answer[SMALLBUF];
 
148
 
 
149
        if (!get_var(var, answer, sizeof(answer), 1))
 
150
                return;
 
151
 
 
152
        printf("%s", answer);
 
153
}
 
154
 
 
155
static void do_status(void)
 
156
{
 
157
        int     i;
 
158
        char    status[SMALLBUF], *ptr, *last = NULL;
 
159
 
 
160
        if (!get_var("ups.status", status, sizeof(status), 1)) {
 
161
                return;
 
162
        }
 
163
 
 
164
        for (ptr = strtok_r(status, " \n", &last); ptr != NULL; ptr = strtok_r(NULL, " \n", &last)) {
 
165
 
 
166
                /* expand from table in status.h */
 
167
                for (i = 0; stattab[i].name != NULL; i++) {
 
168
 
 
169
                        if (!strcasecmp(ptr, stattab[i].name)) {
 
170
                                printf("%s<br>", stattab[i].desc);
 
171
                        }
 
172
                }
 
173
        }
 
174
}
 
175
 
 
176
static void do_runtime(void)
 
177
{
 
178
        int     total, hours, minutes, seconds;
 
179
        char    runtime[SMALLBUF];
 
180
 
 
181
        if (!get_var("battery.runtime", runtime, sizeof(runtime), 1))
 
182
                return;
 
183
 
 
184
        total = (int) strtol(runtime, (char **) NULL, 10);
 
185
 
 
186
        hours = total / 3600;
 
187
        minutes = (total - (hours * 3600)) / 60;
 
188
        seconds = total % 60;
 
189
 
 
190
        printf("%02d:%02d:%02d", hours, minutes, seconds);
 
191
 
 
192
}
 
193
 
 
194
static int do_date(const char *buf)
 
195
{
 
196
        char    datebuf[SMALLBUF];
 
197
        time_t  tod;
 
198
 
 
199
        time(&tod);
 
200
        if (strftime(datebuf, sizeof(datebuf), buf, localtime(&tod))) {
 
201
                printf("%s", datebuf);
 
202
                return 1;
 
203
        }
 
204
 
 
205
        return 0;
 
206
}
 
207
 
 
208
static int get_img_val(const char *var, const char *desc, const char *imgargs)
 
209
{
 
210
        char    answer[SMALLBUF];
 
211
 
 
212
        if (!get_var(var, answer, sizeof(answer), 1))
 
213
                return 1;
 
214
 
 
215
        printf("<IMG SRC=\"%s?host=%s&amp;display=%s",
 
216
                upsimgpath, currups->sys, var);
 
217
 
 
218
        if ((imgargs) && (strlen(imgargs) > 0))
 
219
                printf("&amp;%s", imgargs);
 
220
 
 
221
        printf("\" ALT=\"%s: %s\">", desc, answer);
 
222
 
 
223
        return 1;
 
224
}
 
225
 
 
226
/* see if <arg> is valid - table from upsimagearg.h */
 
227
static void check_imgarg(char *arg, char *out, size_t outlen)
 
228
{
 
229
        int     i;
 
230
        char    *ep;
 
231
 
 
232
        ep = strchr(arg, '=');
 
233
 
 
234
        if (!ep)
 
235
                return;
 
236
 
 
237
        *ep++= '\0';
 
238
 
 
239
        /* if it's allowed, append it so it can become part of the URL */
 
240
        for (i = 0; imgarg[i].name != NULL; i++) {
 
241
                if (!strcmp(imgarg[i].name, arg)) {
 
242
 
 
243
                        if (strlen(out) == 0)
 
244
                                snprintf(out, outlen, "%s=%s", arg, ep);
 
245
                        else
 
246
                                snprintfcat(out, outlen, "&amp;%s=%s", arg, ep);
 
247
                        return;
 
248
                }
 
249
        }
 
250
}
 
251
 
 
252
/* split out the var=val commands from the IMG line */
 
253
static void split_imgarg(char *in, char *out, size_t outlen)
 
254
{
 
255
        char    *ptr, *sp;
 
256
 
 
257
        if (strlen(in) < 3)
 
258
                return;
 
259
 
 
260
        ptr = in;
 
261
 
 
262
        sp = strchr(ptr, ' ');
 
263
 
 
264
        /* split by spaces, then check each one (can't use parseconf...) */
 
265
        while (sp) {
 
266
                *sp++ = '\0';
 
267
                check_imgarg(ptr, out, outlen);
 
268
 
 
269
                ptr = sp;
 
270
                sp = strchr(ptr, ' ');
 
271
        }
 
272
 
 
273
        check_imgarg(ptr, out, outlen);
 
274
}
 
275
 
 
276
/* IMG <type> [<var>=<val] [<var>=<val>] ... */
 
277
static int do_img(char *buf)
 
278
{
 
279
        char    *type, *ptr, imgargs[SMALLBUF];
 
280
 
 
281
        memset(imgargs, '\0', sizeof(imgargs));
 
282
 
 
283
        type = buf;
 
284
 
 
285
        ptr = strchr(buf, ' ');
 
286
 
 
287
        if (ptr) {
 
288
                *ptr++ = '\0';
 
289
                split_imgarg(ptr, imgargs, sizeof(imgargs));
 
290
        }
 
291
 
 
292
        /* only allow known types through */
 
293
 
 
294
        if (!strcmp(type, "input.voltage") 
 
295
                        || !strcmp(type, "input.L1-N.voltage") 
 
296
                        || !strcmp(type, "input.L2-N.voltage") 
 
297
                        || !strcmp(type, "input.L3-N.voltage")
 
298
                        || !strcmp(type, "input.L1-L2.voltage") 
 
299
                        || !strcmp(type, "input.L2-L3.voltage") 
 
300
                        || !strcmp(type, "input.L3-L1.voltage")) {
 
301
                return get_img_val(type, "Input voltage", imgargs);
 
302
        }
 
303
 
 
304
        if (!strcmp(type, "battery.voltage"))
 
305
                return get_img_val(type, "Battery voltage", imgargs);
 
306
 
 
307
        if (!strcmp(type, "battery.charge"))
 
308
                return get_img_val(type, "Battery charge", imgargs);
 
309
 
 
310
        if (!strcmp(type, "output.voltage")
 
311
                        || !strcmp(type, "output.L1-N.voltage") 
 
312
                        || !strcmp(type, "output.L2-N.voltage") 
 
313
                        || !strcmp(type, "output.L3-N.voltage")
 
314
                        || !strcmp(type, "output.L1-L2.voltage") 
 
315
                        || !strcmp(type, "output.L2-L3.voltage") 
 
316
                        || !strcmp(type, "output.L3-L1.voltage")) {
 
317
                return get_img_val(type, "Output voltage", imgargs);
 
318
        }
 
319
 
 
320
        if (!strcmp(type, "ups.load")
 
321
                        || !strcmp(type, "output.L1.power.percent")
 
322
                        || !strcmp(type, "output.L2.power.percent")
 
323
                        || !strcmp(type, "output.L3.power.percent")
 
324
                        || !strcmp(type, "output.L1.realpower.percent")
 
325
                        || !strcmp(type, "output.L2.realpower.percent")
 
326
                        || !strcmp(type, "output.L3.realpower.percent")) {
 
327
                return get_img_val(type, "UPS load", imgargs);
 
328
        }
 
329
 
 
330
        if (!strcmp(type, "input.frequency"))
 
331
                return get_img_val(type, "Input frequency", imgargs);
 
332
 
 
333
        if (!strcmp(type, "output.frequency"))
 
334
                return get_img_val(type, "Output frequency", imgargs);
 
335
 
 
336
        if (!strcmp(type, "ups.temperature"))
 
337
                return get_img_val(type, "UPS temperature", imgargs);
 
338
 
 
339
        if (!strcmp(type, "ambient.temperature"))
 
340
                return get_img_val(type, "Ambient temperature", imgargs);
 
341
 
 
342
        if (!strcmp(type, "ambient.humidity"))
 
343
                return get_img_val(type, "Ambient humidity", imgargs);
 
344
 
 
345
        return 0;
 
346
}
 
347
 
 
348
static void ups_connect(void)
 
349
{
 
350
        static ulist_t  *lastups = NULL;
 
351
        char    *newups, *newhost;
 
352
        int     newport;
 
353
 
 
354
        /* try to minimize reconnects */
 
355
        if (lastups) {
 
356
 
 
357
                /* don't reconnect if these are both the same UPS */
 
358
                if (!strcmp(lastups->sys, currups->sys)) {
 
359
                        lastups = currups;
 
360
                        return;
 
361
                }
 
362
 
 
363
                /* see if it's just on the same host */
 
364
                newups = newhost = NULL;
 
365
 
 
366
                if (upscli_splitname(currups->sys, &newups, &newhost, 
 
367
                        &newport) != 0) {
 
368
                        printf("Unusable UPS definition [%s]\n", currups->sys);
 
369
                        fprintf(stderr, "Unusable UPS definition [%s]\n", 
 
370
                                currups->sys);
 
371
                        exit(EXIT_FAILURE);
 
372
                }               
 
373
 
 
374
                if ((!strcmp(newhost, hostname)) && (port == newport)) {
 
375
                        free(upsname);
 
376
                        upsname = newups;
 
377
 
 
378
                        free(newhost);
 
379
                        lastups = currups;
 
380
                        return;
 
381
                }
 
382
 
 
383
                /* not the same upsd, so disconnect */
 
384
                free(newups);
 
385
                free(newhost);
 
386
        }
 
387
 
 
388
        upscli_disconnect(&ups);
 
389
 
 
390
        free(upsname);
 
391
        free(hostname);
 
392
 
 
393
        if (upscli_splitname(currups->sys, &upsname, &hostname, &port) != 0) {
 
394
                printf("Unusable UPS definition [%s]\n", currups->sys);
 
395
                fprintf(stderr, "Unusable UPS definition [%s]\n", currups->sys);
 
396
                exit(EXIT_FAILURE);
 
397
        }
 
398
 
 
399
        if (upscli_connect(&ups, hostname, port, 0) < 0)
 
400
                fprintf(stderr, "UPS [%s]: can't connect to server: %s\n", currups->sys, upscli_strerror(&ups));
 
401
 
 
402
        lastups = currups;
 
403
}
 
404
 
 
405
static void do_hostlink(void)
 
406
{
 
407
        if (!currups) {
 
408
                return;
 
409
        }
 
410
 
 
411
        printf("<a href=\"%s?host=%s", upsstatpath, currups->sys);
 
412
 
 
413
        if (refreshdelay > 0) {
 
414
                printf("&amp;refresh=%d", refreshdelay);
 
415
        }
 
416
 
 
417
        printf("\">%s</a>", currups->desc);
 
418
}
 
419
 
 
420
static void do_treelink(void)
 
421
{
 
422
        if (!currups) {
 
423
                return;
 
424
        }
 
425
 
 
426
        printf("<a href=\"%s?host=%s&amp;treemode\">All data</a>", upsstatpath, currups->sys);
 
427
}
 
428
 
 
429
/* see if the UPS supports this variable - skip to the next ENDIF if not */
 
430
/* if val is not null, value returned by var must be equal to val to match */
 
431
static void do_ifsupp(const char *var, const char *val)
 
432
{
 
433
        char    dummy[SMALLBUF];
 
434
 
 
435
        /* if not connected, act like it's not supported and skip the rest */
 
436
        if (!check_ups_fd(0)) {
 
437
                skip_clause = 1;
 
438
                return;
 
439
        }
 
440
 
 
441
        if (!get_var(var, dummy, sizeof(dummy), 0)) {
 
442
                skip_clause = 1;
 
443
                return;
 
444
        }
 
445
 
 
446
        if(!val) {
 
447
                return;
 
448
        }
 
449
 
 
450
        if(strcmp(dummy, val)) {
 
451
                skip_clause = 1;
 
452
                return;
 
453
        }
 
454
}
 
455
 
 
456
static int breakargs(char *s, char **aargs)
 
457
{
 
458
        char    *p;
 
459
        int     i=0;
 
460
 
 
461
        aargs[i]=NULL;
 
462
 
 
463
        for(p=s; *p && i<(MAX_PARSE_ARGS-1); p++) {
 
464
                if(aargs[i] == NULL) {
 
465
                        aargs[i] = p;
 
466
                        aargs[i+1] = NULL;
 
467
                }
 
468
                if(*p==' ') {
 
469
                        *p='\0';
 
470
                        i++;
 
471
                }
 
472
        }
 
473
 
 
474
        /* Check how many valid args we got */
 
475
        for(i=0; aargs[i]; i++);
 
476
 
 
477
        return i;
 
478
}
 
479
 
 
480
static void do_ifeq(const char *s)
 
481
{
 
482
        char    var[SMALLBUF];
 
483
        char    *aa[MAX_PARSE_ARGS];
 
484
        int     nargs;
 
485
 
 
486
        strcpy(var, s);
 
487
 
 
488
        nargs = breakargs(var, aa);
 
489
        if(nargs != 2) {
 
490
                printf("upsstats: IFEQ: Argument error!\n");
 
491
                return;
 
492
        }
 
493
 
 
494
        do_ifsupp(aa[0], aa[1]);
 
495
}
 
496
 
 
497
/* IFBETWEEN var1 var2 var3. Skip if var3 not between var1
 
498
 * and var2 */
 
499
static void do_ifbetween(const char *s)
 
500
{
 
501
        char    var[SMALLBUF];
 
502
        char    *aa[MAX_PARSE_ARGS];
 
503
        char    tmp[SMALLBUF];
 
504
        int     nargs;
 
505
        long    v1, v2, v3;
 
506
        char    *isvalid=NULL;
 
507
 
 
508
        strcpy(var, s);
 
509
 
 
510
        nargs = breakargs(var, aa);
 
511
        if(nargs != 3) {
 
512
                printf("upsstats: IFBETWEEN: Argument error!\n");
 
513
                return;
 
514
        }
 
515
 
 
516
        if (!check_ups_fd(0)) {
 
517
                return;
 
518
        }
 
519
 
 
520
        if (!get_var(aa[0], tmp, sizeof(tmp), 0)) {
 
521
                return;
 
522
        }
 
523
        v1 = strtol(tmp, &isvalid, 10);
 
524
        if(tmp == isvalid) {
 
525
                return;
 
526
        }
 
527
 
 
528
        if (!get_var(aa[1], tmp, sizeof(tmp), 0)) {
 
529
                return;
 
530
        }
 
531
        v2 = strtol(tmp, &isvalid, 10);
 
532
        if(tmp == isvalid) {
 
533
                return;
 
534
        }
 
535
 
 
536
        if (!get_var(aa[2], tmp, sizeof(tmp), 0)) {
 
537
                return;
 
538
        }
 
539
        v3 = strtol(tmp, &isvalid, 10);
 
540
        if(tmp == isvalid) {
 
541
                return;
 
542
        }
 
543
 
 
544
        if(v1 > v3 || v2 < v3) {
 
545
                skip_clause = 1;
 
546
                return;
 
547
        }
 
548
}
 
549
 
 
550
static void do_upsstatpath(const char *s) {
 
551
 
 
552
        if(strlen(s)) {
 
553
                upsstatpath = strdup(s);
 
554
        }
 
555
}
 
556
 
 
557
static void do_upsimgpath(const char *s) {
 
558
 
 
559
        if(strlen(s)) {
 
560
                upsimgpath = strdup(s);
 
561
        }
 
562
}
 
563
 
 
564
static void do_temp(const char *var)
 
565
{
 
566
        char    tempc[SMALLBUF];
 
567
        float   tempf;
 
568
 
 
569
        if (!get_var(var, tempc, sizeof(tempc), 1))
 
570
                return;
 
571
 
 
572
        if (use_celsius) {
 
573
                printf("%s", tempc);
 
574
                return;
 
575
        }
 
576
 
 
577
        tempf = (strtod(tempc, (char **) NULL) * 1.8) + 32;
 
578
        printf("%.1f", tempf);
 
579
}
 
580
 
 
581
static void do_degrees(void)
 
582
{
 
583
        printf("&deg;");
 
584
 
 
585
        if (use_celsius)
 
586
                printf("C");
 
587
        else
 
588
                printf("F");
 
589
}
 
590
 
 
591
/* plug in the right color string (like #FF0000) for the UPS status */
 
592
static void do_statuscolor(void)
 
593
{
 
594
        int     severity, i;
 
595
        char    stat[SMALLBUF], *sp, *ptr;
 
596
 
 
597
        if (!check_ups_fd(0)) {
 
598
 
 
599
                /* can't print the warning here - give a red error condition */
 
600
                printf("#FF0000");
 
601
                return;
 
602
        }
 
603
 
 
604
        if (!get_var("ups.status", stat, sizeof(stat), 0)) {
 
605
                /* status not available - give yellow as a warning */
 
606
                printf("#FFFF00");
 
607
                return;
 
608
        }
 
609
 
 
610
        severity = 0;
 
611
        sp = stat;
 
612
 
 
613
        while (sp) {
 
614
                ptr = strchr(sp, ' ');
 
615
                if (ptr)
 
616
                        *ptr++ = '\0';
 
617
 
 
618
                /* expand from table in status.h */
 
619
                for (i = 0; stattab[i].name != NULL; i++)
 
620
                        if (!strcmp(stattab[i].name, sp))
 
621
                                if (stattab[i].severity > severity)
 
622
                                        severity = stattab[i].severity;
 
623
 
 
624
                sp = ptr;
 
625
        }
 
626
 
 
627
        switch(severity) {
 
628
                case 0: printf("#00FF00"); break;       /* green  : OK      */
 
629
                case 1: printf("#FFFF00"); break;       /* yellow : warning */
 
630
 
 
631
                default: printf("#FF0000"); break;      /* red    : error   */
 
632
        }
 
633
}
 
634
 
 
635
static int do_command(char *cmd)
 
636
{
 
637
        /* ending an if block? */
 
638
        if (!strcmp(cmd, "ENDIF")) {
 
639
                skip_clause = 0;
 
640
                skip_block = 0;
 
641
                return 1;
 
642
        }
 
643
 
 
644
        /* Skipping a block means skip until ENDIF, so... */
 
645
        if (skip_block) {
 
646
                return 1;
 
647
        }
 
648
 
 
649
        /* Toggle state when we run across ELSE */
 
650
        if (!strcmp(cmd, "ELSE")) {
 
651
                if (skip_clause) {
 
652
                        skip_clause = 0;
 
653
                } else {
 
654
                        skip_block = 1;
 
655
                }
 
656
                return 1;
 
657
        }
 
658
 
 
659
        /* don't do any commands if skipping a section */
 
660
        if (skip_clause == 1) {
 
661
                return 1;
 
662
        }
 
663
 
 
664
        if (!strncmp(cmd, "VAR ", 4)) {
 
665
                parse_var(&cmd[4]);
 
666
                return 1;
 
667
        }
 
668
 
 
669
        if (!strcmp(cmd, "HOST")) {
 
670
                printf("%s", currups->sys);
 
671
                return 1;
 
672
        }
 
673
 
 
674
        if (!strcmp(cmd, "HOSTDESC")) {
 
675
                printf("%s", currups->desc);
 
676
                return 1;
 
677
        }
 
678
 
 
679
        if (!strcmp(cmd, "RUNTIME")) {
 
680
                do_runtime();
 
681
                return 1;
 
682
        }
 
683
 
 
684
        if (!strcmp(cmd, "STATUS")) {
 
685
                do_status();
 
686
                return 1;
 
687
        }
 
688
 
 
689
        if (!strcmp(cmd, "STATUSCOLOR")) {
 
690
                do_statuscolor();
 
691
                return 1;
 
692
        }
 
693
 
 
694
        if (!strcmp(cmd, "TEMPF")) {
 
695
                use_celsius = 0;
 
696
                return 1;
 
697
        }
 
698
 
 
699
        if (!strcmp(cmd, "TEMPC")) {
 
700
                use_celsius = 1;
 
701
                return 1;
 
702
        }
 
703
 
 
704
        if (!strncmp(cmd, "DATE ", 5)) {
 
705
                return do_date(&cmd[5]);
 
706
        }
 
707
 
 
708
        if (!strncmp(cmd, "IMG ", 4)) {
 
709
                return do_img(&cmd[4]);
 
710
        }
 
711
 
 
712
        if (!strcmp(cmd, "VERSION")) {
 
713
                printf("%s", UPS_VERSION);
 
714
                return 1;
 
715
        }
 
716
 
 
717
        if (!strcmp(cmd, "REFRESH")) {
 
718
                if (refreshdelay > 0) {
 
719
                        printf("<META HTTP-EQUIV=\"Refresh\" CONTENT=\"%d\">", refreshdelay);
 
720
                }
 
721
                return 1;
 
722
        }
 
723
 
 
724
        if (!strcmp(cmd, "FOREACHUPS")) {
 
725
                forofs = ftell(tf);
 
726
 
 
727
                currups = ulhead;
 
728
                ups_connect();
 
729
                return 1;
 
730
        }
 
731
 
 
732
        if (!strcmp(cmd, "ENDFOR")) {
 
733
 
 
734
                /* if not in a for, ignore this */
 
735
                if (forofs == 0) {
 
736
                        return 1;
 
737
                }
 
738
 
 
739
                currups = currups->next;
 
740
 
 
741
                if (currups) {
 
742
                        fseek(tf, forofs, SEEK_SET);
 
743
                        ups_connect();
 
744
                }
 
745
 
 
746
                return 1;
 
747
        }
 
748
 
 
749
        if (!strcmp(cmd, "HOSTLINK")) {
 
750
                do_hostlink();
 
751
                return 1;
 
752
        }
 
753
 
 
754
        if (!strcmp(cmd, "TREELINK")) {
 
755
                do_treelink();
 
756
                return 1;
 
757
        }
 
758
 
 
759
        if (!strncmp(cmd, "IFSUPP ", 7)) {
 
760
                do_ifsupp(&cmd[7], NULL);
 
761
                return 1;
 
762
        }
 
763
 
 
764
        if (!strcmp(cmd, "UPSTEMP")) {
 
765
                do_temp("ups.temperature");
 
766
                return 1;
 
767
        }
 
768
 
 
769
        if (!strcmp(cmd, "BATTTEMP")) {
 
770
                do_temp("battery.temperature");
 
771
                return 1;
 
772
        }
 
773
 
 
774
        if (!strcmp(cmd, "AMBTEMP")) {
 
775
                do_temp("ambient.temperature");
 
776
                return 1;
 
777
        }
 
778
 
 
779
        if (!strcmp(cmd, "DEGREES")) {
 
780
                do_degrees();
 
781
                return 1;
 
782
        }
 
783
 
 
784
        if (!strncmp(cmd, "IFEQ ", 5)) {
 
785
                do_ifeq(&cmd[5]);
 
786
                return 1;
 
787
        }
 
788
 
 
789
        if (!strncmp(cmd, "IFBETWEEN ", 10)) {
 
790
                do_ifbetween(&cmd[10]);
 
791
                return 1;
 
792
        }
 
793
 
 
794
        if (!strncmp(cmd, "UPSSTATSPATH ", 13)) {
 
795
                do_upsstatpath(&cmd[13]);
 
796
                return 1;
 
797
        }
 
798
 
 
799
        if (!strncmp(cmd, "UPSIMAGEPATH ", 13)) {
 
800
                do_upsimgpath(&cmd[13]);
 
801
                return 1;
 
802
        }
 
803
 
 
804
        return 0;
 
805
}
 
806
 
 
807
static void parse_line(const char *buf)
 
808
{
 
809
        char    cmd[SMALLBUF];
 
810
        int     i, len, do_cmd = 0;
 
811
 
 
812
        for (i = 0; buf[i]; i += len) {
 
813
 
 
814
                len = strcspn(&buf[i], "@");
 
815
 
 
816
                if (len == 0) {
 
817
                        if (do_cmd) {
 
818
                                do_command(cmd);
 
819
                                do_cmd = 0;
 
820
                        } else {
 
821
                                cmd[0] = '\0';
 
822
                                do_cmd = 1;
 
823
                        }
 
824
                        i++;    /* skip over the '@' character */
 
825
                        continue;
 
826
                }
 
827
 
 
828
                if (do_cmd) {
 
829
                        snprintf(cmd, sizeof(cmd), "%.*s", len, &buf[i]);
 
830
                        continue;
 
831
                }
 
832
 
 
833
                if (skip_clause || skip_block) {
 
834
                        /* ignore this */
 
835
                        continue;
 
836
                }
 
837
 
 
838
                /* pass it trough */
 
839
                printf("%.*s", len, &buf[i]);
 
840
        }
 
841
}
 
842
 
 
843
static void display_template(const char *tfn)
 
844
{
 
845
        char    fn[SMALLBUF], buf[LARGEBUF];    
 
846
 
 
847
        snprintf(fn, sizeof(fn), "%s/%s", confpath(), tfn);
 
848
 
 
849
        tf = fopen(fn, "r");
 
850
 
 
851
        if (!tf) {
 
852
                fprintf(stderr, "upsstats: Can't open %s: %s\n", fn, strerror(errno));
 
853
 
 
854
                printf("Error: can't open template file (%s)\n", tfn);
 
855
 
 
856
                exit(EXIT_FAILURE);
 
857
        }
 
858
 
 
859
        while (fgets(buf, sizeof(buf), tf)) {
 
860
                parse_line(buf);
 
861
        }
 
862
 
 
863
        fclose(tf);
 
864
}
 
865
 
 
866
static void display_tree(int verbose)
 
867
{
 
868
        unsigned int    numq, numa;
 
869
        const   char    *query[4];
 
870
        char    **answer;
 
871
 
 
872
        if (!upsname) {
 
873
                if (verbose)
 
874
                        printf("[No UPS name specified]\n");
 
875
                return;
 
876
        }
 
877
 
 
878
        query[0] = "VAR";
 
879
        query[1] = upsname;
 
880
        numq = 2;
 
881
 
 
882
        if (upscli_list_start(&ups, numq, query) < 0) {
 
883
                if (verbose)
 
884
                        report_error();
 
885
                return;
 
886
        }
 
887
 
 
888
        printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"\n");
 
889
        printf("        \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n");
 
890
        printf("<HTML>\n");
 
891
        printf("<HEAD><TITLE>upsstat: data tree of %s</TITLE></HEAD>\n", currups->desc);
 
892
 
 
893
        printf("<BODY BGCOLOR=\"#FFFFFF\" TEXT=\"#000000\" LINK=\"#0000EE\" VLINK=\"#551A8B\">\n"); 
 
894
 
 
895
        printf("<TABLE BGCOLOR=\"#50A0A0\" ALIGN=\"CENTER\">\n");
 
896
        printf("<TR><TD>\n");
 
897
 
 
898
        printf("<TABLE CELLPADDING=\"5\" CELLSPACING=\"0\" ALIGN=\"CENTER\" WIDTH=\"100%%\">\n");
 
899
 
 
900
        /* include the description from checkhost() if present */
 
901
        printf("<TR><TH COLSPAN=3 BGCOLOR=\"#50A0A0\">\n");
 
902
        printf("<FONT SIZE=\"+2\">%s</FONT>\n", currups->desc);
 
903
        printf("</TH></TR>\n");
 
904
 
 
905
        printf("<TR><TH COLSPAN=3 BGCOLOR=\"#60B0B0\"></TH></TR>\n");
 
906
 
 
907
        while (upscli_list_next(&ups, numq, query, &numa, &answer) == 1) {
 
908
 
 
909
                /* VAR <upsname> <varname> <val> */
 
910
                if (numa < 4) {
 
911
                        if (verbose)
 
912
                                printf("[Invalid response]\n");
 
913
                
 
914
                        return;
 
915
                }
 
916
 
 
917
                printf("<TR BGCOLOR=\"#60B0B0\" ALIGN=\"LEFT\">\n");
 
918
        
 
919
                printf("<TD>%s</TD>\n", answer[2]);
 
920
                printf("<TD>:</TD>\n");
 
921
                printf("<TD>%s<br></TD>\n", answer[3]);
 
922
 
 
923
                printf("</TR>\n");
 
924
        }
 
925
 
 
926
        printf("</TABLE>\n");
 
927
        printf("</TD></TR></TABLE>\n");
 
928
 
 
929
        /* FIXME (AQ): add a save button (?), and a checkbt for showing var.desc */
 
930
        printf("</BODY></HTML>\n");
 
931
}
 
932
 
 
933
static void add_ups(char *sys, char *desc)
 
934
{
 
935
        ulist_t *tmp, *last;
 
936
 
 
937
        tmp = last = ulhead;
 
938
 
 
939
        while (tmp) { 
 
940
                last = tmp;
 
941
                tmp = tmp->next;
 
942
        }
 
943
 
 
944
        tmp = xmalloc(sizeof(ulist_t));
 
945
 
 
946
        tmp->sys = xstrdup(sys);
 
947
        tmp->desc = xstrdup(desc);
 
948
        tmp->next = NULL;
 
949
 
 
950
        if (last)
 
951
                last->next = tmp;
 
952
        else
 
953
                ulhead = tmp;
 
954
}
 
955
 
 
956
/* called for fatal errors in parseconf like malloc failures */
 
957
static void upsstats_hosts_err(const char *errmsg)
 
958
{
 
959
        upslogx(LOG_ERR, "Fatal error in parseconf(hosts.conf): %s", errmsg);
 
960
}
 
961
 
 
962
static void load_hosts_conf(void)
 
963
{
 
964
        char    fn[SMALLBUF];
 
965
        PCONF_CTX_t     ctx;
 
966
 
 
967
        snprintf(fn, sizeof(fn), "%s/hosts.conf", CONFPATH);
 
968
 
 
969
        pconf_init(&ctx, upsstats_hosts_err);
 
970
 
 
971
        if (!pconf_file_begin(&ctx, fn)) {
 
972
                pconf_finish(&ctx);
 
973
 
 
974
                printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"\n");
 
975
                printf("        \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n");
 
976
                printf("<HTML><HEAD>\n");
 
977
                printf("<TITLE>Error: can't open hosts.conf</TITLE>\n");
 
978
                printf("</HEAD><BODY>\n");
 
979
                printf("Error: can't open hosts.conf\n");
 
980
                printf("</BODY></HTML>\n");
 
981
 
 
982
                /* leave something for the admin */
 
983
                fprintf(stderr, "upsstats: %s\n", ctx.errmsg);
 
984
                exit(EXIT_FAILURE);
 
985
        }
 
986
 
 
987
        while (pconf_file_next(&ctx)) {
 
988
                if (pconf_parse_error(&ctx)) {
 
989
                        upslogx(LOG_ERR, "Parse error: %s:%d: %s",
 
990
                                fn, ctx.linenum, ctx.errmsg);
 
991
                        continue;
 
992
                }
 
993
 
 
994
                if (ctx.numargs < 3)
 
995
                        continue;
 
996
 
 
997
                /* MONITOR <host> <desc> */
 
998
                if (!strcmp(ctx.arglist[0], "MONITOR"))
 
999
                        add_ups(ctx.arglist[1], ctx.arglist[2]);
 
1000
 
 
1001
        }
 
1002
 
 
1003
        pconf_finish(&ctx);
 
1004
 
 
1005
        if (!ulhead) {
 
1006
                printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"\n");
 
1007
                printf("        \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n");
 
1008
                printf("<HTML><HEAD>\n");
 
1009
                printf("<TITLE>Error: no hosts to monitor</TITLE>\n");
 
1010
                printf("</HEAD><BODY>\n");
 
1011
                printf("Error: no hosts to monitor (check <CODE>hosts.conf</CODE>)\n");
 
1012
                printf("</BODY></HTML>\n");
 
1013
 
 
1014
                /* leave something for the admin */
 
1015
                fprintf(stderr, "upsstats: no hosts to monitor\n");
 
1016
                exit(EXIT_FAILURE);
 
1017
        }
 
1018
}
 
1019
 
 
1020
static void display_single(void)
 
1021
{
 
1022
        if (!checkhost(monhost, &monhostdesc)) {
 
1023
                printf("Access to that host [%s] is not authorized.\n",
 
1024
                        monhost);
 
1025
                exit(EXIT_FAILURE);
 
1026
        }
 
1027
 
 
1028
        add_ups(monhost, monhostdesc);
 
1029
 
 
1030
        currups = ulhead;
 
1031
        ups_connect();
 
1032
 
 
1033
        /* switch between data tree view and standard single view */
 
1034
        if (treemode)
 
1035
                display_tree(1);
 
1036
        else
 
1037
                display_template("upsstats-single.html");
 
1038
 
 
1039
        upscli_disconnect(&ups);
 
1040
}
 
1041
 
 
1042
int main(int argc, char **argv)
 
1043
{
 
1044
        extractcgiargs();
 
1045
 
 
1046
        printf("Content-type: text/html\n"); 
 
1047
        printf("Pragma: no-cache\n");
 
1048
        printf("\n");
 
1049
 
 
1050
        /* if a host is specified, use upsstats-single.html instead */
 
1051
        if (monhost) {
 
1052
                display_single();
 
1053
                exit(EXIT_SUCCESS);
 
1054
        }
 
1055
 
 
1056
        /* default: multimon replacement mode */
 
1057
 
 
1058
        load_hosts_conf();
 
1059
 
 
1060
        currups = ulhead;
 
1061
 
 
1062
        display_template("upsstats.html");
 
1063
 
 
1064
        upscli_disconnect(&ups);
 
1065
 
 
1066
        return 0;
 
1067
}