home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume39 / rperf / part02 / rperf.c next >
Encoding:
C/C++ Source or Header  |  1993-08-30  |  40.1 KB  |  1,627 lines

  1. #ifndef lint
  2. /**
  3.  * This program may be copied, redistributed in any form,
  4.  * source or binary, and used for any purpose, provided
  5.  * this copyright notice is retained.
  6.  **/
  7. static char    *sccsid[] = {
  8.     "@(#)rperf.c    2.1 8/30/93 (c) Copyright Brian P. Fitzgerald",
  9.     "Rensselaer Polytechnic Institute"
  10. };
  11. #endif
  12. /**
  13.  
  14. rperf.c -- print system performance statistics.
  15.  
  16. by Brian P. Fitzgerald
  17. Mechanics of Materials Laboratory
  18. Rensselaer Polytechnic Institute
  19. Troy, New York
  20.  
  21. usage: rperf [ options ] [ interval [ count ] ] [ +sortkey ] [ host ... ]
  22.        rup [ options ] [ interval ] [ host ... ]
  23.  
  24. Send comments and bug fixes to fitz@rpi.edu
  25.  
  26. Tested:
  27. SunOS 4.1.1, 4.1.2, 4.1.3
  28. IBM AIX 3.1, 3.2
  29. HP-UX 8.0
  30. NeXT Mach 20
  31. Alliant FX/2800
  32. SGI PI Iris 4.0.1, 4.0.2
  33. SCO Unix 3.2.2
  34. MIPS RISCos
  35. DEC Ultrix 4.2
  36. ESIX
  37. Amiga 4.0 2.1c
  38.  
  39. Not supported:
  40. AIX 1.2.1 on aix370
  41.  
  42. Send reports of successful compilation on other platforms to
  43. fitz@rpi.edu
  44.  
  45. History:
  46.  
  47. 5/6/92    beta    posted to alt.sources
  48. 5/18/92    1.1    Added multiple hosts, uptime display.  Improved output
  49.         format.
  50. 5/25/92    1.2    Added signal handler.
  51.  
  52. 1/6/93    1.3    Added broadcast mode
  53.  
  54. 2/6/93    1.4    Added output sorting options.
  55.         Added rup alias.
  56.  
  57. 2/10/93    1.5    Corrected rpc version mismatch.  Now if_opackets right.
  58.         Plugged some memory leaks.
  59.  
  60. 3/5/93    1.6    Variable number of disks and cpu states.
  61.         Fixed a line wrap problem.  Added termcap routine.
  62.  
  63. 8/26/93    2.1    posted to comp.sources.misc
  64.  
  65. **/
  66.  
  67. #ifdef STDC_HEADERS
  68. #include <stddef.h>
  69. #endif
  70. #include <sys/types.h>
  71. #include <sys/socket.h>
  72. #include <netinet/in.h>
  73. #include <sys/time.h>
  74.  
  75. #include <time.h>
  76.  
  77. #include <sys/ioctl.h>
  78. #ifndef TIOCGWINSZ
  79. #ifdef HAVE_SYS_TERMIO_H
  80. #include <sys/termio.h>
  81. #endif
  82. #endif
  83. #ifdef HAVE_SYS_BSD_TTY_H
  84. #include <sys/bsd_tty.h>
  85. #endif
  86.  
  87. #include <arpa/inet.h>
  88. #include <netdb.h>
  89. #include <rpc/rpc.h>
  90. #include <rpc/pmap_clnt.h>
  91. #include "rstat.h"
  92. #include <stdio.h>
  93. #include <signal.h>
  94. #include <string.h>
  95. #include <assert.h>
  96. #include <errno.h>
  97.  
  98. /* <unistd.h> */
  99. #define STDOUT_FILENO   1
  100.  
  101. /* <sys/dk.h> */
  102. #define CP_USER         0
  103. #define CP_NICE         1
  104. #define CP_SYS          2
  105. #define CP_IDLE         3
  106.  
  107. /* <sys/ioctl.h> or <sys/ttycom.h> */
  108. struct Winsize {
  109.     unsigned short  ws_row;    /* rows, in characters */
  110.     unsigned short  ws_col;    /* columns, in characters */
  111.     unsigned short  ws_xpixel;    /* horizontal size, pixels - not used */
  112.     unsigned short  ws_ypixel;    /* vertical size, pixels - not used */
  113. };
  114.  
  115. #define O_CP    0x01
  116. #define O_DK    0x02
  117. #define O_VM    0x04
  118. #define O_IF    0x08
  119. #define O_TIME    0x10
  120. #define O_DATE    0x20
  121. #define O_SECS    0x40
  122. #define O_ALL    ( O_CP | O_DK | O_VM | O_IF )
  123. #define O_DEFL    ( O_CP | O_VM | O_IF )
  124. #define O_DEFL1    ( O_CP | O_DK | O_VM | O_IF )
  125. #define O_UP    0x100
  126. #define O_BCST    0x200
  127. #define O_BARE    0x400
  128. #define O_DBG    0x800
  129. #define O_SHOST    0x1000
  130. #define O_NHOST 0x8000
  131. #define O_SORT 0x10000
  132. #define O_RVRS 0x20000
  133.  
  134. #define cpu(dt) (dcpu ? ((dt) * 100 + hdcpu ) / dcpu : 0)
  135. #define loadav(nrun) ( (float) (nrun) / FSCALE )
  136. #define delta(x) ((*dpp)->sn.x - (*dpp)->so.x)    /* use this macro with care */
  137. #define rate(x)    (dt ? ((x) * 1000L + hdt ) / dt : 0)
  138.  
  139. #ifndef abs
  140. #define abs(a) ((a)>= 0 ? (a) : -(a))
  141. #endif /* abs */
  142.  
  143. #ifndef max
  144. #define max(a, b) ((a) > (b) ? (a) : (b))
  145. #endif /* max */
  146.  
  147. #define RSTATVERS_BCST RSTATVERS_TIME
  148. typedef statstime stats_broadcast;
  149. #define RSTATVERS_DEFAULT RSTATVERS_VAR
  150. typedef statsvar stats_default;
  151.  
  152. char           *getenv();
  153. void            exit();
  154. long            strtol();
  155. extern char    *strdup();
  156.  
  157. stats_default  *from_stats();
  158. stats_default  *from_statsswtch();
  159. stats_default  *from_statstime();
  160. stats_default  *from_statsvar();
  161.  
  162. stats_default  *((*stats_convert[]) ()) =
  163. {
  164.     from_stats,
  165.     from_statsswtch,
  166.     from_statstime,
  167.     from_statsvar,
  168. };
  169. #define STATS_CONVERT(version) (stats_convert[(version)-1])
  170.  
  171. bool_t(*xdr_statsproc[]) () =
  172. {
  173.     xdr_stats,
  174.     xdr_statsswtch,
  175.     xdr_statstime,
  176.     xdr_statsvar,
  177. };
  178. #define XDR_STATSPROC(version) (xdr_statsproc[(version)-1])
  179.  
  180. union stats_all {
  181.     struct stats    s1;
  182.     struct statsswtch s2;
  183.     struct statstime s3;
  184.     struct statsvar s4;
  185. };
  186. typedef union stats_all stats_all;
  187.  
  188. struct data {
  189.     struct data    *datap;
  190.     unsigned long   nn;
  191.     unsigned long   no;
  192.     struct in_addr  addr;
  193.     char           *host;
  194.     CLIENT         *cl;
  195.     u_long          cl_vers;
  196.     stats_default   sn;
  197.     stats_default   so;
  198.     stats_default   sd;        /* delta or rate.  uptime = sd.boottime */
  199. };
  200.  
  201. struct key {
  202.     char           *k_name;
  203.     int             k_offset;
  204.     int             k_flag;
  205.     int             k_index;
  206. };
  207. typedef struct key key;
  208.  
  209. #define        K_DELTA 0x1    /* need delta before sorting */
  210. #define        K_ARRAY    0x2    /* the member is an xdr_array */
  211.  
  212. /* C faq */
  213. #ifndef offsetof
  214. #define offsetof(type, mem) ((size_t) \
  215.         ((char *)&((type *) 0)->mem - (char *)((type *) 0)))
  216. #endif                /* offsetof */
  217. #define sd_offset(mem) offsetof(struct data,sd.mem)
  218. #define sn_offset(mem) offsetof(struct data,sn.mem)
  219.  
  220. #define AV1    0
  221. #define AV5    1
  222. #define AV15    2
  223.  
  224. key             keys[] = {
  225.     {"avg", sn_offset(avenrun[AV1]), 0, 0},
  226.     {"ave", sn_offset(avenrun[AV1]), 0, 0},
  227.     {"loadavg", sn_offset(avenrun[AV1]), 0, 0},
  228.     {"loadave", sn_offset(avenrun[AV1]), 0, 0},
  229.     {"avenrun", sn_offset(avenrun[AV1]), 0, 0},
  230.     {"av1", sn_offset(avenrun[AV1]), 0, 0},
  231.     {"av5", sn_offset(avenrun[AV5]), 0, 0},
  232.     {"av15", sn_offset(avenrun[AV15]), 0, 0},
  233.  
  234.     {"boottime", sn_offset(boottime.tv_sec), 0, 0},
  235.     {"uptime", sd_offset(boottime.tv_sec), 0, 0},
  236.  
  237.     {"user", sd_offset(cp_time), K_DELTA | K_ARRAY, 0},
  238.     {"us", sd_offset(cp_time), K_DELTA | K_ARRAY, 0},
  239.     {"nice", sd_offset(cp_time), K_DELTA | K_ARRAY, 1},
  240.     {"ni", sd_offset(cp_time), K_DELTA | K_ARRAY, 1},
  241.     {"sys", sd_offset(cp_time), K_DELTA | K_ARRAY, 2},
  242.     {"system", sd_offset(cp_time), K_DELTA | K_ARRAY, 2},
  243.     {"sy", sd_offset(cp_time), K_DELTA | K_ARRAY, 2},
  244.     {"idle", sd_offset(cp_time), K_DELTA | K_ARRAY, 3},
  245.     {"id", sd_offset(cp_time), K_DELTA | K_ARRAY, 3},
  246.  
  247.     {"intr", sd_offset(v_intr), K_DELTA, 0},
  248.     {"swtch", sd_offset(v_swtch), K_DELTA, 0},
  249.     {"cxsw", sd_offset(v_swtch), K_DELTA, 0},
  250.     {"csw", sd_offset(v_swtch), K_DELTA, 0},
  251.  
  252.     {"pgpgin", sd_offset(v_pgpgin), K_DELTA, 0},
  253.     {"pgin", sd_offset(v_pgpgin), K_DELTA, 0},
  254.     {"pgpgout", sd_offset(v_pgpgout), K_DELTA, 0},
  255.     {"pgout", sd_offset(v_pgpgout), K_DELTA, 0},
  256.     {"pgo", sd_offset(v_pgpgout), K_DELTA, 0},
  257.  
  258.     {"pswpin", sd_offset(v_pswpin), K_DELTA, 0},
  259.     {"swpin", sd_offset(v_pswpin), K_DELTA, 0},
  260.     {"swin", sd_offset(v_pswpin), K_DELTA, 0},
  261.     {"pswpout", sd_offset(v_pswpout), K_DELTA, 0},
  262.     {"swpout", sd_offset(v_pswpout), K_DELTA, 0},
  263.     {"swo", sd_offset(v_pswpout), K_DELTA, 0},
  264.  
  265.     {"dk_xfer", sd_offset(dk_xfer), K_DELTA | K_ARRAY, 0},
  266.     {"sd0", sd_offset(dk_xfer), K_DELTA | K_ARRAY, 0},
  267.     {"disk0", sd_offset(dk_xfer), K_DELTA | K_ARRAY, 0},
  268.     {"d0", sd_offset(dk_xfer), K_DELTA | K_ARRAY, 0},
  269.     {"sd1", sd_offset(dk_xfer), K_DELTA | K_ARRAY, 1},
  270.     {"disk1", sd_offset(dk_xfer), K_DELTA | K_ARRAY, 1},
  271.     {"d1", sd_offset(dk_xfer), K_DELTA | K_ARRAY, 1},
  272.     {"sd2", sd_offset(dk_xfer), K_DELTA | K_ARRAY, 2},
  273.     {"disk2", sd_offset(dk_xfer), K_DELTA | K_ARRAY, 2},
  274.     {"d2", sd_offset(dk_xfer), K_DELTA | K_ARRAY, 2},
  275.     {"sd3", sd_offset(dk_xfer), K_DELTA | K_ARRAY, 3},
  276.     {"disk3", sd_offset(dk_xfer), K_DELTA | K_ARRAY, 3},
  277.     {"d3", sd_offset(dk_xfer), K_DELTA | K_ARRAY, 3},
  278.  
  279.     {"ipackets", sd_offset(if_ipackets), K_DELTA, 0},
  280.     {"ipk", sd_offset(if_ipackets), K_DELTA, 0},
  281.     {"ierrors", sd_offset(if_ierrors), K_DELTA, 0},
  282.     {"ier", sd_offset(if_ierrors), K_DELTA, 0},
  283.     {"oerrors", sd_offset(if_oerrors), K_DELTA, 0},
  284.     {"oer", sd_offset(if_oerrors), K_DELTA, 0},
  285.     {"opackets", sd_offset(if_opackets), K_DELTA, 0},
  286.     {"opk", sd_offset(if_opackets), K_DELTA, 0},
  287.     {"collisions", sd_offset(if_collisions), K_DELTA, 0},
  288.     {"coll", sd_offset(if_collisions), K_DELTA, 0},
  289.     {0, 0, 0, 0}
  290. };
  291.  
  292. key            *key_ptr = NULL;
  293.  
  294. struct datatbl {
  295.     int             val;
  296.     struct data    *dp;
  297. };
  298.  
  299. char           *keyhelp[] = {
  300.     "The sort keys are:\n",
  301.     "\n",
  302.     "loadavg     user      pgpgin      disk0      boottime    ipackets\n",
  303.     "av1         nice      pgpgout     disk1      uptime      ierrors\n",
  304.     "av5         sys       pswpin      disk2                  oerrors\n",
  305.     "av15        idle      pswpout     disk3                  opackets\n",
  306.     "                      intr                               collisions\n",
  307.     "                      swtch\n",
  308.     0
  309. };
  310.  
  311. #define    P_DATA    0
  312. #define    P_UP    1
  313.  
  314. static struct timeval TIMEOUT = {25, 0};
  315.  
  316. static struct data *dp;        /* link list head */
  317. static unsigned nhosts = 0;    /* multiple hosts idea from Larry McVoy */
  318. int             h_seen = 0;    /**
  319.                  * one or more host arguments was supplied.
  320.                  *  > 0 is client (non-broadcast) mode
  321.                  * == 0 is broadcast mode
  322.                  **/
  323. static bool_t   bcst_timo;
  324. long            opts = 0;
  325. static unsigned long thiscount = 0;
  326. unsigned        nresp = 0;
  327.  
  328. /* terminal characteristics */
  329. int             term_rows;
  330. int             term_cols;
  331.  
  332. struct timeval  starttime;
  333. struct timezone tz;
  334.  
  335. char           *f1_cp = "%-15s ";
  336. char           *f2_cp = "%3s %3s %3s %3s ";
  337. char           *fo_cp = "%3d %3d %3d %3d ";
  338.  
  339. char           *f1_av = "%-14s ";
  340. char           *f2_av = "%4s %4s %4s ";
  341. char           *fo_av = "%4.1f %4.1f %4.1f ";
  342. char           *fo_a0 = "%4.2f %4.2f %4.2f ";
  343.  
  344. char           *f1_dk = "%-12s";
  345. char           *f2_dk = "%2s %2s %2s %2s ";
  346. char           *fo_dk = "%2d %2d %2d %2d ";
  347.  
  348. char           *f1_vm = "%2s %2s %2s %2s %3s %3s ";
  349. char           *f2_vm = "%2s %2s %2s %2s %3s %3s ";
  350. char           *fo_vm = "%2u %2u %2u %2u %3u %3u ";
  351.  
  352. char           *f1_if = " %2s %2s %2s %2s %2s";
  353. char           *f2_if = " %2s %2s %2s %2s %2s";
  354. char           *fo_if = " %2d %2d %2d %2d %2d";
  355.  
  356. char           *f_time = "%-9.9s ";
  357. char           *fo_time = "%9d ";
  358.  
  359. char           *f_date = "%-24.24s ";
  360.  
  361. char           *f_secs = "%-5.5s ";
  362. char           *fo_secs = "%5.2f ";
  363.  
  364. char           *f_h = "%12.12s ";
  365.  
  366. char            title1[160];
  367. char            title2[160];
  368. char            ruler[160];
  369.  
  370. struct array {
  371.     u_int           len;
  372.     int            *val;
  373. };
  374. typedef struct array array;
  375.  
  376. /*
  377.  * allocate an int array struct, size n and from a if non-null
  378.  */
  379. void
  380. create_array(a, p, n)
  381.     array          *a;
  382.     int            *p;
  383.     int             n;
  384. {
  385.     int             i;
  386.  
  387.     a->len = n;
  388.     a->val = (int *) malloc((unsigned) n * sizeof(int));
  389.     if (a->val == NULL) {
  390.     perror("malloc");
  391.     exit(1);
  392.     }
  393.     if (p)
  394.     for (i = 0; i < n; i++)
  395.         a->val[i] = p[i];
  396. }
  397.  
  398. /*
  399.  * convert and store the received data
  400.  */
  401. stats_default  *
  402. from_stats(s)
  403.     stats_all      *s;
  404. {
  405.     static stats_default r;
  406.  
  407.     bzero((char *) &r, sizeof(r));
  408.     create_array((array *) & r.cp_time, s->s1.cp_time, CPUSTATES_ORIG);
  409.     create_array((array *) & r.dk_xfer, s->s1.dk_xfer, DK_NDRIVE_ORIG);
  410.     r.v_pgpgin = s->s1.v_pgpgin;
  411.     r.v_pgpgout = s->s1.v_pgpgout;
  412.     r.v_pswpin = s->s1.v_pswpin;
  413.     r.v_pswpout = s->s1.v_pswpout;
  414.     r.v_intr = s->s1.v_intr;
  415.     r.if_ipackets = s->s1.if_ipackets;
  416.     r.if_ierrors = s->s1.if_ierrors;
  417.     r.if_opackets = s->s1.if_opackets;
  418.     r.if_oerrors = s->s1.if_oerrors;
  419.     r.if_collisions = s->s1.if_collisions;
  420.     if (gettimeofday((struct timeval *) & r.curtime,
  421.              (struct timezone *) NULL) == -1) {
  422.     perror("gettimeofday");
  423.     exit(1);
  424.     }
  425.     return &r;
  426. }
  427.  
  428. stats_default  *
  429. from_statsswtch(s)
  430.     stats_all      *s;
  431. {
  432.     static stats_default r;
  433.     int             i;
  434.  
  435.     bzero((char *) &r, sizeof(r));
  436.     create_array((array *) & r.cp_time, s->s2.cp_time, CPUSTATES_ORIG);
  437.     create_array((array *) & r.dk_xfer, s->s2.dk_xfer, DK_NDRIVE_ORIG);
  438.     r.v_pgpgin = s->s2.v_pgpgin;
  439.     r.v_pgpgout = s->s2.v_pgpgout;
  440.     r.v_pswpin = s->s2.v_pswpin;
  441.     r.v_pswpout = s->s2.v_pswpout;
  442.     r.v_intr = s->s2.v_intr;
  443.     r.if_ipackets = s->s2.if_ipackets;
  444.     r.if_ierrors = s->s2.if_ierrors;
  445.     r.if_opackets = s->s2.if_opackets;
  446.     r.if_oerrors = s->s2.if_oerrors;
  447.     r.if_collisions = s->s2.if_collisions;
  448.     r.v_swtch = s->s2.v_swtch;
  449.     for (i = 0; i < 3; i++)
  450.     r.avenrun[i] = s->s2.avenrun[i];
  451.     r.boottime = s->s2.boottime;
  452.     if (gettimeofday((struct timeval *) & r.curtime,
  453.              (struct timezone *) NULL) == -1) {
  454.     perror("gettimeofday");
  455.     exit(1);
  456.     }
  457.     return &r;
  458. }
  459.  
  460. stats_default  *
  461. from_statstime(s)
  462.     stats_all      *s;
  463. {
  464.     static stats_default r;
  465.     int             i;
  466.  
  467.     bzero((char *) &r, sizeof(r));
  468.     create_array((array *) & r.cp_time, s->s3.cp_time, CPUSTATES_ORIG);
  469.     create_array((array *) & r.dk_xfer, s->s3.dk_xfer, DK_NDRIVE_ORIG);
  470.     r.v_pgpgin = s->s3.v_pgpgin;
  471.     r.v_pgpgout = s->s3.v_pgpgout;
  472.     r.v_pswpin = s->s3.v_pswpin;
  473.     r.v_pswpout = s->s3.v_pswpout;
  474.     r.v_intr = s->s3.v_intr;
  475.     r.if_ipackets = s->s3.if_ipackets;
  476.     r.if_ierrors = s->s3.if_ierrors;
  477.     r.if_opackets = s->s3.if_opackets;
  478.     r.if_oerrors = s->s3.if_oerrors;
  479.     r.if_collisions = s->s3.if_collisions;
  480.     r.v_swtch = s->s3.v_swtch;
  481.     for (i = 0; i < 3; i++)
  482.     r.avenrun[i] = s->s3.avenrun[i];
  483.     r.boottime = s->s3.boottime;
  484.     r.curtime = s->s3.curtime;
  485.     return &r;
  486. }
  487.  
  488. stats_default  *
  489. from_statsvar(s)
  490.     stats_all      *s;
  491. {
  492.     static stats_default r;
  493.     int             i;
  494.  
  495.     bzero((char *) &r, sizeof(r));
  496.     create_array((array *) & r.cp_time, s->s4.cp_time.cp_time_val,
  497.          (int) s->s4.cp_time.cp_time_len);
  498.     create_array((array *) & r.dk_xfer, s->s4.dk_xfer.dk_xfer_val,
  499.          (int) s->s4.dk_xfer.dk_xfer_len);
  500.     r.v_pgpgin = s->s4.v_pgpgin;
  501.     r.v_pgpgout = s->s4.v_pgpgout;
  502.     r.v_pswpin = s->s4.v_pswpin;
  503.     r.v_pswpout = s->s4.v_pswpout;
  504.     r.v_intr = s->s4.v_intr;
  505.     r.if_ipackets = s->s4.if_ipackets;
  506.     r.if_ierrors = s->s4.if_ierrors;
  507.     r.if_opackets = s->s4.if_opackets;
  508.     r.if_oerrors = s->s4.if_oerrors;
  509.     r.if_collisions = s->s4.if_collisions;
  510.     r.v_swtch = s->s4.v_swtch;
  511.     for (i = 0; i < 3; i++)
  512.     r.avenrun[i] = s->s4.avenrun[i];
  513.     r.boottime = s->s4.boottime;
  514.     r.curtime = s->s4.curtime;
  515.     return &r;
  516. }
  517.  
  518. /*
  519.  * free the cp_time and dk_xfer array in a stats_default struct
  520.  */
  521. void
  522. free_stats(s)
  523.     stats_default  *s;
  524. {
  525.     free((char *) s->cp_time.cp_time_val);
  526.     free((char *) s->dk_xfer.dk_xfer_val);
  527. }
  528.  
  529. /*
  530.  * save the results in a data structure
  531.  */
  532. void
  533. save_res(d, res)
  534.     struct data    *d;
  535.     stats_default  *res;
  536. {
  537.     if (d->nn == thiscount)
  538.     return;            /* duplicate.  ignore */
  539.     d->no = d->nn;
  540.     d->nn = thiscount;
  541.  
  542.     free_stats(&d->so);
  543.     d->so = d->sn;
  544.     d->sn = *res;
  545.     return;
  546. }
  547.  
  548. /*
  549.  * handle lack of communication with client.
  550.  */
  551. void
  552. drop_from_list(dpp)
  553.     struct data   **dpp;
  554. {
  555.     struct data    *tdp;
  556.  
  557.     if ((*dpp)->cl)
  558.     clnt_destroy((*dpp)->cl);
  559.     free((*dpp)->host);
  560.  
  561.     tdp = *dpp;
  562.     *dpp = (*dpp)->datap;
  563.  
  564.     free_stats(&tdp->so);
  565.     free((char *) tdp);
  566.     (void) putc('d', stdout);
  567.     (void) fflush(stdout);
  568.     nhosts--;
  569.     return;
  570. }
  571.  
  572. /**
  573.  * this function may be called after (*dpp)->addr
  574.  * has been filled with a valid in_addr
  575.  **/
  576. int
  577. make_client(dpp)
  578.     struct data   **dpp;
  579. {
  580.     struct sockaddr_in server_addr;
  581.     struct timeval  p_timo;
  582.     int             sock = RPC_ANYSOCK;
  583.  
  584.     p_timo.tv_sec = 3;
  585.     p_timo.tv_usec = 0;
  586.  
  587.     server_addr.sin_family = AF_INET;
  588.     server_addr.sin_port = 0;
  589.     server_addr.sin_addr = (*dpp)->addr;
  590.  
  591.     /**
  592.      * clntudp_create only determines whether the
  593.      * program is registered.  It does not actually check
  594.      * whether the host supports the requested version.
  595.      * see the pamp_getport man page.
  596.      **/
  597.     (*dpp)->cl = clntudp_create(&server_addr,
  598.                 RSTATPROG,
  599.                 (*dpp)->cl_vers,
  600.                 p_timo,
  601.                 &sock);
  602.  
  603.     if ((*dpp)->cl == NULL) {
  604.     (void) fprintf(stderr, "Can't contact rstatd on %s because%s\n",
  605.                (*dpp)->host, clnt_spcreateerror(""));
  606.     return 0;
  607.     }
  608.     if (opts & O_DBG) {
  609.     (void) putc('m', stdout);
  610.     (void) fflush(stdout);
  611.     }
  612.     return 1;
  613. }
  614.  
  615. /**
  616.  * for each host on the linked list that still needs data:
  617.  * loop over the rpc prog versions,
  618.  *    starting with the highest known version,
  619.  *    or highest previously successful version
  620.  *        make a client, if necessary
  621.  *        call the client
  622.  **/
  623. void
  624. doclnt_calls()
  625. {
  626.     stats_all       res;
  627.     stats_default  *sn;
  628.     static enum clnt_stat clnt_stat;
  629.     struct data   **dpp;
  630.     int             good = 0;
  631.     int             bad = 0;
  632.     u_long          vers;
  633.  
  634.     for (dpp = &dp; *dpp;) {
  635.     if (opts & O_DBG)
  636.         (void) fprintf(stdout, "%s ", inet_ntoa((*dpp)->addr));
  637.     if ((*dpp)->nn == thiscount) {
  638.         dpp = &(*dpp)->datap;
  639.         if (opts & O_DBG) {
  640.         (void) fputs("-\n", stdout);
  641.         }
  642.         continue;        /* already have data */
  643.     }
  644.     if (!(*dpp)->cl_vers)
  645.         (*dpp)->cl_vers = RSTATVERS_DEFAULT;    /* highest version */
  646.     bzero((char *) &res, sizeof(res));
  647.     for (vers = (*dpp)->cl_vers; vers > 0; vers--) {
  648.         (*dpp)->cl_vers = vers;
  649.         if (!(*dpp)->cl)
  650.         if (!make_client(dpp)) {
  651.             drop_from_list(dpp);
  652.             bad++;
  653.             break;    /* vers */
  654.         }
  655.         if (opts & O_DBG) {
  656.         (void) fprintf(stdout, "v%d", vers);
  657.         (void) fflush(stdout);
  658.         }
  659.         clnt_stat = clnt_call((*dpp)->cl,
  660.                   RSTATPROC_STATS,
  661.                   xdr_void,
  662.                   NULL,
  663.                   XDR_STATSPROC((*dpp)->cl_vers),
  664.                   &res,
  665.                   TIMEOUT);
  666.         if (clnt_stat == RPC_SUCCESS) {
  667.         sn = STATS_CONVERT((*dpp)->cl_vers) (&res);
  668.         xdr_free(XDR_STATSPROC((*dpp)->cl_vers), (char *) &res);
  669.         save_res(*dpp, sn);
  670.         if (opts & O_DBG) {
  671.             (void) fputs("c\n", stdout);
  672.         }
  673.         good++;
  674.         dpp = &(*dpp)->datap;
  675.         break;        /* vers */
  676.         }
  677.         if (clnt_stat == RPC_PROGVERSMISMATCH && vers > 1) {
  678.         if (opts & O_DBG) {
  679.             (void) fputs("M ", stdout);
  680.             (void) fflush(stdout);
  681.         }
  682.         clnt_destroy((*dpp)->cl);
  683.         (*dpp)->cl = NULL;
  684.         continue;    /* vers-- */
  685.         }
  686.         (void) fprintf(stderr, "clnt_call: %s %s\n",
  687.                (*dpp)->host, clnt_sperrno(clnt_stat));
  688.         drop_from_list(dpp);
  689.         bad++;
  690.         break;        /* vers */
  691.     }            /* for(vers ... */
  692.     }
  693.  
  694.     if (opts & O_DBG) {
  695.     (void) fprintf(stdout, "done clnt calls good=%d bad=%d\n", good, bad);
  696.     }
  697.     if (!nhosts)
  698.     exit(1);
  699.     return;
  700. }
  701.  
  702. /**
  703.  * given an internet address,
  704.  *    get the hostname,
  705.  *    or the ascii internet address
  706.  **/
  707. char           *
  708. get_hostname(addr)
  709.     struct in_addr  addr;
  710. {
  711.     struct hostent *host_entry;
  712.  
  713.     host_entry = NULL;
  714.     if (opts & O_NHOST) {
  715.     return inet_ntoa(addr);
  716.     } else {
  717.     host_entry = gethostbyaddr((char *) &addr, 4, AF_INET);
  718.     if (!host_entry && opts & O_DBG)
  719.         (void) fputs("byaddr failed\n", stdout);
  720.     return host_entry ? host_entry->h_name : inet_ntoa(addr);
  721.     }
  722. }
  723.  
  724. /*
  725.  * create a new data structure
  726.  */
  727. struct data    *
  728. new_host(addr, hostname)
  729.     struct in_addr *addr;
  730.     char           *hostname;
  731. {
  732.     struct data    *newdpp;
  733.  
  734.     newdpp = (struct data *) calloc(1, sizeof(struct data));
  735.     if (newdpp == NULL) {
  736.     perror("calloc");
  737.     exit(1);
  738.     }
  739.     newdpp->addr = *addr;
  740.     newdpp->host = strdup(hostname);
  741.     if (!newdpp->host) {
  742.     perror("strdup");
  743.     exit(1);
  744.     }
  745.     nhosts++;
  746.     if (!h_seen) {
  747.     (void) putc('+', stdout);
  748.     (void) fflush(stdout);
  749.     }
  750.     return newdpp;
  751. }
  752.  
  753. /*
  754.  * handle each reply to the broadcast
  755.  */
  756. bool_t
  757. each_result(resp, raddr)
  758.     stats_broadcast *resp;
  759.     struct sockaddr_in *raddr;
  760. {
  761.     char           *hostname;
  762.     struct data   **dpp;
  763.     stats_default  *sn;
  764.  
  765.     sn = STATS_CONVERT(RSTATVERS_BCST) (resp);
  766.     xdr_free(XDR_STATSPROC(RSTATVERS_BCST), (char *) resp);
  767.  
  768.     hostname = NULL;
  769.     for (dpp = &dp; *dpp; dpp = &(*dpp)->datap) {
  770.     if (raddr->sin_addr.s_addr == (*dpp)->addr.s_addr) {
  771.         /* duplicate */
  772.         save_res(*dpp, sn);
  773.         (void) putc('.', stdout);
  774.         (void) fflush(stdout);
  775.         return bcst_timo;
  776.     }
  777.     if (!hostname)
  778.         hostname = get_hostname(raddr->sin_addr);
  779.  
  780.     if (opts & O_SHOST ?
  781.         strcmp(hostname, (*dpp)->host) < 0 :
  782.         raddr->sin_addr.s_addr < (*dpp)->addr.s_addr) {
  783.         /* insert */
  784.         struct data    *tdp;
  785.         tdp = *dpp;
  786.         *dpp = new_host(&raddr->sin_addr, hostname);
  787.         save_res(*dpp, sn);
  788.         (*dpp)->datap = tdp;
  789.         return bcst_timo;
  790.     }
  791.     }
  792.     /* append */
  793.     if (!hostname)
  794.     hostname = get_hostname(raddr->sin_addr);
  795.     *dpp = new_host(&raddr->sin_addr, hostname);
  796.     save_res(*dpp, sn);
  797.     (*dpp)->datap = NULL;
  798.     return bcst_timo;
  799. }
  800.  
  801. /*
  802.  * handle termination signals
  803.  */
  804. RETSIGTYPE
  805. cleanup()
  806. {
  807.     exit(0);            /* flush and close stdout */
  808. }
  809.  
  810. /*
  811.  * force end of broadcasting
  812.  */
  813. RETSIGTYPE
  814. bcst_done()
  815. {
  816.     bcst_timo = TRUE;
  817. }
  818.  
  819. /*
  820.  * see if display will wrap.  Try to fix.
  821.  */
  822. char           *
  823. checkwrap(cols, obuf)
  824.     int             cols;
  825.     char           *obuf;
  826. {
  827.     int             olen = strlen(obuf);
  828.     int             rlen = strlen(ruler);
  829.     char           *rp, *op, *tp, *sp, *cp;
  830.     int             rpos = 0, opos;
  831.     int             nsp, err = 0;
  832.  
  833.     if (olen <= rlen || rlen > cols)
  834.     return obuf;        /* leave alone */
  835.  
  836.     if (opts & O_DBG) {
  837.     (void) fprintf(stdout, "wrap terminal=%d ruler=%d output%d\n",
  838.                cols, rlen, olen);
  839.     (void) fputs(ruler, stdout);
  840.     (void) putc('\n', stdout);
  841.     }
  842.     op = obuf;
  843.     for (rp = ruler; *rp;) {
  844.     tp = op;
  845.     for (; *rp && *rp == ' '; rp++);
  846.     for (; *op && *op == ' '; op++);
  847.     nsp = op - tp;
  848.     for (; *rp && *rp != ' '; rp++);
  849.     for (; *op && *op != ' '; op++);
  850.  
  851.     if (!*rp || nsp > 1) {
  852.         rpos = rp - ruler;
  853.         opos = op - obuf;
  854.         err = opos - rpos;
  855.     }
  856.     if (err > 0) {
  857.         if (opts & O_DBG) {
  858.         (void) fputs(obuf, stdout);
  859.         (void) putc('\n', stdout);
  860.         (void) fprintf(stdout, "rpos=%d err=%d\n", rpos, err);
  861.         }
  862.         for (sp = op; sp != obuf; sp--) {
  863.         if (*sp == ' ')
  864.             sp--;
  865.         if (*sp == ' ') {    /* shift left one char */
  866.             sp++;
  867.             for (cp = sp; *cp; cp++)
  868.             *cp = *(cp + 1);
  869.             op--;
  870.             if (!--err)
  871.             break;
  872.         }
  873.         }
  874.     }
  875.     rpos = rp - ruler;
  876.     opos = op - obuf;
  877.     err = opos - rpos;
  878.     }
  879.  
  880.     if (opts & O_DBG)
  881.     (void) fputs(" . . . . 1 . . . . 2 . . . . 3 . . . . 4 . . . . 5 . . . . 6 . . . . 7 . . . .\n", stdout);
  882.     return obuf;
  883. }
  884.  
  885. /*
  886.  * qsort comparison routine
  887.  */
  888. static int
  889. datacompare(i, j)
  890.     struct datatbl *i, *j;
  891. {
  892.     return opts & O_RVRS ?
  893.     i->val - j->val :
  894.     j->val - i->val;
  895. }
  896.  
  897. /*
  898.  * calculate deltas and other items, for later sorting
  899.  */
  900. struct datatbl *
  901. compute_data(tbl)
  902.     struct datatbl *tbl;
  903. {
  904.     struct data   **dpp;
  905.     int             i;
  906.     long            dt, hdt;    /* msec */
  907.     int             dcpu, hdcpu;
  908.  
  909.     nresp = 0;
  910.     for (dpp = &dp; *dpp; dpp = &(*dpp)->datap) {
  911.     /* this data is current */
  912.     if ((*dpp)->nn == thiscount) {
  913.  
  914.         (*dpp)->sd.boottime.tv_sec =    /* uptime */
  915.         (*dpp)->sn.curtime.tv_sec
  916.         - (*dpp)->sn.boottime.tv_sec;
  917.  
  918.         nresp++;
  919.         if ((*dpp)->no) {
  920.         /* this data is not the first response from that host */
  921.  
  922.         /* time in milliseconds, since last call */
  923.         dt = (((*dpp)->sn.curtime.tv_sec -
  924.                (*dpp)->so.curtime.tv_sec) * 1000000 +
  925.               ((*dpp)->sn.curtime.tv_usec -
  926.                (*dpp)->so.curtime.tv_usec) + 500) / 1000;
  927.         hdt = (dt + 1) / 2;
  928.  
  929.         /* first reply from aix3.1 may have wrong cp_time[] */
  930.         dcpu = 0;
  931.         if (!(*dpp)->sd.cp_time.cp_time_val)
  932.             create_array((array *) & (*dpp)->sd.cp_time, (int *) NULL,
  933.                  (int) (*dpp)->sn.cp_time.cp_time_len);
  934.  
  935.         for (i = 0; i < (*dpp)->sn.cp_time.cp_time_len; i++) {
  936.             (*dpp)->sd.cp_time.cp_time_val[i]
  937.             = delta(cp_time.cp_time_val[i]);
  938.             dcpu += (*dpp)->sd.cp_time.cp_time_val[i];
  939.         }
  940.  
  941.         /**
  942.              * From vmstat.c 5.31 (Berkeley)
  943.              * We round upward to avoid losing low-frequency events
  944.              * (i.e., >= 1 per interval but < 1 per second).
  945.              **/
  946.         hdcpu = dcpu / 2;
  947.         for (i = 0; i < (*dpp)->sn.cp_time.cp_time_len; i++)
  948.             (*dpp)->sd.cp_time.cp_time_val[i]
  949.             = cpu((*dpp)->sd.cp_time.cp_time_val[i]);
  950.  
  951.         if (!(*dpp)->sd.dk_xfer.dk_xfer_val)
  952.             create_array((array *) & (*dpp)->sd.dk_xfer, (int *) NULL,
  953.                  (int) (*dpp)->sn.dk_xfer.dk_xfer_len);
  954.  
  955.         for (i = 0; i < (*dpp)->sn.dk_xfer.dk_xfer_len; i++)
  956.             (*dpp)->sd.dk_xfer.dk_xfer_val[i]
  957.             = rate(delta(dk_xfer.dk_xfer_val[i]));
  958.  
  959.         (*dpp)->sd.v_pgpgin = rate(delta(v_pgpgin));
  960.         (*dpp)->sd.v_pgpgout = rate(delta(v_pgpgout));
  961.         (*dpp)->sd.v_pswpin = rate(delta(v_pswpin));
  962.         (*dpp)->sd.v_pswpout = rate(delta(v_pswpout));
  963.         (*dpp)->sd.v_swtch = rate(delta(v_swtch));
  964.         /* Why does v_intr count down on aix370? */
  965.         (*dpp)->sd.v_intr = rate(abs((int) (delta(v_intr))));
  966.  
  967.         (*dpp)->sd.if_ipackets = rate(delta(if_ipackets));
  968.         (*dpp)->sd.if_ierrors = rate(delta(if_ierrors));
  969.         (*dpp)->sd.if_opackets = rate(delta(if_opackets));
  970.         (*dpp)->sd.if_oerrors = rate(delta(if_oerrors));
  971.         (*dpp)->sd.if_collisions = rate(delta(if_collisions));
  972.         }            /* (*dpp)->no */
  973.     }            /* (*dpp)->nn == thiscount */
  974.     }
  975.  
  976.     if (tbl)
  977.     free((char *) tbl);
  978.     tbl = (struct datatbl *) malloc(nresp * sizeof(struct datatbl));
  979.     if (tbl == NULL) {
  980.     perror("malloc");
  981.     exit(1);
  982.     }
  983.     i = 0;
  984.     for (dpp = &dp; *dpp; dpp = &(*dpp)->datap) {
  985.     if ((*dpp)->nn == thiscount) {
  986.  
  987.         tbl[i].dp = *dpp;
  988.         if (opts & O_SORT &&
  989.         (thiscount > 1 || !(key_ptr->k_flag & K_DELTA)))
  990.         if (key_ptr->k_flag & K_ARRAY) {
  991.             array           arr;
  992.  
  993.             arr = *(array *) ((char *) (*dpp) + key_ptr->k_offset);
  994.             tbl[i].val = arr.val[key_ptr->k_index];
  995.         } else {
  996.             tbl[i].val = *(int *) ((char *) (*dpp) + key_ptr->k_offset);
  997.         }
  998.         i++;
  999.     }
  1000.     }
  1001.  
  1002.     if (opts & O_SORT)
  1003.     qsort((char *) tbl, (int) nresp, sizeof(struct datatbl), datacompare);
  1004.     return tbl;
  1005. }
  1006.  
  1007. /*
  1008.  * get screen size from termcap entry
  1009.  */
  1010. check_termcap()
  1011. {
  1012.     char           *term;
  1013.     static int      status;
  1014.     static int      seen;
  1015.     static int      t_rows;
  1016.     static int      t_cols;
  1017.     char            termcap_buf[1024];
  1018.     char           *efmt = "Can't get terminal size because\n%s";
  1019.  
  1020.     if (seen) {
  1021.     if (status == 1) {
  1022.         term_rows = t_rows;
  1023.         term_cols = t_cols;
  1024.     }
  1025.     return;
  1026.     }
  1027.     seen = 1;
  1028.  
  1029.     term = getenv("TERM");
  1030.     if (!term) {
  1031.     (void) fprintf(stderr, efmt, "TERM environment variable not set.\n");
  1032.     return;
  1033.     }
  1034.     status = tgetent(termcap_buf, term);
  1035.     switch (status) {
  1036.     case -1:
  1037.     (void) fprintf(stderr, efmt, "can't open termcap file.\n");
  1038.     return;
  1039.     case 0:
  1040.     (void) fprintf(stderr, efmt, "no termcap entry for a ");
  1041.     (void) fprintf(stderr, "`%s' terminal\n", term);
  1042.     return;
  1043.     case 1:
  1044.     t_rows = tgetnum("li");
  1045.     if (t_rows == -1)
  1046.         t_rows = 0;
  1047.     t_cols = tgetnum("co");
  1048.     if (t_cols == -1)
  1049.         t_cols = 0;
  1050.     term_rows = t_rows;
  1051.     term_cols = t_cols;
  1052.     if (opts & O_DBG)
  1053.         (void) fprintf(stdout, "check_termcap: tgetnum: %d %d\n",
  1054.                term_rows, term_cols);
  1055.     }
  1056. }
  1057.  
  1058. /*
  1059.  * get terminal size
  1060.  */
  1061. void
  1062. check_term()
  1063. {
  1064.     struct Winsize  winsize;
  1065.  
  1066.     winsize.ws_row = 0;
  1067.     winsize.ws_col = 0;
  1068.     term_rows = 0;
  1069.     term_cols = 0;
  1070.     if (ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *) &winsize) == -1) {
  1071.     if (opts & O_DBG)
  1072.         perror("ioctl: TIOCGWINSZ");
  1073.     return;            /* assume not a terminal */
  1074.     }
  1075.     term_rows = winsize.ws_row;
  1076.     term_cols = winsize.ws_col;
  1077.     if (term_rows == 0 || term_cols == 0)
  1078.     check_termcap();
  1079. }
  1080.  
  1081. /*
  1082.  * print the statistics or the uptime
  1083.  */
  1084. void
  1085. print_data(tbl, flag)
  1086.     struct datatbl *tbl;
  1087.     int             flag;
  1088. {
  1089.     char            obuf[160];
  1090.     int             i;
  1091.     long            up, upd, uph, upm;
  1092.     float           s;
  1093.  
  1094.     if (opts & O_SECS) {
  1095.     struct timeval  now;
  1096.     if (gettimeofday(&now, (struct timezone *) 0) == -1) {
  1097.         perror("gettimeofday");
  1098.         exit(1);
  1099.     }
  1100.     s = (now.tv_sec - starttime.tv_sec) +
  1101.         ((now.tv_usec - starttime.tv_usec) + 5000)
  1102.         / 10000 / 100.;
  1103.     }
  1104.     for (i = 0; i < nresp; i++) {
  1105.     switch (flag) {
  1106.     case P_DATA:
  1107.         if (!tbl[i].dp->no)    /* do we have delta? */
  1108.         break;
  1109.         obuf[0] = '\0';
  1110.         if (opts & O_TIME)
  1111.         (void) sprintf(obuf + strlen(obuf), fo_time,
  1112.                    tbl[i].dp->sn.curtime.tv_sec);
  1113.         if (opts & O_DATE) {
  1114.         char            buf[30];
  1115.         struct tm      *tp;
  1116.  
  1117.         tp = localtime((long *) &tbl[i].dp->sn.curtime.tv_sec);
  1118.         if (!strftime(buf, 30, "%a %b %d %H:%M:%S %Y ", tp)) {
  1119.             (void) fputs("can't convert date\n", stderr);
  1120.             exit(1);
  1121.         }
  1122.         (void) sprintf(obuf + strlen(obuf), f_date, buf);
  1123.         }
  1124.         if (opts & O_SECS)
  1125.         (void) sprintf(obuf + strlen(obuf), fo_secs, s);
  1126.         if (nhosts > 1 || !h_seen)
  1127.         (void) sprintf(obuf + strlen(obuf), f_h, tbl[i].dp->host);
  1128.         if (opts & O_CP) {
  1129.         (void) sprintf(obuf + strlen(obuf), fo_cp,
  1130.                    tbl[i].dp->sd.cp_time.cp_time_val[CP_USER],
  1131.                    tbl[i].dp->sd.cp_time.cp_time_val[CP_NICE],
  1132.                    tbl[i].dp->sd.cp_time.cp_time_val[CP_SYS],
  1133.                    tbl[i].dp->sd.cp_time.cp_time_val[CP_IDLE]);
  1134.         /* average run queue lengths */
  1135.         (void) sprintf(obuf + strlen(obuf), fo_av,
  1136.                    loadav(tbl[i].dp->sn.avenrun[AV1]),
  1137.                    loadav(tbl[i].dp->sn.avenrun[AV5]),
  1138.                    loadav(tbl[i].dp->sn.avenrun[AV15]));
  1139.         }
  1140.         if (opts & O_DK)
  1141.         (void) sprintf(obuf + strlen(obuf), fo_dk,
  1142.                    tbl[i].dp->sd.dk_xfer.dk_xfer_val[0],
  1143.                    tbl[i].dp->sd.dk_xfer.dk_xfer_val[1],
  1144.                    tbl[i].dp->sd.dk_xfer.dk_xfer_val[2],
  1145.                    tbl[i].dp->sd.dk_xfer.dk_xfer_val[3]);
  1146.  
  1147.         if (opts & O_VM)
  1148.         (void) sprintf(obuf + strlen(obuf), fo_vm,
  1149.                    tbl[i].dp->sd.v_pgpgin,
  1150.                    tbl[i].dp->sd.v_pgpgout,
  1151.                    tbl[i].dp->sd.v_pswpin,
  1152.                    tbl[i].dp->sd.v_pswpout,
  1153.                    tbl[i].dp->sd.v_swtch,
  1154.                    tbl[i].dp->sd.v_intr);
  1155.  
  1156.         if (opts & O_IF)
  1157.         (void) sprintf(obuf + strlen(obuf), fo_if,
  1158.                    tbl[i].dp->sd.if_ipackets,
  1159.                    tbl[i].dp->sd.if_ierrors,
  1160.                    tbl[i].dp->sd.if_opackets,
  1161.                    tbl[i].dp->sd.if_oerrors,
  1162.                    tbl[i].dp->sd.if_collisions);
  1163.  
  1164.         check_term();
  1165.         (void) fputs(checkwrap(term_cols > 0 ? term_cols - 1 : 0,
  1166.                    obuf), stdout);
  1167.         (void) putc('\n', stdout);
  1168.  
  1169.         if (opts & O_DK) {
  1170.         int             d, dhigh = -1;
  1171.         int             moredisks;
  1172.  
  1173.         for (d = tbl[i].dp->sn.dk_xfer.dk_xfer_len - 1; d >= 0; d--) {
  1174.             if (tbl[i].dp->sn.dk_xfer.dk_xfer_val[d]) {
  1175.             dhigh = d;
  1176.             break;
  1177.             }
  1178.         }
  1179.         moredisks = dhigh - DK_NDRIVE_ORIG + 1;
  1180.         if (moredisks > 0) {
  1181.             (void) fprintf(stdout, "%d more disk%s... ",
  1182.                    moredisks, moredisks == 1 ? "" : "s");
  1183.             for (d = DK_NDRIVE_ORIG; d <= dhigh; d++)
  1184.             (void) fprintf(stdout, "%d ",
  1185.                        tbl[i].dp->sd.dk_xfer.dk_xfer_val[d]);
  1186.             (void) putc('\n', stdout);
  1187.         }
  1188.         }
  1189.         break;
  1190.  
  1191.     case P_UP:
  1192.         if (tbl[i].dp->no)    /* have we already printed the uptime? */
  1193.         break;
  1194.         up = tbl[i].dp->sd.boottime.tv_sec;    /* uptime stored here */
  1195.         upd = up / 86400;
  1196.         up = abs(up - upd * 86400);
  1197.         uph = up / 3600;
  1198.         up -= uph * 3600;
  1199.         upm = up / 60;
  1200.         (void) fprintf(stdout, f_h, tbl[i].dp->host);
  1201.         switch (upd) {
  1202.         case 0:
  1203.         (void) fputs("up           ", stdout);
  1204.         break;
  1205.         case 1:
  1206.         (void) fprintf(stdout, "up %3d day,  ", upd);
  1207.         break;
  1208.         default:
  1209.         (void) fprintf(stdout, "up %3d days, ", upd);
  1210.         break;
  1211.         }
  1212.         (void) fprintf(stdout, "%2d:%02d,", uph, upm);
  1213.         (void) fputs("     load average: ", stdout);
  1214.         /* average run queue lengths */
  1215.         (void) fprintf(stdout, fo_a0,
  1216.                loadav(tbl[i].dp->sn.avenrun[AV1]),
  1217.                loadav(tbl[i].dp->sn.avenrun[AV5]),
  1218.                loadav(tbl[i].dp->sn.avenrun[AV15]));
  1219.         (void) putc('\n', stdout);
  1220.         break;
  1221.     }            /* switch (flag) */
  1222.     }
  1223. }
  1224.  
  1225. /*
  1226.  * make the titles for the columns, depending on the options selected
  1227.  */
  1228. void
  1229. build_title()
  1230. {
  1231.     title1[0] = '\0';
  1232.     title2[0] = '\0';
  1233.     ruler[0] = '\0';
  1234.     if (opts & O_BARE) {
  1235.     return;
  1236.     }
  1237.     if (opts & O_TIME) {
  1238.     (void) sprintf(title1 + strlen(title1), f_time, "unix time");
  1239.     (void) sprintf(title2 + strlen(title2), f_time, "(seconds)");
  1240.     (void) sprintf(ruler + strlen(ruler), fo_time, 100000000);
  1241.     }
  1242.     if (opts & O_DATE) {
  1243.     (void) sprintf(title1 + strlen(title1), f_date, "Date");
  1244.     (void) sprintf(title2 + strlen(title2), f_date, "(local time)");
  1245.     (void) sprintf(ruler + strlen(ruler), f_date,
  1246.                "Thu Jan  1 00:00:00 1970");
  1247.     }
  1248.     if (opts & O_SECS) {
  1249.     (void) sprintf(title1 + strlen(title1), f_secs, "time");
  1250.     (void) sprintf(title2 + strlen(title2), f_secs, "(sec)");
  1251.     (void) sprintf(ruler + strlen(ruler), fo_secs, 10.01);
  1252.     }
  1253.     if (nhosts > 1) {
  1254.     (void) sprintf(title1 + strlen(title1), f_h, "");
  1255.     (void) sprintf(title2 + strlen(title2), f_h, "hostname");
  1256.     (void) sprintf(ruler + strlen(ruler), f_h,
  1257.                "127.000.000.001");
  1258.     }
  1259.     if (opts & O_CP) {
  1260.     (void) sprintf(title1 + strlen(title1), f1_cp, "%cpu");
  1261.     (void) sprintf(title1 + strlen(title1), f1_av, "loadavg (nrun)");
  1262.     (void) sprintf(title2 + strlen(title2), f2_cp, "us", "ni", "sy", "id");
  1263.     (void) sprintf(title2 + strlen(title2), f2_av, "1m", "5m", "15m");
  1264.     (void) sprintf(ruler + strlen(ruler), fo_cp, 100, 100, 100, 100);
  1265.     (void) sprintf(ruler + strlen(ruler), fo_av, 10.00, 10.00, 10.00);
  1266.     }
  1267.     if (opts & O_DK) {
  1268.     (void) sprintf(title1 + strlen(title1), f1_dk, "disk xfers");
  1269.     (void) sprintf(title2 + strlen(title2), f2_dk,
  1270.                "d0", "d1", "d2", "d3");
  1271.     (void) sprintf(ruler + strlen(ruler), fo_dk, 10, 10, 10, 10);
  1272.     }
  1273.     if (opts & O_VM) {
  1274.     (void) sprintf(title1 + strlen(title1), f1_vm,
  1275.                "pg", "pg", "sw", "sw", "cx", "in");
  1276.     (void) sprintf(title2 + strlen(title2), f2_vm,
  1277.                "in", "o", "in", "o", "sw", "tr");
  1278.     (void) sprintf(ruler + strlen(ruler), fo_vm, 10, 10, 10, 10, 100, 100);
  1279.     }
  1280.     if (opts & O_IF) {
  1281.     (void) sprintf(title1 + strlen(title1), f1_if,
  1282.                "i", "i", "o", "o", "co");
  1283.     (void) sprintf(title2 + strlen(title2), f2_if,
  1284.                "pk", "er", "pk", "er", "ll");
  1285.     (void) sprintf(ruler + strlen(ruler), fo_if, 10, 10, 10, 10, 10);
  1286.     }
  1287.     (void) sprintf(title1 + strlen(title1), "\n");
  1288.     (void) sprintf(title2 + strlen(title2), "\n");
  1289.     return;
  1290. }
  1291.  
  1292. /**
  1293.  * initialize signal handlers
  1294.  * parse options
  1295.  * loop endlessly. either:
  1296.  *    resolve host names, do client calls
  1297.  *    or do broadcasts
  1298. **/
  1299. main(argc, argv)
  1300.     int             argc;
  1301.     char           *argv[];
  1302. {
  1303.     int             c, do_usage = 0;
  1304.     int             i_seen = 0;
  1305.     int             c_seen = 0;
  1306.     unsigned        interval = 10;
  1307.     char           *optstring;
  1308.     char           *basename;
  1309.     char           *usage;
  1310.     extern int      opterr, optind;
  1311.     extern char    *optarg;
  1312.     int             opti;
  1313.     unsigned        hdrcnt;
  1314.     unsigned        count;
  1315.     struct data   **dpp;
  1316.     struct datatbl *tbl;
  1317.  
  1318.     tbl = NULL;
  1319.     if (gettimeofday(&starttime, &tz) == -1) {
  1320.     perror("gettimeofday");
  1321.     exit(1);
  1322.     }
  1323.     (void) signal(SIGHUP, cleanup);
  1324.     (void) signal(SIGINT, cleanup);
  1325.     (void) signal(SIGTERM, cleanup);
  1326.  
  1327. #ifdef HAVE_SETLINEBUF
  1328.     /**
  1329.      * line-buffer the output
  1330.      * permits "tail -f" of a growing log file
  1331.      **/
  1332.     (void) setlinebuf(stdout);
  1333. #endif
  1334.     basename = strrchr(argv[0], '/');
  1335.     basename = basename ? ++basename : argv[0];
  1336.  
  1337.     opterr = 1;
  1338.     if (strcmp(basename, "rup") == 0) {
  1339.     optstring = "hltn";
  1340.     usage = "usage: %s [ -%s ] [ interval ] [ host ... ]\n";
  1341.     while ((c = getopt(argc, argv, optstring)) != -1) {
  1342.         switch (c) {
  1343.         case 'h':
  1344.         opts |= O_SHOST;
  1345.         break;
  1346.         case 'l':
  1347.         opts |= O_SORT | O_RVRS;
  1348.         key_ptr = (key *) calloc(1, sizeof(key));
  1349.         key_ptr->k_offset = sn_offset(avenrun[AV1]);
  1350.         break;
  1351.         case 't':
  1352.         opts |= O_SORT;
  1353.         key_ptr = (key *) calloc(1, sizeof(key));
  1354.         key_ptr->k_offset = sd_offset(boottime.tv_sec);    /* uptime */
  1355.         break;
  1356.         case 'n':
  1357.         opts |= O_NHOST;
  1358.         break;
  1359.         case '?':
  1360.         do_usage++;
  1361.         }
  1362.     }
  1363.     c_seen = 1;
  1364.     count = 0;
  1365.     opts |= O_UP;
  1366.     } else {            /* rperf */
  1367.     optstring = "acdivhnSTsbBDr";
  1368.     usage = "usage: %s [ -%s ] [ interval [ count ] ] [ +sortkey ] [ host ... ]\n";
  1369.     while ((c = getopt(argc, argv, optstring)) != -1)
  1370.         switch (c) {
  1371.         case 'a':
  1372.         opts |= O_ALL;
  1373.         break;
  1374.         case 'c':
  1375.         opts |= O_CP;
  1376.         break;
  1377.         case 'd':
  1378.         opts |= O_DK;
  1379.         break;
  1380.         case 'i':
  1381.         opts |= O_IF;
  1382.         break;
  1383.         case 'S':
  1384.         opts |= O_TIME;
  1385.         break;
  1386.         case 'T':
  1387.         opts |= O_DATE;
  1388.         break;
  1389.         case 's':
  1390.         opts |= O_SECS;
  1391.         break;
  1392.         case 'h':
  1393.         opts |= O_SHOST;
  1394.         break;
  1395.         case 'n':
  1396.         opts |= O_NHOST;
  1397.         break;
  1398.         case 'v':
  1399.         opts |= O_VM;
  1400.         break;
  1401.         case 'b':
  1402.         opts |= O_BCST;
  1403.         break;
  1404.         case 'B':
  1405.         opts |= O_BARE;
  1406.         break;
  1407.         case 'r':
  1408.         opts |= O_RVRS;
  1409.         break;
  1410.         case 'D':
  1411.         opts |= O_DBG;
  1412.         break;
  1413.         case '?':
  1414.         do_usage++;
  1415.         }
  1416.  
  1417.     if (!(opts & O_BARE))
  1418.         opts |= O_UP;
  1419.     }
  1420.     if (opts & O_NHOST)
  1421.     f_h = "%15.15s ";
  1422.  
  1423.     opti = optind;
  1424.     while (argv[opti]) {
  1425.     char           *oa;
  1426.     unsigned        l;
  1427.  
  1428.     l = strtol(argv[opti], &oa, 0);
  1429.     if (argv[opti] == oa || *oa) {
  1430.         /* "mml0.meche.rpi.edu" or "128.113.14.20" or "+idle" */
  1431.         if (*argv[opti] == '+') {
  1432.         char           *sortkey;
  1433.         key            *kp;
  1434.  
  1435.         sortkey = argv[opti] + sizeof(char);
  1436.         for (kp = keys; kp->k_name != NULL; kp++) {
  1437.             if (strcmp(sortkey, kp->k_name) == 0) {
  1438.             key_ptr = kp;
  1439.             break;
  1440.             }
  1441.         }
  1442.         if (key_ptr) {
  1443.             opts |= O_SORT;
  1444.         } else {
  1445.             int             i;
  1446.             char           *p;
  1447.  
  1448.             (void) fprintf(stderr, "unknown sort key: %s\n", sortkey);
  1449.             for (i = 0; p = keyhelp[i]; i++)
  1450.             (void) fputs(p, stdout);
  1451.         }
  1452.         } else {
  1453.         h_seen++;
  1454.         }
  1455.     } else {
  1456.         if (!i_seen) {
  1457.         interval = l;
  1458.         i_seen++;
  1459.         } else if (!c_seen) {
  1460.         count = l;
  1461.         c_seen++;
  1462.         }
  1463.     }
  1464.     opti++;
  1465.     }
  1466.  
  1467.     if (do_usage)
  1468.     (void) fprintf(stderr, usage, basename, optstring);
  1469.  
  1470.     if (h_seen) {        /* do client calls */
  1471.     if (opts & O_DBG)
  1472.         (void) fputs("resolving host names\n", stderr);
  1473.     opti = optind;
  1474.     dpp = &dp;
  1475.  
  1476.     while (argv[opti]) {
  1477.         char           *oa;
  1478.         unsigned long   host_address;
  1479.  
  1480.         (void) strtol(argv[opti], &oa, 0);
  1481.         if ((argv[opti] == oa || *oa) && *argv[opti] != '+') {
  1482.         /* "mml0.meche.rpi.edu" or "128.113.14.20" */
  1483.         struct in_addr  addr;
  1484.         char           *hostname;
  1485.         struct hostent *host_entry;
  1486.  
  1487.         hostname = argv[opti];
  1488.         host_entry = gethostbyname(hostname);
  1489.         if (!host_entry) {    /* maybe he typed an address */
  1490.             if (opts & O_DBG)
  1491.             (void) fputs("byname failed\n", stderr);
  1492.             host_address = inet_addr(hostname);
  1493.             if (host_address != -1) {
  1494.             host_entry =
  1495.                 gethostbyaddr((char *) &host_address, 4, AF_INET);
  1496.             if (!host_entry && opts & O_DBG)
  1497.                 (void) fputs("byaddr failed\n", stderr);
  1498.             } else if (opts & O_DBG)
  1499.             (void) fputs("inet_addr failed\n", stderr);
  1500.         }
  1501.         if (host_entry) {
  1502.             bcopy(host_entry->h_addr,
  1503.               (char *) &addr.s_addr,
  1504.               host_entry->h_length);
  1505.         }
  1506.         /*
  1507.          * maybe he typed a valid address anyway --
  1508.          */
  1509.         if (!host_entry && (host_address != -1))
  1510.             addr.s_addr = host_address;
  1511.  
  1512.         if (host_entry || (host_address != -1)) {
  1513.             /* host ok.  add to list */
  1514.             if (opts & O_DBG)
  1515.             (void) fprintf(stdout, "%s\n", inet_ntoa(addr));
  1516.             (*dpp) = new_host(&addr, hostname);
  1517.             (*dpp)->datap = NULL;
  1518.             dpp = &(*dpp)->datap;
  1519.         } else {
  1520.             (void) fprintf(stderr, "can't get address for %s\n",
  1521.                    hostname);
  1522.         }
  1523.         }            /* a host argument */
  1524.         opti++;
  1525.     }
  1526.     if (opts & O_DBG)
  1527.         (void) fprintf(stderr, "%d hosts\n", nhosts);
  1528.  
  1529.     if (!nhosts)
  1530.         exit(1);
  1531.  
  1532.     if (!(opts & O_ALL)) {
  1533.         if (nhosts == 1)
  1534.         opts |= O_DEFL1;
  1535.         else
  1536.         opts |= O_DEFL;
  1537.     }
  1538.     thiscount++;
  1539.     doclnt_calls();
  1540.     tbl = compute_data(tbl);
  1541.  
  1542.     if (opts & O_UP) {
  1543.         print_data(tbl, P_UP);
  1544.     }
  1545.     build_title();
  1546.  
  1547.     for (hdrcnt = 1;;) {
  1548.  
  1549.         if (c_seen && !count--)
  1550.         exit(0);
  1551.  
  1552.         (void) sleep(interval);
  1553.  
  1554.         if (!--hdrcnt || nhosts > 1) {
  1555.         (void) fputs(title1, stdout);
  1556.         (void) fputs(title2, stdout);
  1557.         check_term();
  1558.         hdrcnt = term_rows ? term_rows - 2 : 20;
  1559.         }
  1560.         thiscount++;
  1561.         doclnt_calls();
  1562.         tbl = compute_data(tbl);
  1563.         if (opts & O_DBG)
  1564.         (void) fprintf(stdout,
  1565.                  "%d host%s\n", nhosts, nhosts == 1 ? "" : "s");
  1566.         print_data(tbl, P_DATA);
  1567.     }
  1568.  
  1569.     } else {            /* do broadcasts */
  1570.     if (!(opts & O_ALL)) {
  1571.         opts |= O_DEFL;
  1572.     }
  1573.     nhosts = 2;
  1574.     build_title();
  1575.     nhosts = 0;
  1576.  
  1577.     for (;;) {
  1578.         thiscount++;
  1579.  
  1580.         if (thiscount == 1 || opts & O_BCST) {
  1581.         stats_broadcast resbuf;
  1582.         static enum clnt_stat clnt_stat;
  1583.  
  1584.         (void) signal(SIGALRM, bcst_done);
  1585.         (void) alarm(interval);    /* broadcast interval.  >54 ignored */
  1586.         bcst_timo = FALSE;
  1587.         (void) fputs("broadcasting ", stdout);
  1588.         (void) fflush(stdout);
  1589.         bzero((char *) &resbuf, sizeof resbuf);
  1590.         clnt_stat = clnt_broadcast(RSTATPROG,
  1591.                        RSTATVERS_BCST,
  1592.                        RSTATPROC_STATS,
  1593.                        xdr_void,
  1594.                        (char *) NULL,
  1595.                        XDR_STATSPROC(RSTATVERS_BCST),
  1596.                        (char *) &resbuf,
  1597.                        each_result);
  1598.         if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT) {
  1599.             (void) fprintf(stderr, "\nclnt_broadcast: %s\n",
  1600.                    clnt_sperrno(clnt_stat));
  1601.             exit(1);
  1602.         }
  1603.         (void) putc('\n', stdout);
  1604.         }            /* thiscount == 1 || opts & O_BCST */
  1605.         doclnt_calls();
  1606.         tbl = compute_data(tbl);
  1607.         if (opts & O_DBG)
  1608.         (void) fprintf(stdout,
  1609.                  "%d host%s\n", nhosts, nhosts == 1 ? "" : "s");
  1610.  
  1611.         if (opts & O_UP) {
  1612.         print_data(tbl, P_UP);
  1613.         }
  1614.         if (thiscount > 1) {
  1615.         (void) fputs(title1, stdout);
  1616.         (void) fputs(title2, stdout);
  1617.         print_data(tbl, P_DATA);
  1618.         }
  1619.         if (c_seen && !count--)
  1620.         exit(0);
  1621.  
  1622.         if (!(opts & O_BCST))
  1623.         (void) sleep(interval);
  1624.     }
  1625.     }
  1626. }
  1627.