1 /*
2 MRTG 2.17.4 -- Rateup
3 *********************
4
5 Rateup is a fast add-on to the great MRTG Traffic monitor. It makes
6 the database file updates much faster, and creates the graphic image
7 files, ready for processing by PPMTOGIF. It also reduces memory
8 requirements by a factor of 10, and increases the speed of updates
9 by a factor of at least 10. This makes it feasible to run mrtg
10 every 5 minutes.
11
12 rateup attempts to compensate for missed updates by repeating the last
13 sample, and also tries to catch bad update times. The .log file stores
14 real history every five minutes for 31 hours, then 'compresses' the
15 history into 30 minute samples for a week, then 2-hour samples for
16 31 days, then daily samples for two years. This ensures that the
17 log files don't grow in size.
18
19 The log files are a slightly different format, but convert.perl
20 will fix that for you.
21
22 Enjoy!
23 Dave Rand
24 dlr@bungi.com
25
26 04/26/99 - There was some compilation bug under Watcom 10.6
27 which was fixed when recompiled with VC++ 6.0
28 Alexandre Steinberg
29 steinberg@base.com.br
30
31 */
32
33 #include <stdlib.h>
34 #include <string.h>
35 /* VC++ does not have unistd.h */
36 #ifndef WIN32
37 #ifndef NETWARE
38 #include "../config.h"
39 #endif
40 #include <unistd.h>
41 #endif
42 #include <limits.h>
43 #include <stdio.h>
44 #include <time.h>
45 #include <math.h>
46 #include <ctype.h>
47 #ifndef GFORM_GD
48 #define GFORM_GD gdImagePng
49 #endif
50
51 /* BSD* does not have/need malloc.h */
52 #if !defined(bsdi) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__APPLE__) && !defined(__DragonFly__)
53 #include <malloc.h>
54 #endif
55
56 /* MSVCRT.DLL does not know %ll in printf */
57 #ifdef __MINGW32_VERSION
58 #define LLD "%I64d"
59 #define LLD_FORMAT "I64d"
60 #endif
61
62 #ifdef __EMX__ /* OS/2 */
63 #define strtoll _strtoll
64 #define LLD "%Ld" /* EMX lib use %Ld for long long */
65 #define LLD_FORMAT "Ld"
66 #endif
67
68 #ifndef LLD
69 #define LLD "%lld"
70 #define LLD_FORMAT "lld"
71 #endif
72
73
74 /* WATCOM C/C++ 10.6 under Win95/NT */
75 /* VC++ 6.0 under Win95/NT */
76 #if defined(__WATCOMC__) || defined(WIN32)
77 #include <string.h>
78 #include <sys/types.h>
79 #include <direct.h>
80 #include <io.h>
81 #endif
82
83 #include <gd.h>
84 #include <gdfonts.h>
85
86 char *VERSION = "2.17.4";
87 char *program, *router, *routerpath;
88 int histvalid;
89
90 /* Options */
91 short options = 0;
92 #define OPTION_WITHZEROES 0x0001 /* withzeros */
93 #define OPTION_UNKNASZERO 0x0002 /* unknaszero */
94 #define OPTION_TRANSPARENT 0x0004 /* transparent */
95 #define OPTION_DORELPERCENT 0x0008 /* dorelpercent */
96 #define OPTION_NOBORDER 0x0010 /* noborder */
97 #define OPTION_NOARROW 0x0020 /* noarrow */
98 #define OPTION_NO_I 0x0040 /* ignore 'I' (first) variable */
99 #define OPTION_NO_O 0x0080 /* ignore 'O' (second) variable */
100 #define OPTION_PRINTROUTER 0x0200 /* show title in graph */
101 #define OPTION_LOGGRAPH 0x0400 /* Use a logarithmic Y axis */
102 #define OPTION_MEANOVER 0x0800 /* max Y = mean-above-the-mean */
103 #define OPTION_EXPGRAPH 0x1000 /* exponential scale (opposite of logscale) */
104
105 time_t NOW;
106
107 /* jpt, april 2006 : added 3 lines for date & time logging */
108 struct tm * stLocal;
109 time_t timestamp;
110 char bufftime[32];
111
112 char *short_si_def[] = { "", "k", "M", "G", "T" };
113 int kMGnumber = 4;
114 char **short_si = short_si_def;
115 char *longup = NULL;
116 char *shortup = NULL;
117 char *pngtitle = NULL;
118 char *rtimezone = NULL;
119 char weekformat = 'V'; /* strftime() fmt char for week # */
120
121 #define DAY_COUNT (600) /* 400 samples is 33.33 hours */
122 #define DAY_SAMPLE (5*60) /* Sample every 5 minutes */
123 #define WEEK_COUNT (600) /* 400 samples is 8.33 days */
124 #define WEEK_SAMPLE (30*60) /* Sample every 30 minutes */
125 #define MONTH_COUNT (600) /* 400 samples is 33.33 days */
126 #define MONTH_SAMPLE (2*60*60) /* Sample every 2 hours */
127 #define YEAR_COUNT (2 * 366) /* 1 sample / day, 366 days, 2 years */
128 #define YEAR_SAMPLE (24*60*60) /* Sample every 24 hours */
129
130 /* One 'rounding error' per sample period, so add 4 to total and for
131 good mesure we take 10 :-) */
132 #define MAX_HISTORY (DAY_COUNT+WEEK_COUNT+MONTH_COUNT+YEAR_COUNT+10)
133
134 /* These are the colors used for the variouse parts of the graph */
135 /* the format is Red,Green,Blue */
136
137 #define c_blank 245,245,245
138 #define c_light 194,194,194
139 #define c_dark 100,100,100
140 #define c_major 255,0,0
141 #define c_in 0,235,12
142 #define c_out 0,94,255
143 #define c_grid 0,0,0
144 #define c_inm 0,166,33
145 #define c_outm 255,0,255
146 #define c_outp 239,159,79
147
148 int col_in[3];
149 int col_out[3];
150 int col_inm[3];
151 int col_outm[3];
152 int col_outp[3];
153
154 long long kilo = (long long) 1000;
155 char *kMG = (char *) NULL;
156
157
158 #define MAXL 200 /* Maximum length of last in & out fields */
159
160
161 struct HISTORY
162 {
163 time_t time;
164 double in, out, percent, inmax, outmax;
165 }
166 *history;
167 int Mh;
168
169 struct LAST
170 {
171 time_t time;
172 char in[MAXL], out[MAXL];
173 }
174 last;
175
176 #ifndef max
177 #define max(a,b) ((a) > (b) ? (a) : (b))
178 #endif
179 #ifndef min
180 #define min(a,b) ((a) < (b) ? (a) : (b))
181 #endif
182
183 /*
184
185 notes about the NEXT macro ....
186
187 * position n to the entry in the history array so that NOW is between
188 history[n] and history[n+1]
189
190 * calculate the interval according to steptime and position of
191 now within the history array.
192
193 for debuging
194
195 fprintf (stderr,"%s, NOW: %8lu ST: %4lu N: %4u HTN: %8lu HTN+1: %8lu IV: %6.0f\n", \
196 bufftime,now,steptime,n,history[n].time, history[n+1].time, interval);\
197
198 */
199
200 #define NEXT(steptime) \
201 inmax = outmax = avc = 0; \
202 inr = outr = 0.0;\
203 nextnow = now - steptime;\
204 if (now == history[n].time && \
205 n<histvalid && \
206 nextnow == history[n+1].time) { \
207 inr = (double) history[n].in;\
208 outr = (double) history[n].out;\
209 inmax = history[n].inmax;\
210 outmax = history[n].outmax;\
211 n++;\
212 } else {\
213 if (now > history[n].time) {\
214 fprintf(stderr,"%s, ERROR: Rateup is trying to read ahead of the available data\n" ,bufftime);\
215 } else {\
216 while (now <= history[n+1].time && n < histvalid){n++;}\
217 do {\
218 if (now >= history[n].time) {\
219 if (nextnow <= history[n+1].time) {\
220 interval = history[n].time - history[n+1].time;\
221 } else {\
222 interval = history[n].time - nextnow;\
223 }\
224 } else {\
225 if (nextnow > history[n+1].time) {\
226 interval = steptime;\
227 } else {\
228 interval = now - history[n+1].time;\
229 }\
230 }\
231 inr += (double) history[n].in * interval;\
232 outr += (double) history[n].out * interval;\
233 avc += interval;\
234 inmax = (long long) max(inmax, history[n].inmax);\
235 outmax = (long long) max(outmax,history[n].outmax);\
236 if (nextnow <= history[n+1].time) n++; else break;\
237 } while (n < histvalid && nextnow < history[n].time);\
238 \
239 if (avc != steptime) {\
240 fprintf(stderr,"%s, ERROR: StepTime does not match Avc %8" LLD_FORMAT ". Please Report this.\n", bufftime, avc);\
241 }\
242 \
243 inr /= avc; outr /= avc;\
244 }\
245 }
246
logscale(double y,double maxy)247 static double logscale(double y, double maxy)
248 {
249 y = (y * (maxy - 1) / maxy) + 1;
250 y = log(y) / log (maxy) * maxy;
251 if (y < 0) return 0;
252 if (y > maxy) return maxy;
253 return y;
254 }
255
expscale(double y,double maxy)256 static double expscale(double y, double maxy)
257 {
258 y = exp(y / maxy * log(maxy));
259 return (y - 1) * maxy / (maxy - 1);
260 }
261
262 static void
image(file,maxvi,maxvo,maxx,maxy,xscale,yscale,growright,step,bits,ytics,yticsf,peak,currdatetimeformat,currdatetimepos)263 image (file, maxvi, maxvo, maxx, maxy, xscale, yscale, growright, step, bits,
264 ytics, yticsf, peak, currdatetimeformat, currdatetimepos)
265 char *file;
266 long long maxvi, maxvo;
267 long maxx;
268 long maxy, growright, step, bits;
269 double xscale, yscale;
270 int ytics; /* number of tics on the y axis */
271 double yticsf; /* scale everything on the y axis with this factor */
272 int peak;
273 char *currdatetimeformat;
274 int currdatetimepos;
275 {
276 FILE *fo;
277 char file_tmp[10240];
278 int i, x, n, type;
279
280 long long maxv;
281 double origmaxvi, origmaxvo;
282 long long maxs, avc, inmax, outmax;
283 long long ytrmax;
284 double y, lmx1, lmx2, mea1, mea2, temp;
285 double inr, outr, muli = 1, interval;
286 time_t now, onow, nextnow;
287 struct tm tm2, *tm = &tm2;
288 char **graph_label;
289 char ylab[30];
290 /* scaling helpers */
291 long long maxv_q;
292 long long valsamp, maxin, maxout, digits, digits1, maxpercent = 0;
293 long long sca_ten, sca_hun;
294 double nmax_q;
295 double avmxin, avmxout, avin, avout, latestout = 0, latestin =
296 0, nmax, avpercent = 0, latestpercent = 0;
297 double nex_ten, nex_hun, nex_rnd;
298 double sca_max_q, dummy;
299 double percent;
300 char *short_si_out;
301 char currdatetimestr[256];
302 time_t currdatetime;
303 int currdatetimepos_x, currdatetimepos_y;
304
305 #define NO_TIMESTAMPSTR (0)
306 #define LU_CORNER (1)
307 #define RU_CORNER (2)
308 #define LL_CORNER (3)
309 #define RL_CORNER (4)
310
311
312 struct HISTORY *lhist;
313 /* ################################################# */
314 /* Some general definitions for the graph generation */
315 #define XSIZE (long)((maxx*xscale)+100+((options & OPTION_DORELPERCENT) ? 1 : 0)*30)
316 #define YSIZE (long)((maxy*yscale)+35)
317 /* position the graph */
318 #define ytr(y) (long)(maxy*yscale+14-((y)*yscale))
319 /* translate x/y coord into graph coord */
320 #define xtr(x) (long)((growright) ? (maxx*xscale+81-((x)*xscale)) : (81+((x)*xscale)))
321 /* ################################################# */
322
323
324
325 /* GD LIB declarations */
326 /* Declare the image */
327 gdImagePtr graph, brush_out, brush_outm, brush_outp;
328 /* Declare color indexes */
329 int i_light, i_dark, i_blank, i_major, i_in, i_out, i_grid, i_inm, i_outm;
330 int i_outp, i_outpg;
331 /* Dotted style */
332 int styleDotted[3];
333 if ((graph_label = (char **) calloc (1, sizeof (char *) * maxx)) == NULL)
334 {
335 fprintf (stderr, "%s, Rateup ERROR: Out of memory in graph creation\n", bufftime);
336 exit (1);
337 }
338
339 /* multiplicator for bits/bytes */
340 if (bits) {
341 muli = 8;
342 }
343
344 maxv = (long long) max (maxvi, maxvo);
345 maxv *= (long long) muli;
346
347 origmaxvi = maxvi < (long long) 0 ? -maxvi : maxvi;
348 origmaxvo = maxvo < (long long) 0 ? -maxvo : maxvo;
349
350 if (step > MONTH_SAMPLE)
351 {
352 type = 4;
353 now = (long) (NOW / YEAR_SAMPLE) * YEAR_SAMPLE;
354
355 }
356 else if (step > WEEK_SAMPLE)
357 {
358 type = 3;
359 now = (long) (NOW / MONTH_SAMPLE) * MONTH_SAMPLE;
360 }
361 else if (step > DAY_SAMPLE)
362 {
363 type = 2;
364 now = (long) (NOW / WEEK_SAMPLE) * WEEK_SAMPLE;
365 }
366 else
367 {
368 type = 1;
369 now = (long) (NOW / DAY_SAMPLE) * DAY_SAMPLE;
370 }
371 if ((lhist = calloc (1, sizeof (struct HISTORY) * maxx)) == NULL)
372 {
373 fprintf (stderr, "%s, Rateup ERROR: Out of memory in graph creation\n", bufftime);
374 exit (1);
375 }
376 onow = now;
377 avin = avout = avmxin = avmxout = 0.0;
378 inmax = outmax = maxin = maxout = 0;
379 valsamp = 0;
380 for (maxs = 0, n = 0, x = 0; x < maxx; x++)
381 {
382 NEXT (step);
383 /*scale with muli */
384 inr *= muli;
385 outr *= muli;
386 inmax *= muli;
387 outmax *= muli;
388 /* ignore times when we have not sampled */
389 if (inmax > 0 || outmax > 0 || inr > 0 || outr > 0
390 || (options & OPTION_WITHZEROES)) valsamp++;
391 if (x == 0)
392 {
393 latestin = inr;
394 latestout = outr;
395 if (outr)
396 {
397 latestpercent = inr * (double) 100. / outr;
398 }
399 }
400 avin += inr;
401 avout += outr;
402 avmxin += inmax;
403 avmxout += outmax;
404
405 if (peak)
406 {
407 maxin = (long long) max (maxin, inmax);
408 maxout = (long long) max (maxout, outmax);
409 if (!(options & OPTION_NO_I)){
410 maxs = (long long) max (maxs, inmax);
411 }
412 if (!(options & OPTION_NO_O)){
413 maxs = (long long) max (maxs, outmax);
414 }
415 }
416 else
417 {
418 maxin = (long long) max (maxin, inr);
419 maxout = (long long) max (maxout, outr);
420 if (!(options & OPTION_NO_I)){
421 maxs = (long long) max (maxs, inr);
422 }
423 if (!(options & OPTION_NO_O)){
424 maxs = (long long) max (maxs, outr);
425 }
426 }
427 if ((options & OPTION_DORELPERCENT) && outr)
428 {
429 dummy = (double) 100. *inr / outr;
430 maxpercent = max (dummy, maxpercent);
431 }
432 now -= step;
433 }
434 if (options & OPTION_DORELPERCENT)
435 {
436 if (avout && valsamp)
437 {
438 avpercent = (double) 100. *avin / avout;
439 }
440 else
441 {
442 avpercent = 0;
443 }
444 }
445 if (valsamp)
446 {
447 avin /= valsamp;
448 avout /= valsamp;
449 avmxin /= valsamp;
450 avmxout /= valsamp;
451 }
452
453 printf ("" LLD "\n", (long long) (maxin / (long long) muli + .5));
454 printf ("" LLD "\n", (long long) (maxout / (long long) muli + .5));
455 if (options & OPTION_DORELPERCENT)
456 {
457 printf ("" LLD "\n", (long long) (maxpercent + .5));
458 }
459 printf ("" LLD "\n", (long long) (avin / (long long) muli + .5));
460 printf ("" LLD "\n", (long long) (avout / (long long) muli + .5));
461 if (options & OPTION_DORELPERCENT)
462 {
463 printf ("" LLD "\n", (long long) (avpercent + .5));
464 }
465 printf ("" LLD "\n", (long long) (latestin / (long long) muli + .5));
466 printf ("" LLD "\n", (long long) (latestout / (long long) muli + .5));
467 if (options & OPTION_DORELPERCENT)
468 {
469 printf ("" LLD "\n", (long long) (latestpercent + .5));
470 }
471 printf ("" LLD "\n", (long long) (avmxin / (long long) muli + .5));
472 printf ("" LLD "\n", (long long) (avmxout / (long long) muli + .5));
473
474 if (maxv < 0 || maxv < maxs)
475 {
476 maxv = maxs;
477 }
478
479 now = onow;
480
481 if (maxv <= 0)
482 maxv = 1;
483
484 if (kMG)
485 {
486 if (short_si[0] != kMG)
487 {
488 short_si_out = kMG;
489 kMGnumber = 0;
490 while ((short_si_out = strchr (short_si_out, ',')) != NULL)
491 {
492 short_si_out++;
493 kMGnumber++;
494 }
495 short_si = calloc(kMGnumber + 1, sizeof(*short_si));
496 short_si_out = kMG;
497 for (kMGnumber = 0; ; kMGnumber++)
498 {
499 short_si[kMGnumber] = short_si_out;
500 short_si_out = strchr(short_si_out, ',');
501 if (short_si_out == NULL) break;
502 short_si_out[0] = '\0';
503 short_si_out++;
504 }
505 }
506 }
507
508 /* mangle the 0.25*maxv value so, that we get a number with either */
509 /* one or two digits != 0 and these digits should be at the */
510 /* start of the number ... */
511
512 /* the ceil compensates for rounding with small numbers */
513 maxv_q = ceil ((double) maxv / (double) ytics); /* int */
514
515 digits = 0;
516 {
517 double number = (double) maxv_q;
518 number *= yticsf; /* we just want to scale the lables nothing else */
519
520 /*
521 while (number/(double) kilo >= (double)kilo && digits<kMGnumber*3) {
522 */
523 /* yes this should be kilo, but then the log and pow bits below
524 should be base 'kilo' as well and not base 10 */
525
526 while (digits < (long long) kMGnumber * 3 &&
527 (number >= (double) 1000 || short_si[digits / 3][0] == '-'))
528 {
529 number /= (double) 1000;
530 digits += 3;
531 }
532 sca_max_q = (double) ((int) (((double) 100. * (double) number) /
533 (pow
534 ((double) 10.,
535 (double) (int) (log10 ((double) number))))
536 +
537 (double) 9.999) / (int) 10) / (double) 10 *
538 (pow ((double) 10., (double) (int) (log10 ((double) number))));
539 }
540
541 short_si_out = short_si[min ((signed) (digits / 3), kMGnumber)];
542
543 if (maxv_q * yticsf >= 1)
544 {
545 digits1 = log10 ((double) maxv_q * yticsf);
546 }
547 else
548 {
549 digits1 = 0;
550 }
551
552 /* sca_ten = maxv_q / pow(10.0,(double)digits); */
553 /* sca_hun = maxv_q / pow(10.0,(double)digits-1); */
554 sca_ten = (double) maxv_q *yticsf / pow (10.0, (double) digits1);
555 sca_hun = (double) maxv_q *yticsf / pow (10.0, (double) digits1 - 1);
556 nex_rnd = (sca_hun) * pow (10.0, (double) digits1 - 1);
557 nex_ten = (sca_ten + 1) * pow (10.0, (double) digits1);
558 nex_hun = (sca_hun + 1) * pow (10.0, (double) digits1 - 1);
559
560 /* if (nex_ten <= (1.1 * maxv_q)) { */
561 if (nex_ten <= (1.1 * maxv_q * yticsf))
562 {
563 nmax_q = nex_ten;
564 /* } else if (maxv_q == nex_rnd) { */
565 }
566 else if ((maxv_q * yticsf) == nex_rnd)
567 {
568 nmax_q = nex_rnd;
569 }
570 else
571 {
572 nmax_q = nex_hun;
573 }
574
575 sca_max_q = nmax_q / (pow (10.0, (double) ((int) (digits / 3)) * 3));
576 /* nmax=sca_max_q*ytics*(pow((double)kilo,(double)((int)(digits1/3)))); */
577 nmax =
578 (sca_max_q / yticsf) * ytics *
579 (pow ((double) kilo, (double) ((int) (digits / 3))));
580
581 if (nmax < 1.)
582 {
583 nmax = 1.;
584 }
585
586 for (n = 0, x = 0; x < maxx; x++)
587 {
588 lhist[x].time = 0;
589 graph_label[x] = NULL;
590 /* this seesm to be necessary to work a round a bug in solaris
591 where tm for complex TZ settings gets modified after the
592 fact ... so we whisk the stuff away into our own memspace
593 just in time */
594 memcpy (tm, localtime (&history[n].time), sizeof (struct tm));
595 switch (type)
596 {
597 default:
598 case 1:
599 if (tm->tm_min < 5)
600 {
601 lhist[x].time |= 1;
602 if (tm->tm_hour == 0)
603 lhist[x].time |= 2;
604 }
605 if ((tm->tm_min < 5) && (tm->tm_hour % 2 == 0))
606 {
607 if ((graph_label[x] = calloc (1, sizeof (char) * 4)) == NULL)
608 {
609 fprintf (stderr,
610 "%s, Rateup ERROR: Out of memory in graph labeling\n", bufftime);
611 exit (0);
612 }
613 else
614 {
615 sprintf (graph_label[x], "%i", tm->tm_hour);
616 }
617 }
618 break;
619 case 2:
620 if (tm->tm_min < 30 && tm->tm_hour == 0)
621 {
622 lhist[x].time |= 1;
623 if (tm->tm_wday == 1)
624 lhist[x].time |= 2;
625 }
626
627 /* fprintf(stderr,"%s, x: %i, min:%i, hour:%i day: %i\n",
628 bufftime,x,tm->tm_min,tm->tm_hour,tm->tm_wday); */
629 if ((tm->tm_min < 30) && (tm->tm_hour == 12))
630 {
631 if ((graph_label[x] = calloc (1, sizeof (char) * 5)) == NULL)
632 {
633 fprintf (stderr,
634 "%s, Rateup ERROR: Out of memory in graph labeling\n", bufftime);
635 exit (0);
636 }
637 else
638 {
639 strftime (graph_label[x], 4, "%a", tm);
640 }
641 }
642
643 break;
644 case 3:
645 if (tm->tm_hour < 2)
646 {
647 if (tm->tm_wday == 1)
648 lhist[x].time |= 1;
649 if (tm->tm_mday == 1)
650 lhist[x].time |= 2;
651 }
652 /* label goes to thursday noon */
653
654 if ((tm->tm_hour > 10) && (tm->tm_hour <= 12) && (tm->tm_wday == 4))
655 {
656 if ((graph_label[x] = calloc (1, sizeof (char) * 16)) == NULL)
657 {
658 fprintf (stderr,
659 "%s, Rateup ERROR: Out of memory in graph labeling\n", bufftime);
660 exit (0);
661 }
662 else
663 {
664 char fmtbuf[10];
665 sprintf (fmtbuf, "Week %%%c", weekformat);
666 strftime (graph_label[x], 8, fmtbuf, tm);
667 }
668 }
669 break;
670 case 4:
671 if (tm->tm_mday == 1)
672 lhist[x].time |= 1;
673 if (tm->tm_yday == 0)
674 lhist[x].time |= 2;
675
676
677 if (tm->tm_mday == 15)
678 {
679 if ((graph_label[x] = calloc (1, sizeof (char) * 5)) == NULL)
680 {
681 fprintf (stderr,
682 "%s, Rateup Error: Out of memory in graph labeling\n", bufftime);
683 exit (0);
684 }
685 else
686 {
687 strftime (graph_label[x], 4, "%b", tm);
688 }
689 }
690 break;
691 }
692
693 NEXT (step);
694
695 /*scale with muli */
696 inr *= muli;
697 outr *= muli;
698 inmax *= muli;
699 outmax *= muli;
700
701
702 y = ((double) inr / nmax) * maxy;
703 if (y >= maxy)
704 y = maxy;
705 lhist[x].in = y;
706
707 y = ((double) outr / nmax) * maxy;
708 if (y >= maxy)
709 y = maxy;
710 lhist[x].out = y;
711
712 y = ((double) inmax / nmax) * maxy;
713 if (y >= maxy)
714 y = maxy;
715 lhist[x].inmax = y;
716
717 y = ((double) outmax / nmax) * maxy;
718 if (y >= maxy)
719 y = maxy;
720 lhist[x].outmax = y;
721
722 if (options & OPTION_DORELPERCENT)
723 {
724 if (outr != (long long) 0)
725 {
726 percent = (double) inr / (double) outr;
727 }
728 else
729 {
730 percent = (double) 0.;
731 }
732 if (percent > (double) 1)
733 percent = (double) 1.;
734 percent *= maxy;
735 lhist[x].percent = (long long) percent;
736 }
737 else
738 {
739 lhist[x].percent = (long long) 0;
740 }
741
742 now -= step;
743 }
744 origmaxvi = (origmaxvi * muli / nmax ) * maxy;
745 origmaxvo = (origmaxvo * muli / nmax ) * maxy;
746
747 /* Log and second-mean scaling added by Benjamin Despres, 2004-10-13 */
748 if (options & OPTION_MEANOVER)
749 {
750 lmx1 = lmx2 = mea1 = mea2 = temp = 0.0;
751 for (x = 0; x < maxx; x++)
752 {
753 if (lhist[x].in < 1.0)
754 lhist[x].in = 1.0;
755 if (lhist[x].out < 1.0)
756 lhist[x].out = 1.0;
757 if (lhist[x].inmax < 1.0)
758 lhist[x].inmax = 1.0;
759 if (lhist[x].outmax < 1.0)
760 lhist[x].outmax = 1.0;
761 if (lhist[x].in > lmx1)
762 lmx1 = lhist[x].in;
763 if (lhist[x].out > lmx1)
764 lmx1 = lhist[x].out;
765 if (lhist[x].inmax > lmx1)
766 lmx1 = lhist[x].inmax;
767 if (lhist[x].outmax > lmx1)
768 lmx1 = lhist[x].outmax;
769 mea1 +=
770 (lhist[x].in + lhist[x].out + lhist[x].inmax +
771 lhist[x].outmax) / 4.0;
772 }
773 if (origmaxvi < 1.0)
774 origmaxvi = 1.0;
775 if (origmaxvo < 1.0)
776 origmaxvo = 1.0;
777
778 mea1 /= (double) maxx;
779 for (x = 0; x < maxx; x++)
780 {
781 y =
782 (lhist[x].in + lhist[x].out + lhist[x].inmax +
783 lhist[x].outmax) / 4.0;
784 if (y > mea1)
785 {
786 mea2 += y;
787 temp += 1.0;
788 }
789 }
790 mea2 /= temp;
791 for (x = 0; x < maxx; x++)
792 {
793 if (lhist[x].in > mea2)
794 lhist[x].in = mea2;
795 if (lhist[x].out > mea2)
796 lhist[x].out = mea2;
797 if (lhist[x].inmax > mea2)
798 lhist[x].inmax = mea2;
799 if (lhist[x].outmax > mea2)
800 lhist[x].outmax = mea2;
801 }
802 for (x = 0; x < maxx; x++)
803 {
804 if (lhist[x].in > lmx2)
805 lmx2 = lhist[x].in;
806 if (lhist[x].out > lmx2)
807 lmx2 = lhist[x].out;
808 if (lhist[x].inmax > lmx2)
809 lmx2 = lhist[x].inmax;
810 if (lhist[x].outmax > lmx2)
811 lmx2 = lhist[x].outmax;
812 }
813 if (lmx2 > 0.0)
814 lmx2 = (lmx1 / lmx2);
815 for (x = 0; x < maxx; x++)
816 {
817 lhist[x].in *= lmx2;
818 lhist[x].out *= lmx2;
819 lhist[x].inmax *= lmx2;
820 lhist[x].outmax *= lmx2;
821 }
822 origmaxvi *= lmx2;
823 origmaxvo *= lmx2;
824
825 sca_max_q *= ((float) mea2 / (float) maxy);
826 }
827 else if (options & OPTION_LOGGRAPH)
828 {
829 for (x = 0; x < maxx; x++)
830 {
831 lhist[x].in = logscale (lhist[x].in, maxy);
832 lhist[x].out = logscale (lhist[x].out, maxy);
833 lhist[x].inmax = logscale (lhist[x].inmax, maxy);
834 lhist[x].outmax = logscale (lhist[x].outmax, maxy);
835 }
836 origmaxvi = logscale (origmaxvi, maxy);
837 origmaxvo = logscale (origmaxvo, maxy);
838 } /* end of primary log and second-mean scaling code (more below) */
839 else if (options & OPTION_EXPGRAPH)
840 {
841 for (x = 0; x < maxx; x++)
842 {
843 lhist[x].in = expscale (lhist[x].in, maxy);
844 lhist[x].out = expscale (lhist[x].out, maxy);
845 lhist[x].inmax = expscale (lhist[x].inmax, maxy);
846 lhist[x].outmax = expscale (lhist[x].outmax, maxy);
847 }
848 origmaxvi = expscale (origmaxvi, maxy);
849 origmaxvo = expscale (origmaxvo, maxy);
850 }
851
852 /* the graph is made ten pixels higher to acomodate the x labels */
853 graph = gdImageCreate (XSIZE, YSIZE);
854 brush_out = gdImageCreate (1, 2);
855 brush_outm = gdImageCreate (1, 2);
856 brush_outp = gdImageCreate (1, 2);
857
858 /* the first color allocated will be the background color. */
859 i_blank = gdImageColorAllocate (graph, c_blank);
860 i_light = gdImageColorAllocate (graph, c_light);
861 i_dark = gdImageColorAllocate (graph, c_dark);
862
863 if (options & OPTION_TRANSPARENT)
864 {
865 gdImageColorTransparent (graph, i_blank);
866 }
867 gdImageInterlace (graph, 1);
868
869 /* do NOT delete the out variables. they are dummies, but the actual color
870 allocation for the brush is essential */
871 i_major = gdImageColorAllocate (graph, c_major);
872 i_in = gdImageColorAllocate (graph, col_in[0], col_in[1], col_in[2]);
873 i_out =
874 gdImageColorAllocate (brush_out, col_out[0], col_out[1], col_out[2]);
875 i_grid = gdImageColorAllocate (graph, c_grid);
876 i_inm = gdImageColorAllocate (graph, col_inm[0], col_inm[1], col_inm[2]);
877 i_outm =
878 gdImageColorAllocate (brush_outm, col_outm[0], col_outm[1], col_outm[2]);
879 i_outp =
880 gdImageColorAllocate (brush_outp, col_outp[0], col_outp[1], col_outp[2]);
881 i_outpg =
882 gdImageColorAllocate (graph, col_outp[0], col_outp[1], col_outp[2]);
883
884 /* draw the image border */
885 if (!(options & OPTION_NOBORDER))
886 {
887 gdImageLine (graph, 0, 0, XSIZE - 1, 0, i_light);
888 gdImageLine (graph, 1, 1, XSIZE - 2, 1, i_light);
889 gdImageLine (graph, 0, 0, 0, YSIZE - 1, i_light);
890 gdImageLine (graph, 1, 1, 1, YSIZE - 2, i_light);
891 gdImageLine (graph, XSIZE - 1, 0, XSIZE - 1, YSIZE - 1, i_dark);
892 gdImageLine (graph, 0, YSIZE - 1, XSIZE - 1, YSIZE - 1, i_dark);
893 gdImageLine (graph, XSIZE - 2, 1, XSIZE - 2, YSIZE - 2, i_dark);
894 gdImageLine (graph, 1, YSIZE - 2, XSIZE - 2, YSIZE - 2, i_dark);
895 }
896
897 /* draw the incoming traffic */
898 if (!(options & OPTION_NO_I))
899 {
900 for (x = 0; x < maxx; x++)
901 {
902 /* peak is always above average, we therefore only draw the upper part */
903 if (peak)
904 gdImageLine (graph, xtr (x), ytr (lhist[x].in),
905 xtr (x), ytr (lhist[x].inmax), i_inm);
906 #ifdef INCOMING_UNFILLED
907 gdImageLine (graph, xtr (x), ytr (lhist[x].in), xtr (x),
908 ytr (lhist[x + 1].in), i_in);
909 #else
910 gdImageLine (graph, xtr (x), ytr (0), xtr (x), ytr (lhist[x].in),
911 i_in);
912 /* draw the line a second time offset slightly. makes the graph
913 * look better if xscale is fractional */
914 gdImageLine (graph, xtr (x + 0.5), ytr (0), xtr (x + 0.5),
915 ytr (lhist[x].in), i_in);
916 #endif
917 }
918 }
919
920 /* draw the percentage */
921 if (options & OPTION_DORELPERCENT)
922 {
923 gdImageSetBrush (graph, brush_outp);
924 for (x = 0; x < maxx - 1; x++)
925 gdImageLine (graph, xtr (x), ytr (lhist[x].percent),
926 xtr (x + 1), ytr (lhist[x + 1].percent), gdBrushed);
927 }
928
929 /* draw the outgoing traffic */
930 if (!(options & OPTION_NO_O))
931 {
932 gdImageSetBrush (graph, brush_outm);
933 if (peak)
934 for (x = 0; x < maxx - 1; x++)
935 gdImageLine (graph, xtr (x), ytr (lhist[x].outmax),
936 xtr (x + 1), ytr (lhist[x + 1].outmax), gdBrushed);
937 gdImageSetBrush (graph, brush_out);
938 for (x = 0; x < maxx - 1; x++)
939 gdImageLine (graph, xtr (x), ytr (lhist[x].out),
940 xtr (x + 1), ytr (lhist[x + 1].out), gdBrushed);
941 }
942
943 /* print the graph title */
944 if (pngtitle != NULL)
945 {
946 gdImageString (graph, gdFontSmall, 81, 1,
947 (unsigned char *) pngtitle, i_grid);
948 }
949 else
950 {
951 if (options & OPTION_PRINTROUTER)
952 {
953 gdImageString (graph, gdFontSmall, 81, 1,
954 (unsigned char *) router, i_grid);
955 }
956 }
957
958 /* draw the graph border */
959 gdImageRectangle (graph, xtr (0), ytr (0), xtr (maxx), ytr (maxy), i_grid);
960
961 /*create a dotted style for the grid lines */
962 styleDotted[0] = i_grid;
963 styleDotted[1] = gdTransparent;
964 styleDotted[2] = gdTransparent;
965 gdImageSetStyle (graph, styleDotted, 3);
966
967 /* draw the horizontal grid */
968 if ((longup == NULL) || (shortup == NULL))
969 {
970 if (!bits)
971 {
972 longup = "Bytes per Second";
973 shortup = "Bytes/s";
974 }
975 else
976 {
977 longup = "Bits per Second";
978 shortup = "Bits/s";
979 }
980 }
981 if (maxy < gdFontSmall->w * 16)
982 {
983 gdImageStringUp (graph, gdFontSmall, 8,
984 ytr ((maxy - gdFontSmall->w * strlen (shortup)) / 2),
985 (unsigned char *) shortup, i_grid);
986 }
987 else
988 {
989 gdImageStringUp (graph, gdFontSmall, 8,
990 ytr ((maxy - gdFontSmall->w * strlen (longup)) / 2),
991 (unsigned char *) longup, i_grid);
992 }
993
994 for (i = 0; i <= ytics; i++)
995 {
996
997 gdImageLine (graph, xtr (-2), ytr (i * maxy / ytics),
998 xtr (1), ytr (i * maxy / ytics), i_grid);
999
1000 gdImageLine (graph, xtr (maxx + 2), ytr (i * maxy / ytics),
1001 xtr (maxx - 1), ytr (i * maxy / ytics), i_grid);
1002
1003 gdImageLine (graph, xtr (0), ytr (i * maxy / ytics),
1004 xtr (maxx), ytr (i * maxy / ytics), gdStyled);
1005
1006 /*
1007 sprintf(ylab,"%6.1f %s",sca_max_q*i,short_si[digits/3]);
1008 */
1009 /* sprintf(ylab,"%6.1f %s",sca_max_q*i*yticsf,short_si_out); */
1010 temp = sca_max_q * i;
1011 if (options & OPTION_LOGGRAPH)
1012 temp = expscale(maxy * i / ytics, maxy) * ytics * sca_max_q / maxy;
1013 else if (options & OPTION_EXPGRAPH)
1014 temp = logscale(maxy * i / ytics, maxy) * ytics * sca_max_q / maxy;
1015 else
1016 temp = sca_max_q * i;
1017 sprintf (ylab, "%6.1f %s", temp, short_si_out);
1018
1019 /* sprintf(ylab,"%6.1f %s",sca_max_q*i,short_si_out); */
1020 gdImageString (graph, gdFontSmall, 23,
1021 ytr (i * maxy / ytics + gdFontSmall->h / 2),
1022 (unsigned char *) ylab, i_grid);
1023
1024 if (options & OPTION_DORELPERCENT)
1025 {
1026 /* sprintf(ylab,"% 6.1f%%",(float)25.*i); */
1027 sprintf (ylab, "% 6.1f%%", (float) (temp / (sca_max_q * ytics) * 100));
1028 gdImageString (graph, gdFontSmall, 77 + ((maxx) * xscale) + 1,
1029 ytr (i * maxy / ytics + gdFontSmall->h / 2),
1030 (unsigned char *) ylab, i_outpg);
1031 }
1032 }
1033
1034 /* draw vertical grid and horizontal labels */
1035 for (x = 0; x < maxx; x++)
1036 {
1037 if (lhist[x].time)
1038 {
1039 gdImageLine (graph, xtr (x), ytr (-2), xtr (x), ytr (1), i_grid);
1040 gdImageLine (graph, xtr (x), ytr (0), xtr (x), ytr (maxy),
1041 gdStyled);
1042 }
1043 if (graph_label[x] != NULL)
1044 {
1045 gdImageString (graph, gdFontSmall,
1046 (xtr (x) - (strlen (graph_label[x]) *
1047 gdFontSmall->w / 2)),
1048 ytr (-4), (unsigned char *) graph_label[x], i_grid);
1049 free (graph_label[x]);
1050 }
1051 if (lhist[x].time & 2)
1052 gdImageLine (graph, xtr (x), ytr (0), xtr (x), ytr (maxy), i_major);
1053 }
1054
1055 ytrmax = ytr (origmaxvi);
1056
1057 /* draw line at peak In value in i_major color */
1058 /* only draw the line if it's within the graph ... */
1059 if (ytr (maxy) < ytrmax)
1060 {
1061 styleDotted[0] = i_major;
1062 gdImageSetStyle (graph, styleDotted, 3);
1063 gdImageLine (graph, xtr (0), ytrmax, xtr (maxx), ytrmax, gdStyled);
1064 }
1065
1066 /* draw line at peak Out value in i_major color */
1067 /* only draw the line if it's within the graph ... */
1068 ytrmax = ytr (origmaxvo);
1069
1070 if (ytr (maxy) < ytrmax)
1071 {
1072 styleDotted[0] = i_major;
1073 gdImageSetStyle (graph, styleDotted, 3);
1074 gdImageLine (graph, xtr (0), ytrmax, xtr (maxx), ytrmax, gdStyled);
1075 }
1076
1077 /* draw a red arrow a 0,0 */
1078 if (!(options & OPTION_NOARROW))
1079 {
1080 gdImageLine (graph, xtr (2), ytr (3), xtr (2), ytr (-3), i_major);
1081 gdImageLine (graph, xtr (1), ytr (3), xtr (1), ytr (-3), i_major);
1082 gdImageLine (graph, xtr (0), ytr (2), xtr (0), ytr (-2), i_major);
1083 gdImageLine (graph, xtr (-1), ytr (1), xtr (-1), ytr (-1), i_major);
1084 gdImageLine (graph, xtr (-2), ytr (1), xtr (-2), ytr (-1), i_major);
1085 gdImageLine (graph, xtr (-3), ytr (0), xtr (-3), ytr (0), i_major);
1086 }
1087
1088 if (currdatetimepos > NO_TIMESTAMPSTR)
1089 {
1090 currdatetime = time (NULL);
1091 strftime (currdatetimestr, 250, currdatetimeformat,
1092 localtime (&currdatetime));
1093 switch (currdatetimepos)
1094 {
1095 case LL_CORNER:
1096 currdatetimepos_x = 3;
1097 currdatetimepos_y = YSIZE - gdFontSmall->h - 3;
1098 break;
1099 case RL_CORNER:
1100 currdatetimepos_x =
1101 XSIZE - strlen (currdatetimestr) * gdFontSmall->w - 3;
1102 currdatetimepos_y = YSIZE - gdFontSmall->h - 3;
1103 break;
1104 case LU_CORNER:
1105 currdatetimepos_x = 3;
1106 currdatetimepos_y = 1;
1107 break;
1108 case RU_CORNER:
1109 default:
1110 currdatetimepos_x =
1111 XSIZE - strlen (currdatetimestr) * gdFontSmall->w - 3;
1112 currdatetimepos_y = 1;
1113 };
1114 gdImageString (graph, gdFontSmall,
1115 currdatetimepos_x, currdatetimepos_y,
1116 (unsigned char *)currdatetimestr, i_grid);
1117 }
1118
1119 snprintf(file_tmp,1000,"%s.tmp_%lu",file,(unsigned long)getpid());
1120
1121 if ((fo = fopen (file_tmp, "wb")) == NULL)
1122 {
1123 perror (program);
1124 fprintf (stderr, "%s, Rateup Error: Can't open %s for write\n", bufftime, file_tmp);
1125 exit (1);
1126 }
1127 GFORM_GD (graph, fo);
1128 fclose (fo);
1129 gdImageDestroy (graph);
1130 gdImageDestroy (brush_out);
1131 gdImageDestroy (brush_outm);
1132 gdImageDestroy (brush_outp);
1133 free (lhist);
1134 free (graph_label);
1135 if (kMG) {
1136 free(short_si);
1137 short_si = short_si_def;
1138 }
1139
1140 #ifdef WIN32
1141 /* got to remove the target under win32
1142 or rename will not work ... */
1143 unlink(file);
1144 #endif
1145 if (rename(file_tmp,file)){
1146 perror (program);
1147 fprintf (stderr, "%s, Rateup Error: Can't rename %s to %s\n", bufftime,file_tmp,file);
1148 exit (1);
1149 }
1150
1151
1152 }
1153
1154
1155 static double
diff(a,b)1156 diff (a, b)
1157 char *a, *b;
1158 {
1159 char res[MAXL], *a1, *b1, *r1;
1160 int c, x, m;
1161 if (*a == '-' && *b == '-')
1162 {
1163 b1 = b + 1;
1164 b = a + 1;
1165 a = b1;
1166 }
1167
1168 while (!isdigit ((int) *a))
1169 a++;
1170 while (!isdigit ((int) *b))
1171 b++;
1172 a1 = &a[strlen (a) - 1];
1173 m = max (strlen (a), strlen (b));
1174 r1 = &res[m + 1];
1175 for (b1 = res; b1 <= r1; b1++)
1176 *b1 = ' ';
1177 b1 = &b[strlen (b) - 1];
1178 r1[1] = 0; /* Null terminate result */
1179 c = 0;
1180 for (x = 0; x < m; x++)
1181 {
1182 /* we want to avoid reading off the edge of the string */
1183 char save_a, save_b;
1184 save_a = (a1 >= a) ? *a1 : '0';
1185 save_b = (b1 >= b) ? *b1 : '0';
1186 *r1 = save_a - save_b - c + '0';
1187 if (*r1 < '0')
1188 {
1189 *r1 += 10;
1190 c = 1;
1191 }
1192 else if (*r1 > '9')
1193 { /* 0 - 10 */
1194 *r1 -= 10;
1195 c = 1;
1196 }
1197 else
1198 {
1199 c = 0;
1200 }
1201 a1--;
1202 b1--;
1203 r1--;
1204 }
1205 if (c)
1206 {
1207 r1 = &res[m + 1];
1208 for (x = 0; isdigit ((int) *r1) && x < m; x++, r1--)
1209 {
1210 *r1 = ('9' - *r1 + c) + '0';
1211 if (*r1 > '9')
1212 {
1213 *r1 -= 10;
1214 c = 1;
1215 }
1216 else
1217 {
1218 c = 0;
1219 }
1220 }
1221 return (-atof (res));
1222 }
1223 else
1224 return (atof (res));
1225 }
1226
1227 static int
readhist(file)1228 readhist (file)
1229 char *file;
1230 {
1231 FILE *fi;
1232 int x, retcode = 0;
1233 char buf[256], tempform[50];
1234 struct HISTORY *hist;
1235 long long rd[5];
1236 time_t cur;
1237 long lasttime;
1238
1239 sprintf (tempform, "%%ld %%%ds %%%ds\n", MAXL - 1, MAXL - 1);
1240 if ((fi = fopen (file, "r")) != NULL)
1241 {
1242 if (fscanf (fi, tempform, &lasttime, &last.in[0], &last.out[0]) != 3)
1243 {
1244 fprintf (stderr, "%s, Read Error: File %s lin 1\n", bufftime, file);
1245 retcode = 1;
1246 }
1247 last.time = lasttime;
1248 cur = last.time;
1249 x = histvalid = 0;
1250 hist = history;
1251 while (!feof (fi))
1252 {
1253 fgets (buf, 256, fi);
1254 if (sscanf (buf, "" LLD " " LLD " " LLD " " LLD " " LLD "",
1255 &rd[0], &rd[1], &rd[2], &rd[3], &rd[4]) < 5)
1256 {
1257 rd[3] = rd[1];
1258 rd[4] = rd[2];
1259 }
1260
1261 /* we are long long now, so don't cut bit 8
1262 for (i=0;i<=4;i++){
1263 if (rd[i] & 0x80000000)
1264 rd[i] = 0;
1265 }
1266 */
1267
1268 hist->time = rd[0];
1269 hist->in = rd[1];
1270 hist->out = rd[2];
1271 hist->inmax = rd[3];
1272 hist->outmax = rd[4];
1273 if (hist->inmax < hist->in)
1274 hist->inmax = hist->in;
1275 if (hist->outmax < hist->out)
1276 hist->outmax = hist->out;
1277 if (hist->time > cur)
1278 {
1279 fprintf (stderr,
1280 "%s, Rateup ERROR: %s found %s's log file was corrupt\n or not in sorted order:\ntime: %lu.",
1281 bufftime, program, router, (unsigned long) hist->time);
1282 retcode = 2;
1283 break;
1284 }
1285 cur = hist->time;
1286 if (++x >= Mh)
1287 {
1288 struct HISTORY *lh;
1289
1290 Mh += MAX_HISTORY;
1291 lh = realloc (history, (Mh + 1) * sizeof (struct HISTORY));
1292 if (lh == NULL)
1293 {
1294 fprintf (stderr,
1295 "%s, Rateup WARNING: (pay attention to this)\nWARNING: %s found %s's log file had too many entries, data discarded\n",
1296 bufftime, program, router);
1297 break;
1298 }
1299 hist = lh + (hist - history);
1300 history = lh;
1301 }
1302 hist++;
1303 }
1304 histvalid = x;
1305 fclose (fi);
1306 }
1307 else
1308 {
1309 retcode = 1;
1310 }
1311 return (retcode);
1312 }
1313
1314 static void
readfile()1315 readfile ()
1316 {
1317 char buf[128];
1318 int err, x;
1319 time_t now;
1320 struct HISTORY *hist;
1321
1322 sprintf (buf, "%s.log", router);
1323 if ((err = readhist (buf)) != 0)
1324 { /* Read of log file failed. Try backup */
1325 fprintf (stderr,
1326 "%s, Rateup WARNING: %s could not read the primary log file for %s\n",
1327 bufftime, program, router);
1328 sprintf (buf, "%s.old", router);
1329 if ((err = readhist (buf)) != 0)
1330 { /* Backup failed too. New file? */
1331 fprintf (stderr,
1332 "%s, Rateup WARNING: %s The backup log file for %s was invalid as well\n",
1333 bufftime, program, router);
1334 if (err == 2)
1335 exit (1);
1336
1337 /* File does not exist - it must be created */
1338 now = NOW - DAY_SAMPLE;
1339 hist = history;
1340 histvalid = DAY_COUNT + WEEK_COUNT + MONTH_COUNT + YEAR_COUNT - 1;
1341 last.time = now;
1342 /* calculating a diff does not make sense */
1343 last.in[0] = 'x';
1344 now /= DAY_SAMPLE;
1345 now *= DAY_SAMPLE;
1346 for (x = 0; x < DAY_COUNT; x++, hist++)
1347 {
1348 hist->time = now;
1349 hist->in = hist->inmax = hist->out = hist->outmax = 0;
1350 now -= DAY_SAMPLE;
1351 }
1352 now /= WEEK_SAMPLE;
1353 now *= WEEK_SAMPLE;
1354 for (x = 0; x < WEEK_COUNT; x++, hist++)
1355 {
1356 hist->time = now;
1357 hist->in = hist->inmax = hist->out = hist->outmax = 0;
1358 now -= WEEK_SAMPLE;
1359 }
1360 now /= MONTH_SAMPLE;
1361 now *= MONTH_SAMPLE;
1362 for (x = 0; x < MONTH_COUNT; x++, hist++)
1363 {
1364 hist->time = now;
1365 hist->in = hist->inmax = hist->out = hist->outmax = 0;
1366 now -= MONTH_SAMPLE;
1367 }
1368 now /= YEAR_SAMPLE;
1369 now *= YEAR_SAMPLE;
1370 for (x = 0; x < YEAR_COUNT; x++, hist++)
1371 {
1372 hist->time = now;
1373 hist->in = hist->inmax = hist->out = hist->outmax = 0;
1374 now -= YEAR_SAMPLE;
1375 }
1376 }
1377 }
1378 }
1379
1380 static void
update(in,out,abs_max,absupdate)1381 update (in, out, abs_max, absupdate)
1382 char *in, *out;
1383 long long abs_max;
1384 int absupdate;
1385 {
1386 FILE *fo;
1387 char buf[128], buf1[128], buf2[128];
1388 time_t now, nextnow, plannow;
1389 long long inrate, outrate;
1390 long long avc, inmax, outmax;
1391 double period, interval;
1392 int x, n, nout;
1393 struct HISTORY *lhist, *hist;
1394 double inr, outr;
1395
1396 now = NOW;
1397
1398 if (now < last.time)
1399 {
1400 fprintf (stderr,
1401 "%s, Rateup ERROR: %s found that %s's log file time of %lu was greater than now (%lu)\nERROR: Let's not do the time warp, again. Logfile unchanged.\n",
1402 bufftime, program, router, (unsigned long) last.time,
1403 (unsigned long) now);
1404 return;
1405 }
1406 sprintf (buf, "%s.tmp_%lu", router,(unsigned long)getpid());
1407 sprintf (buf1, "%s.log", router);
1408 sprintf (buf2, "%s.old", router);
1409 if ((lhist = calloc (1, sizeof (struct HISTORY) * (MAX_HISTORY + 1))) ==
1410 NULL)
1411 {
1412 fprintf (stderr, "%s, Rateup ERROR: Out of memory in update\n", bufftime);
1413 exit (1);
1414 }
1415 hist = lhist;
1416
1417 period = (now - last.time);
1418 if (period <= 0 || period > (60 * 60) || last.in[0] == 'x')
1419 { /* if last update is strange */
1420 if (options & OPTION_UNKNASZERO)
1421 {
1422 inrate = 0; /* sync unknown to zero */
1423 outrate = 0;
1424 }
1425 else
1426 {
1427 inrate = history[0].in; /* Sync by using last value */
1428 outrate = history[0].out;
1429 }
1430 }
1431 else
1432 {
1433 /* gauge and absolute */
1434 if (strcmp (in, "-1") == 0 || /* if current count missing */
1435 strcmp (last.in, "-1") == 0)
1436 { /* or previous count missing */
1437 if (options & OPTION_UNKNASZERO)
1438 { /* then use 0 or last value */
1439 inrate = 0;
1440 }
1441 else
1442 {
1443 inrate = history[0].in;
1444 }
1445 }
1446 else
1447 {
1448 if ((absupdate != 0) && (absupdate != 3) && (absupdate != 4))
1449 {
1450 inr = diff (in, "0");
1451 }
1452 else
1453 {
1454 inr = diff (in, last.in);
1455 if (inr < 0) {
1456 if (inr > - (long long) 1 << 32) { /* wrapped 32-bit counter? */
1457 inr += (long long) 1 << 32;
1458 }
1459 else {
1460 inr = 0;
1461 }
1462 }
1463 }
1464 if (absupdate == 2)
1465 {
1466 inrate = inr + .5;
1467 }
1468 else if (absupdate == 3)
1469 {
1470 inrate = inr * (3600.0 / (period * 1.0)) + .5;
1471 }
1472 else if (absupdate == 4)
1473 {
1474 inrate = inr * (60.0 / (period * 1.0)) + .5;
1475 }
1476 else
1477 {
1478 inrate = inr / period + .5;
1479 }
1480 }
1481 if (strcmp (out, "-1") == 0 || /* if current count missing */
1482 strcmp (last.out, "-1") == 0)
1483 { /* or previous count missing */
1484 if (options & OPTION_UNKNASZERO)
1485 { /* then use 0 or last value */
1486 outrate = 0;
1487 }
1488 else
1489 {
1490 outrate = history[0].out;
1491 }
1492 }
1493 else
1494 {
1495 if ((absupdate != 0) && (absupdate != 3) && (absupdate != 4))
1496 {
1497 outr = diff (out, "0");
1498 }
1499 else
1500 {
1501 outr = diff (out, last.out);
1502 if (outr < 0) { /* wrapped counter? */
1503 if (outr > - (long long) 1 << 32) {
1504 outr += (long long) 1 << 32;
1505 }
1506 else {
1507 outr = 0; /* 64bit counters do not wrap usually */
1508 }
1509 }
1510 }
1511 if (absupdate == 2)
1512 {
1513 outrate = outr + .5;
1514 }
1515 else if (absupdate == 3)
1516 {
1517 outrate = outr * (3600.0 / (period * 1.0)) + .5;
1518 }
1519 else if (absupdate == 4)
1520 {
1521 outrate = outr * (60.0 / (period * 1.0)) + .5;
1522 }
1523 else
1524 {
1525 outrate = outr / period + .5;
1526 }
1527 }
1528 }
1529
1530
1531
1532 if (inrate < 0 || inrate > abs_max)
1533 {
1534 if (options & OPTION_UNKNASZERO)
1535 {
1536 inrate = 0; /* sync unknown to zero */
1537 }
1538 else
1539 {
1540 inrate = history[0].in; /* Sync by using last value */
1541 }
1542 }
1543 if (outrate < 0 || outrate > abs_max)
1544 {
1545 if (options & OPTION_UNKNASZERO)
1546 {
1547 outrate = 0; /* sync unknown to zero */
1548 }
1549 else
1550 {
1551 outrate = history[0].out; /* Sync by using last value */
1552 }
1553 }
1554 if ((fo = fopen (buf, "w")) != NULL)
1555 {
1556 fprintf (fo, "%lu %s %s\n", (unsigned long) now, in, out);
1557 last.time = now;
1558 /* what is this good for? */
1559 /* gauge und absolute */
1560 if ((absupdate != 0) && (absupdate != 3) && (absupdate != 4))
1561 {
1562 strcpy (last.in, "0");
1563 strcpy (last.out, "0");
1564 }
1565 else
1566 {
1567 strncpy (last.in, in, MAXL);
1568 last.in[MAXL-1]='\0';
1569 strncpy (last.out, out,MAXL);
1570 last.out[MAXL-1]='\0';
1571 }
1572 fprintf (fo, "%lu " LLD " " LLD " " LLD " " LLD "\n",
1573 (unsigned long) now, inrate, outrate, inrate, outrate);
1574 nout = 1;
1575 hist->time = now;
1576 hist->in = inrate;
1577 hist->out = outrate;
1578 hist->inmax = inrate;
1579 hist->outmax = outrate;
1580 hist++;
1581
1582 /* just in case we were dead for a long time, don't try to gather
1583 data from non existing log entries */
1584 now = plannow = history[0].time;
1585
1586 plannow /= DAY_SAMPLE;
1587 plannow *= DAY_SAMPLE;
1588 n = 0;
1589
1590 /* gobble up every shred of data we can get ... */
1591 if (plannow < now)
1592 {
1593 NEXT ((unsigned long) (now - plannow));
1594 fprintf (fo, "%lu " LLD " " LLD " " LLD " " LLD "\n",
1595 (unsigned long) now, (long long) inr, (long long) outr,
1596 (long long) inmax, (long long) outmax);
1597 hist->time = now;
1598 hist->in = inr;
1599 hist->out = outr;
1600 hist->inmax = inmax;
1601 hist->outmax = outmax;
1602 nout++;
1603 hist++;
1604 now = plannow;
1605
1606 }
1607
1608 for (x = 1; x < DAY_COUNT; x++)
1609 {
1610 NEXT (DAY_SAMPLE);
1611 fprintf (fo, "%lu " LLD " " LLD " " LLD " " LLD "\n",
1612 (unsigned long) now, (long long) inr, (long long) outr,
1613 (long long) inmax, (long long) outmax);
1614 hist->time = now;
1615 hist->in = inr;
1616 hist->out = outr;
1617 hist->inmax = inmax;
1618 hist->outmax = outmax;
1619 nout++;
1620 hist++;
1621 now -= DAY_SAMPLE;
1622 }
1623
1624 plannow = now;
1625 plannow /= WEEK_SAMPLE;
1626 plannow *= WEEK_SAMPLE;
1627
1628 if (plannow < now)
1629 {
1630 NEXT ((unsigned long) (now - plannow));
1631 fprintf (fo, "%lu " LLD " " LLD " " LLD " " LLD "\n",
1632 (unsigned long) now, (long long) inr, (long long) outr,
1633 inmax, outmax);
1634 hist->time = now;
1635 hist->in = inr;
1636 hist->out = outr;
1637 hist->inmax = inmax;
1638 hist->outmax = outmax;
1639 nout++;
1640 hist++;
1641 now = plannow;
1642
1643 }
1644
1645 for (x = 0; x < WEEK_COUNT; x++)
1646 {
1647 NEXT (WEEK_SAMPLE);
1648 fprintf (fo, "%lu " LLD " " LLD " " LLD " " LLD "\n",
1649 (unsigned long) now, (long long) inr, (long long) outr,
1650 inmax, outmax);
1651 hist->time = now;
1652 hist->in = inr;
1653 hist->out = outr;
1654 hist->inmax = inmax;
1655 hist->outmax = outmax;
1656 nout++;
1657 hist++;
1658 now -= WEEK_SAMPLE;
1659 }
1660
1661 plannow = now;
1662 plannow /= MONTH_SAMPLE;
1663 plannow *= MONTH_SAMPLE;
1664
1665 if (plannow < now)
1666 {
1667 NEXT ((unsigned long) (now - plannow));
1668 fprintf (fo, "%lu " LLD " " LLD " " LLD " " LLD "\n",
1669 (unsigned long) now, (long long) inr, (long long) outr,
1670 inmax, outmax);
1671 hist->time = now;
1672 hist->in = inr;
1673 hist->out = outr;
1674 hist->inmax = inmax;
1675 hist->outmax = outmax;
1676 nout++;
1677 hist++;
1678 now = plannow;
1679
1680 }
1681
1682 for (x = 0; x < MONTH_COUNT; x++)
1683 {
1684 NEXT (MONTH_SAMPLE);
1685 fprintf (fo, "%lu " LLD " " LLD " " LLD " " LLD "\n",
1686 (unsigned long) now, (long long) inr, (long long) outr,
1687 inmax, outmax);
1688 hist->time = now;
1689 hist->in = inr;
1690 hist->out = outr;
1691 hist->inmax = inmax;
1692 hist->outmax = outmax;
1693 nout++;
1694 hist++;
1695 now -= MONTH_SAMPLE;
1696 }
1697
1698 plannow = now;
1699 plannow /= YEAR_SAMPLE;
1700 plannow *= YEAR_SAMPLE;
1701
1702 if (plannow < now)
1703 {
1704 NEXT ((unsigned long) (now - plannow));
1705 fprintf (fo, "%lu " LLD " " LLD " " LLD " " LLD "\n",
1706 (unsigned long) now, (long long) inr, (long long) outr,
1707 inmax, outmax);
1708 hist->time = now;
1709 hist->in = inr;
1710 hist->out = outr;
1711 hist->inmax = inmax;
1712 hist->outmax = outmax;
1713 nout++;
1714 hist++;
1715 now = plannow;
1716
1717 }
1718
1719 for (x = 0; x < YEAR_COUNT; x++)
1720 {
1721 NEXT (YEAR_SAMPLE);
1722 fprintf (fo, "%lu " LLD " " LLD " " LLD " " LLD "\n",
1723 (unsigned long) now, (long long) inr, (long long) outr,
1724 inmax, outmax);
1725 hist->time = now;
1726 hist->in = inr;
1727 hist->out = outr;
1728 hist->inmax = inmax;
1729 hist->outmax = outmax;
1730 nout++;
1731 hist++;
1732 now -= YEAR_SAMPLE;
1733 }
1734
1735 if (ferror (fo) || fclose (fo))
1736 {
1737 perror (program);
1738 fprintf (stderr, "%s, Rateup ERROR: Can't write new log file\n", bufftime);
1739 exit (1);
1740 }
1741 #ifdef WIN32
1742 /* another fix to get things working under NT */
1743 if (unlink (buf2))
1744 {
1745 fprintf (stderr,
1746 "%s, Rateup WARNING: %s Can't remove %s updating log file\n",
1747 bufftime, program, buf2);
1748 }
1749 #endif
1750 if (rename (buf1, buf2))
1751 {
1752 fprintf (stderr,
1753 "%s, Rateup WARNING: %s Can't rename %s to %s updating log file\n",
1754 bufftime, program, buf1, buf2);
1755 }
1756 if (rename (buf, buf1))
1757 {
1758 fprintf (stderr,
1759 "%s, Rateup WARNING: %s Can't rename %s to %s updating log file\n",
1760 bufftime, program, buf, buf1);
1761 }
1762 for (n = 0; n < nout && n < MAX_HISTORY; n++)
1763 {
1764 history[n] = lhist[n];
1765 }
1766 }
1767 else
1768 {
1769 perror (program);
1770 fprintf (stderr, "%s, Rateup ERROR: Can't open %s for write\n", bufftime, buf);
1771 exit (1);
1772 }
1773 free (lhist);
1774 }
1775
1776 static void
init_colour(int * colmap,int c0,int c1,int c2)1777 init_colour (int *colmap, int c0, int c1, int c2)
1778 {
1779 *colmap++ = c0;
1780 *colmap++ = c1;
1781 *colmap = c2;
1782 }
1783
1784 /* Constants for readparm option */
1785 #define LENGTH_OF_BUFF (2048)
1786 #define NUMBER_OF_PARM (100)
1787
1788 char buff[LENGTH_OF_BUFF + 1];
1789 char *program;
1790
1791 static int
readparam(char const * file)1792 readparam (char const *file)
1793 {
1794 FILE *fp = NULL;
1795 int cbuf;
1796
1797 /* Open the file */
1798 if ((fp = fopen (file, "r")) == NULL)
1799 {
1800 fprintf (stderr, "%s, %s ERROR: Can't open parameters file: %s\n", bufftime, program,
1801 file);
1802 return (1);
1803 }
1804 /* Check we actually got something */
1805 if (!(cbuf = fread (buff, 1, LENGTH_OF_BUFF, fp)))
1806 {
1807 fprintf (stderr, "%s, %s ERROR: Parameters file empty\n", bufftime, program);
1808 fclose(fp);
1809 return (1);
1810 }
1811 fclose (fp);
1812 buff[cbuf] = '\0';
1813
1814 /* #define READPARAM_INFO */
1815 #ifdef READPARAM_INFO
1816
1817 fprintf (stderr, "%s, %s INFO: Read: %d bytes from File: '%s'\n", bufftime, program, cbuf,
1818 file);
1819
1820 #endif
1821
1822 return (0);
1823 }
1824
1825 int
main(argc,argv)1826 main (argc, argv)
1827 int argc;
1828 char **argv;
1829 {
1830 int x, argi, used, initarg;
1831
1832 program = argv[0];
1833
1834 /* jpt, april 2006 : 3 lines for date & time logging */
1835 (void) time(×tamp);
1836 stLocal = localtime(×tamp);
1837 strftime(bufftime, 32, "%Y-%m-%d %H:%M:%S", stLocal);
1838
1839 /* Is Argv[1] a path/file to passed parameters? */
1840 if ((argc > 1) && (strncasecmp (argv[1], "-F", 2) == 0))
1841 {
1842 char *b, *c, *l;
1843 if (readparam (argv[2]))
1844 {
1845 return (1);
1846 }
1847 /* Parse buffer into argv[] */
1848 argv = calloc (NUMBER_OF_PARM + 1, sizeof (char *));
1849 argc = 0;
1850 b = buff;
1851 l = b + strlen (b);
1852 while (b < l)
1853 {
1854 if (b[0] == '"')
1855 {
1856 b++;
1857 c = strstr (b, "\"");
1858 if (c != NULL)
1859 {
1860 *c = '\0';
1861 argv[argc] = b;
1862 argc++;
1863 b = c + 2;
1864 }
1865 else
1866 {
1867 fprintf (stderr,
1868 "%s, Rateup ERROR: Parameter %d [%s] missing quote\n",
1869 bufftime, argc, b);
1870 break;
1871 }
1872 }
1873 else
1874 {
1875 c = strstr (b, " ");
1876 if (c != NULL)
1877 {
1878 *c = '\0';
1879 argv[argc] = b;
1880 argc++;
1881 b = c + 1;
1882 }
1883 else
1884 {
1885 argv[argc] = b;
1886 argc++;
1887 b = l;
1888 }
1889 }
1890 if (argc == NUMBER_OF_PARM)
1891 {
1892 break;
1893 }
1894 }
1895 /* Check we didn't fill argv[] */
1896 if (argc == NUMBER_OF_PARM)
1897 {
1898 fprintf (stderr, "%s, Rateup ERROR: Too many parameters read: %d\n",
1899 bufftime, argc);
1900 return (1);
1901 }
1902
1903 /* Check we didn't end early */
1904 if (b < l)
1905 {
1906 return (1);
1907 }
1908
1909 /* Mark End of argv[] */
1910 argv[argc] = NULL;
1911
1912 #ifdef READPARAM_DEBUG
1913
1914 for (i = 0; i < argc; i++)
1915 {
1916 printf ("ParameterX %2d : '%s'\n", i, argv[i] ? argv[i] : "<null>");
1917 }
1918
1919 #endif
1920 }
1921
1922 if (argc < 3)
1923 {
1924 fprintf (stderr, "%s, %s for MRTG %s\n"
1925 "Usage: %s -f <parameter file>\n"
1926 " %s directory basename [sampletime] [t sampletime] "
1927 "[-(t)ransparent] [-(b)order]"
1928 "[u|a|g|h|m in out abs_max] "
1929 "[i/p file maxvi maxvo maxx maxy growright step bits]\n",
1930 bufftime, program, VERSION, program, program);
1931 return (1);
1932 }
1933
1934 routerpath = argv[1];
1935 /* this is for NT compatibility, because it does not seem to like
1936 rename across directories */
1937 if (chdir (routerpath))
1938 {
1939 fprintf (stderr, "%s, Rateup ERROR: Chdir to %s failed ...\n", bufftime, routerpath);
1940 return (1);
1941 }
1942
1943 /* Initialiase the colour variables - should be overwritten */
1944 init_colour (&col_in[0], c_in);
1945 init_colour (&col_out[0], c_out);
1946 init_colour (&col_inm[0], c_inm);
1947 init_colour (&col_outm[0], c_outm);
1948 init_colour (&col_outp[0], c_outp);
1949
1950 if ((history = calloc (1, sizeof (struct HISTORY) * (MAX_HISTORY + 1))) ==
1951 NULL)
1952 {
1953 fprintf (stderr, "%s, Rateup ERROR: Out of memory in main\n", bufftime);
1954 exit (1);
1955 }
1956 #if defined(__WATCOMC__) || defined(NETWARE)
1957 memset (history, 0, sizeof (struct HISTORY) * (MAX_HISTORY + 1));
1958 #endif
1959
1960 Mh = MAX_HISTORY;
1961
1962 router = argv[2];
1963 if (strlen(router) > 120)
1964 {
1965 fprintf (stderr, "%s, Rateup ERROR: Too long basename\n", bufftime);
1966 exit (1);
1967 }
1968
1969 /* from mrtg-2.x with x>5 rateup calling syntax changed to
1970 to support time properly ... this is for backward compat
1971 we check if now is remotely reasonable ...
1972 */
1973
1974 if (argc > 3)
1975 {
1976 NOW = atol (argv[3]);
1977 if (NOW > 10 * 365 * 24 * 60 * 60)
1978 {
1979 initarg = 4;
1980 }
1981 else
1982 {
1983 initarg = 3;
1984 time (&NOW);
1985 }
1986 }
1987 else
1988 {
1989 initarg = 3;
1990 time (&NOW);
1991 }
1992
1993 readfile ();
1994 used = 1;
1995
1996 for (argi = initarg; argi < argc; argi += used)
1997 {
1998 switch (argv[argi][0])
1999 {
2000 case '-': /* -options */
2001 switch (argv[argi][1])
2002 {
2003 case 'a': /* Turn off the direction arrow */
2004 options |= OPTION_NOARROW;
2005 used = 1;
2006 break;
2007 case 'A': /* Turn on the direction arrow */
2008 options &= ~OPTION_NOARROW;
2009 used = 1;
2010 break;
2011 case 'b': /* Turn off the shaded border */
2012 options |= OPTION_NOBORDER;
2013 used = 1;
2014 break;
2015 case 'B': /* Turn on the shaded border */
2016 options &= ~OPTION_NOBORDER;
2017 used = 1;
2018 break;
2019 case 'i': /* Do not graph the I variable */
2020 options |= OPTION_NO_I;
2021 used = 1;
2022 break;
2023 case 'I': /* Graph the I variable */
2024 options &= ~OPTION_NO_I;
2025 used = 1;
2026 break;
2027 case 'o': /* Do not graph the O variable */
2028 options |= OPTION_NO_O;
2029 used = 1;
2030 break;
2031 case 'O': /* Graph the O variable */
2032 options &= ~OPTION_NO_O;
2033 used = 1;
2034 break;
2035 case 'l': /* logarithmic scaling */
2036 options |= OPTION_LOGGRAPH;
2037 options &= ~OPTION_MEANOVER;
2038 options &= ~OPTION_EXPGRAPH;
2039 used = 1;
2040 break;
2041 case 'm': /* second-mean scaling */
2042 options |= OPTION_MEANOVER;
2043 options &= ~OPTION_LOGGRAPH;
2044 options &= ~OPTION_EXPGRAPH;
2045 used = 1;
2046 break;
2047 case 'p': /* print router name in image */
2048 options |= OPTION_PRINTROUTER;
2049 used = 1;
2050 break;
2051 case 't': /* Transparent Image */
2052 options |= OPTION_TRANSPARENT;
2053 used = 1;
2054 break;
2055 case 'T': /* non-Transparent Image */
2056 options &= ~OPTION_TRANSPARENT;
2057 used = 1;
2058 break;
2059 case 'x': /* exponential scaling */
2060 options |= OPTION_EXPGRAPH;
2061 options &= ~OPTION_MEANOVER;
2062 options &= ~OPTION_LOGGRAPH;
2063 used = 1;
2064 break;
2065 case 'z': /* unknown as zero */
2066 options |= OPTION_UNKNASZERO;
2067 used = 1;
2068 break;
2069 case 'Z': /* repeat last */
2070 options &= ~OPTION_UNKNASZERO;
2071 used = 1;
2072 break;
2073 case '0': /* assume zeroes */
2074 options |= OPTION_WITHZEROES;
2075 used = 1;
2076 break;
2077 default:
2078 fprintf (stderr, "%s, Rateup ERROR: Unknown option: %s, sorry!\n",
2079 bufftime, argv[argi]);
2080 return (1);
2081 }
2082 break;
2083 case 'i': /* Create PPM Image record */
2084 image (argv[argi + 1], /* Image */
2085 strtoll (argv[argi + 2], NULL, 10), /* Max Value In */
2086 strtoll (argv[argi + 3], NULL, 10), /* Max Value Out */
2087 atol (argv[argi + 4]), /* xsize maxx */
2088 atol (argv[argi + 5]), /* ysize maxy */
2089 atof (argv[argi + 6]), /* xscale */
2090 atof (argv[argi + 7]), /* yscale */
2091 atol (argv[argi + 8]), /* growright */
2092 atol (argv[argi + 9]), /* step */
2093 atol (argv[argi + 10]), /* bits */
2094 atol (argv[argi + 11]), /* ytics */
2095 atof (argv[argi + 12]), /* yticsfactor */
2096 0, argv[argi + 13], atol (argv[argi + 14]));
2097 used = 15;
2098 break;
2099 case 'p': /* Create PPM Image record with Peak values */
2100 image (argv[argi + 1], strtoll (argv[argi + 2], NULL, 10), /* Max Value In */
2101 strtoll (argv[argi + 3], NULL, 10), /* Max Value Out */
2102 atol (argv[argi + 4]), /* xsize maxx */
2103 atol (argv[argi + 5]), /* ysize maxy */
2104 atof (argv[argi + 6]), /* xscale */
2105 atof (argv[argi + 7]), /* yscale */
2106 atol (argv[argi + 8]), /* growright */
2107 atol (argv[argi + 9]), /* step */
2108 atol (argv[argi + 10]), /* bits */
2109 atol (argv[argi + 11]), /* ytics */
2110 atof (argv[argi + 12]), /* yticsfactor */
2111 1, argv[argi + 13], atol (argv[argi + 14]));
2112 used = 15;
2113 break;
2114 case 'r': /* Create random records, then update */
2115 for (x = 0; x < histvalid; x++)
2116 {
2117 history[x].in = rand () % atoi (argv[argi + 1]);
2118 history[x].out = rand () % atoi (argv[argi + 2]);
2119 }
2120 /* fallthrough */
2121 case 'u': /* Update file */
2122 if (argv[argi][1] == 'p')
2123 {
2124 options |= OPTION_DORELPERCENT;
2125 }
2126 update (argv[argi + 1], argv[argi + 2],
2127 strtoll (argv[argi + 3], NULL, 10), 0);
2128 used = 4;
2129 break;
2130 case 'a': /* Absolute Update file */
2131 if (argv[argi][1] == 'p')
2132 {
2133 options |= OPTION_DORELPERCENT;
2134 }
2135 update (argv[argi + 1], argv[argi + 2],
2136 strtoll (argv[argi + 3], NULL, 10), 1);
2137 used = 4;
2138 break;
2139 case 'g': /* Gauge Update file */
2140 if (argv[argi][1] == 'p')
2141 {
2142 options |= OPTION_DORELPERCENT;
2143 }
2144 update (argv[argi + 1], argv[argi + 2],
2145 strtoll (argv[argi + 3], NULL, 10), 2);
2146 used = 4;
2147 break;
2148 case 'h':
2149 if (argv[argi][1] == 'p')
2150 {
2151 options |= OPTION_DORELPERCENT;
2152 }
2153 update (argv[argi + 1], argv[argi + 2],
2154 strtoll (argv[argi + 3], NULL, 10), 3);
2155 used = 4;
2156 break;
2157 case 'm':
2158 if (argv[argi][1] == 'p')
2159 {
2160 options |= OPTION_DORELPERCENT;
2161 }
2162 update (argv[argi + 1], argv[argi + 2],
2163 strtoll (argv[argi + 3], NULL, 10), 4);
2164 used = 4;
2165 break;
2166 case 'W': /* Week format */
2167 weekformat = argv[argi + 1][0];
2168 used = 2;
2169 break;
2170 case 'c': /* Colour Map */
2171 sscanf (argv[argi + 1], "#%2x%2x%2x", &col_in[0], &col_in[1],
2172 &col_in[2]);
2173 sscanf (argv[argi + 2], "#%2x%2x%2x", &col_out[0], &col_out[1],
2174 &col_out[2]);
2175 sscanf (argv[argi + 3], "#%2x%2x%2x", &col_inm[0], &col_inm[1],
2176 &col_inm[2]);
2177 sscanf (argv[argi + 4], "#%2x%2x%2x", &col_outm[0], &col_outm[1],
2178 &col_outm[2]);
2179 used = 5;
2180 break;
2181 case 'C': /* Extented Colour Map */
2182 sscanf (argv[argi + 1], "#%2x%2x%2x", &col_in[0], &col_in[1],
2183 &col_in[2]);
2184 sscanf (argv[argi + 2], "#%2x%2x%2x", &col_out[0], &col_out[1],
2185 &col_out[2]);
2186 sscanf (argv[argi + 3], "#%2x%2x%2x", &col_inm[0], &col_inm[1],
2187 &col_inm[2]);
2188 sscanf (argv[argi + 4], "#%2x%2x%2x", &col_outm[0], &col_outm[1],
2189 &col_outm[2]);
2190 sscanf (argv[argi + 5], "#%2x%2x%2x", &col_outp[0], &col_outp[1],
2191 &col_outp[2]);
2192 used = 6;
2193 break;
2194 case 't':
2195 NOW = atol (argv[argi + 1]);
2196 used = 2;
2197 break;
2198 case 'k':
2199 kilo = atol (argv[argi + 1]);
2200 used = 2;
2201 break;
2202 case 'K':
2203 kMG = calloc (strlen (argv[argi + 1]) + 1, sizeof (char));
2204 strcpy (kMG, argv[argi + 1]);
2205 used = 2;
2206 break;
2207 case 'Z': /* Timezone name */
2208 rtimezone = argv[argi + 1];
2209 used = 2;
2210 break;
2211 case 'l': /* YLegend - rewritten by Oliver Haidi, re-rewritten by Jon Barber */
2212 {
2213 int i, j, k, loop = 1;
2214 int start = 1, got_esc = 0, append_ok;
2215 char *qstr;
2216 longup = (char *) calloc (1, 100);
2217 *longup = 0;
2218 /* this rather twisty argument scanning is necesary
2219 because NT command.coms rather dumb argument
2220 passing .... or because we don't know
2221 better. Under Unix we just would say. if
2222 ((sscanf(argv[argi+1],"[%[^]]]", longup); */
2223 /* at start, check 1st char must be [ */
2224 if (argv[argi + 1][0] != '[')
2225 {
2226 fprintf (stderr,
2227 "%s, Rateup ERROR: YLegend: Option must be passed with '[' at start and ']' at end (these will not be printed).\n", bufftime);
2228 return (1);
2229 }
2230 for (i = 1; (i < argc) && loop; i++)
2231 { /* check all args until unescaped ']' */
2232 qstr = argv[argi + i];
2233 for (j = start; ((size_t) j < strlen (qstr)) && loop; j++)
2234 {
2235 start = 0; /* 1st char in 1st arg already checked */
2236 append_ok = 1; /* OK to append unless we find otherwise */
2237 if (qstr[j] == '\\')
2238 {
2239 if (++got_esc == 1)
2240 {
2241 append_ok = 0; /* don't append 1st '/' */
2242 }
2243 else
2244 {
2245 got_esc = 0; /* 2nd '/' in a row, i.e. '//' */
2246 }
2247 }
2248 if (qstr[j] == ']')
2249 { /* is this the end? */
2250 if (got_esc == 1)
2251 {
2252 if (strlen (qstr + j) >= 2)
2253 {
2254 append_ok = 1;
2255 got_esc = 0;
2256 }
2257 else
2258 {
2259 fprintf (stderr,
2260 "%s, 1a: rateup ERROR: YLegend: use \"\\]\" for \"]\" or \"\\\\\" for \"\\\".\n", bufftime);
2261 return (1);
2262 }
2263 }
2264 else
2265 {
2266 if (strlen (qstr + j) >= 2)
2267 {
2268 fprintf (stderr,
2269 "%s, 2a: rateup ERROR: YLegend: use \"\\]\" for \"]\" or \"\\\\\" for \"\\\".\n", bufftime);
2270 return (1);
2271 }
2272 loop = 0;
2273 append_ok = 0;
2274 }
2275 }
2276 if (append_ok == 1)
2277 {
2278 k = strlen (longup);
2279 if ((size_t) (k + 1) > 99)
2280 {
2281 fprintf (stderr,
2282 "%s, 3a: rateup ERROR: YLegend too long\n", bufftime);
2283 return (1);
2284 }
2285 longup[k] = qstr[j];
2286 longup[k + 1] = 0;
2287 }
2288 } /* for (j=start...) */
2289 /* append space */
2290 k = strlen (longup);
2291 if ((size_t) (k + 1) > 99)
2292 {
2293 fprintf (stderr, "%s, 4a: rateup ERROR: YLegend too long\n", bufftime);
2294 return (1);
2295 }
2296 longup[k] = ' ';
2297 longup[k + 1] = 0;
2298 } /* for (i =1 ... */
2299 used = i;
2300 }
2301 /* remove trailing space */
2302 longup[max (0, (signed) strlen (longup) - 1)] = 0;
2303 shortup = longup;
2304 /* fprintf(stderr, "%s, YLegend = \"%s\"\n", bufftime, longup); */
2305 break;
2306 case 'T': /* pngTitle - based on YLegend */
2307 {
2308 int i, j, k, loop = 1;
2309 int start = 1, got_esc = 0, append_ok;
2310 char *qstr;
2311 pngtitle = (char *) calloc (1, 100);
2312 *pngtitle = 0;
2313 /* this rather twisty argument scanning is necesary
2314 because NT command.coms rather dumb argument
2315 passing .... or because we don't know
2316 better. Under Unix we just would say. if
2317 ((sscanf(argv[argi+1],"[%[^]]]", pngtitle); */
2318 /* at start, check 1st char must be [ */
2319 if (argv[argi + 1][0] != '[')
2320 {
2321 fprintf (stderr,
2322 "%s, Rateup ERROR: YLegend: Option must be passed with '[' at start and ']' at end (these will not be printed).\n", bufftime);
2323 return (1);
2324 }
2325 for (i = 1; (i < argc) && loop; i++)
2326 { /* check all args until unescaped ']' */
2327 qstr = argv[argi + i];
2328 for (j = start; ((size_t) j < strlen (qstr)) && loop; j++)
2329 {
2330 start = 0; /* 1st char in 1st arg already checked */
2331 append_ok = 1; /* OK to append unless we find otherwise */
2332 if (qstr[j] == '\\')
2333 {
2334 if (++got_esc == 1)
2335 {
2336 append_ok = 0; /* don't append 1st '/' */
2337 }
2338 else
2339 {
2340 got_esc = 0; /* 2nd '/' in a row, i.e. '//' */
2341 }
2342 }
2343 if (qstr[j] == ']')
2344 { /* is this the end? */
2345 if (got_esc == 1)
2346 {
2347 if (strlen (qstr + j) >= 2)
2348 {
2349 append_ok = 1;
2350 got_esc = 0;
2351 }
2352 else
2353 {
2354 fprintf (stderr,
2355 "%s, 1b: rateup ERROR: YLegend: use \"\\]\" for \"]\" or \"\\\\\" for \"\\\".\n", bufftime);
2356 return (1);
2357 }
2358 }
2359 else
2360 {
2361 if (strlen (qstr + j) >= 2)
2362 {
2363 fprintf (stderr,
2364 "%s, 2b: rateup ERROR: YLegend: use \"\\]\" for \"]\" or \"\\\\\" for \"\\\".\n", bufftime);
2365 return (1);
2366 }
2367 loop = 0;
2368 append_ok = 0;
2369 }
2370 }
2371 if (append_ok == 1)
2372 {
2373 k = strlen (pngtitle);
2374 if ((size_t) (k + 1) > 99)
2375 {
2376 fprintf (stderr,
2377 "%s, 3b: rateup ERROR: YLegend too long\n", bufftime);
2378 return (1);
2379 }
2380 pngtitle[k] = qstr[j];
2381 pngtitle[k + 1] = 0;
2382 }
2383 } /* for (j=start...) */
2384 /* append space */
2385 k = strlen (pngtitle);
2386 if ((size_t) (k + 1) > 99)
2387 {
2388 fprintf (stderr, "%s, 4b: rateup ERROR: YLegend too long\n", bufftime);
2389 return (1);
2390 }
2391 pngtitle[k] = ' ';
2392 pngtitle[k + 1] = 0;
2393 } /* for (i =1 ... */
2394 used = i;
2395 }
2396 /* remove trailing space */
2397 pngtitle[max (0, (signed) strlen (pngtitle) - 1)] = 0;
2398 /* fprintf(stderr, "%s, YLegend = \"%s\"\n", bufftime, pngtitle); */
2399 break;
2400 default:
2401 fprintf (stderr, "%s, Rateup ERROR: Can't cope with %s, sorry!\n",
2402 bufftime, argv[argi]);
2403 return (1);
2404 }
2405 }
2406 return (0);
2407 }
2408