1 /* upsimage - cgi program to create graphical ups information reports
2
3 Status:
4 20020814 - Simon Rozman
5 - redesigned the meters
6 20020823 - Simon Rozman
7 - added support for width, height and scale_height parameters
8 - added support for outvolt
9 - noimage now writes out a clue, why upsimage failed
10 20020902 - Simon Rozman
11 - background now transparent by default
12 - added support for colorization parameters
13 - removed linear antialiasing of the scale, until I come up with a better algorithm
14 20020913 - Simon Rozman
15 - added width, height and scale_height to imgarg table
16 20020928 - Simon Rozman
17 - added imgvar table to hold description, how to draw each UPS variable supported
18 - added support for ACFREQ, OUT_FREQ and UPSTEMP
19
20 Copyrights:
21 (C) 1998 Russell Kroll <rkroll@exploits.org>
22 (C) 2002 Simon Rozman <simon@rozman.net>
23
24 This program is free software; you can redistribute it and/or modify
25 it under the terms of the GNU General Public License as published by
26 the Free Software Foundation; either version 2 of the License, or
27 (at your option) any later version.
28
29 This program is distributed in the hope that it will be useful,
30 but WITHOUT ANY WARRANTY; without even the implied warranty of
31 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 GNU General Public License for more details.
33
34 You should have received a copy of the GNU General Public License
35 along with this program; if not, write to the Free Software
36 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
37 */
38
39 #include "common.h"
40 #include "upsclient.h"
41 #include "cgilib.h"
42 #include <stdlib.h>
43 #include <gd.h>
44 #include <gdfontmb.h>
45
46 #include "nut_stdint.h"
47 #include "upsimagearg.h"
48
49 #define MAX_CGI_STRLEN 64
50
51 static char *monhost = NULL, *cmd = NULL;
52
53 static int port;
54 static char *upsname, *hostname;
55 static UPSCONN_t ups;
56
57 #define RED(x) ((x >> 16) & 0xff)
58 #define GREEN(x) ((x >> 8) & 0xff)
59 #define BLUE(x) (x & 0xff)
60
61
parsearg(char * var,char * value)62 void parsearg(char *var, char *value)
63 {
64 long long i, v; /* Be big enough to fit all expected inputs; truncate later */
65
66 /* avoid bogus junk from evil people */
67 if ((strlen(var) > MAX_CGI_STRLEN) || (strlen(value) > MAX_CGI_STRLEN))
68 return;
69
70 if (!strcmp(var, "host")) {
71 free(monhost);
72 monhost = xstrdup(value);
73 return;
74 }
75
76 if (!strcmp(var, "display")) {
77 free(cmd);
78 cmd = xstrdup(value);
79 return;
80 }
81
82 /* see if this is one of the shared (upsimagearg.h) variables */
83 for (i = 0; imgarg[i].name != NULL; i++) {
84 if (!strcmp(imgarg[i].name, var)) {
85 if (!strncmp(value, "0x", 2))
86 v = (long long)strtoul(value + 2, (char **)NULL, 16);
87 else
88 v = (long long)atoi(value);
89
90 /* avoid false numbers from bad people */
91 if (v < imgarg[i].min)
92 imgarg[i].val = imgarg[i].min;
93 else if (v > imgarg[i].max)
94 imgarg[i].val = imgarg[i].max;
95 else {
96 assert (v < INT_MAX);
97 assert (v > INT_MIN);
98 imgarg[i].val = (int)v;
99 }
100 return;
101 }
102 }
103 }
104
105 /* return the value from the URL or the default if it wasn't set */
get_imgarg(const char * name)106 static int get_imgarg(const char *name)
107 {
108 int i;
109
110 for (i = 0; imgarg[i].name != NULL; i++)
111 if (!strcmp(imgarg[i].name, name))
112 return imgarg[i].val;
113
114 return -1;
115 }
116
117 /* write the HTML header then have gd dump the image */
118 static void drawimage(gdImagePtr im)
119 __attribute__((noreturn));
120
drawimage(gdImagePtr im)121 static void drawimage(gdImagePtr im)
122 {
123 printf("Pragma: no-cache\n");
124 printf("Content-type: image/png\n\n");
125
126 gdImagePng(im, stdout);
127 gdImageDestroy(im);
128
129 upscli_disconnect(&ups);
130
131 exit(EXIT_SUCCESS);
132 }
133
134 /* helper function to allocate color in the image */
color_alloc(gdImagePtr im,int rgb)135 static int color_alloc(gdImagePtr im, int rgb)
136 {
137 return gdImageColorAllocate(im, RED(rgb), GREEN(rgb), BLUE(rgb));
138 }
139
140 /* draws the scale behind the bar indicator */
drawscale(gdImagePtr im,int lvllo,int lvlhi,int step,int step5,int step10,int redlo1,int redhi1,int redlo2,int redhi2,int grnlo,int grnhi)141 static void drawscale(
142 gdImagePtr im, /* image where we would like to draw scale */
143 int lvllo, int lvlhi, /* min and max numbers on the scale */
144 int step, int step5, int step10, /* steps for minor, submajor and major dashes */
145 int redlo1, int redhi1, /* first red zone start and end */
146 int redlo2, int redhi2, /* second red zone start and end */
147 int grnlo, int grnhi) /* green zone start and end */
148 {
149 int col1, col2, back_color, scale_num_color, ok_zone_maj_color,
150 ok_zone_min_color, neutral_zone_maj_color,
151 neutral_zone_min_color, warn_zone_maj_color,
152 warn_zone_min_color;
153 char lbltxt[SMALLBUF];
154 int y, level, range;
155 int width, height, scale_height;
156
157 back_color = color_alloc(im, get_imgarg("back_col"));
158 scale_num_color = color_alloc(im, get_imgarg("scale_num_col"));
159 ok_zone_maj_color = color_alloc(im, get_imgarg("ok_zone_maj_col"));
160 ok_zone_min_color = color_alloc(im, get_imgarg("ok_zone_min_col"));
161 neutral_zone_maj_color = color_alloc(im, get_imgarg("neutral_zone_maj_col"));
162 neutral_zone_min_color = color_alloc(im, get_imgarg("neutral_zone_min_col"));
163 warn_zone_maj_color = color_alloc(im, get_imgarg("warn_zone_maj_col"));
164 warn_zone_min_color = color_alloc(im, get_imgarg("warn_zone_min_col"));
165
166 width = get_imgarg("width");
167 height = get_imgarg("height");
168 scale_height = get_imgarg("scale_height");
169
170 /* start out with a background color and make it transparent */
171 gdImageFilledRectangle(im, 0, 0, width, height, back_color);
172 gdImageColorTransparent(im, back_color);
173
174 range = lvlhi - lvllo;
175
176 /* draw scale to correspond with the values */
177 for (level = lvlhi; level >= lvllo; level -= step) {
178 /* select dash RGB color according to the level */
179 if (((redlo1 <= level) && (level <=redhi1)) ||
180 ((redlo2 <= level) && (level <=redhi2))) {
181 col1 = warn_zone_maj_color;
182 col2 = warn_zone_min_color;
183 } else if ((grnlo <= level) && (level <= grnhi)) {
184 col1 = ok_zone_maj_color;
185 col2 = ok_zone_min_color;
186 } else {
187 col1 = neutral_zone_maj_color;
188 col2 = neutral_zone_min_color;
189 }
190
191 /* calculate integer value for y */
192 y = scale_height * (lvlhi - level) / range;
193
194 /* draw major, semimajor or minor dash accordingly */
195 if (level % step10 == 0) {
196 gdImageLine(im, 0, y, width, y, col1);
197 } else {
198 if (level % step5 == 0)
199 gdImageLine(im, 5, y, width - 5, y, col2);
200 else
201 gdImageLine(im, 10, y, width - 10, y, col2);
202 }
203 }
204
205 /* put the values on the scale */
206 for (level = lvlhi; level >= lvllo; level -= step) {
207 if (level % step10 == 0) {
208 y = scale_height * (lvlhi - level) / range;
209 snprintf(lbltxt, sizeof(lbltxt), "%d", level);
210 gdImageString(im, gdFontMediumBold,
211 width - (int)(strlen(lbltxt)) * gdFontMediumBold->w,
212 y, (unsigned char *) lbltxt, scale_num_color);
213 }
214 }
215 }
216
217 /* draws the bar style indicator */
218 static void drawbar(
219 int lvllo, int lvlhi, /* min and max numbers on the scale */
220 int step, int step5, int step10, /* steps for minor, submajor and major dashes */
221 int redlo1, int redhi1, /* first red zone start and end */
222 int redlo2, int redhi2, /* second red zone start and end */
223 int grnlo, int grnhi, /* green zone start and end */
224 double value, /* UPS variable value to draw */
225 const char *format /* printf style format to be used when rendering summary text */
226 )
227 __attribute__((noreturn));
228
drawbar(int lvllo,int lvlhi,int step,int step5,int step10,int redlo1,int redhi1,int redlo2,int redhi2,int grnlo,int grnhi,double value,const char * format)229 static void drawbar(
230 int lvllo, int lvlhi, /* min and max numbers on the scale */
231 int step, int step5, int step10, /* steps for minor, submajor and major dashes */
232 int redlo1, int redhi1, /* first red zone start and end */
233 int redlo2, int redhi2, /* second red zone start and end */
234 int grnlo, int grnhi, /* green zone start and end */
235 double value, /* UPS variable value to draw */
236 const char *format /* printf style format to be used when rendering summary text */
237 )
238 {
239 gdImagePtr im;
240 int bar_color, summary_color;
241 char text[SMALLBUF];
242 int bar_y;
243 int width, height, scale_height;
244
245 /* get the dimension parameters */
246 width = get_imgarg("width");
247 height = get_imgarg("height");
248 scale_height = get_imgarg("scale_height");
249
250 /* create the image */
251 im = gdImageCreate(width, height);
252
253 /* draw the scale */
254 drawscale(im, lvllo, lvlhi, step, step5, step10, redlo1, redhi1,
255 redlo2, redhi2, grnlo, grnhi);
256
257 /* allocate colors for the bar and summary text */
258 bar_color = color_alloc(im, get_imgarg("bar_col"));
259 summary_color = color_alloc(im, get_imgarg("summary_col"));
260
261 /* rescale UPS value to fit in the scale */
262 bar_y = (int)((1.0 - (value - lvllo) / (lvlhi - lvllo)) * scale_height);
263
264 /* sanity checks: */
265
266 /* 1: if value is above maximum, then bar_y goes negative */
267 if (bar_y < 0)
268 bar_y = 0;
269
270 /* 2: if value is below minimum, bar_y goes off the scale */
271 if (bar_y > scale_height)
272 bar_y = scale_height;
273
274 /* draw it */
275 gdImageFilledRectangle(im, 25, bar_y, width - 25, scale_height,
276 bar_color);
277
278 /* stick the text version of the value at the bottom center */
279 #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL
280 #pragma GCC diagnostic push
281 #endif
282 #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL
283 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
284 #endif
285 #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY
286 #pragma GCC diagnostic ignored "-Wformat-security"
287 #endif
288 snprintf(text, sizeof(text), format, value);
289 #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL
290 #pragma GCC diagnostic pop
291 #endif
292 gdImageString(im, gdFontMediumBold,
293 (width - (int)(strlen(text))*gdFontMediumBold->w)/2,
294 height - gdFontMediumBold->h,
295 (unsigned char *) text, summary_color);
296
297 drawimage(im);
298
299 /* NOTREACHED */
300 }
301
302 /* draws the error image */
303 static void noimage(const char *fmt, ...)
304 __attribute__((noreturn));
305
noimage(const char * fmt,...)306 static void noimage(const char *fmt, ...)
307 {
308 gdImagePtr im;
309 int back_color, summary_color;
310 int width, height;
311 char msg[SMALLBUF];
312 va_list ap;
313
314 va_start(ap, fmt);
315 #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL
316 #pragma GCC diagnostic push
317 #endif
318 #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL
319 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
320 #endif
321 #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY
322 #pragma GCC diagnostic ignored "-Wformat-security"
323 #endif
324 vsnprintf(msg, sizeof(msg), fmt, ap);
325 #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL
326 #pragma GCC diagnostic pop
327 #endif
328 va_end(ap);
329
330 width = get_imgarg("width");
331 height = get_imgarg("height");
332
333 im = gdImageCreate(width, height);
334 back_color = color_alloc(im, get_imgarg("back_col"));
335 summary_color = color_alloc(im, get_imgarg("summary_col"));
336
337 gdImageFilledRectangle(im, 0, 0, width, height, back_color);
338 gdImageColorTransparent(im, back_color);
339
340 if (width > height)
341 gdImageString(im, gdFontMediumBold,
342 (width - (int)(strlen(msg))*gdFontMediumBold->w)/2,
343 (height - gdFontMediumBold->h)/2,
344 (unsigned char *) msg, summary_color);
345 else
346 gdImageStringUp(im, gdFontMediumBold,
347 (width - gdFontMediumBold->h)/2,
348 (height + (int)(strlen(msg))*gdFontMediumBold->w)/2,
349 (unsigned char *) msg, summary_color);
350
351 drawimage(im);
352
353 /* NOTE: Earlier code called noimage() and then exit(EXIT_FAILURE);
354 * to signal an error via process exit code. Now that drawimage()
355 * always ends with exit(EXIT_SUCCESS) - which might make webserver
356 * feel good - the command-line use if any suffers no error returns.
357 */
358
359 /* NOTREACHED */
360 }
361
362 /* draws bar indicator when minimum, nominal or maximum values for the given
363 UPS variable can be determined.
364 deviation < 0 means that values below nom should be grey instead of
365 green */
366 static void drawgeneralbar(double var, int min, int nom, int max,
367 int deviation, const char *format)
368 __attribute__((noreturn));
369
drawgeneralbar(double var,int min,int nom,int max,int deviation,const char * format)370 static void drawgeneralbar(double var, int min, int nom, int max,
371 int deviation, const char *format)
372 {
373 int hi, lo, step1, step5, step10, graybelownom=0;
374
375 if(deviation < 0) {
376 deviation=-deviation;
377 graybelownom=1;
378 }
379
380 if ((nom == -1) && ((min == -1) || (max == -1)))
381 noimage("Can't determine range");
382
383 /* if min, max and nom are mixed up, arrange them appropriately */
384 if (nom != -1) {
385 if (min == -1)
386 min = nom - 3*deviation;
387
388 if (max == -1)
389 max = nom + 3*deviation;
390 } else {
391 /* if nominal value isn't available, assume, it's the
392 average between min and max */
393 nom = (min + max) / 2;
394 }
395
396 /* draw scale in the background */
397 if ((max - min) <= 50) {
398 /* the scale is sparse enough to draw finer scale */
399 step1 = 1;
400 step5 = 5;
401 step10 = 10;
402 } else if((max - min) <= 100) {
403 step1 = 2;
404 step5 = 10;
405 step10 = 20;
406 } else {
407 step1 = 5;
408 step5 = 20;
409 step10 = 40;
410 }
411
412 /* round min and max points to get high and low numbers for graph */
413 lo = ((min - deviation) / step10) * step10;
414 hi = ((max + deviation + step10/2) / step10) * step10;
415
416 if(!graybelownom) {
417 drawbar(lo, hi, step1, step5, step10, max, hi, lo, min,
418 nom - deviation, nom + deviation, var, format);
419 }
420 else {
421 drawbar(lo, hi, step1, step5, step10, 0, min, max, hi,
422 nom, max, var, format);
423 }
424
425 /* NOTREACHED */
426 }
427
428 /* draws input and output voltage bar style indicators */
429 static void draw_utility(double var, int min, int nom, int max,
430 int deviation, const char *format)
431 __attribute__((noreturn));
432
draw_utility(double var,int min,int nom,int max,int deviation,const char * format)433 static void draw_utility(double var, int min, int nom, int max,
434 int deviation, const char *format)
435 {
436 /* hack: deal with hardware that doesn't have known transfer points */
437 if (min == -1) {
438 if(var < 200) {
439 min = 90;
440 }
441 else if(var < 300) {
442 min = 200;
443 }
444 else {
445 min = 340;
446 }
447 }
448
449 /* somewhere between 220 and 230 V, to keep everybody satisfied */
450 if (nom == -1) {
451 if(var < 200) {
452 nom = 110;
453 }
454 else if(var < 300) {
455 nom = 225;
456 }
457 else {
458 nom = 400;
459 }
460 }
461
462 /* symmetrical around nom */
463 if (max == -1)
464 max = nom+(nom-min);
465
466 /* Acceptable range of voltage is 85%-110% of nominal voltage
467 * in EU at least. Be conservative and say +-10% */
468 deviation = (int)(nom * 0.1);
469
470 drawgeneralbar(var, min, nom, max, deviation, format);
471
472 /* NOTREACHED */
473 }
474
475 /* draws battery.percent bar style indicator */
476 static void draw_battpct(double var, int min, int nom,
477 int max, int deviation, const char *format)
478 __attribute__((noreturn));
479
draw_battpct(double var,int min,int nom,int max,int deviation,const char * format)480 static void draw_battpct(double var, int min, int nom,
481 int max, int deviation, const char *format)
482 {
483 NUT_UNUSED_VARIABLE(nom);
484 NUT_UNUSED_VARIABLE(max);
485 NUT_UNUSED_VARIABLE(deviation);
486
487 if (min < 0) {
488 min = 50;
489 }
490
491 drawbar(0, 100, 2, 10, 20, 0, min, -1, -1, 80, 100, var, format);
492 }
493
494 /* draws battery.voltage bar style indicator */
495 static void draw_battvolt(double var, int min, int nom, int max,
496 int deviation, const char *format)
497 __attribute__((noreturn));
498
draw_battvolt(double var,int min,int nom,int max,int deviation,const char * format)499 static void draw_battvolt(double var, int min, int nom, int max,
500 int deviation, const char *format)
501 {
502 if(nom == -1) {
503 /* Use a fixed set of reasonable nominal voltages, seems to
504 * be the only way to get reasonable behaviour during
505 * discharge */
506
507 if(var < 9)
508 nom = 6;
509 else if(var < 18)
510 nom = 12;
511 else if(var < 30)
512 nom = 24;
513 else if(var < 60)
514 nom = 48;
515 else if(var < 120)
516 nom = 96;
517 else if(var < 230)
518 nom = 192;
519 else
520 nom = 384;
521
522 }
523
524 if(min == -1) {
525 min = (int)(nom/2*1.6+1); /* Assume a 2V cell is dead at 1.6V */
526 }
527
528 if(max == -1) {
529 max = (int)(nom/2*2.3+1); /* Assume 2.3V float charge voltage */
530 }
531
532 if (nom < min || nom > max)
533 nom = -1;
534
535 deviation = (int)(-nom*0.05); /* 5% deviation from nominal voltage */
536 if(deviation==0) {
537 deviation = -1;
538 }
539
540 drawgeneralbar(var, min, nom, max, deviation, format);
541 }
542
543 /* draws ups.load bar style indicator */
544 static void draw_upsload(double var, int min,
545 int nom, int max,
546 int deviation, const char *format)
547 __attribute__((noreturn));
548
draw_upsload(double var,int min,int nom,int max,int deviation,const char * format)549 static void draw_upsload(double var, int min,
550 int nom, int max,
551 int deviation, const char *format)
552 {
553 NUT_UNUSED_VARIABLE(min);
554 NUT_UNUSED_VARIABLE(nom);
555 NUT_UNUSED_VARIABLE(max);
556 NUT_UNUSED_VARIABLE(deviation);
557
558 drawbar(0, 125, 5, 5, 25, 100, 125, -1, -1, 0, 50, var, format);
559 }
560
561 /* draws temperature bar style indicator */
562 static void draw_temperature(double var, int min, int nom, int max,
563 int deviation, const char *format)
564 __attribute__((noreturn));
565
draw_temperature(double var,int min,int nom,int max,int deviation,const char * format)566 static void draw_temperature(double var, int min, int nom, int max,
567 int deviation, const char *format)
568 {
569 int hi = get_imgarg("tempmax");
570 int lo = get_imgarg("tempmin");
571 NUT_UNUSED_VARIABLE(nom);
572 NUT_UNUSED_VARIABLE(deviation);
573
574 drawbar(lo, hi, 1, 5, 10, lo, min, max, hi, -1, -1, var, format);
575 }
576
577 /* draws humidity bar style indicator */
578 static void draw_humidity(double var, int min, int nom, int max,
579 int deviation, const char *format)
580 __attribute__((noreturn));
581
draw_humidity(double var,int min,int nom,int max,int deviation,const char * format)582 static void draw_humidity(double var, int min, int nom, int max,
583 int deviation, const char *format)
584 {
585 NUT_UNUSED_VARIABLE(nom);
586 NUT_UNUSED_VARIABLE(deviation);
587
588 drawbar(0, 100, 2, 10, 20, 0, min, max, 100, -1, -1, var, format);
589 }
590
get_var(const char * var,char * buf,size_t buflen)591 static int get_var(const char *var, char *buf, size_t buflen)
592 {
593 int ret;
594 size_t numq, numa;
595 const char *query[4];
596 char **answer;
597
598 query[0] = "VAR";
599 query[1] = upsname;
600 query[2] = var;
601
602 numq = 3;
603
604 ret = upscli_get(&ups, numq, query, &numa, &answer);
605
606 if (ret < 0)
607 return 0;
608
609 if (numa < numq)
610 return 0;
611
612 snprintf(buf, buflen, "%s", answer[3]);
613 return 1;
614 }
615
main(int argc,char ** argv)616 int main(int argc, char **argv)
617 {
618 char str[SMALLBUF];
619 int i, min, nom, max;
620 double var = 0;
621 NUT_UNUSED_VARIABLE(argc);
622 NUT_UNUSED_VARIABLE(argv);
623
624 extractcgiargs();
625
626 /* no 'host=' or 'display=' given */
627 if ((!monhost) || (!cmd))
628 noimage("No host or display");
629
630 if (!checkhost(monhost, NULL))
631 noimage("Access denied");
632
633 upsname = hostname = NULL;
634
635 if (upscli_splitname(monhost, &upsname, &hostname, &port) != 0) {
636 noimage("Invalid UPS definition (upsname[@hostname[:port]])\n");
637 #ifndef HAVE___ATTRIBUTE__NORETURN
638 exit(EXIT_FAILURE); /* Should not get here in practice, but compiler is afraid we can fall through */
639 #endif
640 }
641
642 if (upscli_connect(&ups, hostname, port, 0) < 0) {
643 noimage("Can't connect to server:\n%s\n",
644 upscli_strerror(&ups));
645 #ifndef HAVE___ATTRIBUTE__NORETURN
646 exit(EXIT_FAILURE); /* Should not get here in practice, but compiler is afraid we can fall through */
647 #endif
648 }
649
650 for (i = 0; imgvar[i].name; i++)
651 if (!strcmp(cmd, imgvar[i].name)) {
652
653 /* sanity check whether we have draw function
654 registered with this variable */
655 if (!imgvar[i].drawfunc) {
656 noimage("Draw function N/A");
657 #ifndef HAVE___ATTRIBUTE__NORETURN
658 exit(EXIT_FAILURE); /* Should not get here in practice, but compiler is afraid we can fall through */
659 #endif
660 }
661
662 /* get the variable value */
663 if (get_var(imgvar[i].name, str, sizeof(str)) == 1) {
664 var = strtod(str, NULL);
665 } else {
666 /* no value, no fun */
667 snprintf(str, sizeof(str), "%s N/A",
668 imgvar[i].name);
669 noimage(str);
670 #ifndef HAVE___ATTRIBUTE__NORETURN
671 exit(EXIT_FAILURE); /* Should not get here in practice, but compiler is afraid we can fall through */
672 #endif
673 }
674
675 /* when getting minimum, nominal and maximum values,
676 we first look if the marginal value is supported
677 by the UPS driver, if not, we look it up in the
678 imgarg table under the SAME name */
679
680 /* get the minimum value */
681 if (imgvar[i].minimum) {
682 if (get_var(imgvar[i].minimum, str,
683 sizeof(str)) == 1) {
684 min = atoi(str);
685 } else {
686 min = get_imgarg(imgvar[i].minimum);
687 }
688
689 } else {
690 min = -1;
691 }
692
693 /* get the nominal value */
694 if (imgvar[i].nominal) {
695 if (get_var(imgvar[i].nominal, str,
696 sizeof(str)) == 1) {
697 nom = atoi(str);
698 } else {
699 nom = get_imgarg(imgvar[i].nominal);
700 }
701
702 } else {
703 nom = -1;
704 }
705
706 /* get the maximum value */
707 if (imgvar[i].maximum) {
708 if (get_var(imgvar[i].maximum, str,
709 sizeof(str)) == 1) {
710 max = atoi(str);
711 } else {
712 max = get_imgarg(imgvar[i].maximum);
713 }
714
715 } else {
716 max = -1;
717 }
718
719 imgvar[i].drawfunc(var, min, nom, max,
720 imgvar[i].deviation, imgvar[i].format);
721 exit(EXIT_SUCCESS);
722 }
723
724 noimage("Unknown display");
725 #ifndef HAVE___ATTRIBUTE__NORETURN
726 exit(EXIT_FAILURE);
727 #endif
728 }
729
730 imgvar_t imgvar[] = {
731 { "input.voltage", "input.transfer.low", "input.voltage.nominal",
732 "input.transfer.high", 0,
733 "%.1f VAC", draw_utility },
734
735 { "input.L1-N.voltage", "input.transfer.low", "input.voltage.nominal",
736 "input.transfer.high", 0,
737 "%.1f VAC", draw_utility },
738
739 { "input.L2-N.voltage", "input.transfer.low", "input.voltage.nominal",
740 "input.transfer.high", 0,
741 "%.1f VAC", draw_utility },
742
743 { "input.L3-N.voltage", "input.transfer.low", "input.voltage.nominal",
744 "input.transfer.high", 0,
745 "%.1f VAC", draw_utility },
746
747 { "input.L1-L2.voltage", "input.transfer.low", "input.voltage.nominal",
748 "input.transfer.high", 0,
749 "%.1f VAC", draw_utility },
750
751 { "input.L2-L3.voltage", "input.transfer.low", "input.voltage.nominal",
752 "input.transfer.high", 0,
753 "%.1f VAC", draw_utility },
754
755 { "input.L3-L1.voltage", "input.transfer.low", "input.voltage.nominal",
756 "input.transfer.high", 0,
757 "%.1f VAC", draw_utility },
758
759 { "battery.charge", "battery.charge.low", NULL, NULL, 0,
760 "%.1f %%", draw_battpct },
761
762 { "battery.voltage", "battery.voltage.low", "battery.voltage.nominal",
763 "battery.voltage.high", 0,
764 "%.1f VDC", draw_battvolt },
765
766 /* We use 'high' ASCII for the degrees symbol, since the gdImageString()
767 * function doesn't understand UTF-8 or HTML escape sequences. :-( */
768 { "ups.temperature", "ups.temperature.low", NULL,
769 "ups.temperature.high", 0,
770 "%.1f \260C", draw_temperature },
771
772 /* Same here. */
773 { "ambient.temperature", "ambient.temperature.low", NULL,
774 "ambient.temperature.high", 0,
775 "%.1f \260C", draw_temperature },
776
777 { "ambient.humidity", "ambient.humidity.low", NULL,
778 "ambient.humidity.high", 0,
779 "%.1f %%", draw_humidity },
780
781 { "input.frequency", NULL, "input.frequency.nominal", NULL, 2,
782 "%.1f Hz", drawgeneralbar },
783
784 { "ups.load", NULL, NULL, NULL, 0,
785 "%.1f %%", draw_upsload },
786
787 { "output.L1.power.percent", NULL, NULL, NULL, 0,
788 "%.1f %%", draw_upsload },
789
790 { "output.L2.power.percent", NULL, NULL, NULL, 0,
791 "%.1f %%", draw_upsload },
792
793 { "output.L3.power.percent", NULL, NULL, NULL, 0,
794 "%.1f %%", draw_upsload },
795
796 { "output.L1.realpower.percent", NULL, NULL, NULL, 0,
797 "%.1f %%", draw_upsload },
798
799 { "output.L2.realpower.percent", NULL, NULL, NULL, 0,
800 "%.1f %%", draw_upsload },
801
802 { "output.L3.realpower.percent", NULL, NULL, NULL, 0,
803 "%.1f %%", draw_upsload },
804
805 { "output.voltage", "input.transfer.low", "output.voltage.nominal",
806 "input.transfer.high", 0,
807 "%.1f VAC", draw_utility },
808
809 { "output.L1-N.voltage", "input.transfer.low",
810 "output.voltage.nominal", "input.transfer.high", 0,
811 "%.1f VAC", draw_utility },
812
813 { "output.L2-N.voltage", "input.transfer.low",
814 "output.voltage.nominal", "input.transfer.high", 0,
815 "%.1f VAC", draw_utility },
816
817 { "output.L3-N.voltage", "input.transfer.low",
818 "output.voltage.nominal", "input.transfer.high", 0,
819 "%.1f VAC", draw_utility },
820
821 { "output.L1-L2.voltage", "input.transfer.low",
822 "output.voltage.nominal", "input.transfer.high", 0,
823 "%.1f VAC", draw_utility },
824
825 { "output.L2-L3.voltage", "input.transfer.low",
826 "output.voltage.nominal", "input.transfer.high", 0,
827 "%.1f VAC", draw_utility },
828
829 { "output.L3-L1.voltage", "input.transfer.low",
830 "output.voltage.nominal", "input.transfer.high", 0,
831 "%.1f VAC", draw_utility },
832
833 { "output.frequency", NULL, "output.frequency.nominal", NULL, 2,
834 "%.1f Hz", drawgeneralbar },
835
836 { NULL, NULL, NULL, NULL, 0,
837 NULL, NULL }
838 };
839