home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume41 / rperf / part03 < prev    next >
Encoding:
Text File  |  1993-12-19  |  54.3 KB  |  1,959 lines

  1. Newsgroups: comp.sources.misc
  2. From: fitz@rpi.edu (Brian P. Fitzgerald)
  3. Subject: v41i041:  rperf - performance monitoring of network hosts, v3.1, Part03/04
  4. Message-ID: <1993Dec19.205313.28507@sparky.sterling.com>
  5. X-Md4-Signature: 47ca0c5031a7a67638a282895403fda9
  6. Sender: kent@sparky.sterling.com (Kent Landfield)
  7. Organization: Rensselaer Polytechnic Institute, Troy NY
  8. Date: Sun, 19 Dec 1993 20:53:13 GMT
  9. Approved: kent@sparky.sterling.com
  10.  
  11. Submitted-by: fitz@rpi.edu (Brian P. Fitzgerald)
  12. Posting-number: Volume 41, Issue 41
  13. Archive-name: rperf/part03
  14. Environment: UNIX
  15. Supersedes: rperf: Volume 39, Issue 69-71
  16.  
  17. #! /bin/sh
  18. # This is a shell archive.  Remove anything before this line, then unpack
  19. # it by saving it into a file and typing "sh file".  To overwrite existing
  20. # files, type "sh file -c".  You can also feed this as standard input via
  21. # unshar, or by typing "sh <file", e.g..  The tool that generated this
  22. # shell archive is called "shar", and is available by anonymous ftp
  23. # from ftp.uu.net in subdirectory /usenet/comp.sources.unix, and from many
  24. # other places. Check 'archie' for the latest locations.  If this archive
  25. # is complete, you will see the following message at the end:
  26. #        "End of archive 3 (of 4)."
  27. # Contents:  rperf.c hsearch.c
  28. # Wrapped by fitzgb@mml0.meche.rpi.edu on Wed Dec 15 13:06:56 1993
  29. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  30. if test -f 'rperf.c' -a "${1}" != "-c" ; then 
  31.   echo shar: Will not clobber existing file \"'rperf.c'\"
  32. else
  33. echo shar: Extracting \"'rperf.c'\" \(47595 characters\)
  34. sed "s/^X//" >'rperf.c' <<'END_OF_FILE'
  35. X/**
  36. X * This program may be copied, redistributed in any form,
  37. X * source or binary, and used for any purpose, provided
  38. X * this copyright notice is retained.
  39. X **/
  40. Xstatic char    *copyright[] = {
  41. X    "@(#)rperf.c    3.1 12/15/93 (c) Copyright Brian P. Fitzgerald",
  42. X    "Rensselaer Polytechnic Institute",
  43. X    0
  44. X};
  45. X
  46. X/**
  47. X
  48. Xrperf.c -- print system performance statistics.
  49. X
  50. Xby Brian P. Fitzgerald
  51. XMechanics of Materials Laboratory
  52. XRensselaer Polytechnic Institute
  53. XTroy, New York
  54. X
  55. Xusage: rperf [ options ] [ interval [ count ] ] [ +sortkey ] [ host ... ]
  56. X       rup [ options ] [ interval ] [ host ... ]
  57. X
  58. XSend comments and bug fixes to fitz@rpi.edu.  Please indicate the
  59. Xmanufacturer and model of your computer, the name and version of your
  60. Xoperating system and the version of rperf that you are using.
  61. X
  62. XTested:
  63. X386BSD
  64. XAlliant FX/2800
  65. XAmiga 4.0 2.1c
  66. XBSDi
  67. XDEC Ultrix 4.2
  68. XDG/UX v5.4.2
  69. XEISA PC NetBSD-0.9
  70. XESIX 4.0.4    (configure script in development)
  71. XHP-UX 8.0, 9.01
  72. XIBM AIX 3.1, 3.2
  73. XLinux 0.99p14    (minimum required)
  74. XMIPS RISCos
  75. XMotorola R40V4.1, FH32.31
  76. XNeXT Mach 20
  77. XSCO Unix 3.2.2
  78. XSGI PI Iris 4.0.1, 4.0.2, 4.0.5
  79. XSunOS 4.1.1, 4.1.2, 4.1.3, 5.2
  80. X
  81. XNot supported:
  82. XAIX 1.2.1 on aix370
  83. X
  84. XBroadcast mode not supported:
  85. XLinux 0.99p13
  86. X
  87. XSend reports of successful compilation on other platforms to
  88. Xfitz@rpi.edu
  89. X
  90. XHistory:
  91. X
  92. X5/6/92    beta    posted to alt.sources
  93. X
  94. X5/18/92    1.1    Added multiple hosts, uptime display.
  95. X        Improved output format.
  96. X        posted to alt.sources
  97. X
  98. X5/25/92    1.2    Added signal handler.
  99. X
  100. X1/6/93    1.3    Added broadcast mode
  101. X
  102. X2/6/93    1.4    Added output sorting options.
  103. X        Added rup alias.
  104. X
  105. X2/10/93    1.5    Corrected rpc version mismatch.  Now if_opackets right.
  106. X        Plugged some memory leaks.
  107. X
  108. X3/5/93    1.6    Variable number of disks and cpu states.
  109. X        Fixed a line wrap problem.  Added termcap routine.
  110. X        posted to alt.sources
  111. X
  112. X8/26/93    2.1    posted to comp.sources.misc
  113. X
  114. X9/13/93    2.2    Solaris 2 port
  115. X
  116. X9/26/93    2.3    verbose help, setrlimit
  117. X        mailed to comp.sources.testers volunteers
  118. X
  119. X10/26/93 2.4    fixed dk_xfer array problem
  120. X        fixed cp_time problem on AIX
  121. X        split up rperf.c
  122. X        broadcast over multiple versions
  123. X        use hash table for addresses
  124. X        used comments from testers -- thanks:
  125. X         hostname trim
  126. X         screen clear
  127. X         print '-' for unreported statistics
  128. X         eliminate duplication for routers
  129. X
  130. X10/28/93 2.5    broadcast interval algorithm
  131. X
  132. X11/2/93     2.6    debugging version to check each_result
  133. X
  134. X11/10/93 2.7    mailed out to testers for review
  135. X
  136. X11/17/93 2.8    always try to adjust lines longer than ruler
  137. X
  138. X11/24/93 2.9    report when server has rebooted
  139. X
  140. X12/15/93 3.1    posted to comp.sources.misc
  141. X
  142. X**/
  143. X
  144. X#include "common.h"
  145. X#include "rperf.h"
  146. X#include "term.h"
  147. X
  148. Xkey             keys[] = {
  149. X    {"avg", sn_offset(avenrun[AV1]), sn_offset(avenrun[AV1]), 0, 0},
  150. X    {"ave", sn_offset(avenrun[AV1]), sn_offset(avenrun[AV1]), 0, 0},
  151. X    {"loadavg", sn_offset(avenrun[AV1]), sn_offset(avenrun[AV1]), 0, 0},
  152. X    {"loadave", sn_offset(avenrun[AV1]), sn_offset(avenrun[AV1]), 0, 0},
  153. X    {"loadav", sn_offset(avenrun[AV1]), sn_offset(avenrun[AV1]), 0, 0},
  154. X    {"load", sn_offset(avenrun[AV1]), sn_offset(avenrun[AV1]), 0, 0},
  155. X    {"avenrun", sn_offset(avenrun[AV1]), sn_offset(avenrun[AV1]), 0, 0},
  156. X    {"av1", sn_offset(avenrun[AV1]), sn_offset(avenrun[AV1]), 0, 0},
  157. X    {"av5", sn_offset(avenrun[AV5]), sn_offset(avenrun[AV5]), 0, 0},
  158. X    {"av15", sn_offset(avenrun[AV15]), sn_offset(avenrun[AV15]), 0, 0},
  159. X
  160. X    {"boottime", sn_offset(boottime.tv_sec), sn_offset(boottime.tv_sec), K_NZERO, 0},
  161. X    {"boot", sn_offset(boottime.tv_sec), sn_offset(boottime.tv_sec), K_NZERO, 0},
  162. X    {"uptime", sn_offset(boottime.tv_sec), sd_offset(boottime.tv_sec), K_NZERO, 0},
  163. X    {"up", sn_offset(boottime.tv_sec), sd_offset(boottime.tv_sec), K_NZERO, 0},
  164. X
  165. X    {"curtime", sn_offset(curtime.tv_sec), sn_offset(curtime.tv_sec), K_NZERO, 0},
  166. X    {"time", sn_offset(curtime.tv_sec), sn_offset(curtime.tv_sec), K_NZERO, 0},
  167. X    {"clock", sn_offset(curtime.tv_sec), sn_offset(curtime.tv_sec), K_NZERO, 0},
  168. X
  169. X    {"user", sn_offset(cp_time), sd_offset(cp_time), K_DELTA | K_ARRAY, 0},
  170. X    {"us", sn_offset(cp_time), sd_offset(cp_time), K_DELTA | K_ARRAY, 0},
  171. X    {"nice", sn_offset(cp_time), sd_offset(cp_time), K_DELTA | K_ARRAY, 1},
  172. X    {"ni", sn_offset(cp_time), sd_offset(cp_time), K_DELTA | K_ARRAY, 1},
  173. X    {"sys", sn_offset(cp_time), sd_offset(cp_time), K_DELTA | K_ARRAY, 2},
  174. X    {"system", sn_offset(cp_time), sd_offset(cp_time), K_DELTA | K_ARRAY, 2},
  175. X    {"sy", sn_offset(cp_time), sd_offset(cp_time), K_DELTA | K_ARRAY, 2},
  176. X    {"idle", sn_offset(cp_time), sd_offset(cp_time), K_DELTA | K_ARRAY, 3},
  177. X    {"id", sn_offset(cp_time), sd_offset(cp_time), K_DELTA | K_ARRAY, 3},
  178. X
  179. X    {"intr", sn_offset(v_intr), sd_offset(v_intr), K_DELTA, 0},
  180. X    {"swtch", sn_offset(v_swtch), sd_offset(v_swtch), K_DELTA, 0},
  181. X    {"cxsw", sn_offset(v_swtch), sd_offset(v_swtch), K_DELTA, 0},
  182. X    {"csw", sn_offset(v_swtch), sd_offset(v_swtch), K_DELTA, 0},
  183. X
  184. X    {"pgpgin", sn_offset(v_pgpgin), sd_offset(v_pgpgin), K_DELTA, 0},
  185. X    {"pgin", sn_offset(v_pgpgin), sd_offset(v_pgpgin), K_DELTA, 0},
  186. X    {"pgpgout", sn_offset(v_pgpgout), sd_offset(v_pgpgout), K_DELTA, 0},
  187. X    {"pgout", sn_offset(v_pgpgout), sd_offset(v_pgpgout), K_DELTA, 0},
  188. X    {"pgo", sn_offset(v_pgpgout), sd_offset(v_pgpgout), K_DELTA, 0},
  189. X
  190. X    {"pswpin", sn_offset(v_pswpin), sd_offset(v_pswpin), K_DELTA, 0},
  191. X    {"swpin", sn_offset(v_pswpin), sd_offset(v_pswpin), K_DELTA, 0},
  192. X    {"swin", sn_offset(v_pswpin), sd_offset(v_pswpin), K_DELTA, 0},
  193. X    {"pswpout", sn_offset(v_pswpout), sd_offset(v_pswpout), K_DELTA, 0},
  194. X    {"swpout", sn_offset(v_pswpout), sd_offset(v_pswpout), K_DELTA, 0},
  195. X    {"swo", sn_offset(v_pswpout), sd_offset(v_pswpout), K_DELTA, 0},
  196. X
  197. X    {"dk_xfer", sn_offset(dk_xfer), sd_offset(dk_xfer), K_DELTA | K_ARRAY, 0},
  198. X    {"sd0", sn_offset(dk_xfer), sd_offset(dk_xfer), K_DELTA | K_ARRAY, 0},
  199. X    {"disk0", sn_offset(dk_xfer), sd_offset(dk_xfer), K_DELTA | K_ARRAY, 0},
  200. X    {"d0", sn_offset(dk_xfer), sd_offset(dk_xfer), K_DELTA | K_ARRAY, 0},
  201. X    {"sd1", sn_offset(dk_xfer), sd_offset(dk_xfer), K_DELTA | K_ARRAY, 1},
  202. X    {"disk1", sn_offset(dk_xfer), sd_offset(dk_xfer), K_DELTA | K_ARRAY, 1},
  203. X    {"d1", sn_offset(dk_xfer), sd_offset(dk_xfer), K_DELTA | K_ARRAY, 1},
  204. X    {"sd2", sn_offset(dk_xfer), sd_offset(dk_xfer), K_DELTA | K_ARRAY, 2},
  205. X    {"disk2", sn_offset(dk_xfer), sd_offset(dk_xfer), K_DELTA | K_ARRAY, 2},
  206. X    {"d2", sn_offset(dk_xfer), sd_offset(dk_xfer), K_DELTA | K_ARRAY, 2},
  207. X    {"sd3", sn_offset(dk_xfer), sd_offset(dk_xfer), K_DELTA | K_ARRAY, 3},
  208. X    {"disk3", sn_offset(dk_xfer), sd_offset(dk_xfer), K_DELTA | K_ARRAY, 3},
  209. X    {"d3", sn_offset(dk_xfer), sd_offset(dk_xfer), K_DELTA | K_ARRAY, 3},
  210. X
  211. X    {"ipackets", sn_offset(if_ipackets), sd_offset(if_ipackets), K_DELTA, 0},
  212. X    {"ipk", sn_offset(if_ipackets), sd_offset(if_ipackets), K_DELTA, 0},
  213. X    {"ierrors", sn_offset(if_ierrors), sd_offset(if_ierrors), K_DELTA, 0},
  214. X    {"ier", sn_offset(if_ierrors), sd_offset(if_ierrors), K_DELTA, 0},
  215. X    {"oerrors", sn_offset(if_oerrors), sd_offset(if_oerrors), K_DELTA, 0},
  216. X    {"oer", sn_offset(if_oerrors), sd_offset(if_oerrors), K_DELTA, 0},
  217. X    {"opackets", sn_offset(if_opackets), sd_offset(if_opackets), K_DELTA, 0},
  218. X    {"opk", sn_offset(if_opackets), sd_offset(if_opackets), K_DELTA, 0},
  219. X    {"collisions", sn_offset(if_collisions), sd_offset(if_collisions), K_DELTA, 0},
  220. X    {"coll", sn_offset(if_collisions), sd_offset(if_collisions), K_DELTA, 0},
  221. X    {0, 0, 0, 0, 0}
  222. X};
  223. X
  224. Xkey            *key_ptr = NULL;
  225. X
  226. X/* xx keep up to date */
  227. Xchar           *rperfusagev[] = {
  228. X    "usage: rperf [ options ] [ interval [ count ]] [ +sortkey ] [ host ... ]",
  229. X    "rperf options:",
  230. X    "-a    almost all (-cdiv)    -S    seconds in unix time",
  231. X    "-c    cpu time, load average    -T    date and local time",
  232. X    "-d    disk activity        -s    elapsed time, seconds",
  233. X    "-i    ethernet activity    -u    uptime",
  234. X    "-v    virtual memory        -A    all (-aSTsu)",
  235. X    "-1,-2,-3,-4 rstat version    -b    broadcast continuously",
  236. X    "-h    sort by hostname    -D    debug (also -DD, -DDD, etc.)",
  237. X    "-n    don't resolve hostnames    -r    reverse sort",
  238. X    "-N    never clear the screen    -B    bare display.  no headers",
  239. X    "-?    verbose help (this message)",
  240. X    0
  241. X};
  242. X
  243. X/* xx keep up to date */
  244. Xchar           *rupusagev[] = {
  245. X    "rup [ options ] [ interval ] [ host ... ]",
  246. X    "-h    sort by hostname    -l    sort by 1 min load avg",
  247. X    "-t    sort by uptime        -n    don't resolve host names",
  248. X    "-D    debug (also -DD, -DDD, etc.)",
  249. X    0
  250. X};
  251. X
  252. X/* xx keep up to date */
  253. Xchar           *keyhelp[] = {
  254. X    "The sort keys are:",
  255. X    "loadavg     user      pgpgin      disk0      boottime    ipackets",
  256. X    "av1         nice      pgpgout     disk1      uptime      ierrors",
  257. X    "av5         sys       pswpin      disk2      curtime     oerrors",
  258. X    "av15        idle      pswpout     disk3                  opackets",
  259. X    "                      intr                               collisions",
  260. X    "                      swtch",
  261. X    0
  262. X};
  263. X
  264. Xu_long          nhosts = 0;    /* multiple hosts idea from Larry McVoy */
  265. Xu_long          mode = MODE_BCST;    /* assume */
  266. Xu_long          opts = 0;
  267. Xu_long          thiscount = 0;
  268. Xu_long          nresp = 0;
  269. Xu_long          nprint = 0;
  270. Xu_long          dbg_lvl = 0;
  271. X
  272. Xstruct timeval  starttime;
  273. X
  274. Xchar           *f1_cp = "%-15s ";
  275. Xchar           *f2_cp = "%3s %3s %3s %3s ";
  276. Xchar           *fr_cp = "%3s %3s %3s %3s ";
  277. X
  278. Xchar           *f1_av = "%-14s ";
  279. Xchar           *f2_av = "%4s %4s %4s ";
  280. Xchar           *fo_av = "%4.2f %4.2f %4.2f ";
  281. Xchar           *fo_a0 = "%4.1f %4.1f %4.1f ";
  282. X
  283. Xchar           *f1_dk = "%-12s";
  284. Xchar           *f2_dk = "%2s %2s %2s %2s ";
  285. Xchar           *fr_dk = "%2s %2s %2s %2s ";
  286. X
  287. Xchar           *f1_vm = "%2s %2s %2s %2s %3s %3s ";
  288. Xchar           *f2_vm = "%2s %2s %2s %2s %3s %3s ";
  289. Xchar           *fr_vm = "%2s %2s %2s %2s %3s %3s ";
  290. X
  291. Xchar           *f1_if = " %2s %2s %2s %2s %2s";
  292. Xchar           *f2_if = " %2s %2s %2s %2s %2s";
  293. Xchar           *fr_if = " %2s %2s %2s %2s %2s";
  294. X
  295. Xchar           *f_time = "%-9.9s ";
  296. Xchar           *fo_time = "%9d ";
  297. X
  298. Xchar           *f_date = "%-15.15s ";
  299. X
  300. Xchar           *f_secs = "%-5.5s ";
  301. Xchar           *fo_secs = "%5.2f ";
  302. X
  303. Xchar           *f2_up = "%15.15s ";
  304. Xchar           *f_up = "%-15.15s ";
  305. X
  306. Xchar           *f_haddr = "%-15.15s ";
  307. Xchar            f_h[20] = "%12.12s ";
  308. X
  309. Xchar            title1[160];
  310. Xchar            title2[160];
  311. Xchar            ruler[160];
  312. X
  313. Xvoid
  314. Xmsg(s, fp)
  315. X    char          **s;
  316. X    FILE           *fp;
  317. X{
  318. X    while (*s) {
  319. X    (void) fputs(*s++, fp);
  320. X    (void) fputc('\n', fp);
  321. X    }
  322. X}
  323. X
  324. Xvoid
  325. Xverbosehelp()
  326. X{
  327. X    msg(copyright, stderr);
  328. X    msg(rperfusagev, stderr);
  329. X    msg(keyhelp, stderr);
  330. X    msg(rupusagev, stderr);
  331. X    exit(0);
  332. X}
  333. X
  334. X/**
  335. X * handle termination signals
  336. X**/
  337. XRETSIGTYPE
  338. Xcleanup()
  339. X{
  340. X    exit(0);            /* flush and close stdout */
  341. X}
  342. X
  343. X/**
  344. X * Check whether the data line is longer than the ruler.
  345. X * Try to adjust.
  346. X * Return the adjusted string.
  347. X**/
  348. Xchar           *
  349. Xadjust_line(obuf)
  350. X    char           *obuf;
  351. X{
  352. X    int             olen = strlen(obuf);
  353. X    int             rlen = strlen(ruler);
  354. X    int             rpos = 0, opos;
  355. X    int             nsp, err = 0;
  356. X    char           *rp, *op, *tp, *sp, *cp;
  357. X
  358. X    if (olen <= rlen) {
  359. X    if (olen < rlen && dbg_lvl >= 2) {
  360. X        (void) fprintf(stderr, "short line ruler=%d output%d\n",
  361. X               rlen, olen);
  362. X        (void) fputs(ruler, stderr);
  363. X        (void) putc('\n', stderr);
  364. X    }
  365. X    return obuf;        /* leave alone */
  366. X    }
  367. X    if (dbg_lvl >= 2) {
  368. X    (void) fprintf(stderr, "line too long ruler=%d output%d\n",
  369. X               rlen, olen);
  370. X    (void) fputs(ruler, stderr);
  371. X    (void) putc('\n', stderr);
  372. X    }
  373. X    op = obuf;
  374. X    for (rp = ruler; *rp;) {
  375. X    tp = op;
  376. X    for (; *rp && *rp == ' '; rp++);
  377. X    for (; *op && *op == ' '; op++);
  378. X    nsp = op - tp;
  379. X    for (; *rp && *rp != ' '; rp++);
  380. X    for (; *op && *op != ' '; op++);
  381. X
  382. X    if (!*rp || nsp > 1) {
  383. X        rpos = rp - ruler;
  384. X        opos = op - obuf;
  385. X        err = opos - rpos;
  386. X    }
  387. X    if (err > 0) {
  388. X        if (dbg_lvl >= 2) {
  389. X        (void) fputs(obuf, stderr);
  390. X        (void) putc('\n', stderr);
  391. X        (void) fprintf(stderr, "rpos=%d err=%d\n", rpos, err);
  392. X        }
  393. X        for (sp = op; sp != obuf; sp--) {
  394. X        if (*sp == ' ')
  395. X            sp--;
  396. X        if (*sp == ' ') {    /* shift left one char */
  397. X            sp++;
  398. X            for (cp = sp; *cp; cp++)
  399. X            *cp = *(cp + 1);
  400. X            op--;
  401. X            if (!--err)
  402. X            break;
  403. X        }
  404. X        }
  405. X    }
  406. X    rpos = rp - ruler;
  407. X    opos = op - obuf;
  408. X    err = opos - rpos;
  409. X    }
  410. X
  411. X    if (dbg_lvl >= 2)
  412. X    (void) fputs(" . . . . 1 . . . . 2 . . . . 3 . . . . 4 . . . . 5 . . . . 6 . . . . 7 . . . .\n", stderr);
  413. X    return obuf;
  414. X}
  415. X
  416. X/**
  417. X * qsort comparison routine
  418. X *
  419. X * if i is to precede j, return a value < 0
  420. X * otherwise, return a value > 0
  421. X**/
  422. Xstatic int
  423. Xdatacompare(i, j)
  424. X    struct datatbl *i, *j;
  425. X{
  426. X    return opts & O_RVRS
  427. X    ? i->val - j->val
  428. X    : j->val - i->val;
  429. X}
  430. X
  431. X/**
  432. X * Calculate deltas and other items.
  433. X * Prepare array of keys and pointers.
  434. X * Sort if required.
  435. X * Return a pointer to the sorted array.
  436. X**/
  437. Xvoid
  438. Xcompute_data()
  439. X{
  440. X    long            dt, hdt;    /* msec */
  441. X    int             i;
  442. X    int             dcpu, hdcpu;
  443. X    struct data   **dpp;
  444. X    enum cp_time_kind kind_tmp;
  445. X
  446. X    if (dbg_lvl >= 4) {
  447. X    (void) fprintf(stderr, "in compute_data\n");
  448. X    }
  449. X    nresp = 0;
  450. X    for (dpp = &dp; *dpp; dpp = &(*dpp)->datap) {
  451. X    /* this data is current */
  452. X    if ((*dpp)->nn == thiscount) {
  453. X
  454. X        (*dpp)->sd.boottime.tv_sec =    /* uptime */
  455. X        (*dpp)->sn.boottime.tv_sec ?    /* if boottime reported */
  456. X        (*dpp)->sn.curtime.tv_sec
  457. X        - (*dpp)->sn.boottime.tv_sec : 0;
  458. X
  459. X        nresp++;
  460. X        if ((*dpp)->no) {
  461. X        /* this data is not the first response from that host */
  462. X        int             rebooted;
  463. X
  464. X        /* time in milliseconds, since last call */
  465. X        dt = (((*dpp)->sn.curtime.tv_sec
  466. X               - (*dpp)->so.curtime.tv_sec) * 1000000
  467. X              + ((*dpp)->sn.curtime.tv_usec
  468. X             - (*dpp)->so.curtime.tv_usec) + 500) / 1000;
  469. X        hdt = (dt + 1) / 2;
  470. X
  471. X        if (!(*dpp)->sd.cp_val)
  472. X            create_array((array *) & (*dpp)->sd.cp_time,
  473. X                 (*dpp)->sn.cp_len);
  474. X
  475. X        /**
  476. X         * calculate cp_time deltas
  477. X         *
  478. X         * if cp_time is reckoned cumulatively, then a negative delta
  479. X         * is impossible.  Therefore, if delta is negative the remote
  480. X         * hosts's rpc.rstatd must be reporting cp_time as an
  481. X         * increment since the previous call.  IBM AIX does it that
  482. X         * way.
  483. X        **/
  484. X        kind_tmp = (*dpp)->cp_kind;
  485. X        /**
  486. X         * All counters are reset on reboot.
  487. X         * Arbitrarily pick if_ipackets as an indicator
  488. X         * Can't use: t_n(i).boottime.tv_sec > t_o(i).boottime.tv_sec
  489. X         * because on some machines it is a derived quantity
  490. X         * (curtime - _lbolt * _hz), and therefore fluctuates a bit.
  491. X        **/
  492. X        rebooted = (*dpp)->sn.if_ipackets < (*dpp)->so.if_ipackets;
  493. X        for (i = 0; i < (*dpp)->sn.cp_len; i++) {
  494. X            (*dpp)->sd.cp_val[i] = delta(cp_val[i]);
  495. X            if ((*dpp)->sd.cp_val[i] < 0 && !rebooted)
  496. X            (*dpp)->cp_kind = CP_TIME_INC;
  497. X        }
  498. X        if (dbg_lvl >= 1 && kind_tmp == CP_TIME_CUM
  499. X            && (*dpp)->cp_kind == CP_TIME_INC) {
  500. X            (void) fprintf(stderr,
  501. X                 "%s: rpc.rstatd reports incremental cp_time\n",
  502. X                   (*dpp)->host);
  503. X        }
  504. X        /**
  505. X             * From vmstat.c 5.31 (Berkeley)
  506. X             * We round upward to avoid losing low-frequency events
  507. X             * (i.e., >= 1 per interval but < 1 per second).
  508. X             **/
  509. X        dcpu = 0;
  510. X        switch ((*dpp)->cp_kind) {
  511. X
  512. X        case CP_TIME_CUM:
  513. X            for (i = 0; i < (*dpp)->sn.cp_len; i++) {
  514. X            dcpu += (*dpp)->sd.cp_val[i];
  515. X            }
  516. X            hdcpu = dcpu / 2;
  517. X            for (i = 0; i < (*dpp)->sn.cp_len; i++)
  518. X            (*dpp)->sd.cp_val[i] = cpu((*dpp)->sd.cp_val[i]);
  519. X            break;
  520. X
  521. X        case CP_TIME_INC:    /* incremental.  disregard old data */
  522. X            for (i = 0; i < (*dpp)->sn.cp_len; i++) {
  523. X            dcpu += (*dpp)->sn.cp_val[i];
  524. X            }
  525. X            hdcpu = dcpu / 2;
  526. X            for (i = 0; i < (*dpp)->sn.cp_len; i++)
  527. X            /* store it in sd anyway because sd is printed */
  528. X            (*dpp)->sd.cp_val[i] = cpu((*dpp)->sn.cp_val[i]);
  529. X            break;
  530. X
  531. X        }        /* switch cp_kind */
  532. X
  533. X        /* if different RSTAT versions for so and sn */
  534. X        if ((*dpp)->sn.dk_len != (*dpp)->so.dk_len
  535. X        /* or sd.dk_xfer is uninitialized */
  536. X            || !(*dpp)->sd.dk_len) {
  537. X            if ((*dpp)->sd.dk_val)
  538. X            destroy_array((array *) & (*dpp)->sd.dk_xfer);
  539. X            create_array((array *) & (*dpp)->sd.dk_xfer,
  540. X                 Max((*dpp)->sn.dk_len, (*dpp)->so.dk_len));
  541. X        }
  542. X        /**
  543. X         * calculate the deltas for dk_xfer
  544. X        **/
  545. X        for (i = 0; i < Min((*dpp)->sn.dk_len, (*dpp)->so.dk_len); i++)
  546. X            (*dpp)->sd.dk_val[i] = rate(delta(dk_val[i]));
  547. X
  548. X        (*dpp)->sd.v_pgpgin = rate(delta(v_pgpgin));
  549. X        (*dpp)->sd.v_pgpgout = rate(delta(v_pgpgout));
  550. X        (*dpp)->sd.v_pswpin = rate(delta(v_pswpin));
  551. X        (*dpp)->sd.v_pswpout = rate(delta(v_pswpout));
  552. X        (*dpp)->sd.v_swtch = rate(delta(v_swtch));
  553. X        /* Why does v_intr count down on aix370? */
  554. X        (*dpp)->sd.v_intr = rate(Abs((int) (delta(v_intr))));
  555. X
  556. X        (*dpp)->sd.if_ipackets = rate(delta(if_ipackets));
  557. X        (*dpp)->sd.if_ierrors = rate(delta(if_ierrors));
  558. X        (*dpp)->sd.if_opackets = rate(delta(if_opackets));
  559. X        (*dpp)->sd.if_oerrors = rate(delta(if_oerrors));
  560. X        (*dpp)->sd.if_collisions = rate(delta(if_collisions));
  561. X        }            /* (*dpp)->no */
  562. X    }            /* (*dpp)->nn == thiscount */
  563. X    }
  564. X    if (dbg_lvl >= 4) {
  565. X    (void) fprintf(stderr, "returning from compute_data\n");
  566. X    }
  567. X}
  568. X
  569. Xstruct datatbl *
  570. Xsort_data(tbl)
  571. X    struct datatbl *tbl;
  572. X{
  573. X    int             sort_needs_delta;
  574. X    int             will_sort;
  575. X    int             i;
  576. X    struct data   **dpp;
  577. X
  578. X    if (dbg_lvl >= 4) {
  579. X    (void) fprintf(stderr, "in sort_data\n");
  580. X    }
  581. X    will_sort = opts & O_SORT;
  582. X    sort_needs_delta = will_sort && key_ptr->k_flag & K_DELTA;
  583. X
  584. X    if (tbl)
  585. X    free((char *) tbl);
  586. X    tbl = (struct datatbl *) malloc((unsigned) nresp * sizeof(struct datatbl));
  587. X    if (tbl == NULL) {
  588. X    perror("malloc");
  589. X    exit(1);
  590. X    }
  591. X    i = 0;
  592. X    for (dpp = &dp; *dpp; dpp = &(*dpp)->datap) {
  593. X    if ((*dpp)->nn == thiscount) {
  594. X
  595. X        tbl[i].dp = *dpp;
  596. X        if (will_sort && (!sort_needs_delta || (*dpp)->no)) {
  597. X        if (key_ptr->k_flag & K_ARRAY) {
  598. X            array           arr;
  599. X
  600. X            arr = *(array *) ((char *) (*dpp) + key_ptr->k_doffset);
  601. X            tbl[i].val = arr.val[key_ptr->k_index];
  602. X        } else {
  603. X            tbl[i].val = *(int *) ((char *) (*dpp) + key_ptr->k_doffset);
  604. X        }
  605. X        } else {
  606. X        /* this val can be sorted but will not be printed */
  607. X        tbl[i].val = 0;
  608. X        }
  609. X        i++;
  610. X    }
  611. X    }
  612. X
  613. X    if (will_sort)
  614. X    qsort((char *) tbl, (int) nresp, sizeof(struct datatbl), datacompare);
  615. X
  616. X    if (dbg_lvl >= 4) {
  617. X    (void) fprintf(stderr, "returning from sort_data\n");
  618. X    }
  619. X    return tbl;
  620. X}
  621. X
  622. X/**
  623. X * make the titles for the columns, depending on the options selected
  624. X**/
  625. Xvoid
  626. Xbuild_title()
  627. X{
  628. X    if (dbg_lvl >= 4) {
  629. X    (void) fprintf(stderr, "in build_title\n");
  630. X    }
  631. X    title1[0] = '\0';
  632. X    title2[0] = '\0';
  633. X    ruler[0] = '\0';
  634. X    if (opts & O_BARE) {
  635. X    if (dbg_lvl >= 4) {
  636. X        (void) fprintf(stderr,
  637. X               "returning from build_title (opts & O_BARE)\n");
  638. X    }
  639. X    return;
  640. X    }
  641. X    if (opts & O_TIME) {
  642. X    (void) sprintf(title1 + strlen(title1), f_time, "unix time");
  643. X    (void) sprintf(title2 + strlen(title2), f_time, "(seconds)");
  644. X    (void) sprintf(ruler + strlen(ruler), fo_time, 100000000);
  645. X    }
  646. X    if (opts & O_DATE) {
  647. X    (void) sprintf(title1 + strlen(title1), f_date, "Date   Time");
  648. X    (void) sprintf(title2 + strlen(title2), f_date, "       (local)");
  649. X    (void) sprintf(ruler + strlen(ruler), f_date,
  650. X               "700101 00:00:00");
  651. X    }
  652. X    if (opts & O_SECS) {
  653. X    (void) sprintf(title1 + strlen(title1), f_secs, "time");
  654. X    (void) sprintf(title2 + strlen(title2), f_secs, "(sec)");
  655. X    (void) sprintf(ruler + strlen(ruler), fo_secs, 10.01);
  656. X    }
  657. X    if (nhosts > 1) {
  658. X    (void) sprintf(title1 + strlen(title1), f_h, "");
  659. X    (void) sprintf(title2 + strlen(title2), f_h, "host");
  660. X    (void) sprintf(ruler + strlen(ruler), f_h,
  661. X               "127.000.000.001");
  662. X    }
  663. X    if (opts & O_UP) {
  664. X    (void) sprintf(title1 + strlen(title1), f_up, "");
  665. X    (void) sprintf(title2 + strlen(title2), f2_up, "uptime");
  666. X    (void) sprintf(ruler + strlen(ruler), f_up, "365 days, 23:59 ");
  667. X    }
  668. X    if (opts & O_CP) {
  669. X    (void) sprintf(title1 + strlen(title1), f1_cp, "%cpu");
  670. X    (void) sprintf(title1 + strlen(title1), f1_av, "loadavg (nrun)");
  671. X    (void) sprintf(title2 + strlen(title2), f2_cp, "us", "ni", "sy", "id");
  672. X    (void) sprintf(title2 + strlen(title2), f2_av, "1m", "5m", "15m");
  673. X    (void) sprintf(ruler + strlen(ruler), fr_cp, "100", "100", "100", "100");
  674. X    (void) sprintf(ruler + strlen(ruler), fo_a0, 10.00, 10.00, 10.00);
  675. X    }
  676. X    if (opts & O_DK) {
  677. X    (void) sprintf(title1 + strlen(title1), f1_dk, "disk xfers");
  678. X    (void) sprintf(title2 + strlen(title2), f2_dk,
  679. X               "d0", "d1", "d2", "d3");
  680. X    (void) sprintf(ruler + strlen(ruler), fr_dk, "10", "10", "10", "10");
  681. X    }
  682. X    if (opts & O_VM) {
  683. X    (void) sprintf(title1 + strlen(title1), f1_vm,
  684. X               "pg", "pg", "sw", "sw", "cx", "in");
  685. X    (void) sprintf(title2 + strlen(title2), f2_vm,
  686. X               "in", "o", "in", "o", "sw", "tr");
  687. X    (void) sprintf(ruler + strlen(ruler), fr_vm, "10", "10", "10", "10", "100", "100");
  688. X    }
  689. X    if (opts & O_IF) {
  690. X    (void) sprintf(title1 + strlen(title1), f1_if,
  691. X               "i", "i", "o", "o", "co");
  692. X    (void) sprintf(title2 + strlen(title2), f2_if,
  693. X               "pk", "er", "pk", "er", "ll");
  694. X    (void) sprintf(ruler + strlen(ruler), fr_if, "10", "10", "10", "10", "10");
  695. X    }
  696. X    (void) sprintf(title1 + strlen(title1), "\n");
  697. X    (void) sprintf(title2 + strlen(title2), "\n");
  698. X    if (dbg_lvl >= 4) {
  699. X    (void) fprintf(stderr, "returning from build_title\n");
  700. X    }
  701. X    return;
  702. X}
  703. X
  704. Xchar           *
  705. Xcommon_suffix(tbl)
  706. X    struct datatbl *tbl;
  707. X{
  708. X    int             i;
  709. X    int             suflen = 0;
  710. X    char           *dotp, *hp, *sp;
  711. X    char           *hname;
  712. X    static char     suffix[256];
  713. X
  714. X    /* determine the longest common suffix starting with a '.' */
  715. X    if (dbg_lvl >= 4) {
  716. X    (void) fprintf(stderr, "in common_suffix\n");
  717. X    }
  718. X    suffix[0] = '\0';
  719. X    for (i = 0; i < nprint; ++i) {
  720. X    hname = tbl[i].dp->host_dup;
  721. X
  722. X    if (strcmp(hname, "localhost") == 0)
  723. X        continue;
  724. X
  725. X    if (!isalpha(*hname))
  726. X        continue;
  727. X    if (!suffix[0]) {
  728. X        dotp = strchr(hname, '.');
  729. X        if (dotp) {
  730. X        (void) strcpy(suffix, dotp);
  731. X        suflen = strlen(suffix);
  732. X        }
  733. X    }
  734. X    sp = suffix + suflen - 1;
  735. X    hp = hname + strlen(hname) - 1;
  736. X    while (sp >= suffix && hp >= hname && *sp == *hp)
  737. X        --sp, --hp;
  738. X
  739. X    dotp = strchr(hp + 1, '.');
  740. X    if (!dotp) {
  741. X        *suffix = '\0';
  742. X        if (dbg_lvl >= 4) {
  743. X        (void) fprintf(stderr,
  744. X                   "returning from common_suffix (!dotp)\n");
  745. X        }
  746. X        return suffix;
  747. X    }
  748. X    if (sp > suffix) {
  749. X        (void) strcpy(suffix, dotp);
  750. X        suflen = strlen(suffix);
  751. X    }
  752. X    }
  753. X    if (dbg_lvl >= 4) {
  754. X    (void) fprintf(stderr, "returning from common_suffix\n");
  755. X    }
  756. X    return suffix;
  757. X}
  758. X
  759. X/**
  760. X * remove common suffix from hostnames
  761. X * by sreiz@aie.nl (Steven Reiz)
  762. X**/
  763. Xvoid
  764. Xstrip_hostnames(tbl)
  765. X    struct datatbl *tbl;
  766. X{
  767. X    int             i, suflen, maxlen;
  768. X    char           *p;
  769. X    char           *suffix;
  770. X
  771. X    static int      oldmaxlen;
  772. X
  773. X    if (dbg_lvl >= 4) {
  774. X    (void) fprintf(stderr, "in strip_hostnames\n");
  775. X    }
  776. X    if (opts & O_NHOST) {
  777. X    if (dbg_lvl >= 4) {
  778. X        (void) fprintf(stderr,
  779. X               "returning from strip_hostnames (opts & O_NHOST)\n");
  780. X    }
  781. X    return;
  782. X    }
  783. X    suffix = common_suffix(tbl);
  784. X    suflen = strlen(suffix);
  785. X    if (dbg_lvl >= 1)
  786. X    (void) fprintf(stderr, "suffix %s\n", suffix);
  787. X    /* remove the suffix */
  788. X    maxlen = 4;            /* length of the "host" header string */
  789. X    for (i = 0; i < nprint; ++i) {
  790. X    int             oldplen, newplen;
  791. X
  792. X    (void) strcpy(tbl[i].dp->host, tbl[i].dp->host_dup);
  793. X    p = tbl[i].dp->host;
  794. X    if (strcmp(p, "localhost") == 0)
  795. X        continue;
  796. X    if (!isalpha(p[0]))
  797. X        continue;
  798. X    oldplen = strlen(p);
  799. X    newplen = oldplen - suflen;
  800. X    p[newplen] = '\0';
  801. X    maxlen = Max(maxlen, newplen);
  802. X    }
  803. X    /* set f_h */
  804. X    maxlen = Min(maxlen, 12);    /* never longer than default */
  805. X    if (oldmaxlen != maxlen) {
  806. X    oldmaxlen = maxlen;
  807. X    (void) sprintf(f_h, "%%%d.%ds ", maxlen, maxlen);
  808. X    /* rebuild title */
  809. X    build_title();
  810. X    }
  811. X    if (dbg_lvl >= 4) {
  812. X    (void) fprintf(stderr, "returning from strip_hostnames\n");
  813. X    }
  814. X}
  815. X
  816. X/**
  817. X * print the statistics or the uptime
  818. X**/
  819. Xvoid
  820. Xprint_data(tbl, flag)
  821. X    struct datatbl *tbl;
  822. X    int             flag;
  823. X{
  824. X    long            up, upd, uph, upm;
  825. X    float           s = 0.0;
  826. X    int             i;
  827. X    char           *out;
  828. X    char            obuf[160];
  829. X    char            fo_bf[32];
  830. X
  831. X    if (dbg_lvl >= 4) {
  832. X    (void) fprintf(stderr, "in print_data\n");
  833. X    }
  834. X    if (opts & O_SECS && flag == P_DATA) {
  835. X    struct timeval  now;
  836. X    if (gettimeofday(&now, (struct timezone *) NULL) == -1) {
  837. X        perror("gettimeofday");
  838. X        exit(1);
  839. X    }
  840. X    s = (now.tv_sec - starttime.tv_sec)
  841. X        + ((now.tv_usec - starttime.tv_usec) + 5000)
  842. X        / 10000 / 100.;
  843. X    }
  844. X    for (i = 0; i < nprint; i++) {
  845. X    if (!tbl[i].dp->no && flag == P_DATA)    /* do we have delta? */
  846. X        continue;
  847. X    if (tbl[i].dp->no && flag == P_UP)    /* do we have delta? */
  848. X        continue;
  849. X    if (tbl[i].dp->no
  850. X        && t_n(i).if_ipackets < t_o(i).if_ipackets) {
  851. X        if (dbg_lvl >= 1) {
  852. X        (void) fprintf(stderr, "%s was rebooted.\n", tbl[i].dp->host);
  853. X        }
  854. X        continue;
  855. X    }
  856. X    obuf[0] = '\0';
  857. X    if (opts & O_TIME && flag == P_DATA)
  858. X        (void) sprintf(obuf + strlen(obuf), fo_time,
  859. X               t_n(i).curtime.tv_sec);
  860. X    if (opts & O_DATE && flag == P_DATA) {
  861. X        char            buf[30];
  862. X        struct tm      *tp;
  863. X
  864. X        tp = localtime((long *) &t_n(i).curtime.tv_sec);
  865. X        if (!strftime(buf, 30, "%y%m%d %H:%M:%S ", tp)) {
  866. X        (void) fputs("can't convert date\n", stderr);
  867. X        exit(1);
  868. X        }
  869. X        (void) sprintf(obuf + strlen(obuf), f_date, buf);
  870. X    }
  871. X    if (opts & O_SECS && flag == P_DATA)
  872. X        (void) sprintf(obuf + strlen(obuf), fo_secs, s);
  873. X
  874. X    if (nhosts > 1 || mode == MODE_BCST || flag == P_UP)
  875. X        (void) sprintf(obuf + strlen(obuf),
  876. X               (isalpha(*tbl[i].dp->host) ? f_h : f_haddr),
  877. X               tbl[i].dp->host);
  878. X
  879. X    if (opts & O_UP || flag == P_UP) {
  880. X        if (t_n(i).boottime.tv_sec) {    /* > vers 1 ) */
  881. X        up = t_d(i).boottime.tv_sec;    /* uptime stored here */
  882. X        upd = up / 86400;
  883. X        up = Abs(up - upd * 86400);
  884. X        uph = up / 3600;
  885. X        up -= uph * 3600;
  886. X        upm = up / 60;
  887. X        if (flag == P_UP)
  888. X            (void) sprintf(obuf + strlen(obuf), "up ");
  889. X        switch (upd) {
  890. X        case 0:
  891. X            (void) sprintf(obuf + strlen(obuf), "          ");
  892. X            break;
  893. X        case 1:
  894. X            (void) sprintf(obuf + strlen(obuf), "%3d day,  ", upd);
  895. X            break;
  896. X        default:
  897. X            (void) sprintf(obuf + strlen(obuf), "%3d days, ", upd);
  898. X            break;
  899. X        }        /* switch upd */
  900. X        (void) sprintf(obuf + strlen(obuf), "%2d:%02d", uph, upm);
  901. X        if (flag == P_UP)
  902. X            (void) sprintf(obuf + strlen(obuf), ",");
  903. X        (void) sprintf(obuf + strlen(obuf), " ");
  904. X        } else {        /* vers 1 ) */
  905. X        (void) sprintf(obuf + strlen(obuf), f_up, "-");
  906. X        }
  907. X    }
  908. X    /**
  909. X     * macros to control what to print:
  910. X     * data or '-'
  911. X     *
  912. X     * use these macros with care
  913. X    **/
  914. X#define on_nzero(a) (t_o(i).a && t_n(i).a)    /* old and new nonzero */
  915. X#define f_nzero2(a) (on_nzero(a) ? "%2d" : " %c")
  916. X#define f_nzero3(a) (on_nzero(a) ? "%3d" : "  %c")
  917. X#define d_nzero(a) (on_nzero(a) ? t_d(i).a : '-')
  918. X
  919. X    if (opts & O_CP && flag == P_DATA) {
  920. X        (void) sprintf(fo_bf, fr_cp,
  921. X               f_nzero3(cp_val[CP_USER]),
  922. X               f_nzero3(cp_val[CP_NICE]),
  923. X               f_nzero3(cp_val[CP_SYS]),
  924. X               f_nzero3(cp_val[CP_IDLE]));
  925. X        (void) sprintf(obuf + strlen(obuf), fo_bf,
  926. X               d_nzero(cp_val[CP_USER]),
  927. X               d_nzero(cp_val[CP_NICE]),
  928. X               d_nzero(cp_val[CP_SYS]),
  929. X               d_nzero(cp_val[CP_IDLE]));
  930. X    }
  931. X    if (opts & O_CP || flag == P_UP) {
  932. X        /* average run queue lengths */
  933. X        if (t_n(i).boottime.tv_sec) {    /* > vers 1 */
  934. X        if (flag == P_UP)
  935. X            (void) sprintf(obuf + strlen(obuf),
  936. X                   "     load average: ");
  937. X        /* average run queue lengths */
  938. X        (void) sprintf(obuf + strlen(obuf),
  939. X                   flag == P_UP ? fo_av : fo_a0,
  940. X                   loadav(t_n(i).avenrun[AV1]),
  941. X                   loadav(t_n(i).avenrun[AV5]),
  942. X                   loadav(t_n(i).avenrun[AV15]));
  943. X        } else {        /* vers 1 */
  944. X        (void) sprintf(obuf + strlen(obuf),
  945. X                   f2_av, "-", "-", "-");
  946. X        }
  947. X    }
  948. X    if (opts & O_DK && flag == P_DATA) {
  949. X        (void) sprintf(fo_bf, fr_dk,
  950. X               f_nzero2(dk_val[0]),
  951. X               f_nzero2(dk_val[1]),
  952. X               f_nzero2(dk_val[2]),
  953. X               f_nzero2(dk_val[3]));
  954. X        (void) sprintf(obuf + strlen(obuf), fo_bf,
  955. X               d_nzero(dk_val[0]),
  956. X               d_nzero(dk_val[1]),
  957. X               d_nzero(dk_val[2]),
  958. X               d_nzero(dk_val[3]));
  959. X    }
  960. X    if (opts & O_VM && flag == P_DATA) {
  961. X        (void) sprintf(fo_bf, fr_vm,
  962. X               f_nzero2(v_pgpgin),
  963. X               f_nzero2(v_pgpgout),
  964. X               f_nzero2(v_pswpin),
  965. X               f_nzero2(v_pswpout),
  966. X               f_nzero3(v_swtch),
  967. X               f_nzero3(v_intr));
  968. X        (void) sprintf(obuf + strlen(obuf), fo_bf,
  969. X               d_nzero(v_pgpgin),
  970. X               d_nzero(v_pgpgout),
  971. X               d_nzero(v_pswpin),
  972. X               d_nzero(v_pswpout),
  973. X               d_nzero(v_swtch),
  974. X               d_nzero(v_intr));
  975. X    }
  976. X    if (opts & O_IF && flag == P_DATA) {
  977. X        (void) sprintf(fo_bf, fr_if,
  978. X               f_nzero2(if_ipackets),
  979. X               f_nzero2(if_ierrors),
  980. X               f_nzero2(if_opackets),
  981. X               f_nzero2(if_oerrors),
  982. X               f_nzero2(if_collisions));
  983. X        (void) sprintf(obuf + strlen(obuf), fo_bf,
  984. X               d_nzero(if_ipackets),
  985. X               d_nzero(if_ierrors),
  986. X               d_nzero(if_opackets),
  987. X               d_nzero(if_oerrors),
  988. X               d_nzero(if_collisions));
  989. X    }
  990. X    if (flag == P_DATA) {
  991. X        out = adjust_line(obuf);
  992. X    } else {
  993. X        out = obuf;
  994. X    }            /* switch flag */
  995. X
  996. X    (void) fputs(out, stdout);
  997. X    (void) putc('\n', stdout);
  998. X
  999. X    if (opts & O_CP && flag == P_DATA) {
  1000. X        int             c, chigh = 0, morestates = 0;
  1001. X
  1002. X        for (c = CPUSTATES;
  1003. X         c < Min(t_n(i).cp_len, t_o(i).cp_len); c++) {
  1004. X        static          cp_len_flag;
  1005. X        if (dbg_lvl >= 1 && !cp_len_flag) {
  1006. X            (void) fprintf(stderr,
  1007. X            "%s: cp_len > 4.  rperf cannot handle this case yet.\n",
  1008. X                   tbl[i].dp->host);
  1009. X            cp_len_flag = 1;
  1010. X        }
  1011. X        if (on_nzero(cp_val[c])) {
  1012. X            chigh = c;
  1013. X            morestates++;
  1014. X        }
  1015. X        }
  1016. X        if (morestates > 0) {
  1017. X        (void) fprintf(stdout, "%d more cpu states%s...",
  1018. X                   morestates, morestates == 1 ? "" : "s");
  1019. X        for (c = CPUSTATES; c <= chigh; c++)
  1020. X            if (on_nzero(cp_val[c]))
  1021. X            (void) fprintf(stdout,
  1022. X                  "  cpu state%d: %d", c, t_d(i).cp_val[c]);
  1023. X        (void) putc('\n', stdout);
  1024. X        }
  1025. X    }
  1026. X    if (opts & O_DK && flag == P_DATA) {
  1027. X        int             d, dhigh = 0, moredisks = 0;
  1028. X
  1029. X        for (d = DK_NDRIVE;
  1030. X         d < Min(t_n(i).dk_len, t_o(i).dk_len); d++) {
  1031. X        if (on_nzero(dk_val[d])) {
  1032. X            dhigh = d;
  1033. X            moredisks++;
  1034. X        }
  1035. X        }
  1036. X        if (moredisks > 0) {
  1037. X        (void) fprintf(stdout, "%d more disk%s...",
  1038. X                   moredisks, moredisks == 1 ? "" : "s");
  1039. X        for (d = DK_NDRIVE; d <= dhigh; d++)
  1040. X            if (on_nzero(dk_val[d]))
  1041. X            (void) fprintf(stdout,
  1042. X                       "  disk%d: %d", d, t_d(i).dk_val[d]);
  1043. X        (void) putc('\n', stdout);
  1044. X        }
  1045. X    }
  1046. X    }
  1047. X    if (dbg_lvl >= 4) {
  1048. X    (void) fprintf(stderr, "returning from print_data\n");
  1049. X    }
  1050. X}
  1051. X
  1052. X/**
  1053. X * If we are sorting, delete hosts which have had zero counts since boot
  1054. X * time.  They may not be capable of reporting that statistic
  1055. X**/
  1056. Xvoid
  1057. Xdelete_zeros()
  1058. X{
  1059. X    struct data   **dpp;
  1060. X
  1061. X    if (dbg_lvl >= 4) {
  1062. X    (void) fprintf(stderr, "in delete_zeros\n");
  1063. X    }
  1064. X    if (!key_ptr) {
  1065. X    if (dbg_lvl >= 4) {
  1066. X        (void) fprintf(stderr, "returning from delete_zeros (!key_ptr)\n");
  1067. X    }
  1068. X    return;
  1069. X    }
  1070. X    for (dpp = &dp; *dpp; dpp = &(*dpp)->datap) {
  1071. X
  1072. X    if (!(*dpp)->nn)
  1073. X        continue;
  1074. X
  1075. X    if (key_ptr->k_noffset == sn_offset(cp_time)
  1076. X        && (*dpp)->cp_kind == CP_TIME_INC)
  1077. X        continue;
  1078. X
  1079. X    if (key_ptr->k_flag & K_NZERO) {
  1080. X        int             val;
  1081. X        val = *(int *) ((char *) (*dpp) + key_ptr->k_noffset);
  1082. X        if (!val) {
  1083. X        if (dbg_lvl >= 1) {
  1084. X            (void) fprintf(stderr,
  1085. X                  "%s: rpc.rstatd vers %d does not report %s\n",
  1086. X              (*dpp)->host, (*dpp)->bcst_vers, key_ptr->k_name);
  1087. X        }
  1088. X        (*dpp)->nn = 0;    /* mark as not received */
  1089. X        continue;
  1090. X        }
  1091. X    }            /* K_NZERO */
  1092. X    if (key_ptr->k_flag & K_DELTA) {
  1093. X        int             sinceboot;
  1094. X        if (key_ptr->k_flag & K_ARRAY) {
  1095. X        array           arr;
  1096. X
  1097. X        arr = *(array *) ((char *) (*dpp) + key_ptr->k_noffset);
  1098. X        sinceboot = arr.val[key_ptr->k_index];
  1099. X        } else {
  1100. X        sinceboot = *(int *) ((char *) (*dpp) + key_ptr->k_noffset);
  1101. X        }
  1102. X        if (!sinceboot) {
  1103. X        if (dbg_lvl >= 1)
  1104. X            (void) fprintf(stderr,
  1105. X                " %s zero %s events since boot.  ignore.\n",
  1106. X                   (*dpp)->host, key_ptr->k_name);
  1107. X        (*dpp)->nn = 0;    /* mark as not received */
  1108. X        }
  1109. X    }            /* K_DELTA */
  1110. X    }                /* for dpp */
  1111. X    if (dbg_lvl >= 4) {
  1112. X    (void) fprintf(stderr, "returning from delete_zeros\n");
  1113. X    }
  1114. X}
  1115. X
  1116. X/**
  1117. X * If possible, increase the user's file descriptor table size to the maximum
  1118. X * allowable by the system, or to a very large number.
  1119. X *
  1120. X * In any case, return the file descriptor table size.
  1121. X**/
  1122. Xint
  1123. Xset_max_nofiles()
  1124. X{
  1125. X    static struct Rlimit nofiles;
  1126. X
  1127. X#ifdef RLIMIT_NOFILE
  1128. X    if (getrlimit(RLIMIT_NOFILE, &nofiles) == -1) {
  1129. X    (void) perror("getrlimit");
  1130. X    exit(1);
  1131. X    }
  1132. X    nofiles.rlim_cur = nofiles.rlim_max;
  1133. X    if (setrlimit(RLIMIT_NOFILE, &nofiles) == -1) {
  1134. X    (void) perror("setrlimit");
  1135. X    /* don't exit -- just use existing limit */
  1136. X    }
  1137. X    if (getrlimit(RLIMIT_NOFILE, &nofiles) == -1) {
  1138. X    (void) perror("getrlimit");
  1139. X    exit(1);
  1140. X    }
  1141. X#else                /* !RLIMIT_NOFILE */
  1142. X#ifdef HAVE_SETDTABLESIZE
  1143. X    /* thanks -- Ric Anderson <ric@cs.arizona.edu> */
  1144. X    nofiles.rlim_cur = setdtablesize(1000 /* huge */ );
  1145. X    if (nofiles.rlim_cur == -1) {
  1146. X    (void) perror("setdtablesize");
  1147. X    /* don't exit -- just use existing limit */
  1148. X    }
  1149. X#else                /* !HAVE_SETDTABLESIZE */
  1150. X#ifdef HAVE_UNISTD_H
  1151. X    /* thanks -- Colin M. Clark <cmc@srg-ssr.ch> */
  1152. X    nofiles.rlim_cur = sysconf(_SC_OPEN_MAX);
  1153. X    if (nofiles.rlim_cur == -1) {
  1154. X    (void) perror("sysconf");
  1155. X    exit(1);
  1156. X    }
  1157. X#else                /* !HAVE_UNISTD_H */
  1158. X    nofiles.rlim_cur = getdtablesize();
  1159. X#endif                /* !HAVE_UNISTD_H */
  1160. X#endif                /* !HAVE_SETDTABLESIZE */
  1161. X#endif                /* !RLIMIT_NOFILE */
  1162. X
  1163. X    if (dbg_lvl >= 1)
  1164. X    (void) fprintf(stderr, "Open file descriptor limit now %d\n",
  1165. X               nofiles.rlim_cur);
  1166. X    return nofiles.rlim_cur;
  1167. X}
  1168. X
  1169. Xvoid
  1170. Xdumplist()
  1171. X{
  1172. X    int             i = 0;
  1173. X    int             d;
  1174. X    struct data   **dpp;
  1175. X    char           *dotquad;
  1176. X
  1177. X    (void) fprintf(stdout, "\nexpecting %d hosts\n", nhosts);
  1178. X
  1179. X    for (dpp = &dp; *dpp; dpp = &(*dpp)->datap) {
  1180. X    (void) fprintf(stdout, "%2d/%2d ", ++i, nhosts);
  1181. X    (void) fprintf(stdout, "%s %s\n", (*dpp)->host_dup, (*dpp)->host);
  1182. X    dotquad = inet_ntoa((*dpp)->addr);
  1183. X    (void) fputs(dotquad, stdout);
  1184. X    (void) fprintf(stdout, "\t*dpp=0x%08x (*dpp)->datap=0x%08x\n",
  1185. X               (u_long) (*dpp), (u_long) (*dpp)->datap);
  1186. X    (void) fputs(dotquad, stdout);
  1187. X    (void) fprintf(stdout,
  1188. X          "\tno=%d, nn=%d, clnt_vers=%d, bcst_vers=%d, ok_to_call=%d\n",
  1189. X               (*dpp)->no,
  1190. X               (*dpp)->nn,
  1191. X               (*dpp)->clnt_vers,
  1192. X               (*dpp)->bcst_vers,
  1193. X               (*dpp)->ok_to_call);
  1194. X
  1195. X    (void) fputs(dotquad, stdout);
  1196. X    if ((*dpp)->sn.cp_val) {
  1197. X        (void) fprintf(stdout, "\tcp_time\t%08x %08x %08x %08x\n",
  1198. X               (*dpp)->sn.cp_val[CP_USER],
  1199. X               (*dpp)->sn.cp_val[CP_NICE],
  1200. X               (*dpp)->sn.cp_val[CP_SYS],
  1201. X               (*dpp)->sn.cp_val[CP_IDLE]);
  1202. X    } else {
  1203. X        (void) fprintf(stdout, "\tcp_val = NULL\n");
  1204. X    }
  1205. X
  1206. X    (void) fputs(dotquad, stdout);
  1207. X    (void) fprintf(stdout, "\tavenrun\t%08x %08x %08x\n",
  1208. X               (*dpp)->sn.avenrun[AV1],
  1209. X               (*dpp)->sn.avenrun[AV5],
  1210. X               (*dpp)->sn.avenrun[AV15]);
  1211. X
  1212. X    (void) fputs(dotquad, stdout);
  1213. X    if ((*dpp)->sn.dk_val) {
  1214. X        (void) fprintf(stdout, "\tdk_xfer\t%08x %08x %08x %08x\n",
  1215. X               (*dpp)->sn.dk_val[0],
  1216. X               (*dpp)->sn.dk_val[1],
  1217. X               (*dpp)->sn.dk_val[2],
  1218. X               (*dpp)->sn.dk_val[3]);
  1219. X    } else {
  1220. X        (void) fprintf(stdout, "\tdk_val = NULL\n");
  1221. X    }
  1222. X
  1223. X    for (d = DK_NDRIVE; d < (*dpp)->sn.dk_len; d += 4) {
  1224. X        int             e;
  1225. X
  1226. X        (void) fputs(dotquad, stdout);
  1227. X        (void) fprintf(stdout, "\t.....dk\t");
  1228. X        for (e = 0; e < Min((*dpp)->sn.dk_len - d, 4); e++) {
  1229. X        (void) fprintf(stdout, " %08x", (*dpp)->sn.dk_val[d + e]);
  1230. X        }
  1231. X        (void) putc('\n', stdout);
  1232. X    }
  1233. X
  1234. X    (void) fputs(dotquad, stdout);
  1235. X    (void) fprintf(stdout, "\tvm\t%08x %08x %08x %08x %08x %08x\n",
  1236. X               (*dpp)->sn.v_pgpgin,
  1237. X               (*dpp)->sn.v_pgpgout,
  1238. X               (*dpp)->sn.v_pswpin,
  1239. X               (*dpp)->sn.v_pswpout,
  1240. X               (*dpp)->sn.v_swtch,
  1241. X               (*dpp)->sn.v_intr);
  1242. X    (void) fputs(dotquad, stdout);
  1243. X    (void) fprintf(stdout, "\tif\t%08x %08x %08x %08x %08x\n",
  1244. X               (*dpp)->sn.if_ipackets,
  1245. X               (*dpp)->sn.if_ierrors,
  1246. X               (*dpp)->sn.if_opackets,
  1247. X               (*dpp)->sn.if_oerrors,
  1248. X               (*dpp)->sn.if_collisions);
  1249. X    }
  1250. X    (void) fprintf(stdout, "end of dump\n");
  1251. X}
  1252. X
  1253. XRETSIGTYPE
  1254. Xillhdlr()
  1255. X{
  1256. X    (void) fprintf(stderr, "Illegal instruction\n");
  1257. X    dumplist();
  1258. X    (void) fprintf(stderr, "exiting from illhdlr\n");
  1259. X    exit(1);
  1260. X}
  1261. X
  1262. XRETSIGTYPE
  1263. Xsegvhdlr()
  1264. X{
  1265. X    (void) fprintf(stderr, "Segmentation fault\n");
  1266. X    dumplist();
  1267. X    (void) fprintf(stderr, "exiting from segvhdlr\n");
  1268. X    exit(1);
  1269. X}
  1270. X
  1271. X/**
  1272. X * line-buffer the output
  1273. X * permits "tail -f" of a growing log file or a pipe
  1274. X **/
  1275. Xvoid
  1276. Xlinebuf_stdout()
  1277. X{
  1278. X#ifdef HAVE_SETLINEBUF
  1279. X    (void) setlinebuf(stdout);
  1280. X#else                /* !HAVE_SETLINEBUF */
  1281. X    errno = 0;
  1282. X#ifdef SETVBUF_REVERSED
  1283. X    if (setvbuf(stdout, _IOLBF, (char *) NULL, BUFSIZ))
  1284. X#else                /* !SETVBUF_REVERSED */
  1285. X    if (setvbuf(stdout, (char *) NULL, _IOLBF, BUFSIZ))
  1286. X#endif                /* !SETVBUF_REVERSED */
  1287. X    {
  1288. X    if (errno)
  1289. X        perror("setvbuf");
  1290. X    else
  1291. X        (void) fprintf(stderr, "setvbuf error\n");
  1292. X    exit(1);
  1293. X    }
  1294. X#endif                /* !HAVE_SETLINEBUF */
  1295. X}
  1296. X
  1297. X/**
  1298. X * initialize signal handlers
  1299. X * parse options
  1300. X * resolve host names
  1301. X * loop endlessly. either:
  1302. X *    do client calls
  1303. X *    or do broadcasts
  1304. X**/
  1305. Xint
  1306. Xmain(argc, argv)
  1307. X    int             argc;
  1308. X    char           *argv[];
  1309. X{
  1310. X    u_long          vers_max;
  1311. X    u_long          nbcst_vers;
  1312. X    int             stdout_is_a_tty;
  1313. X    int             c_seen = 0;
  1314. X    int             do_uptime = 0;
  1315. X    int             n_ofiles;
  1316. X    int             opti;
  1317. X    int             c;
  1318. X    int             i_seen = 0;
  1319. X    unsigned        count = 0;
  1320. X    unsigned        interval = 10;
  1321. X    unsigned        bcst_interval;
  1322. X    unsigned        hdrcnt;
  1323. X    unsigned        telapse;
  1324. X    unsigned short  term_rows;
  1325. X    char           *optstring;
  1326. X    char           *basename;
  1327. X    struct data   **dpp;
  1328. X    struct datatbl *tbl;
  1329. X    struct timeval  time1, time2;
  1330. X
  1331. X    stdout_is_a_tty = isatty(STDOUT_FILENO);
  1332. X
  1333. X    tbl = NULL;
  1334. X    if (gettimeofday(&starttime, (struct timezone *) NULL) == -1) {
  1335. X    perror("gettimeofday");
  1336. X    exit(1);
  1337. X    }
  1338. X    (void) signal(SIGHUP, cleanup);
  1339. X    (void) signal(SIGINT, cleanup);
  1340. X    (void) signal(SIGTERM, cleanup);
  1341. X    (void) signal(SIGILL, illhdlr);
  1342. X    (void) signal(SIGSEGV, segvhdlr);
  1343. X
  1344. X    linebuf_stdout();
  1345. X    basename = strrchr(argv[0], '/');
  1346. X    basename = basename ? ++basename : argv[0];
  1347. X
  1348. X    opterr = 0;
  1349. X    if (strcmp(basename, "rup") == 0) {
  1350. X    vers_max = RSTATVERS_TIME;
  1351. X    optstring = "hltnD";
  1352. X    while ((c = getopt(argc, argv, optstring)) != -1) {
  1353. X        switch (c) {
  1354. X        case 'h':
  1355. X        opts |= O_SHOST;
  1356. X        break;
  1357. X        case 'l':
  1358. X        opts |= O_SORT | O_RVRS;
  1359. X        key_ptr = (key *) calloc(1, sizeof(key));
  1360. X        key_ptr->k_doffset = sn_offset(avenrun[AV1]);
  1361. X        break;
  1362. X        case 't':
  1363. X        opts |= O_SORT;
  1364. X        key_ptr = (key *) calloc(1, sizeof(key));
  1365. X        /* sd.boottime is uptime */
  1366. X        key_ptr->k_doffset = sd_offset(boottime.tv_sec);
  1367. X        break;
  1368. X        case 'n':
  1369. X        opts |= O_NHOST;
  1370. X        break;
  1371. X        case 'D':
  1372. X        opts |= O_DBG;
  1373. X        dbg_lvl++;
  1374. X        break;
  1375. X        case '?':
  1376. X        msg(rupusagev, stderr);
  1377. X        exit(1);
  1378. X        }
  1379. X    }
  1380. X    c_seen = 1;
  1381. X    count = 1;
  1382. X    do_uptime = 1;
  1383. X    opts |= O_NCLR;        /* never clear the screen in rup mode */
  1384. X    } else {            /* rperf */
  1385. X    vers_max = RSTATVERS_VAR;
  1386. X    optstring = "aAcdivhnSTsub1234BDrN";
  1387. X    while ((c = getopt(argc, argv, optstring)) != -1)
  1388. X        switch (c) {
  1389. X        case 'a':
  1390. X        opts |= O_MOST;
  1391. X        break;
  1392. X        case 'A':
  1393. X        opts |= O_ALL;    /* everything! */
  1394. X        break;
  1395. X        case 'c':
  1396. X        opts |= O_CP;
  1397. X        break;
  1398. X        case 'd':
  1399. X        opts |= O_DK;
  1400. X        break;
  1401. X        case 'i':
  1402. X        opts |= O_IF;
  1403. X        break;
  1404. X        case 'S':
  1405. X        opts |= O_TIME;
  1406. X        break;
  1407. X        case 'T':
  1408. X        opts |= O_DATE;
  1409. X        break;
  1410. X        case 's':
  1411. X        opts |= O_SECS;
  1412. X        break;
  1413. X        case 'h':
  1414. X        opts |= O_SHOST;
  1415. X        break;
  1416. X        case 'u':
  1417. X        opts |= O_UP;
  1418. X        break;
  1419. X        case 'n':
  1420. X        opts |= O_NHOST;
  1421. X        break;
  1422. X        case 'v':
  1423. X        opts |= O_VM;
  1424. X        break;
  1425. X        case 'b':
  1426. X        opts |= O_BCST;
  1427. X        break;
  1428. X        case '1':
  1429. X        vers_max = RSTATVERS_ORIG;
  1430. X        break;
  1431. X        case '2':
  1432. X        vers_max = RSTATVERS_SWTCH;
  1433. X        break;
  1434. X        case '3':
  1435. X        vers_max = RSTATVERS_TIME;
  1436. X        break;
  1437. X        case '4':
  1438. X        vers_max = RSTATVERS_VAR;
  1439. X        break;
  1440. X        case 'B':
  1441. X        opts |= O_BARE | O_NCLR;
  1442. X        break;
  1443. X        case 'r':
  1444. X        opts |= O_RVRS;
  1445. X        break;
  1446. X        case 'D':
  1447. X        opts |= O_DBG;
  1448. X        dbg_lvl++;
  1449. X        break;
  1450. X        case 'N':
  1451. X        opts |= O_NCLR;
  1452. X        break;
  1453. X        case '?':
  1454. X        verbosehelp();
  1455. X        }
  1456. X
  1457. X    if (!(opts & O_BARE))
  1458. X        do_uptime = 1;
  1459. X    }
  1460. X
  1461. X    init_termcap();
  1462. X
  1463. X    n_ofiles = set_max_nofiles();
  1464. X    {
  1465. X    /**
  1466. X     * Estimate size of hash table.
  1467. X     *
  1468. X     * The hash table gets filled with the ascii host address, the official
  1469. X     * host name, and alias host names.
  1470. X     *
  1471. X     * Machines with more than one interface get each address stored in the
  1472. X     * table, as replies are received from them.
  1473. X     *
  1474. X     * The table is used to for quick lookup when a broadcast reply is
  1475. X     * received, and to eliminate duplication for hosts with more than
  1476. X     * one network interface
  1477. X    **/
  1478. X    errno = 0;
  1479. X    if (!hcreate((unsigned) Max(2 * n_ofiles, 1031 /* big */ ))) {
  1480. X        if (errno)
  1481. X        perror("hcreate");
  1482. X        else
  1483. X        (void) fprintf(stderr, "Can't hcreate\n");
  1484. X        exit(1);
  1485. X    }
  1486. X    }
  1487. X
  1488. X    if (opts & O_NHOST)
  1489. X    (void) strcpy(f_h, f_haddr);
  1490. X
  1491. X    opti = optind;
  1492. X    while (argv[opti]) {
  1493. X    char           *oa;
  1494. X    long            l;
  1495. X
  1496. X    l = strtol(argv[opti], &oa, 0);
  1497. X    if (argv[opti] == oa || *oa) {
  1498. X        /* "mml0.meche.rpi.edu" or "128.113.14.20" or "+idle" */
  1499. X        if (*argv[opti] == '+') {
  1500. X        char           *sortkey;
  1501. X        key            *kp;
  1502. X
  1503. X        sortkey = argv[opti] + sizeof(char);
  1504. X        for (kp = keys; kp->k_name != NULL; kp++) {
  1505. X            if (strcmp(sortkey, kp->k_name) == 0) {
  1506. X            key_ptr = kp;
  1507. X            break;
  1508. X            }
  1509. X        }
  1510. X        if (!key_ptr) {
  1511. X            (void) fprintf(stderr, "unknown sort key: %s\n", sortkey);
  1512. X            msg(keyhelp, stderr);
  1513. X            exit(1);
  1514. X        }
  1515. X        if (vers_max < RSTATVERS_TIME) {
  1516. X            if (key_ptr->k_noffset == sn_offset(curtime.tv_sec)) {
  1517. X            (void) fprintf(stderr,
  1518. X                  "Cannot sort by %s in version %d of rstatd\n",
  1519. X                       sortkey, vers_max);
  1520. X            exit(1);
  1521. X            }
  1522. X        }
  1523. X        if (vers_max == RSTATVERS_ORIG) {
  1524. X            if (key_ptr->k_noffset == sn_offset(boottime.tv_sec)
  1525. X            || key_ptr->k_noffset == sn_offset(v_swtch)
  1526. X            || key_ptr->k_noffset == sn_offset(avenrun[AV1])
  1527. X            || key_ptr->k_noffset == sn_offset(avenrun[AV5])
  1528. X            || key_ptr->k_noffset == sn_offset(avenrun[AV15])) {
  1529. X            (void) fprintf(stderr,
  1530. X                  "Cannot sort by %s in version %d of rstatd\n",
  1531. X                       sortkey, vers_max);
  1532. X            exit(1);
  1533. X            }
  1534. X        }
  1535. X        opts |= O_SORT;
  1536. X        } else {
  1537. X        /* not a sort key.  Must be a host name or address */
  1538. X        mode = MODE_CALL;
  1539. X        }
  1540. X    } else {
  1541. X        /* arg is a decimal number */
  1542. X        if (!i_seen) {
  1543. X        if (l <= 0) {
  1544. X            (void) fprintf(stderr, "%s interval invalid\n",
  1545. X                   l ? "Negative" : "Zero");
  1546. X            exit(1);
  1547. X        }
  1548. X        interval = l;
  1549. X        i_seen = 1;
  1550. X        } else if (!c_seen) {
  1551. X        count = l + 1;    /* the user wants l data displays */
  1552. X        c_seen = 1;
  1553. X        } else {
  1554. X        /* third decimal argument */
  1555. X        (void) fprintf(stderr, "Unknown option %s\n", argv[opti]);
  1556. X        verbosehelp();
  1557. X        }
  1558. X    }
  1559. X    opti++;
  1560. X    }
  1561. X
  1562. X
  1563. X    if (mode == MODE_CALL) {
  1564. X    if (opts & O_BCST) {
  1565. X        (void) fprintf(stderr,
  1566. X             "Can't use -b and hostname arguments together.\n");
  1567. X        exit(1);
  1568. X    }
  1569. X    if (opts & O_NHOST) {
  1570. X        (void) fprintf(stderr,
  1571. X             "Can't use -n and hostname arguments together.\n");
  1572. X        exit(1);
  1573. X    }
  1574. X    if (opts & O_SHOST) {
  1575. X        (void) fprintf(stderr,
  1576. X             "Can't use -h and hostname arguments together.\n");
  1577. X        exit(1);
  1578. X    }
  1579. X    if (dbg_lvl >= 1)
  1580. X        (void) fputs("resolving host names\n", stderr);
  1581. X    opti = optind;
  1582. X    dpp = &dp;
  1583. X
  1584. X    while (argv[opti]) {
  1585. X        char           *oa;
  1586. X        u_long          host_address;
  1587. X
  1588. X        (void) strtol(argv[opti], &oa, 0);
  1589. X        if ((argv[opti] == oa || *oa) && *argv[opti] != '+') {
  1590. X        /* "mml0.meche.rpi.edu" or "128.113.14.20" */
  1591. X        struct in_addr  addr;
  1592. X        char           *hostname;
  1593. X        struct hostent *host_entry;
  1594. X
  1595. X        hostname = argv[opti];
  1596. X        host_entry = gethostbyname(hostname);
  1597. X        if (!host_entry) {    /* maybe he typed an address */
  1598. X            if (dbg_lvl >= 1)
  1599. X            (void) fputs("byname failed\n", stderr);
  1600. X#ifdef STRUCT_IN_ADDR_INET_ADDR
  1601. X            /**
  1602. X             * Data General.
  1603. X             * thanks mpc@mbs.linet.org (Mark Clements)
  1604. X            **/
  1605. X            {
  1606. X            struct in_addr  host_in_addr;
  1607. X            host_in_addr = inet_addr(hostname);
  1608. X            host_address = host_in_addr.s_addr;
  1609. X            }
  1610. X#else                /* u_long inet_addr(); */
  1611. X            host_address = inet_addr(hostname);
  1612. X#endif                /* u_long inet_addr(); */
  1613. X            if (host_address != -1) {
  1614. X            host_entry =
  1615. X                gethostbyaddr((char *) &host_address, 4, AF_INET);
  1616. X            if (!host_entry && dbg_lvl >= 1)
  1617. X                (void) fputs("byaddr failed\n", stderr);
  1618. X            } else if (dbg_lvl >= 1)
  1619. X            (void) fputs("inet_addr failed\n", stderr);
  1620. X        }
  1621. X        if (host_entry) {
  1622. X            bcopy(host_entry->h_addr,
  1623. X              (char *) &addr.s_addr,
  1624. X              host_entry->h_length);
  1625. X        }
  1626. X        /**
  1627. X         * maybe he typed a valid address anyway --
  1628. X        **/
  1629. X        if (!host_entry && (host_address != -1))
  1630. X            addr.s_addr = host_address;
  1631. X
  1632. X        if (host_entry || (host_address != -1)) {
  1633. X            /* host ok.  add to list */
  1634. X            if (dbg_lvl >= 1)
  1635. X            (void) fprintf(stderr, "%s\n", inet_ntoa(addr));
  1636. X            (*dpp) = new_host(&addr, hostname);
  1637. X            (*dpp)->datap = NULL;
  1638. X            dpp = &(*dpp)->datap;
  1639. X        } else {
  1640. X            (void) fprintf(stderr, "can't get address for %s\n",
  1641. X                   hostname);
  1642. X        }
  1643. X        }            /* a host argument */
  1644. X        opti++;
  1645. X    }
  1646. X    if (dbg_lvl >= 1)
  1647. X        (void) fprintf(stderr, "%d hosts\n", nhosts);
  1648. X    if (!nhosts)
  1649. X        exit(0);
  1650. X    }
  1651. X    switch (mode) {
  1652. X    case MODE_CALL:
  1653. X    if (!(opts & O_ALL)) {
  1654. X        if (nhosts == 1)
  1655. X        opts |= O_DEFL1;
  1656. X        else
  1657. X        opts |= O_DEFL;
  1658. X    }
  1659. X    build_title();
  1660. X    break;
  1661. X    case MODE_BCST:
  1662. X    if (!(opts & O_ALL)) {
  1663. X        opts |= O_DEFL;
  1664. X    }
  1665. X    nhosts = 2;
  1666. X    build_title();
  1667. X    nhosts = 0;
  1668. X    break;
  1669. X    }
  1670. X
  1671. X    if (vers_max == RSTATVERS_ORIG) {
  1672. X    if (opts & O_UP)
  1673. X        (void) fprintf(stderr,
  1674. X           "Warning, no uptime available in version 1 of rstatd\n");
  1675. X    if (opts & O_CP)
  1676. X        (void) fprintf(stderr,
  1677. X         "Warning, no load average available in version 1 of rstatd\n");
  1678. X    if (opts & O_VM)
  1679. X        (void) fprintf(stderr,
  1680. X          "Warning, no v_swtch available in version 1 of rstatd\n");
  1681. X    }
  1682. X    nbcst_vers = Max(0, (int) vers_max - (int) RSTATVERS_TIME) + 1;
  1683. X    bcst_interval = interval / nbcst_vers;
  1684. X
  1685. X    for (hdrcnt = 1;;) {    /* main loop */
  1686. X    thiscount++;
  1687. X
  1688. X    if (gettimeofday(&time1, (struct timezone *) NULL) == -1) {
  1689. X        perror("gettimeofday");
  1690. X        exit(1);
  1691. X    }
  1692. X    if (dbg_lvl >= 1)
  1693. X        (void) fprintf(stderr, "thiscount %d\n", thiscount);
  1694. X
  1695. X    if (mode == MODE_BCST && (thiscount == 1 || opts & O_BCST)) {
  1696. X        do_broadcast(vers_max, bcst_interval);
  1697. X    }
  1698. X    if (stdout_is_a_tty && nhosts > 1 && !(opts & O_NCLR))
  1699. X        clear();
  1700. X
  1701. X    doclnt_calls(vers_max);
  1702. X
  1703. X    if (dbg_lvl >= 3) {
  1704. X        dumplist();
  1705. X        (void) fprintf(stderr, "end of debug dump\n");
  1706. X    }
  1707. X    delete_zeros();
  1708. X    compute_data();
  1709. X    tbl = sort_data(tbl);
  1710. X    if (stdout_is_a_tty
  1711. X        && (!(opts & O_NCLR) || mode == MODE_CALL)) {
  1712. X        check_term(&term_rows, (unsigned short *) NULL);
  1713. X        if (term_rows)
  1714. X        nprint = Min(nresp, term_rows - 3);
  1715. X    } else
  1716. X        nprint = nresp;
  1717. X
  1718. X    strip_hostnames(tbl);
  1719. X
  1720. X    if (dbg_lvl >= 1)
  1721. X        (void) fprintf(stderr, "%d host%s\n",
  1722. X               nhosts, nhosts == 1 ? "" : "s");
  1723. X
  1724. X    if (do_uptime && vers_max > RSTATVERS_ORIG) {
  1725. X        print_data(tbl, P_UP);
  1726. X    }
  1727. X    if (thiscount > 1
  1728. X        && ((mode == MODE_CALL && (!--hdrcnt || nhosts > 1))
  1729. X        || (mode == MODE_BCST))) {
  1730. X        (void) fputs(title1, stdout);
  1731. X        (void) fputs(title2, stdout);
  1732. X        hdrcnt = Max(1, term_rows ? term_rows - 2 : 20);
  1733. X    }
  1734. X    if (thiscount > 1) {
  1735. X        print_data(tbl, P_DATA);
  1736. X    }
  1737. X    if (c_seen && !--count)
  1738. X        exit(0);
  1739. X
  1740. X    if (gettimeofday(&time2, (struct timezone *) NULL) == -1) {
  1741. X        perror("gettimeofday");
  1742. X        exit(1);
  1743. X    }
  1744. X    telapse = time2.tv_sec - time1.tv_sec;
  1745. X
  1746. X    if (interval > telapse)
  1747. X        (void) sleep(interval - telapse);
  1748. X
  1749. X    if (!(opts & O_BCST) && (mode == MODE_BCST) && thiscount == 1)
  1750. X        (void) sleep(interval);
  1751. X    }                /* main loop */
  1752. X}
  1753. END_OF_FILE
  1754. if test 47595 -ne `wc -c <'rperf.c'`; then
  1755.     echo shar: \"'rperf.c'\" unpacked with wrong size!
  1756. fi
  1757. # end of 'rperf.c'
  1758. fi
  1759. if test -f 'hsearch.c' -a "${1}" != "-c" ; then 
  1760.   echo shar: Will not clobber existing file \"'hsearch.c'\"
  1761. else
  1762. echo shar: Extracting \"'hsearch.c'\" \(3560 characters\)
  1763. sed "s/^X//" >'hsearch.c' <<'END_OF_FILE'
  1764. X/**
  1765. X * hsearch.c --- PD simple implementation of System V hsearch(3c) routine
  1766. X * It is by Arnold Robbins (arnold@skeeve.atl.ga.us) -- thanks!
  1767. X**/
  1768. X
  1769. X#include "hsearch.h"
  1770. X
  1771. Xstatic ELEMENT **Table = NULL;    /* pointer to dynamicly allocated table */
  1772. Xstatic int Num_elem = -1;    /* number of elements */
  1773. X
  1774. Xstatic int hashit();
  1775. X
  1776. X/*
  1777. X * table of primes just below 2^n, n=2..31 for use in finding the right prime
  1778. X * number to be the table size.  this table may be generally useful...
  1779. X */
  1780. X
  1781. Xstatic unsigned int primetab[] = {
  1782. X/*
  1783. X * comment these out, so that table will always have a minimal size...
  1784. X3, 7, 13, 31, 61,
  1785. X*/
  1786. X127, 251, 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071,
  1787. X262139, 524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393,
  1788. X67108859, 134217689, 268435399, 536870909, 1073741789, 2147483647
  1789. X};
  1790. X
  1791. X/* hcreate --- create a hash table at least how_many big */
  1792. X
  1793. Xint hcreate (how_many)
  1794. Xregister unsigned int how_many;
  1795. X{
  1796. X    register int i, j;
  1797. X
  1798. X    /*
  1799. X     * find first prime number >= how_many, and use it for table size
  1800. X     */
  1801. X
  1802. X    if (Num_elem != -1)    /* already a table out there */
  1803. X        hdestroy();    /* remove it */
  1804. X
  1805. X    j = sizeof (primetab) / sizeof (primetab[0]);
  1806. X    for (i = 0; i < j; i++)
  1807. X        if (primetab[i] >= how_many)
  1808. X            break;
  1809. X
  1810. X    if (i >= j)    /* how_many bigger than any prime we have, use it */
  1811. X        Num_elem = how_many;
  1812. X    else
  1813. X        Num_elem = primetab[i];
  1814. X
  1815. X    if ((Table = (ELEMENT **) calloc ((unsigned) Num_elem, sizeof (ELEMENT *))) == NULL)
  1816. X        return (0);
  1817. X    else
  1818. X        return (1);
  1819. X}
  1820. X
  1821. X/* idestroy --- destroy a single element on a chain */
  1822. X
  1823. Xstatic void idestroy (elem)
  1824. XELEMENT *elem;
  1825. X{
  1826. X    if (elem != NULL)
  1827. X    {
  1828. X        idestroy (elem->next);
  1829. X        free ((char *) elem);
  1830. X    }
  1831. X}
  1832. X
  1833. X/* hdestroy --- nuke the existing hash table */
  1834. X
  1835. Xvoid hdestroy()
  1836. X{
  1837. X    register unsigned int i;
  1838. X
  1839. X    if (Table != NULL)
  1840. X    {
  1841. X        /* free all the chains */
  1842. X        for (i = 0; i < Num_elem; i++)
  1843. X            idestroy (Table[i]);
  1844. X
  1845. X        /* now the table itself */
  1846. X        free ((char *) Table);
  1847. X        Num_elem = -1;
  1848. X        Table = NULL;
  1849. X    }
  1850. X}
  1851. X
  1852. X/* hsearch --- lookup or enter an item in the hash table */
  1853. X
  1854. XENTRY *hsearch (entry, action)
  1855. XENTRY entry;
  1856. XACTION action;
  1857. X{
  1858. X    ELEMENT e;
  1859. X    ELEMENT *ep = NULL;
  1860. X    ELEMENT *ep2 = NULL;
  1861. X    int hindex;
  1862. X
  1863. X    if (Table == NULL)
  1864. X        return (NULL);
  1865. X
  1866. X    hindex = hashit (entry.key);
  1867. X    if (Table[hindex] == NULL)    /* nothing there */
  1868. X    {
  1869. X        if (action == FIND)
  1870. X            return (NULL);
  1871. X        else
  1872. X        {
  1873. X            /* add it to the table */
  1874. X            e.item = entry;
  1875. X            e.next = NULL;
  1876. X            if ((Table[hindex] = (ELEMENT *) calloc (1, sizeof (ELEMENT))) == NULL)
  1877. X                return (NULL);
  1878. X            *Table[hindex] = e;
  1879. X            return (& Table[hindex]->item);
  1880. X        }
  1881. X    }
  1882. X    else
  1883. X    {
  1884. X        /* something in bucket, see if already on chain */
  1885. X        for (ep = Table[hindex]; ep != NULL; ep = ep->next)
  1886. X        {
  1887. X            if (strcmp (ep->item.key, entry.key) == 0)
  1888. X            {
  1889. X                if (action == ENTER)
  1890. X                    ep->item.data = entry.data;
  1891. X                    /* already there, just change data */
  1892. X                /* or action was just find it */
  1893. X                return (& ep->item);
  1894. X            }
  1895. X            else
  1896. X                ep2 = ep;
  1897. X        }
  1898. X        /* at this point, item was not in table */
  1899. X        /* ep2 points at last element on the list */
  1900. X        if (action == ENTER)
  1901. X        {
  1902. X            if ((ep2->next = (ELEMENT *) calloc (1, sizeof (ELEMENT))) == NULL)
  1903. X                return (NULL);
  1904. X            ep2->next->item = entry;
  1905. X            ep2->next->next = NULL;
  1906. X            return (& ep2->next->item);
  1907. X        }
  1908. X        else
  1909. X            return (NULL);
  1910. X    }
  1911. X    /*NOTREACHED*/
  1912. X}
  1913. X
  1914. X/* hashit --- do the hashing algorithm */
  1915. X
  1916. X/*
  1917. X * algorithm is sum of string elements, plus string length
  1918. X * mod table size.
  1919. X */
  1920. X
  1921. Xstatic int hashit (text)
  1922. Xregister char *text;
  1923. X{
  1924. X    register long int sum = 0;
  1925. X    register int i;
  1926. X
  1927. X    for (i = 0; text[i] != '\0'; i++)
  1928. X        sum += text[i];
  1929. X    sum += i;
  1930. X
  1931. X    return (sum % Num_elem);
  1932. X}
  1933. END_OF_FILE
  1934. if test 3560 -ne `wc -c <'hsearch.c'`; then
  1935.     echo shar: \"'hsearch.c'\" unpacked with wrong size!
  1936. fi
  1937. # end of 'hsearch.c'
  1938. fi
  1939. echo shar: End of archive 3 \(of 4\).
  1940. cp /dev/null ark3isdone
  1941. MISSING=""
  1942. for I in 1 2 3 4 ; do
  1943.     if test ! -f ark${I}isdone ; then
  1944.     MISSING="${MISSING} ${I}"
  1945.     fi
  1946. done
  1947. if test "${MISSING}" = "" ; then
  1948.     echo You have unpacked all 4 archives.
  1949.     echo "Now do 'sh ./configure' or 'sh ./configure -prefix=PATH' (Default = /usr/local)"
  1950.     rm -f ark[1-9]isdone
  1951. else
  1952.     echo You still need to unpack the following archives:
  1953.     echo "        " ${MISSING}
  1954. fi
  1955. ##  End of shell archive.
  1956. exit 0
  1957.  
  1958. exit 0 # Just in case...
  1959.