home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / ip / dialupip / dialupip2.0 / src / dialmon / dialmon.c next >
Encoding:
C/C++ Source or Header  |  1991-01-14  |  41.3 KB  |  1,674 lines

  1. /*
  2. **  Copyright (c) 1991 Bolt Beranek and Newman, Inc.
  3. **  All rights reserved.
  4. **
  5. **  Redistribution and use in source and binary forms are permitted
  6. **  provided that: (1) source distributions retain this entire copyright
  7. **  notice and comment, and (2) distributions including binaries display
  8. **  the following acknowledgement:  ``This product includes software
  9. **  developed by Bolt Beranek and Newman, Inc. and CREN/CSNET'' in the
  10. **  documentation or other materials provided with the distribution and in
  11. **  all advertising materials mentioning features or use of this software.
  12. **  Neither the name of Bolt Beranek and Newman nor CREN/CSNET may be used
  13. **  to endorse or promote products derived from this software without
  14. **  specific prior written permission.
  15. **
  16. **  THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  17. **  WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  18. **  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19. */
  20. #include <stdio.h>
  21. #include <ctype.h>
  22. #include <curses.h>
  23. #include <signal.h>
  24. #include <sys/types.h>
  25. #include <sys/socket.h>
  26. #include <sys/file.h>
  27. #include <sys/ioctl.h>
  28. #include <sys/time.h>
  29. #include <netinet/in.h>
  30. #include <net/if.h>
  31. #include <sys/dk.h>
  32. #include <netdb.h>
  33. #include <arpa/inet.h>
  34. #include <sys/param.h>
  35. #include <netinet/in_systm.h>
  36. #include <netinet/ip.h>
  37. #include <net/if_du.h>
  38. #include "dialmon.h"
  39.  
  40.     /* Shut up, lint */
  41. #define Refresh        (void)refresh
  42. #define Wrefresh    (void)wrefresh
  43. #define Wclear        (void)wclear
  44. #define Wclrtoeol    (void)wclrtoeol
  45. #define Wprintw        (void)wprintw
  46. #define Wmove        (void)wmove
  47.  
  48.     /* Configuration data. */
  49. #define MAXRECS        40    /* Max # of types of log records    */
  50. #define MAXPLOTS    49    /* # of plots per log record graph    */
  51. #define MAXWINDOWS    4    /* # of available windows        */
  52. #define HOSTNAMESIZE    25    /* Size of a host name            */
  53. #define MAXINTERVALS    1    /* intervals/average            */
  54. #define HOSTNAMELEN    128
  55.  
  56.     /* Window numbers */
  57. #define W_GLOBAL    0    /* Site-wide statistics            */
  58. #define W_LINE        1    /* Active line statistics        */
  59. #define W_TOTAL        2    /* Active line totals            */
  60. #define W_HELP        3    /* Help function            */
  61.  
  62. #define NOTSET        -1    /* When a yloc is not in use        */
  63. #define LINE_NOTCONF    'N'    /* When a serial line is not configured    */
  64. #define MAXREQUEST    25    /* Maximum size of a request        */
  65.  
  66.  
  67.     /* Fields in status structures, and statistics computed from them. */
  68. #define R_CIPUP         0
  69. #define R_CIPLN         1
  70. #define R_COPUP         2
  71. #define R_COPLN         3
  72. #define R_CPSIP         4
  73. #define R_CPRIP         5
  74. #define R_CTPBUSY     6
  75. #define R_CTPIDLE     7
  76. #define R_CCHS         8
  77. #define R_CCHR         9
  78. #define R_gCHS        10    /* Global chars sent            */
  79. #define R_gCHR        11    /* Global chars received        */
  80. #define R_aCHS        12    /* Average chars sent            */
  81. #define R_aPKTS        13    /* Average pkts sent            */
  82. #define R_aCHPKTS    14    /* Average chars/pkt sent        */
  83. #define R_aCHR        15    /* Average chars received        */
  84. #define R_aPKTR        16    /* Average pkts received        */
  85. #define R_aCHPKTR    17    /* Average chars/pkt received        */
  86. #define R_aPCTESC    18    /* Average percent of esc chars sent    */
  87. #define R_STATE        19    /* State of the du_softc interface    */
  88. #define R_ESCR        20    /* number of esc chars received        */
  89. #define R_ESCS        21    /* number of esc chars sent        */
  90. #define R_IERROR    22
  91. #define R_OERROR    23
  92. #define R_gIERROR    24    /* Global                */
  93. #define R_gOERROR    25    /* Global                */
  94.  
  95.  
  96.     /* A dial log record. */
  97. typedef struct _DIALLOGREC {
  98.     int        yloc;        /* Where to graph packet counts with the
  99.                  * corresponding attributes        */
  100.     int        Count;        /* new packet count            */
  101.     int        Old;        /* old count, so can update plots without
  102.                  * redrawing entire plot        */
  103.     float    fCount;        /* New count packets as a float        */
  104.     int        Line;        /* line number, 0 for global stats    */
  105.     int        Window;        /* window to display this record in    */
  106. } DIALLOGREC;
  107.  
  108.     /* Averages */
  109. typedef struct _AVERAGES {
  110.     int        chs;        /* Characters sent            */
  111.     int        pkts;        /* Packets sent                */
  112.     int        chr;        /* Characters received            */
  113.     int        pktr;        /* Packets received            */
  114.     int        sescs;        /* Escape chars sent            */
  115.     int        rescs;        /* Escape chars received        */
  116.     int        ierror;        /* Input errors                */
  117.     int        oerror;        /* Output errors            */
  118.     int        sec;        /* Seconds between getting new data    */
  119. } AVERAGES;
  120.  
  121.  
  122. static AVERAGES        Averages[MAX_NDU][MAXINTERVALS];
  123. static char        HostName[HOSTNAMELEN];
  124. static char        OtherHost[MAX_NDU][HOSTNAMESIZE];
  125. static DIALSTATS    StatsCur;
  126. static DIALSTATS    StatsOld;
  127. static DIALSTATS    StatsReset;
  128. static int        fd;        /* Descriptor connected to server */
  129. static int        CurrLine;    /* Current serial line */
  130. static int        freset;        /* Using reset totals? */
  131. static int        CurrWind;    /* Current window */
  132. static int        maxyloc;    /* largest y-local in graph window */
  133. static int        newdata;    /* Index into Averages */
  134. static int        cursed;        /* Curses set up? */
  135. static WINDOW        *Wgraph;
  136. static WINDOW        *Whelp;
  137. static WINDOW        *Wprompt;
  138. static WINDOW        *Wtitle;
  139. static WINDOW        *Wtypes;
  140.  
  141.     /* Pointers to log records which hold 5 sec data, logical line number this
  142.      * log record applies to and the y-position where this data is printed. */
  143. static DIALLOGREC    *Records[MAXRECS];
  144.  
  145.     /* State of du_softc interface.  One message/bit. */
  146. static char    *DUStateMessages[] = {
  147.     "ESCAPED",
  148.     "OACTIVE",
  149.     "",
  150.     "",
  151.     "LWAITING",
  152.     "LACTIVE",
  153.     "LDOWN",
  154.     "FAILCALL",
  155.     "MONITORON"
  156. };
  157.  
  158.     /* Type descriptions. */
  159. static char *TypeDescriptions[] = {
  160.     "Pkts received from IP",
  161.     "Pkts from remote site",
  162.     "Pkts passed to IP",
  163.     "Pkts sent to remote site",
  164.     "Pkts passed to IP",
  165.     "Pkts received from IP",
  166.     "Status of line",
  167.     "Tty busy",
  168.     "Percent tty idle",
  169.     "Characters sent",
  170.     "Characters received",
  171.     "Characters sent",
  172.     "Characters received",
  173.     "Avg chars sent/sec",
  174.     "Avg pkts sent/sec",
  175.     "Avg chars/pkt sent",
  176.     "Avg chars received/sec",
  177.     "Avg pkts received/sec",
  178.     "Avg chars/pkt received",
  179.     "Avg chars received/interrupt",
  180.     "Avg chars escaped",
  181.     "Escape chars received",
  182.     "State of interface",
  183.     "Escape chars sent",
  184.     "Line Input Errors",
  185.     "Line Output Errors",
  186.     "Global Input Errors",
  187.     "Global Output Errors"
  188. };
  189.  
  190.  
  191. extern char    *progname;
  192. extern char    *dip_release();
  193.  
  194. extern int        errno;
  195. extern int        h_errno;
  196. extern int        optind;
  197. extern char        *ctime();
  198. extern char        *malloc();
  199. extern char        *optarg;
  200. extern char        *strchr();
  201. extern char        *strcpy();
  202. extern char        *strerror();
  203. extern char        *strncpy();
  204. extern time_t        time();
  205. extern unsigned int    sleep();
  206. extern void        bcopy();
  207. extern void        exit();
  208.  
  209.  
  210.  
  211. /*
  212. **  Normal exit.
  213. */
  214. static void
  215. ext()
  216. {
  217.     (void)close(fd);
  218.     if (cursed)
  219.     endwin();
  220.     (void)printf("\n");
  221.     exit(0);
  222. }
  223.  
  224. /*
  225. **  Print error and exit.
  226. */
  227. static void
  228. fatal(text)
  229.     char    *text;
  230. {
  231.     int        oerrno;
  232.  
  233.     oerrno = errno;
  234.     (void)close(fd);
  235.     if (cursed) {
  236.     Wmove(stdscr, COLS - 1, LINES - 1);
  237.     Refresh();
  238.     endwin();
  239.     }
  240.     (void)fprintf(stderr, "\n\n%s, %s\n", text, strerror(oerrno));
  241.     exit(1);
  242. }
  243.  
  244.  
  245.  
  246.  
  247. /*
  248. **  Compute the average stats for a line.
  249. */
  250. static void
  251. computeavgs(i)
  252.     int        i;
  253. {
  254.     int        j;
  255.     float    *fp1;
  256.     float    *fp2;
  257.     float    time;
  258.     AVERAGES    *aptr;
  259.  
  260.     /* Get the pointer to the new data. */
  261.     aptr = &Averages[i][newdata];
  262.     aptr->chs = Records[R_CCHS][i].Count;
  263.     aptr->pkts = Records[R_CPSIP][i].Count;
  264.     aptr->chr = Records[R_CCHR][i].Count;
  265.     aptr->pktr = Records[R_CPRIP][i].Count;
  266.     aptr->rescs = Records[R_ESCR][i].Count;
  267.     aptr->sescs = Records[R_ESCS][i].Count;
  268.     aptr->sec = StatsCur.when - StatsOld.when;
  269.     aptr->ierror = Records[R_IERROR][i].Count;
  270.     aptr->oerror = Records[R_OERROR][i].Count;
  271.  
  272.     /* Total over MAXINTERVALS intervals. */
  273.     Records[R_aCHS][i].fCount = 0.0;
  274.     Records[R_aPKTS][i].fCount = 0.0;
  275.     Records[R_aCHR][i].fCount = 0.0;
  276.     Records[R_aPKTR][i].fCount = 0.0;
  277.     Records[R_aPCTESC][i].fCount = 0.0;
  278.     for (time = 0.0, j = 0; j < MAXINTERVALS; j++) {
  279.         aptr = &Averages[i][j];
  280.         Records[R_aCHS][i].fCount += aptr->chs;
  281.         Records[R_aPKTS][i].fCount += aptr->pkts;
  282.         Records[R_aCHR][i].fCount += aptr->chr;
  283.         Records[R_aPKTR][i].fCount += aptr->pktr;
  284.     Records[R_aPCTESC][i].fCount += aptr->rescs;
  285.     time += aptr->sec;
  286.     }
  287.  
  288.     /* Compute average chars sent/packet. */
  289.     fp1 = &Records[R_aCHS][i].fCount;
  290.     fp2 = &Records[R_aPKTS][i].fCount;
  291.     Records[R_aCHPKTS][i].fCount = *fp2 ? *fp1 / *fp2 : 0.0;
  292.  
  293.     if (time)
  294.         *fp2 /= time;
  295.  
  296.     /* Factor in escape characters sent. */
  297.     fp2 = &Records[R_aPCTESC][i].fCount;
  298.     *fp2 = *fp1 ? (*fp2 / *fp1 ) * 100. : 0.0;
  299.  
  300.     if (time)
  301.         *fp1 /= time;
  302.  
  303.  
  304.     /* Computer average chars received/packet. */
  305.     fp1 = &Records[R_aCHR][i].fCount;
  306.     fp2 = &Records[R_aPKTR][i].fCount;
  307.     Records[R_aCHPKTR][i].fCount = *fp2 ? *fp1 / *fp2 : 0.0;
  308.     if (time) {
  309.         *fp1 /= time;
  310.         *fp2 /= time;
  311.     }
  312. }
  313.  
  314. /*
  315. **  Compute the differences between the old and new values of the stats
  316. **  structures and save the results in a log record.  Since not all
  317. **  lines need have been configured on a host, set it to NOTCONF if
  318. **  necessary.  The StatsReset variable holds all totals since the last
  319. **  reset command.
  320. */
  321. static void
  322. computediffs()
  323. {
  324.     LINESTATS        *old;
  325.     LINESTATS        *cur;
  326.     LINESTATS        *res;
  327.     int            i;
  328.     struct hostent    *hp;
  329.     unsigned long    *paddr;
  330.  
  331.     /* global stats */
  332.     StatsReset.ipup +=
  333.     Records[R_CIPUP]->Count = StatsCur.ipup - StatsOld.ipup;
  334.     StatsOld.ipup = StatsCur.ipup;
  335.  
  336.     StatsReset.ipln +=
  337.     Records[R_CIPLN]->Count = StatsCur.ipln - StatsOld.ipln;
  338.     StatsOld.ipln = StatsCur.ipln;
  339.  
  340.     StatsReset.opup +=
  341.     Records[R_COPUP]->Count = StatsCur.opup - StatsOld.opup;
  342.     StatsOld.opup = StatsCur.opup;
  343.  
  344.     StatsReset.opln +=
  345.     Records[R_COPLN]->Count = StatsCur.opln - StatsOld.opln;
  346.     StatsOld.opln = StatsCur.opln;
  347.  
  348.     /* line stats */
  349.     old = StatsOld.ln;
  350.     cur = StatsCur.ln;
  351.     res = StatsReset.ln;
  352.     for (i = 0; i < StatsCur.ndu; i++, old++, res++) {
  353.         if (cur->ln == i) {
  354.             /* line i is configured and new data was sent */
  355.         Records[R_STATE][i].Count = cur->flags;
  356.             res->cchr += Records[R_CCHR][i].Count = cur->cchr - old->cchr;
  357.             old->cchr = cur->cchr;
  358.  
  359.             /* sum up characters received for global stats */
  360.             Records[R_gCHR]->Count += Records[R_CCHR][i].Count;
  361.             res->cchs += Records[R_CCHS][i].Count = cur->cchs - old->cchs;
  362.             old->cchs = cur->cchs;
  363.  
  364.             /* sum up characters sent for global stats */
  365.             Records[R_gCHS]->Count += Records[R_CCHS][i].Count;
  366.             res->cpsip += Records[R_CPSIP][i].Count = cur->cpsip - old->cpsip;
  367.             old->cpsip = cur->cpsip;
  368.             res->cprip += Records[R_CPRIP][i].Count = cur->cprip - old->cprip;
  369.             old->cprip = cur->cprip;
  370.  
  371.             res->ierror +=
  372.         Records[R_IERROR][i].Count = cur->ierror - old->ierror;
  373.             old->ierror = cur->ierror;
  374.         Records[R_gIERROR]->Count += Records[R_IERROR][i].Count;
  375.  
  376.             res->oerror +=
  377.         Records[R_OERROR][i].Count = cur->oerror - old->oerror;
  378.             old->oerror = cur->oerror;
  379.             Records[R_gOERROR]->Count += Records[R_OERROR][i].Count;
  380.  
  381.         /* Handle wrap-around */
  382.         Records[R_CTPBUSY][i].fCount = cur->ctpbusy < old->ctpbusy
  383.         ? (float)((unsigned int)cur->ctpbusy - (unsigned int)old->ctpbusy)
  384.         : (float)(cur->ctpbusy - old->ctpbusy);
  385.             res->ctpbusy += (int)Records[R_CTPBUSY][i].fCount;
  386.             old->ctpbusy = cur->ctpbusy;
  387.  
  388.                 /* Counter wrapped around. */
  389.         Records[R_CTPIDLE][i].fCount = cur->ctpidle < old->ctpidle
  390.         ? (unsigned int)cur->ctpidle - (unsigned int)old->ctpidle
  391.         : cur->ctpidle - old->ctpidle;
  392.  
  393.             res->ctpidle += (int)Records[R_CTPIDLE][i].fCount;
  394.             old->ctpidle = cur->ctpidle;
  395.  
  396.         res->resc += Records[R_ESCR][i].Count = cur->resc - old->resc;
  397.         old->resc = cur->resc;
  398.         res->sesc += Records[R_ESCS][i].Count = cur->sesc - old->sesc;
  399.         old->sesc = cur->sesc;
  400.  
  401.         /* Get the nost on the other end of the line, if different. */
  402.         cur->dest.s_addr = ntohl(cur->dest.s_addr);
  403.         if (old->dest.s_addr != cur->dest.s_addr) {
  404.                 paddr = &cur->dest.s_addr;
  405.             if (*paddr) {
  406.             if (hp = gethostbyaddr(paddr, sizeof *paddr, AF_INET)) {
  407.                 (void)strncpy(OtherHost[i], hp->h_name,
  408.                 sizeof OtherHost[i] - 1);
  409.             OtherHost[i][HOSTNAMESIZE - 1] = '\0';
  410.             }
  411.             else
  412.                 (void)strcpy(OtherHost[i], inet_ntoa(*paddr));
  413.         }
  414.         else
  415.             (void)strcpy(OtherHost[i], "UNINITIALIZED");
  416.             res->dest.s_addr = old->dest.s_addr = cur->dest.s_addr;
  417.         }
  418.  
  419.             res->ln = old->ln = cur->ln;
  420.             cur->ln = LINE_NOTCONF;
  421.             cur++;
  422.         computeavgs(i);
  423.     }
  424.         else {
  425.         /* line i not configured, no new data was sent */
  426.             res->ln = old->ln = LINE_NOTCONF;
  427.             if ((CurrWind == W_LINE || CurrWind == W_TOTAL) && CurrLine == i)
  428.                 LineNotConf(i);
  429.     }
  430.     }
  431.  
  432.     /* finished storing this set of data, increment for the next set */
  433.     if (++newdata >= MAXINTERVALS)
  434.         newdata = 0;
  435.  
  436.     /* save current time value */
  437.     StatsOld.when = StatsCur.when;
  438. }
  439.  
  440.  
  441. /*
  442. **  Convert fields in struct to host order
  443. */
  444. FromNetworkOrder(sp)
  445.     DIALSTATS    *sp;
  446. {
  447.     int        i;
  448.     LINESTATS    *lsp;
  449.  
  450.     sp->when = ntohl((unsigned long)sp->when);
  451.     for (i = 0; i < 3; i++)
  452.     sp->avenrun[i] = ntohl(sp->avenrun[i]);
  453.     for (i = 0; i < CPUSTATES; i++)
  454.     sp->cputime[i] = ntohl(sp->cputime[i]);
  455.     sp->ipup = ntohl(sp->ipup);
  456.     sp->ipln = ntohl(sp->ipln);
  457.     sp->opln = ntohl(sp->opln);
  458.     sp->opup = ntohl(sp->opup);
  459.     sp->ndu = ntohl(sp->ndu);
  460.     for (lsp = sp->ln; lsp < &sp->ln[sp->ndu]; lsp++) {
  461.     lsp->cchr = ntohl(lsp->cchr);
  462.     lsp->cchs = ntohl(lsp->cchs);
  463.     lsp->cpsip = ntohl(lsp->cpsip);
  464.     lsp->cprip = ntohl(lsp->cprip);
  465.     lsp->flags = ntohl(lsp->flags);
  466.     lsp->ctpbusy = ntohl(lsp->ctpbusy);
  467.     lsp->ctpidle = ntohl(lsp->ctpidle);
  468.     lsp->sesc = ntohl(lsp->sesc);
  469.     lsp->resc = ntohl(lsp->resc);
  470.     lsp->dest.s_addr = ntohl(lsp->dest.s_addr);
  471.     lsp->ierror = ntohl(lsp->ierror);
  472.     lsp->oerror = ntohl(lsp->oerror);
  473.     lsp->ln = ntohl(lsp->ln);
  474.     }
  475. }
  476.  
  477.  
  478. /*
  479. **  Compute tty percents per line.
  480. */
  481. static void
  482. computettypercent()
  483. {
  484.     float    ttysum;
  485.     float    percent;
  486.     int        i;
  487.     DIALLOGREC    *busyp;
  488.     DIALLOGREC    *idlep;
  489.  
  490.     busyp = Records[R_CTPBUSY];
  491.     idlep = Records[R_CTPIDLE];
  492.     for (i = 0; i < MAX_NDU; i++, busyp++, idlep++) {
  493.         ttysum = busyp->fCount + idlep->fCount;
  494.         if (ttysum == 0.0)
  495.             continue;
  496.         percent = (busyp->fCount / ttysum) * 100.0;
  497.         busyp->fCount = percent;
  498.         percent = (idlep->fCount / ttysum) * 100.0;
  499.         idlep->fCount = percent;
  500.     }
  501. }
  502.  
  503.  
  504. /*
  505. **  Read data from the socket.
  506. */
  507. static void
  508. readsocket(fd)
  509.     int            fd;
  510. {
  511.     char        *timep;
  512.     char        *p;
  513.     int            n;
  514.     int            ntot;
  515.     unsigned long    size;
  516.  
  517.     /* Find out how much to read. */
  518.     if (read(fd, (caddr_t)&size, sizeof size) != sizeof size)
  519.         fatal("Can't read size of stats");
  520.     size = ntohl(size);
  521.  
  522.     /* Read in all the data. */
  523.     for (ntot = 0, p = (char *)&StatsCur; ntot < size; ntot += n, p += n)
  524.         if ((n = read(fd, p, size - ntot)) <= 0)
  525.             fatal("Read from server failed");
  526.     FromNetworkOrder(&StatsCur);
  527.  
  528.     /* Update the time. */
  529.     timep = ctime(&StatsCur.when);
  530.     if (p = strchr(timep, '\n'))
  531.     *p = '\0';
  532.     Wmove(Wtitle, 1, 36);
  533.     Wprintw(Wtitle, "%s", timep);
  534.  
  535.     /* Update the status fields. */
  536.     UpdateStatus();
  537.     Wrefresh(Wtitle);
  538.  
  539.     /* Compute differences, update the records. */
  540.     computediffs();
  541.     computettypercent();
  542.  
  543.     /* Update the graphs for the displayed window */
  544.     if (CurrWind == W_GLOBAL || CurrWind == W_LINE)
  545.         UpdateGraphs();
  546.     else if (CurrWind == W_TOTAL)
  547.         UpdateTotals();
  548.     Wrefresh(Wprompt);
  549. }
  550.  
  551.  
  552.  
  553. /*
  554. **  Process the request read from the terminal.
  555. */
  556. static void
  557. processrequest(buff)
  558.     char    *buff;
  559. {
  560.     char    *p;
  561.     int        arg;
  562.     int        c;
  563.  
  564.     for (arg = NOTSET, p = buff; *p && isspace(*p); p++)
  565.     ;
  566.  
  567.     for (c = *p; *++p && isspace(*p); )
  568.     ;
  569.  
  570.     switch (c) {
  571.  
  572.     case 'g':
  573.     globalstats();
  574.     return;
  575.  
  576.     case 'q':
  577.     ext();
  578.     /* NOTREACHED */
  579.  
  580.     case 'l':
  581.     if (isdigit(*p) && (arg = atoi(p)) < MAX_NDU) {
  582.         linestats(arg);
  583.         return;
  584.     }
  585.  
  586.     case 't':
  587.     if (*p == 'g') {
  588.         totalstats(NOTSET);
  589.         return;
  590.     }
  591.     if (isdigit(*p) && (arg = atoi(p)) < MAX_NDU) {
  592.         totalstats(arg);
  593.         return;
  594.     }
  595.     break;
  596.  
  597.     case 'r':
  598.     switch (*p) {
  599.     case 'n':
  600.         reset(FALSE);
  601.         return;
  602.     case 'y':
  603.         reset(TRUE);
  604.         return;
  605.     }
  606.     break;
  607.     }
  608.  
  609.     helpwindow();
  610. }
  611.  
  612.  
  613. /*
  614. **  Read input from the user.
  615. */
  616. readterminal()
  617. {
  618.     static char    buff[MAXREQUEST];
  619.     static int    curpos;
  620.     int        count;
  621.     int        done;
  622.     int        i;
  623.     char    *p;
  624.  
  625.     /* Refresh the screen, read if there is any input. */
  626.     Wrefresh(Wprompt);
  627.     if (ioctl(0, FIONREAD, (caddr_t)&count) >= 0 && count <= 0)
  628.     return;
  629.  
  630.     p = &buff[curpos];
  631.     for (done = FALSE, i = 0; i < count && !done; i++) {
  632.     switch (*p = wgetch(Wprompt)) {
  633.     default:
  634.         if (p < &buff[sizeof buff - 1])
  635.         p++;
  636.         break;
  637.     case '\n':
  638.     case '\r':
  639.         *p = '\0';
  640.         done = TRUE;
  641.         break;
  642.     case '\177':
  643.     case '\b':
  644.         if (p > buff)
  645.         p--;
  646.         break;
  647.     case '\f':
  648.         Wrefresh(curscr);
  649.         break;
  650.     }
  651.     }
  652.  
  653.     /* Redraw the line. */
  654.     curpos = p - buff;
  655.     Wclear(Wprompt);
  656.     Wprintw(Wprompt, " ? ");
  657.     for (p = buff, i = 0; i < curpos; i++, p++)
  658.     Wprintw(Wprompt, "%c", *p);
  659.     Wrefresh(Wprompt);
  660.  
  661.     /* If we got a full line, execute it. */
  662.     if (done) {
  663.     curpos = 0;
  664.     processrequest(buff);
  665.     Wclear(Wprompt);
  666.     Wprintw(Wprompt, " ? ");
  667.     Wrefresh(Wprompt);
  668.     }
  669. }
  670.  
  671.  
  672.  
  673. /*
  674. **  Allocate storage for global log records
  675. */
  676. static void
  677. AllocGStor(i, yloc)
  678.     int        i;
  679.     int        yloc;
  680. {
  681.     DIALLOGREC    *drp;
  682.  
  683.     if (yloc >= maxyloc)
  684.         fatal("Screen too small (global stats)");
  685.     if ((drp = (DIALLOGREC *)malloc(sizeof *drp)) == NULL)
  686.         fatal("Can't malloc storage for global log record");
  687.     drp->yloc = yloc;
  688.     drp->Old = 0;
  689.     drp->Count = 0;
  690.     drp->fCount = 0.0;
  691.     drp->Line = 0;
  692.     drp->Window = W_GLOBAL;
  693.     Records[i] = drp;
  694. }
  695.  
  696.  
  697. /*
  698. **  Allocate storage for line log records
  699. */
  700. static void
  701. AllocLStor(i, yloc)
  702.     int        i;
  703.     int        yloc;
  704. {
  705.     DIALLOGREC    *drp;
  706.     int        j;
  707.  
  708.     if (yloc >= maxyloc)
  709.         fatal("Screen too small (line stats)");
  710.     if ((drp = (DIALLOGREC *)malloc(MAX_NDU * sizeof *drp)) == NULL)
  711.         fatal("Can't malloc storage for line log record");
  712.  
  713.     for (Records[i] = drp, j = 0; j < MAX_NDU; j++, drp++) {
  714.         drp->yloc = yloc;
  715.         drp->Old = 0;
  716.         drp->Count = 0;
  717.     drp->fCount = 0.0;
  718.         drp->Line = j;
  719.         drp->Window = W_LINE;
  720.     }
  721. }
  722.  
  723.  
  724. /*
  725. **  Initialize data structures.
  726. */
  727. static void
  728. initdata()
  729. {
  730.     int            i;
  731.     int            j;
  732.     LINESTATS        *old;
  733.     LINESTATS        *cur;
  734.     LINESTATS        *res;
  735.     struct timeval    tv;
  736.     AVERAGES        *aptr;
  737.  
  738.     CurrWind = NOTSET;
  739.     CurrLine = NOTSET;
  740.     freset = FALSE;
  741.     newdata = 0;
  742.     maxyloc = LINES - 5;    /* 4 lines at top, one for prompt at bottom */
  743.  
  744.     StatsCur.when = gettimeofday(&tv, (struct timezone *)NULL) < 0
  745.             ? 0 : tv.tv_sec;
  746.     StatsCur.avenrun[0] = 0;
  747.     StatsCur.avenrun[1] = 0;
  748.     StatsCur.avenrun[2] = 0;
  749.  
  750.     for (i = 0; i < CPUSTATES; i++)
  751.         StatsCur.cputime[i] = 0;
  752.  
  753.     StatsReset.ipup = StatsCur.ipup = StatsOld.ipup = 0;
  754.     StatsReset.ipln = StatsCur.ipln = StatsOld.ipln = 0;
  755.     StatsReset.opln = StatsCur.opln = StatsOld.opln = 0;
  756.     StatsReset.opup = StatsCur.opup = StatsOld.opup = 0;
  757.  
  758.     old = StatsOld.ln;
  759.     cur = StatsCur.ln;
  760.     res = StatsReset.ln;
  761.     for (i = 0; i < StatsCur.ndu; i++, cur++, old++, res++) {
  762.     /* Assume all lines configured, if we found out it's not, then
  763.      * we will save the correct value in StatsOld. */
  764.         cur->ln = LINE_NOTCONF;
  765.         res->ln = old->ln = i;
  766.     res->dest.s_addr = cur->dest.s_addr = old->dest.s_addr = 0L;
  767.         res->cchr = cur->cchr = old->cchr = 0;
  768.         res->cchs = cur->cchs = old->cchs = 0;
  769.         res->cpsip = cur->cpsip = old->cpsip = 0;
  770.         res->cprip = cur->cprip = old->cprip = 0;
  771.         res->ierror = cur->ierror = old->ierror = 0;
  772.         res->oerror = cur->oerror = old->oerror = 0;
  773.         res->flags = cur->flags = old->flags = 0;
  774.         res->ctpbusy = cur->ctpbusy = old->ctpbusy = 0;
  775.         res->ctpidle = cur->ctpidle = old->ctpidle = 0;
  776.         res->resc = cur->resc = old->resc = 0;
  777.         res->sesc = cur->sesc = old->sesc = 0;
  778.  
  779.     /* Set up the averages table. */
  780.     for (j = 0; j < MAXINTERVALS; j++) {
  781.         aptr = &Averages[i][j];
  782.         aptr->chs = 0;
  783.         aptr->pkts = 0;
  784.         aptr->chr = 0;
  785.         aptr->pktr = 0;
  786.         aptr->rescs = 0;
  787.         aptr->sescs = 0;
  788.         aptr->sec = 0;
  789.     }
  790.  
  791.     (void)strcpy(OtherHost[i], "UNINITIALIZED");
  792.     }
  793.  
  794.     /* Get storage for loc records, assign y locations. */
  795.     i = 1;
  796.     AllocGStor(R_CIPUP, i++);
  797.     AllocGStor(R_CIPLN, i++);
  798.     AllocGStor(R_COPUP, i++);
  799.     AllocGStor(R_COPLN, i++);
  800.     AllocGStor(R_gIERROR, i++);
  801.     AllocGStor(R_gOERROR, i++);
  802.     AllocGStor(R_gCHS, i);
  803.     AllocGStor(R_gCHR, i++);
  804.  
  805.     /* Local storage.  Note that some share the same location. */
  806.     i = 1;
  807.     AllocLStor(R_CPSIP, i++);
  808.     AllocLStor(R_CPRIP, i++);
  809.     AllocLStor(R_CTPBUSY, i);
  810.     AllocLStor(R_CTPIDLE, NOTSET);
  811.     AllocLStor(R_aPCTESC, i++);
  812.     AllocLStor(R_ESCS, NOTSET);
  813.     AllocLStor(R_ESCR, NOTSET);
  814.     AllocLStor(R_CCHS, i);
  815.     AllocLStor(R_CCHR, i++);
  816.     AllocLStor(R_aCHPKTS, i);
  817.     AllocLStor(R_aCHPKTR, i++);
  818.     AllocLStor(R_aCHS, i);
  819.     AllocLStor(R_aCHR, i++);
  820.     AllocLStor(R_aPKTS, i);
  821.     AllocLStor(R_aPKTR, i++);
  822.     AllocLStor(R_IERROR, i++);
  823.     AllocLStor(R_OERROR, i++);
  824.     AllocLStor(R_STATE, i++);
  825. }
  826.  
  827.  
  828.  
  829. /*
  830. **  Blank out a row of stars.
  831. */
  832. removeplot(oldx, newx, yloc)
  833.     int        oldx;
  834.     int        newx;
  835.     int        yloc;
  836. {
  837.     for (; oldx > newx; oldx--)
  838.         mvwaddch(Wgraph, yloc, oldx - 1, ' ');
  839. }
  840.  
  841.  
  842. /*
  843. **  Add a row of stars.
  844. */
  845. addplot(oldx, newx, yloc)
  846.     int        oldx;
  847.     int        newx;
  848.     int        yloc;
  849. {
  850.     while (++oldx <= newx)
  851.         mvwaddch(Wgraph, yloc, oldx - 1, '*');
  852. }
  853.  
  854.  
  855. /*
  856.  * globalstats -- set-up global statistics window for monitoring
  857.  */
  858. globalstats()
  859. {
  860.     int        line;
  861.  
  862.     /* window already global, don't change it */
  863.     if (CurrWind == W_GLOBAL)
  864.         return;
  865.  
  866.     CurrWind = W_GLOBAL;
  867.     Wclear(Whelp);
  868.     Wclear(Wtypes);
  869.     Wclear(Wgraph);
  870.     Wrefresh(Whelp);
  871.  
  872.     /* print title and scale */
  873.     line = 0;
  874.     Wmove(Wtypes, line, 0);
  875.     Wprintw(Wtypes, "GLOBAL STATISTICS:");
  876.     Wmove(Wgraph, line++, 0);
  877.     Wprintw(Wgraph, "1        10        20        30        40");
  878.  
  879.     InitDisplay(R_CIPUP, 0);
  880.     InitDisplay(R_CIPLN, 0);
  881.     InitDisplay(R_COPUP, 0);
  882.     InitDisplay(R_COPLN, 0);
  883.     InitDisplay(R_gCHS, 0);
  884.     InitDisplay(R_gCHR, 0);
  885.     InitDisplay(R_gIERROR,0);
  886.     InitDisplay(R_gOERROR,0);
  887.     Wrefresh(Wtypes);
  888.     Wrefresh(Wgraph);
  889.     UpdateGraphs();
  890. }
  891.  
  892.  
  893. /*
  894. **  Set-up line statistics window for monitoring.
  895. */
  896. linestats(ln)
  897.     int        ln;
  898. {
  899.     int        line;
  900.  
  901.     if (CurrWind == W_LINE && CurrLine == ln)
  902.         return;
  903.  
  904.     if (StatsOld.ln[ln].ln == LINE_NOTCONF) {
  905.         LineNotConf(ln);
  906.         return;
  907.     }
  908.  
  909.     CurrWind = W_LINE;
  910.     CurrLine = ln;
  911.     Wclear(Whelp);
  912.     Wclear(Wtypes);
  913.     Wclear(Wgraph);
  914.     Wrefresh(Whelp);
  915.  
  916.     line = 0;
  917.     Wmove(Wtypes, line, 0);
  918.     Wprintw(Wtypes, "LINE TO %.20s:", OtherHost[ln]);
  919.     Wmove(Wgraph, line++, 0);
  920.     Wprintw(Wgraph, "1        10        20        30        40");
  921.  
  922.     InitDisplay(R_CPSIP, ln);
  923.     InitDisplay(R_CPRIP, ln);
  924.     InitDisplay(R_CTPBUSY, ln);
  925.     InitDisplay(R_aPCTESC, ln);
  926.     InitDisplay(R_CCHS, ln);
  927.     InitDisplay(R_CCHR, ln);
  928.     InitDisplay(R_aCHPKTS, ln);
  929.     InitDisplay(R_aCHPKTR, ln);
  930.     InitDisplay(R_aCHS, ln);
  931.     InitDisplay(R_aCHR, ln);
  932.     InitDisplay(R_aPKTS, ln);
  933.     InitDisplay(R_aPKTR, ln);
  934.     InitDisplay(R_STATE, ln);
  935.     InitDisplay(R_IERROR, ln);
  936.     InitDisplay(R_OERROR, ln);
  937.     Wrefresh(Wtypes);
  938.     Wrefresh(Wgraph);
  939.     UpdateGraphs();
  940. }
  941.  
  942.  
  943. /*
  944. **  Set-up total statistics window for monitoring.
  945. */
  946. totalstats(ln)
  947.     int        ln;
  948. {
  949.     int        line;
  950.  
  951.     if (CurrWind == W_TOTAL && CurrLine == ln)
  952.         return;
  953.  
  954.     if (ln != NOTSET && StatsOld.ln[ln].ln == LINE_NOTCONF) {
  955.         LineNotConf(ln);
  956.         return;
  957.     }
  958.  
  959.     CurrWind = W_TOTAL;
  960.     CurrLine = ln;
  961.     Wclear(Whelp);
  962.     Wclear(Wtypes);
  963.     Wclear(Wgraph);
  964.     Wrefresh(Whelp);
  965.  
  966.     /* Pint title and scale. */
  967.     line = 0;
  968.     Wmove(Wtypes, line, 0);
  969.  
  970.     if (ln == NOTSET)
  971.         Wprintw(Wtypes, "GLOBAL TOTALS:");
  972.     else
  973.         Wprintw(Wtypes, "LINE TOTALS TO %.20s:", OtherHost[ln]);
  974.     Wmove(Wgraph, line++, 0);
  975.     Wprintw(Wgraph, " TOTAL COUNTS");
  976.  
  977.     if (CurrLine == NOTSET) {
  978.     /* Global records. */
  979.         InitDisplay(R_CIPUP, 0);
  980.         InitDisplay(R_CIPLN, 0);
  981.         InitDisplay(R_COPUP, 0);
  982.         InitDisplay(R_COPLN, 0);
  983.         InitDisplay(R_gCHS, 0);
  984.         InitDisplay(R_gCHR, 0);
  985.         InitDisplay(R_gIERROR,0);
  986.         InitDisplay(R_gOERROR,0);
  987.     }
  988.     else  {
  989.     /* Line records. */
  990.         InitDisplay(R_CPSIP, ln);
  991.         InitDisplay(R_CPRIP, ln);
  992.         InitDisplay(R_CTPBUSY, ln);
  993.         InitDisplay(R_aPCTESC, ln);
  994.         InitDisplay(R_CCHS, ln);
  995.         InitDisplay(R_CCHR, ln);
  996.         InitDisplay(R_aCHPKTS, ln);
  997.         InitDisplay(R_aCHPKTR, ln);
  998.     InitDisplay(R_IERROR, ln);
  999.     InitDisplay(R_OERROR, ln);
  1000.     }
  1001.     Wrefresh(Wtypes);
  1002.     Wrefresh(Wgraph);
  1003.     UpdateTotals();
  1004. }
  1005.  
  1006.  
  1007. /*
  1008. **  If flag is TRUE, reset totals to 0 and start accumulating, else use
  1009. **  real totals as sent from monitored site.
  1010. */
  1011. reset(flag)
  1012.     int        flag;
  1013. {
  1014.     int        i;
  1015.     LINESTATS    *res;
  1016.  
  1017.     freset = flag;
  1018.     if (freset) {
  1019.         StatsReset.ipup = 0;
  1020.         StatsReset.ipln = 0;
  1021.         StatsReset.opup = 0;
  1022.         StatsReset.opln = 0;
  1023.         for (res = StatsReset.ln, i = 0; i < StatsCur.ndu; i++, res++) {
  1024.             res->cchr = 0;
  1025.             res->cchs = 0;
  1026.             res->cpsip = 0;
  1027.             res->cprip = 0;
  1028.             res->ierror = 0;
  1029.             res->oerror = 0;
  1030.             res->ctpbusy = 0;
  1031.             res->ctpidle = 0;
  1032.         res->resc = 0;
  1033.         res->sesc = 0;
  1034.     }
  1035.     }
  1036.     if (CurrWind == W_TOTAL)
  1037.         UpdateTotals();
  1038. }
  1039.  
  1040.  
  1041. /*
  1042. **  Help function, displays the windows that are available.
  1043. */
  1044.  
  1045. helpwindow()
  1046. {
  1047.     int        line;
  1048.  
  1049.     CurrWind = W_HELP;
  1050.     Wclear(Whelp);
  1051.     Wclear(Wtypes);
  1052.     Wclear(Wgraph);
  1053.     Wrefresh(Wtypes);
  1054.     Wrefresh(Wgraph);
  1055.  
  1056.     /* Print title. */
  1057.     line = 0;
  1058.     Wmove(Whelp, line++, 0);
  1059.     Wprintw(Whelp, "COMMANDS:\n");
  1060.     Wprintw(Whelp, "  l#\t\tSerial line statistics for line #\n");
  1061.     Wprintw(Whelp, "  t# | tg\tTotal statistics for line # or g for global\n");
  1062.     Wprintw(Whelp, "  h or ?\tHelp\n");
  1063.     Wprintw(Whelp, "  ^L\t\tRedraw\n");
  1064.     Wprintw(Whelp, "  ry\t\tUse the reset totals\n");
  1065.     Wprintw(Whelp, "  rn\t\tUse totals since last reboot\n");
  1066.     Wprintw(Whelp, "  q\t\tQuit\n");
  1067.     Wrefresh(Whelp);
  1068. }
  1069.  
  1070.  
  1071. /*
  1072. **  Clear screen and print message if the line to be monitored is not
  1073. **  configured.
  1074. */
  1075. LineNotConf(ln)
  1076.     int        ln;
  1077. {
  1078.     Wclear(Whelp);
  1079.     Wclear(Wgraph);
  1080.     Wclear(Wtypes);
  1081.     Wrefresh(Whelp);
  1082.     Wmove(Wtypes, 0, 0);
  1083.     Wprintw(Wtypes, "SERIAL LINE %d NOT CONFIGURED", ln);
  1084.     CurrWind = W_HELP;
  1085.     Wrefresh(Wtypes);
  1086.     Wrefresh(Wgraph);
  1087. }
  1088.  
  1089.  
  1090. /*
  1091. **  Initialize one type of log record's data structure for the line to be
  1092. **  displayed and display the title.
  1093. */
  1094. InitDisplay(t, l)
  1095.     int        t;
  1096.     int        l;
  1097. {
  1098.     DIALLOGREC    *drp;
  1099.  
  1100.     drp = &Records[t][l];
  1101.     drp->Old = 0;
  1102.  
  1103.     switch (t) {
  1104.     default:
  1105.     Wmove(Wtypes, drp->yloc, 0);
  1106.     Wprintw(Wtypes, "%s", TypeDescriptions[t]);
  1107.     mvwaddch(Wtypes, drp->yloc, 29, ':');
  1108.     break;
  1109.     case R_CTPBUSY:
  1110.     case R_CCHS:
  1111.     case R_gCHS:
  1112.     case R_aCHS:
  1113.     case R_aPKTS:
  1114.     case R_aCHPKTS:
  1115.     Wmove(Wtypes, drp->yloc, 0);
  1116.     Wprintw(Wtypes, "%s", TypeDescriptions[t]);
  1117.     break;
  1118.     case R_aPCTESC:
  1119.     case R_CCHR:
  1120.     case R_gCHR:
  1121.     case R_aCHR:
  1122.     case R_aPKTR:
  1123.     case R_aCHPKTR:
  1124.     Wmove(Wgraph, drp->yloc, 0);
  1125.     Wprintw(Wgraph, "%s", TypeDescriptions[t]);
  1126.     break;
  1127.     }
  1128. }
  1129.  
  1130.  
  1131. /*
  1132. **  Update the system status lines.
  1133. */
  1134. UpdateStatus()
  1135. {
  1136.     float    pct[CPUSTATES];
  1137.     int        i;
  1138.     int        w;
  1139.  
  1140.     /* sum up the time spent in each cpu state and initialize pct */
  1141.     for (w = 0, i = 0; i < CPUSTATES; i++) {
  1142.         pct[i] = 0.0;
  1143.         w += StatsCur.cputime[i];
  1144.     }
  1145.  
  1146.     /* compute the percent of time spent in each cpu state */
  1147.     if (w)
  1148.         for (i = 0; i < CPUSTATES; i++)
  1149.             pct[i] = ((float)StatsCur.cputime[i] / (float)w) * 100.0;
  1150.  
  1151.     Wmove(Wtitle, 2, 26);
  1152.     Wprintw(Wtitle, "%6.2f", pct[0]);
  1153.     Wmove(Wtitle, 2, 42);
  1154.     Wprintw(Wtitle, "%6.2f", pct[2]);
  1155.     Wmove(Wtitle, 2, 56);
  1156.     Wprintw(Wtitle, "%6.2f", pct[1]);
  1157.     Wmove(Wtitle, 2, 70);
  1158.     Wprintw(Wtitle, "%6.2f", pct[3]);
  1159.     Wmove(Wtitle, 3, 37);
  1160.     Wprintw(Wtitle, "%5.2f", ((float)StatsCur.avenrun[0]) / 100.);
  1161.     Wmove(Wtitle, 3, 44);
  1162.     Wprintw(Wtitle, "%5.2f", ((float)StatsCur.avenrun[1]) / 100.);
  1163.     Wmove(Wtitle, 3, 51);
  1164.     Wprintw(Wtitle, "%5.2f", ((float)StatsCur.avenrun[2]) / 100.);
  1165. }
  1166.  
  1167.  
  1168. /*
  1169. **  Update the plots in the active window. Does not update the Old of
  1170. **  any log record not being displayed or that prints a floating point
  1171. **  number.
  1172. */
  1173. UpdateGraphs()
  1174. {
  1175.     DIALLOGREC    *drp;
  1176.  
  1177.     if (CurrWind == W_GLOBAL) {
  1178.     /* Update all global plots */
  1179.         UpdatePlot(Records[R_CIPUP]);
  1180.         UpdatePlot(Records[R_CIPLN]);
  1181.         UpdatePlot(Records[R_COPUP]);
  1182.         UpdatePlot(Records[R_COPLN]);
  1183.         drp = Records[R_gCHS];
  1184.         PrintNum(Wtypes, (unsigned long)drp->Count, drp->yloc, 17);
  1185.         drp->Old = drp->Count;
  1186.         drp = Records[R_gCHR];
  1187.         PrintNum(Wgraph, (unsigned long)drp->Count, drp->yloc, 21);
  1188.         drp->Old = drp->Count;
  1189.         drp = Records[R_gIERROR];
  1190.         PrintNum(Wgraph, (unsigned long)drp->Count, drp->yloc, 0);
  1191.         drp->Old = drp->Count;
  1192.         drp = Records[R_gOERROR];
  1193.         PrintNum(Wgraph, (unsigned long)drp->Count, drp->yloc, 0);
  1194.         drp->Old = drp->Count;
  1195.     }
  1196.     else if (CurrWind == W_LINE) {
  1197.     /* Update the displayed line's stats */
  1198.         Wmove(Wtypes, 0, 8);
  1199.     Wclrtoeol(Wtypes);
  1200.     Wmove(Wtypes, 0, 8);
  1201.     Wprintw(Wtypes, "%-.20s", OtherHost[CurrLine]);
  1202.     mvwaddch(Wtypes, 0, 29, ':');
  1203.         UpdatePlot(&Records[R_CPSIP][CurrLine]);
  1204.         UpdatePlot(&Records[R_CPRIP][CurrLine]);
  1205.         drp = &Records[R_CTPBUSY][CurrLine];
  1206.         PrintPct(Wtypes, drp->fCount, drp->yloc, 19);
  1207.         drp = &Records[R_CCHS][CurrLine];
  1208.         PrintNum(Wtypes, (unsigned long)drp->Count, drp->yloc, 17);
  1209.         drp->Old = drp->Count;
  1210.         drp = &Records[R_aCHPKTS][CurrLine];
  1211.         PrintNumf(Wtypes, drp->fCount, drp->yloc, 19);
  1212.         drp = &Records[R_aCHS][CurrLine];
  1213.         PrintNumf(Wtypes, drp->fCount, drp->yloc, 19);
  1214.         drp = &Records[R_aPKTS][CurrLine];
  1215.         PrintNumf(Wtypes, drp->fCount, drp->yloc, 19);
  1216.         drp = &Records[R_aPCTESC][CurrLine];
  1217.         PrintPct(Wgraph, drp->fCount, drp->yloc, 28);
  1218.         drp = &Records[R_CCHR][CurrLine];
  1219.         PrintNum(Wgraph, (unsigned long)drp->Count, drp->yloc, 26);
  1220.         drp->Old = drp->Count;
  1221.         drp = &Records[R_aCHPKTR][CurrLine];
  1222.         PrintNumf(Wgraph, drp->fCount, drp->yloc, 28);
  1223.         drp = &Records[R_aCHR][CurrLine];
  1224.         PrintNumf(Wgraph, drp->fCount, drp->yloc, 28);
  1225.         drp = &Records[R_aPKTR][CurrLine];
  1226.         PrintNumf(Wgraph, drp->fCount, drp->yloc, 28);
  1227.     drp = &Records[R_STATE][CurrLine];
  1228.     PrintState(Wgraph, drp->Count, drp->yloc, 5);
  1229.     drp = &Records[R_IERROR][CurrLine];
  1230.     PrintNum(Wgraph, (unsigned long)drp->Count, drp->yloc, 0);
  1231.     drp = &Records[R_OERROR][CurrLine];
  1232.     PrintNum(Wgraph, (unsigned long)drp->Count, drp->yloc, 0);
  1233.     }
  1234.     Wrefresh(Wtypes);
  1235.     Wrefresh(Wgraph);
  1236. }
  1237.  
  1238. /*
  1239. **  Update the total counts being displayed
  1240. */
  1241. UpdateTotals()
  1242. {
  1243.     int            i;
  1244.     int            yloc;
  1245.     LINESTATS        *lsp;
  1246.     DIALSTATS        *sp;
  1247.     float        ttysum;
  1248.     unsigned long    totchr;
  1249.     unsigned long    totchs;
  1250.     unsigned long    totierror;
  1251.     unsigned long    totoerror;
  1252.  
  1253.     sp = freset ? &StatsReset : &StatsOld;
  1254.  
  1255.     if (CurrLine == NOTSET) {
  1256.     /* Global totals */
  1257.         PrintNum(Wgraph, sp->ipup, Records[R_CIPUP]->yloc, 0);
  1258.         PrintNum(Wgraph, sp->ipln, Records[R_CIPLN]->yloc, 0);
  1259.         PrintNum(Wgraph, sp->opup, Records[R_COPUP]->yloc, 0);
  1260.         PrintNum(Wgraph, sp->opln, Records[R_COPLN]->yloc, 0);
  1261.  
  1262.         /* total chars received and sent and total silo overflows */
  1263.     totchs = 0;
  1264.     totchr = 0;
  1265.     totierror = 0;
  1266.     totoerror = 0;
  1267.         for (i = 0; i < StatsCur.ndu; i++) {
  1268.             totchs += sp->ln[i].cchs;
  1269.             totchr += sp->ln[i].cchr;
  1270.         totierror += sp->ln[i].ierror;
  1271.         totoerror += sp->ln[i].oerror;
  1272.     }
  1273.         PrintNum(Wtypes, totchs, Records[R_gCHS]->yloc, 17);
  1274.         PrintNum(Wgraph, totchr, Records[R_gCHR]->yloc, 21);
  1275.     PrintNum(Wgraph, totierror, Records[R_gIERROR]->yloc, 17);
  1276.     PrintNum(Wgraph, totoerror, Records[R_gOERROR]->yloc, 17);
  1277.     }
  1278.     else {
  1279.     /* Displayed line totals */
  1280.         Wmove(Wtypes, 0, 15);
  1281.     Wclrtoeol(Wtypes);
  1282.         Wmove(Wtypes, 0, 15);
  1283.     Wprintw(Wtypes, "%-.14s", OtherHost[CurrLine]);
  1284.     mvwaddch(Wtypes, 0, 29, ':');
  1285.         lsp = &sp->ln[CurrLine];
  1286.         PrintNum(Wgraph, lsp->cpsip, Records[R_CPSIP][CurrLine].yloc, 0);
  1287.         PrintNum(Wgraph, lsp->cprip, Records[R_CPRIP][CurrLine].yloc, 0);
  1288.         PrintNum(Wgraph, lsp->ierror, Records[R_IERROR][CurrLine].yloc, 0);
  1289.         PrintNum(Wgraph, lsp->oerror, Records[R_OERROR][CurrLine].yloc, 0);
  1290.         if (ttysum = (float)(lsp->ctpbusy + lsp->ctpidle))
  1291.         PrintPct(Wtypes,
  1292.         ((float)lsp->ctpbusy / (float)ttysum) * 100.0,
  1293.         Records[R_CTPBUSY][CurrLine].yloc, 19);
  1294.     else
  1295.         PrintPct(Wtypes, 0.0, Records[R_CTPBUSY][CurrLine].yloc, 19);
  1296.  
  1297.     yloc = Records[R_aPCTESC][CurrLine].yloc;
  1298.     Wmove(Wgraph, yloc, 0);
  1299.     Wclrtoeol(Wgraph);
  1300.     Wmove(Wgraph, yloc, 0);
  1301.         if (lsp->cchs)
  1302.         Wprintw(Wgraph, "%10.5f%%s %10.5f%%r",
  1303.           ((float)lsp->sesc / (float)lsp->cchs) * 100.0,
  1304.           ((float)lsp->resc / (float)lsp->cchr) * 100.0);
  1305.     else
  1306.         Wprintw(Wgraph, "%10.5f%%", (float)lsp->cchs);
  1307.  
  1308.     PrintNum(Wtypes, lsp->cchs, Records[R_CCHS][CurrLine].yloc, 17);
  1309.         PrintNum(Wgraph, lsp->cchr, Records[R_CCHR][CurrLine].yloc, 26);
  1310.     }
  1311.     Wrefresh(Wtypes);
  1312.     Wrefresh(Wgraph);
  1313. }
  1314.  
  1315.  
  1316. /*
  1317. **  Print the number in the specified window at the specified location.
  1318. */
  1319. PrintNum(wn, num, yloc, xloc)
  1320.     WINDOW        *wn;
  1321.     unsigned long    num;
  1322.     int            yloc;
  1323.     int            xloc;
  1324. {
  1325.     Wmove(wn, yloc, xloc);
  1326.     Wclrtoeol(wn);
  1327.     Wmove(wn, yloc, xloc);
  1328.     Wprintw(wn, "%10d", num);
  1329. }
  1330.  
  1331.  
  1332. /*
  1333. **  Print the float in the specified window at the specified location.
  1334. */
  1335. PrintNumf(wn, num, yloc, xloc)
  1336.     WINDOW    *wn;
  1337.     float    num;
  1338.     int        yloc;
  1339.     int        xloc;
  1340. {
  1341.     Wmove(wn, yloc, xloc);
  1342.     Wclrtoeol(wn);
  1343.     Wmove(wn, yloc, xloc);
  1344.     Wprintw(wn, "%8.2f  ", num);
  1345. }
  1346.  
  1347.  
  1348. /*
  1349. **  Print the percent of time a tty is busy.
  1350. */
  1351. PrintPct(wn, num, yloc, xloc)
  1352.     WINDOW    *wn;
  1353.     float    num;
  1354.     int        yloc;
  1355.     int        xloc;
  1356. {
  1357.     Wmove(wn, yloc, xloc);
  1358.     Wclrtoeol(wn);
  1359.     Wmove(wn, yloc, xloc);
  1360.     Wprintw(wn, "%8.2f %%", num);
  1361. }
  1362.  
  1363. PrintState(wn, state, yloc, xloc)
  1364.     WINDOW    *wn;
  1365.     int        state;
  1366.     int        yloc;
  1367.     int        xloc;
  1368. {
  1369.     int        i;
  1370.     int        j;
  1371.  
  1372.     Wmove(wn, yloc, xloc);
  1373.     Wclrtoeol(wn);
  1374.     Wmove(wn,yloc,xloc);
  1375.     for (i = 0, j = 1; i < 32 ; i++, j <<= 1)
  1376.     if (state & j)
  1377.         Wprintw(wn, "%s ", DUStateMessages[i]);
  1378. }
  1379.  
  1380.  
  1381. /*
  1382. **  Update the plot for the log record passed in.
  1383. */
  1384. UpdatePlot(drp)
  1385.     DIALLOGREC    *drp;
  1386. {
  1387.    if (drp->Count == drp->Old)
  1388.        return;
  1389.  
  1390.    if (drp->Count < 0) {
  1391.        Wmove(Wgraph, drp->yloc, 0);
  1392.        Wclrtoeol(Wgraph);
  1393.        drp->Count = 0;
  1394.        drp->Old = 0;
  1395.    }
  1396.    else if (drp->Count > MAXPLOTS && drp->Old > MAXPLOTS) {
  1397.        PrintNum(Wgraph, (unsigned long)drp->Count, drp->yloc, 0);
  1398.        drp->Old = drp->Count;
  1399.    }
  1400.    else if (drp->Count > MAXPLOTS && drp->Old <= MAXPLOTS) {
  1401.        PrintNum(Wgraph, (unsigned long)drp->Count, drp->yloc, 0);
  1402.        drp->Old = drp->Count;
  1403.    }
  1404.     else if (drp->Count <= MAXPLOTS && drp->Old > MAXPLOTS) {
  1405.        Wmove(Wgraph, drp->yloc, 0);
  1406.        Wclrtoeol(Wgraph);
  1407.        addplot(0, drp->Count, drp->yloc);
  1408.        drp->Old = drp->Count;
  1409.    }
  1410.    else if (drp->Count > drp->Old) {
  1411.        /* add to old graph */
  1412.        addplot(drp->Old, drp->Count, drp->yloc);
  1413.        drp->Old = drp->Count;
  1414.    }
  1415.    else if (drp->Count < drp->Old) {
  1416.        /* remove from old graph */
  1417.        removeplot(drp->Old, drp->Count, drp->yloc);
  1418.        drp->Old = drp->Count;
  1419.    }
  1420. }
  1421.  
  1422.  
  1423. /*
  1424. **  Look up a hostname, fill in the socket.  Return -1 on error.
  1425. */
  1426. static int
  1427. hosttosocket(p, psin)
  1428.     char        *p;
  1429.     struct sockaddr_in    *psin;
  1430. {
  1431.     struct hostent    *hp;
  1432.     unsigned long    w;
  1433.  
  1434.     bzero((caddr_t)psin, sizeof *psin);
  1435.     if (isdigit(*p)) {
  1436.     if ((w = inet_addr(p)) == (unsigned long)-1)
  1437.         return -1;
  1438.     psin->sin_addr.s_addr = w;
  1439.     psin->sin_family = AF_INET;
  1440.     return 0;
  1441.     }
  1442.  
  1443.     if ((hp = gethostbyname(p)) == NULL) {
  1444.     (void)fprintf(stderr, "Can't get address of \"%s\":  ", p);
  1445. #ifndef    HOST_NOT_FOUND
  1446.     (void)fprintf(stderr, "Host not found\n");
  1447. #else
  1448.     switch (h_errno) {
  1449.     default:
  1450.         (void)fprintf(stderr, "Unknown error: %d\n", h_errno);
  1451.         break;
  1452.     case HOST_NOT_FOUND:
  1453.         (void)fprintf(stderr, "Host not found\n");
  1454.         break;
  1455.     case TRY_AGAIN:
  1456.         (void)fprintf(stderr, "Try again later\n");
  1457.         break;
  1458.     case NO_RECOVERY:
  1459.         (void)fprintf(stderr, "No recovery possible\n");
  1460.         break;
  1461.     case NO_ADDRESS:
  1462.         (void)fprintf(stderr, "No IP address\n");
  1463.         break;
  1464.     }
  1465. #endif    /* NOT_NOT_FOUND */
  1466.     return -1;
  1467.     }
  1468.  
  1469.     psin->sin_family = hp->h_addrtype;
  1470.     bcopy(hp->h_addr, (char *)&psin->sin_addr, hp->h_length);
  1471.     return 0;
  1472. }
  1473.  
  1474. /*
  1475. **  Print usage message and exit.
  1476. */
  1477. static void
  1478. usage(p)
  1479.     char    *p;
  1480. {
  1481.     (void)fprintf(stderr, "Usage error:  %s\n", p);
  1482.     (void)fprintf(stderr, "Usage: %s [-g] [-l line] [-t g|line] [site]\n",
  1483.         progname);
  1484.     exit(1);
  1485. }
  1486.  
  1487.  
  1488. main(argc, argv)
  1489.     int            argc;
  1490.     char        *argv[];
  1491. {
  1492.     char        *p;
  1493.     struct servent    *sp;
  1494.     struct sockaddr_in    sin;
  1495.     int            i;
  1496.     int            fildes[2];
  1497.     char        *timep;
  1498.     char        buff[90];
  1499.     fd_set        readers;
  1500.     int            win;
  1501.     int            arg;
  1502.     int            localpipe;
  1503.  
  1504.     /* Set defaults. */
  1505.     win = W_GLOBAL;
  1506.     arg = NOTSET;
  1507.     localpipe = 0;
  1508.  
  1509.     /* Get options. */
  1510.     while ((i = getopt(argc, argv, "gl:pt:")) != EOF)
  1511.     switch (i) {
  1512.     default:
  1513.         usage("Bad flag");
  1514.         /* NOTREACHED */
  1515.     case 'g':        /* global stats, no arg */
  1516.         win = W_GLOBAL;
  1517.         arg = NOTSET;
  1518.         break;
  1519.     case 'l':        /* line stats, next arg must be ln # */
  1520.         if (!isdigit(*optarg) || (arg = atoi(optarg)) > MAX_NDU)
  1521.         usage("Bad number for -l");
  1522.         win = W_LINE;
  1523.         break;
  1524.     case 'p':
  1525.         localpipe = 1;
  1526.         break;
  1527.     case 't':        /* total stats, next arg must be */
  1528.         if (*optarg == 'g') {
  1529.         win = W_TOTAL;
  1530.         arg = NOTSET;
  1531.         }
  1532.         else if (!isdigit(*optarg) || (arg = atoi(optarg)) >= MAX_NDU)
  1533.         usage("Bad number for -t");
  1534.         win = W_TOTAL;
  1535.         break;
  1536.     }
  1537.     argc -= optind;
  1538.     argv += optind;
  1539.  
  1540.     if (!localpipe) {
  1541.     switch (argc) {
  1542.     default:
  1543.         usage("Wrong number of arguments");
  1544.         /* NOTREACHED */
  1545.     case 0:
  1546.         (void)gethostname(HostName, sizeof HostName);
  1547.         break;
  1548.     case 1:
  1549.         (void)strcpy(HostName, *argv);
  1550.         break;
  1551.     }
  1552.  
  1553.     if ((sp = getservbyname(DIALMON_SERVICE, "tcp")) == NULL) {
  1554.         (void)fprintf(stderr,
  1555.             "Warning: %s/tcp unknown service; using port %d\n",
  1556.             DIALMON_SERVICE, DIALMON_DEFAULT_PORT);
  1557.         (void)sleep(2);
  1558.     }
  1559.     }
  1560.     else {
  1561.     if (argc)
  1562.         usage("Wrong number of arguments");
  1563.     (void)gethostname(HostName, sizeof HostName);
  1564.     }
  1565.  
  1566.     /* Initialize screen */
  1567.     (void)initscr();
  1568.     (void)noecho();
  1569.     (void)nonl();
  1570.     (void)crmode();
  1571.     cursed++;
  1572.     if (LINES < 24 || COLS < 80)
  1573.     fatal("Screen too small");
  1574.     (void)signal(SIGINT, ext);
  1575.     Wtitle = newwin(4, 0, 0, 0);        /* 4 lines at top */
  1576.     Wgraph = newwin(maxyloc, COLS - 30, 4, 30);    /* 14 lines at center left*/
  1577.     Wtypes = newwin(maxyloc, 30, 4, 0);        /* 14 lines at center right */
  1578.     Wprompt = newwin(1, 0, LINES - 1, 0);
  1579.     Whelp = newwin(maxyloc, 0, 5, 0);
  1580.     Wmove(Wtitle, 0, 14);
  1581.     Wprintw(Wtitle, "%s Monitor: ", dip_release());
  1582.     Wmove(Wtitle, 1, 11);
  1583.     Wprintw(Wtitle, "Time of the last update: ");
  1584.     Wmove(Wtitle, 2, 5);
  1585.     Wprintw(Wtitle, "Cpu utilization USER:      %%, SYSTEM:      %%, ");
  1586.     Wprintw(Wtitle, "NICE:      %%, IDLE:      %%");
  1587.     Wmove(Wtitle, 3, 23);
  1588.     Wprintw(Wtitle, "Load average:      ,      ,      ");
  1589.     Wrefresh(Wtitle);
  1590.  
  1591.     /* This must be AFTER curses has been called, sigh. */
  1592.     initdata();
  1593.  
  1594.     switch (win) {
  1595.     default:
  1596.     helpwindow();
  1597.     break;
  1598.     case W_GLOBAL:
  1599.     globalstats();
  1600.     break;
  1601.     case W_LINE:
  1602.     linestats(arg);
  1603.     break;
  1604.     case W_TOTAL:
  1605.     totalstats(arg);
  1606.     break;
  1607.     }
  1608.  
  1609.     /* Connect to server */
  1610.     if (localpipe) {
  1611.     if (pipe(fildes) < 0)
  1612.         fatal("Can't make pipe");
  1613.     switch (fork()) {
  1614.     case -1:
  1615.         fatal("Can't fork");
  1616.         /* NOTREACHED */
  1617.     case 0:
  1618.         (void)close(fildes[0]);
  1619.         (void)close(0);
  1620.         (void)dup(fildes[1]);
  1621.         (void)close(fildes[1]);
  1622.         (void)execl(DIALMOND_PATH, "dialmond", (char *)NULL);
  1623.         fatal(DIALMOND_PATH);
  1624.         /* NOTREACHED */
  1625.     }
  1626.     (void)close(fildes[1]);
  1627.     fd = fildes[0];
  1628.     }
  1629.     else {
  1630.     if (hosttosocket(HostName, &sin) < 0) {
  1631.         (void)sprintf(buff, "Unknown host %s", HostName);
  1632.         fatal(buff);
  1633.     }
  1634.     if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  1635.         fatal("Socket failed");
  1636.     sin.sin_port = sp ? sp->s_port : DIALMON_DEFAULT_PORT;
  1637.     if (connect(fd, (caddr_t)&sin, sizeof sin) < 0) {
  1638.         (void)sprintf(buff, "Can't connect to port %d at %s",
  1639.             ntohs(sin.sin_port), HostName);
  1640.         fatal(buff);
  1641.     }
  1642.     }
  1643.     Wmove(Wtitle, 0, 36);
  1644.     Wprintw(Wtitle, "connected to %s", HostName);
  1645.  
  1646.     /* Print the current time. */
  1647.     timep = ctime(&StatsCur.when);
  1648.     if (p = strchr(timep, '\n'))
  1649.     *p = '\0';
  1650.     Wmove(Wtitle, 1, 36);
  1651.     Wprintw(Wtitle, "%s", timep);
  1652.     UpdateStatus();
  1653.     Wrefresh(Wtitle);
  1654.  
  1655.     /* Set up the prompt. */
  1656.     Wclear(Wprompt);
  1657.     Wprintw(Wprompt, " ? ");
  1658.     Wrefresh(Wprompt);
  1659.  
  1660.     /* read and plot responses */
  1661.     for ( ; ; ) {
  1662.     FD_ZERO(&readers);
  1663.     FD_SET(fd, &readers);
  1664.     FD_SET(0, &readers);
  1665.     if (select(fd + 1, &readers,
  1666.         (fd_set *)NULL, (fd_set *)NULL, (struct timeval *)NULL) > 0) {
  1667.         if (FD_ISSET(fd, &readers))
  1668.         readsocket(fd);
  1669.         if (FD_ISSET(0, &readers))
  1670.         readterminal();
  1671.     }
  1672.     }
  1673. }
  1674.