rateup.c
上传用户:shbosideng
上传日期:2013-05-04
资源大小:1555k
文件大小:59k
源码类别:

SNMP编程

开发平台:

C/C++

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