2 * upsimage - cgi program to create graphical ups information reports
4 * Original Author: Russell Kroll <rkroll@exploits.org>
6 * When used together, upsstats and upsimage create interesting looking web
7 * pages with graphical representations of the battery capacity, utility
8 * voltage, and UPS load.
10 * This program utilizes the gd graphics library for snappy IMG generation.
11 * I highly recommend this package for anyone doing similar graphics
14 * This binary needs to be installed some place where upsstats can find it.
16 * Modified: Jonathan Benson <jbenson@technologist.com>
17 * 19/6/98 to suit apcupsd
18 * 23/6/98 added more graphs and menu options
20 * Modified by Kern Sibbald to include additional graphs as well as
21 * to adapt the graphs to varing conditions (voltage, ...). Also,
22 * consolidate a lot of code into subroutines.
24 * Modified by Riccardo Facchetti to support both GIF and PNG formats.
30 #if !defined(SYS_IMGFMT_PNG) && !defined(SYS_IMGFMT_GIF) && !defined(IMGFMT_GIF)
31 # error "A graphic file format must be defined to compile this program."
38 #include "cgiconfig.h"
41 static char mycmd
[16] = "";
42 static char upsval
[16] = "";
43 static char upsval2
[16] = "";
44 static char upsval3
[16] = "";
46 static int green
, black
, white
, grey
, darkgrey
, red
;
48 static void allocate_colors(gdImagePtr im
)
50 black
= gdImageColorAllocate (im
, 0, 0, 0);
51 green
= gdImageColorAllocate (im
, 0, 255, 0);
52 white
= gdImageColorAllocate (im
, 255, 255, 255);
53 grey
= gdImageColorAllocate (im
, 200, 200, 200);
54 darkgrey
= gdImageColorAllocate (im
, 50, 50, 50);
55 red
= gdImageColorAllocate (im
, 255, 0, 0);
58 static void DrawTickLines(gdImagePtr im
)
60 gdImageLine (im
, 50, 60, 150, 60, darkgrey
);
61 gdImageLine (im
, 50, 120, 150, 120, darkgrey
);
62 gdImageLine (im
, 50, 180, 150, 180, darkgrey
);
63 gdImageLine (im
, 50, 240, 150, 240, darkgrey
);
64 gdImageLine (im
, 50, 300, 150, 300, darkgrey
);
67 static void DrawText(gdImagePtr im
, int min
, int step
)
73 (void) snprintf(text
, sizeof(text
), "%d", next
);
74 gdImageString(im
, gdFontLarge
, 0, 295, (unsigned char *)text
, black
);
77 (void) snprintf(text
, sizeof(text
), "%d", next
);
78 gdImageString(im
, gdFontLarge
, 0, 235, (unsigned char *)text
, black
);
81 (void) snprintf(text
, sizeof(text
), "%d", next
);
82 gdImageString(im
, gdFontLarge
, 0, 175, (unsigned char *)text
, black
);
85 (void) snprintf(text
, sizeof(text
), "%d", next
);
86 gdImageString(im
, gdFontLarge
, 0, 115, (unsigned char *)text
, black
);
89 (void) snprintf(text
, sizeof(text
), "%d", next
);
90 gdImageString(im
, gdFontLarge
, 0, 55, (unsigned char *)text
, black
);
93 (void) snprintf(text
, sizeof(text
), "%d", next
);
94 gdImageString(im
, gdFontLarge
, 0, 0, (unsigned char *)text
, black
);
97 static gdImagePtr
InitImage(void)
101 im
= gdImageCreate(150, 350);
103 gdImageColorTransparent (im
, grey
);
104 gdImageFilledRectangle (im
, 0, 0, 150, 350, grey
);
105 gdImageFilledRectangle (im
, 50, 0, 150, 300, green
);
111 void parsearg(const char *var
, const char *value
)
113 if (strcmp(var
, "display") == 0) {
114 strncpy (mycmd
, value
, sizeof(mycmd
));
115 mycmd
[sizeof(mycmd
) - 1] = '\0';
117 } else if (strcmp(var
, "value") == 0) {
118 strncpy (upsval
, value
, sizeof(upsval
));
119 upsval
[sizeof(upsval
) - 1] = '\0';
121 } else if (strcmp(var
, "value2") == 0) {
122 strncpy (upsval2
, value
, sizeof(upsval2
));
123 upsval2
[sizeof(upsval2
) - 1] = '\0';
125 } else if (strcmp(var
, "value3") == 0) {
126 strncpy (upsval3
, value
, sizeof(upsval3
));
127 upsval3
[sizeof(upsval3
) - 1] = '\0';
132 static void imgheader (void)
134 #ifdef SYS_IMGFMT_PNG
135 puts ("Content-Type: image/png");
137 puts ("Content-Type: image/gif");
140 * Since this image is generated based on the parameters passed in
141 * the URL, caching is acceptable. No need for Cache-Control.
146 static void TermImage(gdImagePtr im
)
150 #ifdef SYS_IMGFMT_PNG
151 gdImagePng (im
, stdout
);
153 gdImageGif (im
, stdout
);
158 static void drawbattcap(const char *battcaps
, const char *minbchgs
)
167 battcap
= strtod(battcaps
, NULL
);
168 minbchg
= strtod(minbchgs
, NULL
);
174 minbchgpos
= (int)(300 - (minbchg
* 3));
175 gdImageFilledRectangle(im
, 50, minbchgpos
, 150, 300, red
);
177 battpos
= (int)(300 - (battcap
* 3));
178 gdImageFilledRectangle(im
, 75, battpos
, 125, 300, black
);
180 (void) snprintf(batttxt
, sizeof(batttxt
), "%.1f %%", battcap
);
181 gdImageString(im
, gdFontLarge
, 70, 320, (unsigned char *)batttxt
, black
);
186 static void drawbattvolt(const char *battvolts
, const char *nombattvs
)
194 double hip
, lowp
; /* hi and low red line conditions */
195 int minv
, maxv
, deltav
;
199 battvolt
= strtod(battvolts
, NULL
);
200 nombattv
= strtod(nombattvs
, NULL
);
202 /* NOTE, if you tweek minv and maxv, ensure that the difference
203 * is evenly divisible by 5 or the scales will be wrong!!!
205 switch ((int)nombattv
) {
209 hip
= 12 + 3; /* high redline -- guess */
210 lowp
= 12 - 3; /* low redline -- guess */
226 maxv
= (int)(battvolt
/10 + 1) * 10;
231 deltav
= maxv
- minv
;
233 DrawText(im
, minv
, (deltav
)/5);
236 /* Do proper scaling of battery voltage and redline positions */
237 battpos
= (int)(300 - (((battvolt
- minv
) / deltav
) * 300));
238 hipos
= (int)( 300 - (((hip
- minv
) / deltav
) * 300) );
239 lowpos
= (int)( 300 - (((lowp
- minv
) / deltav
) * 300) );
241 gdImageFilledRectangle (im
, 50, 0, 150, hipos
, red
);
242 gdImageFilledRectangle (im
, 50, lowpos
, 150, 300, red
);
245 gdImageFilledRectangle (im
, 75, battpos
, 125, 300, black
);
247 (void) snprintf (batttxt
, sizeof(batttxt
), "%.1f VDC", battvolt
);
248 gdImageString(im
, gdFontLarge
, 70, 320, (unsigned char *)batttxt
, black
);
254 static void noimage (void)
258 im
= gdImageCreate (150, 350);
262 gdImageColorTransparent (im
, grey
);
264 gdImageFilledRectangle (im
, 0, 0, 150, 300, grey
);
266 gdImageString (im
, gdFontLarge
, 0, 0, (unsigned char *)"Data not available", black
);
269 #ifdef SYS_IMGFMT_PNG
270 gdImagePng (im
, stdout
);
272 gdImageGif (im
, stdout
);
278 static void drawupsload(const char *upsloads
)
285 upsload
= strtod(upsloads
, NULL
);
291 gdImageFilledRectangle (im
, 50, 0, 150, 60, red
);
292 gdImageFilledRectangle (im
, 50, 60, 150, 300, green
);
294 loadpos
= (int)(300 - ((upsload
/ 125) * 300));
295 gdImageFilledRectangle(im
, 75, loadpos
, 125, 300, black
);
297 (void) snprintf(loadtxt
, sizeof(loadtxt
), "%.1f %%", upsload
);
298 gdImageString(im
, gdFontLarge
, 70, 320, (unsigned char *)loadtxt
, black
);
305 static void drawutility (const char *utilitys
, const char *translos
,
306 const char *transhis
)
310 int utilpos
, translopos
, transhipos
;
311 double utility
, translo
, transhi
;
314 utility
= strtod(utilitys
, NULL
);
315 translo
= strtod(translos
, NULL
);
316 transhi
= strtod(transhis
, NULL
);
320 if (utility
> 180) { /* Europe 230V */
323 } else if (utility
> 110) { /* US 110-120 V */
326 } else if (utility
> 95) { /* Japan 100V */
329 } else { /* No voltage */
334 DrawText(im
, minv
, deltav
/5);
335 utilpos
= (int)(300 - (((utility
- minv
) / deltav
) * 300) );
336 translopos
= (int)(300 - (((translo
- minv
) / deltav
) * 300) );
337 transhipos
= (int)(300 - (((transhi
- minv
) / deltav
) * 300) );
339 gdImageFilledRectangle(im
, 50, 0, 150, transhipos
, red
);
340 gdImageFilledRectangle(im
, 50, translopos
, 150, 300, red
);
342 gdImageFilledRectangle (im
, 75, utilpos
, 125, 300, black
);
344 (void) snprintf (utiltxt
, sizeof(utiltxt
), "%.1f VAC", utility
);
345 gdImageString (im
, gdFontLarge
, 65, 320, (unsigned char *)utiltxt
, black
);
353 static void drawupsout (const char *upsouts
)
361 upsout
= strtod(upsouts
, NULL
);
368 } else if (upsout
> 110) {
371 } else if (upsout
> 95) {
379 DrawText(im
, minv
, deltav
/5);
380 uoutpos
= (int)(300 - (((upsout
- minv
) / deltav
) * 300) );
382 gdImageFilledRectangle(im
, 75, uoutpos
, 125, 300, black
);
384 (void) snprintf(utiltxt
, sizeof(utiltxt
), "%.1f VAC", upsout
);
385 gdImageString(im
, gdFontLarge
, 65, 320, (unsigned char *)utiltxt
, black
);
390 static void drawruntime (const char *upsrunts
, const char *lowbatts
)
394 int uoutpos
, lowbattpos
;
399 upsrunt
= strtod(upsrunts
, NULL
);
400 lowbatt
= strtod(lowbatts
, NULL
);
404 step
= (int)(upsrunt
+ 4) / 5;
406 step
= 1; /* make sure we have a positive step */
407 DrawText(im
, 0, step
);
410 uoutpos
= 300 - (int)(upsrunt
* 300 ) / maxt
;
411 lowbattpos
= 300 - (int)(lowbatt
* 300) / maxt
;
413 gdImageFilledRectangle(im
, 50, lowbattpos
, 150, 300, red
);
415 gdImageFilledRectangle(im
, 75, uoutpos
, 125, 300, black
);
417 (void) snprintf(utiltxt
, sizeof(utiltxt
), "%.1f mins", upsrunt
);
418 gdImageString(im
, gdFontLarge
, 65, 320, (unsigned char *)utiltxt
, black
);
424 int main (int argc
, char **argv
)
427 setmode(fileno(stdout
), O_BINARY
);
430 (void) extractcgiargs();
432 if (strcmp(mycmd
, "upsload") == 0) {
435 } else if (strcmp(mycmd
, "battcap") == 0) {
436 drawbattcap(upsval
, upsval2
);
438 } else if (strcmp(mycmd
, "battvolt") == 0) {
439 drawbattvolt(upsval
, upsval2
);
441 } else if (strcmp(mycmd
, "utility") == 0) {
442 drawutility(upsval
, upsval2
, upsval3
);
444 } else if (strcmp(mycmd
, "outputv") == 0) {
447 } else if (strcmp(mycmd
, "runtime") == 0) {
448 drawruntime(upsval
, upsval2
);
451 puts("Status: 400 Bad request");
452 puts("Content-Type: text/plain; charset=utf-8\n");
453 puts("400 Bad request");