home *** CD-ROM | disk | FTP | other *** search
- /**
- * This program may be copied, redistributed in any form,
- * source or binary, and used for any purpose, provided
- * this copyright notice is retained.
- **/
- static char *copyright[] = {
- "@(#)rperf.c 3.1 12/15/93 (c) Copyright Brian P. Fitzgerald",
- "Rensselaer Polytechnic Institute",
- 0
- };
-
- /**
-
- rperf.c -- print system performance statistics.
-
- by Brian P. Fitzgerald
- Mechanics of Materials Laboratory
- Rensselaer Polytechnic Institute
- Troy, New York
-
- usage: rperf [ options ] [ interval [ count ] ] [ +sortkey ] [ host ... ]
- rup [ options ] [ interval ] [ host ... ]
-
- Send comments and bug fixes to fitz@rpi.edu. Please indicate the
- manufacturer and model of your computer, the name and version of your
- operating system and the version of rperf that you are using.
-
- Tested:
- 386BSD
- Alliant FX/2800
- Amiga 4.0 2.1c
- BSDi
- DEC Ultrix 4.2
- DG/UX v5.4.2
- EISA PC NetBSD-0.9
- ESIX 4.0.4 (configure script in development)
- HP-UX 8.0, 9.01
- IBM AIX 3.1, 3.2
- Linux 0.99p14 (minimum required)
- MIPS RISCos
- Motorola R40V4.1, FH32.31
- NeXT Mach 20
- SCO Unix 3.2.2
- SGI PI Iris 4.0.1, 4.0.2, 4.0.5
- SunOS 4.1.1, 4.1.2, 4.1.3, 5.2
-
- Not supported:
- AIX 1.2.1 on aix370
-
- Broadcast mode not supported:
- Linux 0.99p13
-
- Send reports of successful compilation on other platforms to
- fitz@rpi.edu
-
- History:
-
- 5/6/92 beta posted to alt.sources
-
- 5/18/92 1.1 Added multiple hosts, uptime display.
- Improved output format.
- posted to alt.sources
-
- 5/25/92 1.2 Added signal handler.
-
- 1/6/93 1.3 Added broadcast mode
-
- 2/6/93 1.4 Added output sorting options.
- Added rup alias.
-
- 2/10/93 1.5 Corrected rpc version mismatch. Now if_opackets right.
- Plugged some memory leaks.
-
- 3/5/93 1.6 Variable number of disks and cpu states.
- Fixed a line wrap problem. Added termcap routine.
- posted to alt.sources
-
- 8/26/93 2.1 posted to comp.sources.misc
-
- 9/13/93 2.2 Solaris 2 port
-
- 9/26/93 2.3 verbose help, setrlimit
- mailed to comp.sources.testers volunteers
-
- 10/26/93 2.4 fixed dk_xfer array problem
- fixed cp_time problem on AIX
- split up rperf.c
- broadcast over multiple versions
- use hash table for addresses
- used comments from testers -- thanks:
- hostname trim
- screen clear
- print '-' for unreported statistics
- eliminate duplication for routers
-
- 10/28/93 2.5 broadcast interval algorithm
-
- 11/2/93 2.6 debugging version to check each_result
-
- 11/10/93 2.7 mailed out to testers for review
-
- 11/17/93 2.8 always try to adjust lines longer than ruler
-
- 11/24/93 2.9 report when server has rebooted
-
- 12/15/93 3.1 posted to comp.sources.misc
-
- **/
-
- #include "common.h"
- #include "rperf.h"
- #include "term.h"
-
- key keys[] = {
- {"avg", sn_offset(avenrun[AV1]), sn_offset(avenrun[AV1]), 0, 0},
- {"ave", sn_offset(avenrun[AV1]), sn_offset(avenrun[AV1]), 0, 0},
- {"loadavg", sn_offset(avenrun[AV1]), sn_offset(avenrun[AV1]), 0, 0},
- {"loadave", sn_offset(avenrun[AV1]), sn_offset(avenrun[AV1]), 0, 0},
- {"loadav", sn_offset(avenrun[AV1]), sn_offset(avenrun[AV1]), 0, 0},
- {"load", sn_offset(avenrun[AV1]), sn_offset(avenrun[AV1]), 0, 0},
- {"avenrun", sn_offset(avenrun[AV1]), sn_offset(avenrun[AV1]), 0, 0},
- {"av1", sn_offset(avenrun[AV1]), sn_offset(avenrun[AV1]), 0, 0},
- {"av5", sn_offset(avenrun[AV5]), sn_offset(avenrun[AV5]), 0, 0},
- {"av15", sn_offset(avenrun[AV15]), sn_offset(avenrun[AV15]), 0, 0},
-
- {"boottime", sn_offset(boottime.tv_sec), sn_offset(boottime.tv_sec), K_NZERO, 0},
- {"boot", sn_offset(boottime.tv_sec), sn_offset(boottime.tv_sec), K_NZERO, 0},
- {"uptime", sn_offset(boottime.tv_sec), sd_offset(boottime.tv_sec), K_NZERO, 0},
- {"up", sn_offset(boottime.tv_sec), sd_offset(boottime.tv_sec), K_NZERO, 0},
-
- {"curtime", sn_offset(curtime.tv_sec), sn_offset(curtime.tv_sec), K_NZERO, 0},
- {"time", sn_offset(curtime.tv_sec), sn_offset(curtime.tv_sec), K_NZERO, 0},
- {"clock", sn_offset(curtime.tv_sec), sn_offset(curtime.tv_sec), K_NZERO, 0},
-
- {"user", sn_offset(cp_time), sd_offset(cp_time), K_DELTA | K_ARRAY, 0},
- {"us", sn_offset(cp_time), sd_offset(cp_time), K_DELTA | K_ARRAY, 0},
- {"nice", sn_offset(cp_time), sd_offset(cp_time), K_DELTA | K_ARRAY, 1},
- {"ni", sn_offset(cp_time), sd_offset(cp_time), K_DELTA | K_ARRAY, 1},
- {"sys", sn_offset(cp_time), sd_offset(cp_time), K_DELTA | K_ARRAY, 2},
- {"system", sn_offset(cp_time), sd_offset(cp_time), K_DELTA | K_ARRAY, 2},
- {"sy", sn_offset(cp_time), sd_offset(cp_time), K_DELTA | K_ARRAY, 2},
- {"idle", sn_offset(cp_time), sd_offset(cp_time), K_DELTA | K_ARRAY, 3},
- {"id", sn_offset(cp_time), sd_offset(cp_time), K_DELTA | K_ARRAY, 3},
-
- {"intr", sn_offset(v_intr), sd_offset(v_intr), K_DELTA, 0},
- {"swtch", sn_offset(v_swtch), sd_offset(v_swtch), K_DELTA, 0},
- {"cxsw", sn_offset(v_swtch), sd_offset(v_swtch), K_DELTA, 0},
- {"csw", sn_offset(v_swtch), sd_offset(v_swtch), K_DELTA, 0},
-
- {"pgpgin", sn_offset(v_pgpgin), sd_offset(v_pgpgin), K_DELTA, 0},
- {"pgin", sn_offset(v_pgpgin), sd_offset(v_pgpgin), K_DELTA, 0},
- {"pgpgout", sn_offset(v_pgpgout), sd_offset(v_pgpgout), K_DELTA, 0},
- {"pgout", sn_offset(v_pgpgout), sd_offset(v_pgpgout), K_DELTA, 0},
- {"pgo", sn_offset(v_pgpgout), sd_offset(v_pgpgout), K_DELTA, 0},
-
- {"pswpin", sn_offset(v_pswpin), sd_offset(v_pswpin), K_DELTA, 0},
- {"swpin", sn_offset(v_pswpin), sd_offset(v_pswpin), K_DELTA, 0},
- {"swin", sn_offset(v_pswpin), sd_offset(v_pswpin), K_DELTA, 0},
- {"pswpout", sn_offset(v_pswpout), sd_offset(v_pswpout), K_DELTA, 0},
- {"swpout", sn_offset(v_pswpout), sd_offset(v_pswpout), K_DELTA, 0},
- {"swo", sn_offset(v_pswpout), sd_offset(v_pswpout), K_DELTA, 0},
-
- {"dk_xfer", sn_offset(dk_xfer), sd_offset(dk_xfer), K_DELTA | K_ARRAY, 0},
- {"sd0", sn_offset(dk_xfer), sd_offset(dk_xfer), K_DELTA | K_ARRAY, 0},
- {"disk0", sn_offset(dk_xfer), sd_offset(dk_xfer), K_DELTA | K_ARRAY, 0},
- {"d0", sn_offset(dk_xfer), sd_offset(dk_xfer), K_DELTA | K_ARRAY, 0},
- {"sd1", sn_offset(dk_xfer), sd_offset(dk_xfer), K_DELTA | K_ARRAY, 1},
- {"disk1", sn_offset(dk_xfer), sd_offset(dk_xfer), K_DELTA | K_ARRAY, 1},
- {"d1", sn_offset(dk_xfer), sd_offset(dk_xfer), K_DELTA | K_ARRAY, 1},
- {"sd2", sn_offset(dk_xfer), sd_offset(dk_xfer), K_DELTA | K_ARRAY, 2},
- {"disk2", sn_offset(dk_xfer), sd_offset(dk_xfer), K_DELTA | K_ARRAY, 2},
- {"d2", sn_offset(dk_xfer), sd_offset(dk_xfer), K_DELTA | K_ARRAY, 2},
- {"sd3", sn_offset(dk_xfer), sd_offset(dk_xfer), K_DELTA | K_ARRAY, 3},
- {"disk3", sn_offset(dk_xfer), sd_offset(dk_xfer), K_DELTA | K_ARRAY, 3},
- {"d3", sn_offset(dk_xfer), sd_offset(dk_xfer), K_DELTA | K_ARRAY, 3},
-
- {"ipackets", sn_offset(if_ipackets), sd_offset(if_ipackets), K_DELTA, 0},
- {"ipk", sn_offset(if_ipackets), sd_offset(if_ipackets), K_DELTA, 0},
- {"ierrors", sn_offset(if_ierrors), sd_offset(if_ierrors), K_DELTA, 0},
- {"ier", sn_offset(if_ierrors), sd_offset(if_ierrors), K_DELTA, 0},
- {"oerrors", sn_offset(if_oerrors), sd_offset(if_oerrors), K_DELTA, 0},
- {"oer", sn_offset(if_oerrors), sd_offset(if_oerrors), K_DELTA, 0},
- {"opackets", sn_offset(if_opackets), sd_offset(if_opackets), K_DELTA, 0},
- {"opk", sn_offset(if_opackets), sd_offset(if_opackets), K_DELTA, 0},
- {"collisions", sn_offset(if_collisions), sd_offset(if_collisions), K_DELTA, 0},
- {"coll", sn_offset(if_collisions), sd_offset(if_collisions), K_DELTA, 0},
- {0, 0, 0, 0, 0}
- };
-
- key *key_ptr = NULL;
-
- /* xx keep up to date */
- char *rperfusagev[] = {
- "usage: rperf [ options ] [ interval [ count ]] [ +sortkey ] [ host ... ]",
- "rperf options:",
- "-a almost all (-cdiv) -S seconds in unix time",
- "-c cpu time, load average -T date and local time",
- "-d disk activity -s elapsed time, seconds",
- "-i ethernet activity -u uptime",
- "-v virtual memory -A all (-aSTsu)",
- "-1,-2,-3,-4 rstat version -b broadcast continuously",
- "-h sort by hostname -D debug (also -DD, -DDD, etc.)",
- "-n don't resolve hostnames -r reverse sort",
- "-N never clear the screen -B bare display. no headers",
- "-? verbose help (this message)",
- 0
- };
-
- /* xx keep up to date */
- char *rupusagev[] = {
- "rup [ options ] [ interval ] [ host ... ]",
- "-h sort by hostname -l sort by 1 min load avg",
- "-t sort by uptime -n don't resolve host names",
- "-D debug (also -DD, -DDD, etc.)",
- 0
- };
-
- /* xx keep up to date */
- char *keyhelp[] = {
- "The sort keys are:",
- "loadavg user pgpgin disk0 boottime ipackets",
- "av1 nice pgpgout disk1 uptime ierrors",
- "av5 sys pswpin disk2 curtime oerrors",
- "av15 idle pswpout disk3 opackets",
- " intr collisions",
- " swtch",
- 0
- };
-
- u_long nhosts = 0; /* multiple hosts idea from Larry McVoy */
- u_long mode = MODE_BCST; /* assume */
- u_long opts = 0;
- u_long thiscount = 0;
- u_long nresp = 0;
- u_long nprint = 0;
- u_long dbg_lvl = 0;
-
- struct timeval starttime;
-
- char *f1_cp = "%-15s ";
- char *f2_cp = "%3s %3s %3s %3s ";
- char *fr_cp = "%3s %3s %3s %3s ";
-
- char *f1_av = "%-14s ";
- char *f2_av = "%4s %4s %4s ";
- char *fo_av = "%4.2f %4.2f %4.2f ";
- char *fo_a0 = "%4.1f %4.1f %4.1f ";
-
- char *f1_dk = "%-12s";
- char *f2_dk = "%2s %2s %2s %2s ";
- char *fr_dk = "%2s %2s %2s %2s ";
-
- char *f1_vm = "%2s %2s %2s %2s %3s %3s ";
- char *f2_vm = "%2s %2s %2s %2s %3s %3s ";
- char *fr_vm = "%2s %2s %2s %2s %3s %3s ";
-
- char *f1_if = " %2s %2s %2s %2s %2s";
- char *f2_if = " %2s %2s %2s %2s %2s";
- char *fr_if = " %2s %2s %2s %2s %2s";
-
- char *f_time = "%-9.9s ";
- char *fo_time = "%9d ";
-
- char *f_date = "%-15.15s ";
-
- char *f_secs = "%-5.5s ";
- char *fo_secs = "%5.2f ";
-
- char *f2_up = "%15.15s ";
- char *f_up = "%-15.15s ";
-
- char *f_haddr = "%-15.15s ";
- char f_h[20] = "%12.12s ";
-
- char title1[160];
- char title2[160];
- char ruler[160];
-
- void
- msg(s, fp)
- char **s;
- FILE *fp;
- {
- while (*s) {
- (void) fputs(*s++, fp);
- (void) fputc('\n', fp);
- }
- }
-
- void
- verbosehelp()
- {
- msg(copyright, stderr);
- msg(rperfusagev, stderr);
- msg(keyhelp, stderr);
- msg(rupusagev, stderr);
- exit(0);
- }
-
- /**
- * handle termination signals
- **/
- RETSIGTYPE
- cleanup()
- {
- exit(0); /* flush and close stdout */
- }
-
- /**
- * Check whether the data line is longer than the ruler.
- * Try to adjust.
- * Return the adjusted string.
- **/
- char *
- adjust_line(obuf)
- char *obuf;
- {
- int olen = strlen(obuf);
- int rlen = strlen(ruler);
- int rpos = 0, opos;
- int nsp, err = 0;
- char *rp, *op, *tp, *sp, *cp;
-
- if (olen <= rlen) {
- if (olen < rlen && dbg_lvl >= 2) {
- (void) fprintf(stderr, "short line ruler=%d output%d\n",
- rlen, olen);
- (void) fputs(ruler, stderr);
- (void) putc('\n', stderr);
- }
- return obuf; /* leave alone */
- }
- if (dbg_lvl >= 2) {
- (void) fprintf(stderr, "line too long ruler=%d output%d\n",
- rlen, olen);
- (void) fputs(ruler, stderr);
- (void) putc('\n', stderr);
- }
- op = obuf;
- for (rp = ruler; *rp;) {
- tp = op;
- for (; *rp && *rp == ' '; rp++);
- for (; *op && *op == ' '; op++);
- nsp = op - tp;
- for (; *rp && *rp != ' '; rp++);
- for (; *op && *op != ' '; op++);
-
- if (!*rp || nsp > 1) {
- rpos = rp - ruler;
- opos = op - obuf;
- err = opos - rpos;
- }
- if (err > 0) {
- if (dbg_lvl >= 2) {
- (void) fputs(obuf, stderr);
- (void) putc('\n', stderr);
- (void) fprintf(stderr, "rpos=%d err=%d\n", rpos, err);
- }
- for (sp = op; sp != obuf; sp--) {
- if (*sp == ' ')
- sp--;
- if (*sp == ' ') { /* shift left one char */
- sp++;
- for (cp = sp; *cp; cp++)
- *cp = *(cp + 1);
- op--;
- if (!--err)
- break;
- }
- }
- }
- rpos = rp - ruler;
- opos = op - obuf;
- err = opos - rpos;
- }
-
- if (dbg_lvl >= 2)
- (void) fputs(" . . . . 1 . . . . 2 . . . . 3 . . . . 4 . . . . 5 . . . . 6 . . . . 7 . . . .\n", stderr);
- return obuf;
- }
-
- /**
- * qsort comparison routine
- *
- * if i is to precede j, return a value < 0
- * otherwise, return a value > 0
- **/
- static int
- datacompare(i, j)
- struct datatbl *i, *j;
- {
- return opts & O_RVRS
- ? i->val - j->val
- : j->val - i->val;
- }
-
- /**
- * Calculate deltas and other items.
- * Prepare array of keys and pointers.
- * Sort if required.
- * Return a pointer to the sorted array.
- **/
- void
- compute_data()
- {
- long dt, hdt; /* msec */
- int i;
- int dcpu, hdcpu;
- struct data **dpp;
- enum cp_time_kind kind_tmp;
-
- if (dbg_lvl >= 4) {
- (void) fprintf(stderr, "in compute_data\n");
- }
- nresp = 0;
- for (dpp = &dp; *dpp; dpp = &(*dpp)->datap) {
- /* this data is current */
- if ((*dpp)->nn == thiscount) {
-
- (*dpp)->sd.boottime.tv_sec = /* uptime */
- (*dpp)->sn.boottime.tv_sec ? /* if boottime reported */
- (*dpp)->sn.curtime.tv_sec
- - (*dpp)->sn.boottime.tv_sec : 0;
-
- nresp++;
- if ((*dpp)->no) {
- /* this data is not the first response from that host */
- int rebooted;
-
- /* time in milliseconds, since last call */
- dt = (((*dpp)->sn.curtime.tv_sec
- - (*dpp)->so.curtime.tv_sec) * 1000000
- + ((*dpp)->sn.curtime.tv_usec
- - (*dpp)->so.curtime.tv_usec) + 500) / 1000;
- hdt = (dt + 1) / 2;
-
- if (!(*dpp)->sd.cp_val)
- create_array((array *) & (*dpp)->sd.cp_time,
- (*dpp)->sn.cp_len);
-
- /**
- * calculate cp_time deltas
- *
- * if cp_time is reckoned cumulatively, then a negative delta
- * is impossible. Therefore, if delta is negative the remote
- * hosts's rpc.rstatd must be reporting cp_time as an
- * increment since the previous call. IBM AIX does it that
- * way.
- **/
- kind_tmp = (*dpp)->cp_kind;
- /**
- * All counters are reset on reboot.
- * Arbitrarily pick if_ipackets as an indicator
- * Can't use: t_n(i).boottime.tv_sec > t_o(i).boottime.tv_sec
- * because on some machines it is a derived quantity
- * (curtime - _lbolt * _hz), and therefore fluctuates a bit.
- **/
- rebooted = (*dpp)->sn.if_ipackets < (*dpp)->so.if_ipackets;
- for (i = 0; i < (*dpp)->sn.cp_len; i++) {
- (*dpp)->sd.cp_val[i] = delta(cp_val[i]);
- if ((*dpp)->sd.cp_val[i] < 0 && !rebooted)
- (*dpp)->cp_kind = CP_TIME_INC;
- }
- if (dbg_lvl >= 1 && kind_tmp == CP_TIME_CUM
- && (*dpp)->cp_kind == CP_TIME_INC) {
- (void) fprintf(stderr,
- "%s: rpc.rstatd reports incremental cp_time\n",
- (*dpp)->host);
- }
- /**
- * From vmstat.c 5.31 (Berkeley)
- * We round upward to avoid losing low-frequency events
- * (i.e., >= 1 per interval but < 1 per second).
- **/
- dcpu = 0;
- switch ((*dpp)->cp_kind) {
-
- case CP_TIME_CUM:
- for (i = 0; i < (*dpp)->sn.cp_len; i++) {
- dcpu += (*dpp)->sd.cp_val[i];
- }
- hdcpu = dcpu / 2;
- for (i = 0; i < (*dpp)->sn.cp_len; i++)
- (*dpp)->sd.cp_val[i] = cpu((*dpp)->sd.cp_val[i]);
- break;
-
- case CP_TIME_INC: /* incremental. disregard old data */
- for (i = 0; i < (*dpp)->sn.cp_len; i++) {
- dcpu += (*dpp)->sn.cp_val[i];
- }
- hdcpu = dcpu / 2;
- for (i = 0; i < (*dpp)->sn.cp_len; i++)
- /* store it in sd anyway because sd is printed */
- (*dpp)->sd.cp_val[i] = cpu((*dpp)->sn.cp_val[i]);
- break;
-
- } /* switch cp_kind */
-
- /* if different RSTAT versions for so and sn */
- if ((*dpp)->sn.dk_len != (*dpp)->so.dk_len
- /* or sd.dk_xfer is uninitialized */
- || !(*dpp)->sd.dk_len) {
- if ((*dpp)->sd.dk_val)
- destroy_array((array *) & (*dpp)->sd.dk_xfer);
- create_array((array *) & (*dpp)->sd.dk_xfer,
- Max((*dpp)->sn.dk_len, (*dpp)->so.dk_len));
- }
- /**
- * calculate the deltas for dk_xfer
- **/
- for (i = 0; i < Min((*dpp)->sn.dk_len, (*dpp)->so.dk_len); i++)
- (*dpp)->sd.dk_val[i] = rate(delta(dk_val[i]));
-
- (*dpp)->sd.v_pgpgin = rate(delta(v_pgpgin));
- (*dpp)->sd.v_pgpgout = rate(delta(v_pgpgout));
- (*dpp)->sd.v_pswpin = rate(delta(v_pswpin));
- (*dpp)->sd.v_pswpout = rate(delta(v_pswpout));
- (*dpp)->sd.v_swtch = rate(delta(v_swtch));
- /* Why does v_intr count down on aix370? */
- (*dpp)->sd.v_intr = rate(Abs((int) (delta(v_intr))));
-
- (*dpp)->sd.if_ipackets = rate(delta(if_ipackets));
- (*dpp)->sd.if_ierrors = rate(delta(if_ierrors));
- (*dpp)->sd.if_opackets = rate(delta(if_opackets));
- (*dpp)->sd.if_oerrors = rate(delta(if_oerrors));
- (*dpp)->sd.if_collisions = rate(delta(if_collisions));
- } /* (*dpp)->no */
- } /* (*dpp)->nn == thiscount */
- }
- if (dbg_lvl >= 4) {
- (void) fprintf(stderr, "returning from compute_data\n");
- }
- }
-
- struct datatbl *
- sort_data(tbl)
- struct datatbl *tbl;
- {
- int sort_needs_delta;
- int will_sort;
- int i;
- struct data **dpp;
-
- if (dbg_lvl >= 4) {
- (void) fprintf(stderr, "in sort_data\n");
- }
- will_sort = opts & O_SORT;
- sort_needs_delta = will_sort && key_ptr->k_flag & K_DELTA;
-
- if (tbl)
- free((char *) tbl);
- tbl = (struct datatbl *) malloc((unsigned) nresp * sizeof(struct datatbl));
- if (tbl == NULL) {
- perror("malloc");
- exit(1);
- }
- i = 0;
- for (dpp = &dp; *dpp; dpp = &(*dpp)->datap) {
- if ((*dpp)->nn == thiscount) {
-
- tbl[i].dp = *dpp;
- if (will_sort && (!sort_needs_delta || (*dpp)->no)) {
- if (key_ptr->k_flag & K_ARRAY) {
- array arr;
-
- arr = *(array *) ((char *) (*dpp) + key_ptr->k_doffset);
- tbl[i].val = arr.val[key_ptr->k_index];
- } else {
- tbl[i].val = *(int *) ((char *) (*dpp) + key_ptr->k_doffset);
- }
- } else {
- /* this val can be sorted but will not be printed */
- tbl[i].val = 0;
- }
- i++;
- }
- }
-
- if (will_sort)
- qsort((char *) tbl, (int) nresp, sizeof(struct datatbl), datacompare);
-
- if (dbg_lvl >= 4) {
- (void) fprintf(stderr, "returning from sort_data\n");
- }
- return tbl;
- }
-
- /**
- * make the titles for the columns, depending on the options selected
- **/
- void
- build_title()
- {
- if (dbg_lvl >= 4) {
- (void) fprintf(stderr, "in build_title\n");
- }
- title1[0] = '\0';
- title2[0] = '\0';
- ruler[0] = '\0';
- if (opts & O_BARE) {
- if (dbg_lvl >= 4) {
- (void) fprintf(stderr,
- "returning from build_title (opts & O_BARE)\n");
- }
- return;
- }
- if (opts & O_TIME) {
- (void) sprintf(title1 + strlen(title1), f_time, "unix time");
- (void) sprintf(title2 + strlen(title2), f_time, "(seconds)");
- (void) sprintf(ruler + strlen(ruler), fo_time, 100000000);
- }
- if (opts & O_DATE) {
- (void) sprintf(title1 + strlen(title1), f_date, "Date Time");
- (void) sprintf(title2 + strlen(title2), f_date, " (local)");
- (void) sprintf(ruler + strlen(ruler), f_date,
- "700101 00:00:00");
- }
- if (opts & O_SECS) {
- (void) sprintf(title1 + strlen(title1), f_secs, "time");
- (void) sprintf(title2 + strlen(title2), f_secs, "(sec)");
- (void) sprintf(ruler + strlen(ruler), fo_secs, 10.01);
- }
- if (nhosts > 1) {
- (void) sprintf(title1 + strlen(title1), f_h, "");
- (void) sprintf(title2 + strlen(title2), f_h, "host");
- (void) sprintf(ruler + strlen(ruler), f_h,
- "127.000.000.001");
- }
- if (opts & O_UP) {
- (void) sprintf(title1 + strlen(title1), f_up, "");
- (void) sprintf(title2 + strlen(title2), f2_up, "uptime");
- (void) sprintf(ruler + strlen(ruler), f_up, "365 days, 23:59 ");
- }
- if (opts & O_CP) {
- (void) sprintf(title1 + strlen(title1), f1_cp, "%cpu");
- (void) sprintf(title1 + strlen(title1), f1_av, "loadavg (nrun)");
- (void) sprintf(title2 + strlen(title2), f2_cp, "us", "ni", "sy", "id");
- (void) sprintf(title2 + strlen(title2), f2_av, "1m", "5m", "15m");
- (void) sprintf(ruler + strlen(ruler), fr_cp, "100", "100", "100", "100");
- (void) sprintf(ruler + strlen(ruler), fo_a0, 10.00, 10.00, 10.00);
- }
- if (opts & O_DK) {
- (void) sprintf(title1 + strlen(title1), f1_dk, "disk xfers");
- (void) sprintf(title2 + strlen(title2), f2_dk,
- "d0", "d1", "d2", "d3");
- (void) sprintf(ruler + strlen(ruler), fr_dk, "10", "10", "10", "10");
- }
- if (opts & O_VM) {
- (void) sprintf(title1 + strlen(title1), f1_vm,
- "pg", "pg", "sw", "sw", "cx", "in");
- (void) sprintf(title2 + strlen(title2), f2_vm,
- "in", "o", "in", "o", "sw", "tr");
- (void) sprintf(ruler + strlen(ruler), fr_vm, "10", "10", "10", "10", "100", "100");
- }
- if (opts & O_IF) {
- (void) sprintf(title1 + strlen(title1), f1_if,
- "i", "i", "o", "o", "co");
- (void) sprintf(title2 + strlen(title2), f2_if,
- "pk", "er", "pk", "er", "ll");
- (void) sprintf(ruler + strlen(ruler), fr_if, "10", "10", "10", "10", "10");
- }
- (void) sprintf(title1 + strlen(title1), "\n");
- (void) sprintf(title2 + strlen(title2), "\n");
- if (dbg_lvl >= 4) {
- (void) fprintf(stderr, "returning from build_title\n");
- }
- return;
- }
-
- char *
- common_suffix(tbl)
- struct datatbl *tbl;
- {
- int i;
- int suflen = 0;
- char *dotp, *hp, *sp;
- char *hname;
- static char suffix[256];
-
- /* determine the longest common suffix starting with a '.' */
- if (dbg_lvl >= 4) {
- (void) fprintf(stderr, "in common_suffix\n");
- }
- suffix[0] = '\0';
- for (i = 0; i < nprint; ++i) {
- hname = tbl[i].dp->host_dup;
-
- if (strcmp(hname, "localhost") == 0)
- continue;
-
- if (!isalpha(*hname))
- continue;
- if (!suffix[0]) {
- dotp = strchr(hname, '.');
- if (dotp) {
- (void) strcpy(suffix, dotp);
- suflen = strlen(suffix);
- }
- }
- sp = suffix + suflen - 1;
- hp = hname + strlen(hname) - 1;
- while (sp >= suffix && hp >= hname && *sp == *hp)
- --sp, --hp;
-
- dotp = strchr(hp + 1, '.');
- if (!dotp) {
- *suffix = '\0';
- if (dbg_lvl >= 4) {
- (void) fprintf(stderr,
- "returning from common_suffix (!dotp)\n");
- }
- return suffix;
- }
- if (sp > suffix) {
- (void) strcpy(suffix, dotp);
- suflen = strlen(suffix);
- }
- }
- if (dbg_lvl >= 4) {
- (void) fprintf(stderr, "returning from common_suffix\n");
- }
- return suffix;
- }
-
- /**
- * remove common suffix from hostnames
- * by sreiz@aie.nl (Steven Reiz)
- **/
- void
- strip_hostnames(tbl)
- struct datatbl *tbl;
- {
- int i, suflen, maxlen;
- char *p;
- char *suffix;
-
- static int oldmaxlen;
-
- if (dbg_lvl >= 4) {
- (void) fprintf(stderr, "in strip_hostnames\n");
- }
- if (opts & O_NHOST) {
- if (dbg_lvl >= 4) {
- (void) fprintf(stderr,
- "returning from strip_hostnames (opts & O_NHOST)\n");
- }
- return;
- }
- suffix = common_suffix(tbl);
- suflen = strlen(suffix);
- if (dbg_lvl >= 1)
- (void) fprintf(stderr, "suffix %s\n", suffix);
- /* remove the suffix */
- maxlen = 4; /* length of the "host" header string */
- for (i = 0; i < nprint; ++i) {
- int oldplen, newplen;
-
- (void) strcpy(tbl[i].dp->host, tbl[i].dp->host_dup);
- p = tbl[i].dp->host;
- if (strcmp(p, "localhost") == 0)
- continue;
- if (!isalpha(p[0]))
- continue;
- oldplen = strlen(p);
- newplen = oldplen - suflen;
- p[newplen] = '\0';
- maxlen = Max(maxlen, newplen);
- }
- /* set f_h */
- maxlen = Min(maxlen, 12); /* never longer than default */
- if (oldmaxlen != maxlen) {
- oldmaxlen = maxlen;
- (void) sprintf(f_h, "%%%d.%ds ", maxlen, maxlen);
- /* rebuild title */
- build_title();
- }
- if (dbg_lvl >= 4) {
- (void) fprintf(stderr, "returning from strip_hostnames\n");
- }
- }
-
- /**
- * print the statistics or the uptime
- **/
- void
- print_data(tbl, flag)
- struct datatbl *tbl;
- int flag;
- {
- long up, upd, uph, upm;
- float s = 0.0;
- int i;
- char *out;
- char obuf[160];
- char fo_bf[32];
-
- if (dbg_lvl >= 4) {
- (void) fprintf(stderr, "in print_data\n");
- }
- if (opts & O_SECS && flag == P_DATA) {
- struct timeval now;
- if (gettimeofday(&now, (struct timezone *) NULL) == -1) {
- perror("gettimeofday");
- exit(1);
- }
- s = (now.tv_sec - starttime.tv_sec)
- + ((now.tv_usec - starttime.tv_usec) + 5000)
- / 10000 / 100.;
- }
- for (i = 0; i < nprint; i++) {
- if (!tbl[i].dp->no && flag == P_DATA) /* do we have delta? */
- continue;
- if (tbl[i].dp->no && flag == P_UP) /* do we have delta? */
- continue;
- if (tbl[i].dp->no
- && t_n(i).if_ipackets < t_o(i).if_ipackets) {
- if (dbg_lvl >= 1) {
- (void) fprintf(stderr, "%s was rebooted.\n", tbl[i].dp->host);
- }
- continue;
- }
- obuf[0] = '\0';
- if (opts & O_TIME && flag == P_DATA)
- (void) sprintf(obuf + strlen(obuf), fo_time,
- t_n(i).curtime.tv_sec);
- if (opts & O_DATE && flag == P_DATA) {
- char buf[30];
- struct tm *tp;
-
- tp = localtime((long *) &t_n(i).curtime.tv_sec);
- if (!strftime(buf, 30, "%y%m%d %H:%M:%S ", tp)) {
- (void) fputs("can't convert date\n", stderr);
- exit(1);
- }
- (void) sprintf(obuf + strlen(obuf), f_date, buf);
- }
- if (opts & O_SECS && flag == P_DATA)
- (void) sprintf(obuf + strlen(obuf), fo_secs, s);
-
- if (nhosts > 1 || mode == MODE_BCST || flag == P_UP)
- (void) sprintf(obuf + strlen(obuf),
- (isalpha(*tbl[i].dp->host) ? f_h : f_haddr),
- tbl[i].dp->host);
-
- if (opts & O_UP || flag == P_UP) {
- if (t_n(i).boottime.tv_sec) { /* > vers 1 ) */
- up = t_d(i).boottime.tv_sec; /* uptime stored here */
- upd = up / 86400;
- up = Abs(up - upd * 86400);
- uph = up / 3600;
- up -= uph * 3600;
- upm = up / 60;
- if (flag == P_UP)
- (void) sprintf(obuf + strlen(obuf), "up ");
- switch (upd) {
- case 0:
- (void) sprintf(obuf + strlen(obuf), " ");
- break;
- case 1:
- (void) sprintf(obuf + strlen(obuf), "%3d day, ", upd);
- break;
- default:
- (void) sprintf(obuf + strlen(obuf), "%3d days, ", upd);
- break;
- } /* switch upd */
- (void) sprintf(obuf + strlen(obuf), "%2d:%02d", uph, upm);
- if (flag == P_UP)
- (void) sprintf(obuf + strlen(obuf), ",");
- (void) sprintf(obuf + strlen(obuf), " ");
- } else { /* vers 1 ) */
- (void) sprintf(obuf + strlen(obuf), f_up, "-");
- }
- }
- /**
- * macros to control what to print:
- * data or '-'
- *
- * use these macros with care
- **/
- #define on_nzero(a) (t_o(i).a && t_n(i).a) /* old and new nonzero */
- #define f_nzero2(a) (on_nzero(a) ? "%2d" : " %c")
- #define f_nzero3(a) (on_nzero(a) ? "%3d" : " %c")
- #define d_nzero(a) (on_nzero(a) ? t_d(i).a : '-')
-
- if (opts & O_CP && flag == P_DATA) {
- (void) sprintf(fo_bf, fr_cp,
- f_nzero3(cp_val[CP_USER]),
- f_nzero3(cp_val[CP_NICE]),
- f_nzero3(cp_val[CP_SYS]),
- f_nzero3(cp_val[CP_IDLE]));
- (void) sprintf(obuf + strlen(obuf), fo_bf,
- d_nzero(cp_val[CP_USER]),
- d_nzero(cp_val[CP_NICE]),
- d_nzero(cp_val[CP_SYS]),
- d_nzero(cp_val[CP_IDLE]));
- }
- if (opts & O_CP || flag == P_UP) {
- /* average run queue lengths */
- if (t_n(i).boottime.tv_sec) { /* > vers 1 */
- if (flag == P_UP)
- (void) sprintf(obuf + strlen(obuf),
- " load average: ");
- /* average run queue lengths */
- (void) sprintf(obuf + strlen(obuf),
- flag == P_UP ? fo_av : fo_a0,
- loadav(t_n(i).avenrun[AV1]),
- loadav(t_n(i).avenrun[AV5]),
- loadav(t_n(i).avenrun[AV15]));
- } else { /* vers 1 */
- (void) sprintf(obuf + strlen(obuf),
- f2_av, "-", "-", "-");
- }
- }
- if (opts & O_DK && flag == P_DATA) {
- (void) sprintf(fo_bf, fr_dk,
- f_nzero2(dk_val[0]),
- f_nzero2(dk_val[1]),
- f_nzero2(dk_val[2]),
- f_nzero2(dk_val[3]));
- (void) sprintf(obuf + strlen(obuf), fo_bf,
- d_nzero(dk_val[0]),
- d_nzero(dk_val[1]),
- d_nzero(dk_val[2]),
- d_nzero(dk_val[3]));
- }
- if (opts & O_VM && flag == P_DATA) {
- (void) sprintf(fo_bf, fr_vm,
- f_nzero2(v_pgpgin),
- f_nzero2(v_pgpgout),
- f_nzero2(v_pswpin),
- f_nzero2(v_pswpout),
- f_nzero3(v_swtch),
- f_nzero3(v_intr));
- (void) sprintf(obuf + strlen(obuf), fo_bf,
- d_nzero(v_pgpgin),
- d_nzero(v_pgpgout),
- d_nzero(v_pswpin),
- d_nzero(v_pswpout),
- d_nzero(v_swtch),
- d_nzero(v_intr));
- }
- if (opts & O_IF && flag == P_DATA) {
- (void) sprintf(fo_bf, fr_if,
- f_nzero2(if_ipackets),
- f_nzero2(if_ierrors),
- f_nzero2(if_opackets),
- f_nzero2(if_oerrors),
- f_nzero2(if_collisions));
- (void) sprintf(obuf + strlen(obuf), fo_bf,
- d_nzero(if_ipackets),
- d_nzero(if_ierrors),
- d_nzero(if_opackets),
- d_nzero(if_oerrors),
- d_nzero(if_collisions));
- }
- if (flag == P_DATA) {
- out = adjust_line(obuf);
- } else {
- out = obuf;
- } /* switch flag */
-
- (void) fputs(out, stdout);
- (void) putc('\n', stdout);
-
- if (opts & O_CP && flag == P_DATA) {
- int c, chigh = 0, morestates = 0;
-
- for (c = CPUSTATES;
- c < Min(t_n(i).cp_len, t_o(i).cp_len); c++) {
- static cp_len_flag;
- if (dbg_lvl >= 1 && !cp_len_flag) {
- (void) fprintf(stderr,
- "%s: cp_len > 4. rperf cannot handle this case yet.\n",
- tbl[i].dp->host);
- cp_len_flag = 1;
- }
- if (on_nzero(cp_val[c])) {
- chigh = c;
- morestates++;
- }
- }
- if (morestates > 0) {
- (void) fprintf(stdout, "%d more cpu states%s...",
- morestates, morestates == 1 ? "" : "s");
- for (c = CPUSTATES; c <= chigh; c++)
- if (on_nzero(cp_val[c]))
- (void) fprintf(stdout,
- " cpu state%d: %d", c, t_d(i).cp_val[c]);
- (void) putc('\n', stdout);
- }
- }
- if (opts & O_DK && flag == P_DATA) {
- int d, dhigh = 0, moredisks = 0;
-
- for (d = DK_NDRIVE;
- d < Min(t_n(i).dk_len, t_o(i).dk_len); d++) {
- if (on_nzero(dk_val[d])) {
- dhigh = d;
- moredisks++;
- }
- }
- if (moredisks > 0) {
- (void) fprintf(stdout, "%d more disk%s...",
- moredisks, moredisks == 1 ? "" : "s");
- for (d = DK_NDRIVE; d <= dhigh; d++)
- if (on_nzero(dk_val[d]))
- (void) fprintf(stdout,
- " disk%d: %d", d, t_d(i).dk_val[d]);
- (void) putc('\n', stdout);
- }
- }
- }
- if (dbg_lvl >= 4) {
- (void) fprintf(stderr, "returning from print_data\n");
- }
- }
-
- /**
- * If we are sorting, delete hosts which have had zero counts since boot
- * time. They may not be capable of reporting that statistic
- **/
- void
- delete_zeros()
- {
- struct data **dpp;
-
- if (dbg_lvl >= 4) {
- (void) fprintf(stderr, "in delete_zeros\n");
- }
- if (!key_ptr) {
- if (dbg_lvl >= 4) {
- (void) fprintf(stderr, "returning from delete_zeros (!key_ptr)\n");
- }
- return;
- }
- for (dpp = &dp; *dpp; dpp = &(*dpp)->datap) {
-
- if (!(*dpp)->nn)
- continue;
-
- if (key_ptr->k_noffset == sn_offset(cp_time)
- && (*dpp)->cp_kind == CP_TIME_INC)
- continue;
-
- if (key_ptr->k_flag & K_NZERO) {
- int val;
- val = *(int *) ((char *) (*dpp) + key_ptr->k_noffset);
- if (!val) {
- if (dbg_lvl >= 1) {
- (void) fprintf(stderr,
- "%s: rpc.rstatd vers %d does not report %s\n",
- (*dpp)->host, (*dpp)->bcst_vers, key_ptr->k_name);
- }
- (*dpp)->nn = 0; /* mark as not received */
- continue;
- }
- } /* K_NZERO */
- if (key_ptr->k_flag & K_DELTA) {
- int sinceboot;
- if (key_ptr->k_flag & K_ARRAY) {
- array arr;
-
- arr = *(array *) ((char *) (*dpp) + key_ptr->k_noffset);
- sinceboot = arr.val[key_ptr->k_index];
- } else {
- sinceboot = *(int *) ((char *) (*dpp) + key_ptr->k_noffset);
- }
- if (!sinceboot) {
- if (dbg_lvl >= 1)
- (void) fprintf(stderr,
- " %s zero %s events since boot. ignore.\n",
- (*dpp)->host, key_ptr->k_name);
- (*dpp)->nn = 0; /* mark as not received */
- }
- } /* K_DELTA */
- } /* for dpp */
- if (dbg_lvl >= 4) {
- (void) fprintf(stderr, "returning from delete_zeros\n");
- }
- }
-
- /**
- * If possible, increase the user's file descriptor table size to the maximum
- * allowable by the system, or to a very large number.
- *
- * In any case, return the file descriptor table size.
- **/
- int
- set_max_nofiles()
- {
- static struct Rlimit nofiles;
-
- #ifdef RLIMIT_NOFILE
- if (getrlimit(RLIMIT_NOFILE, &nofiles) == -1) {
- (void) perror("getrlimit");
- exit(1);
- }
- nofiles.rlim_cur = nofiles.rlim_max;
- if (setrlimit(RLIMIT_NOFILE, &nofiles) == -1) {
- (void) perror("setrlimit");
- /* don't exit -- just use existing limit */
- }
- if (getrlimit(RLIMIT_NOFILE, &nofiles) == -1) {
- (void) perror("getrlimit");
- exit(1);
- }
- #else /* !RLIMIT_NOFILE */
- #ifdef HAVE_SETDTABLESIZE
- /* thanks -- Ric Anderson <ric@cs.arizona.edu> */
- nofiles.rlim_cur = setdtablesize(1000 /* huge */ );
- if (nofiles.rlim_cur == -1) {
- (void) perror("setdtablesize");
- /* don't exit -- just use existing limit */
- }
- #else /* !HAVE_SETDTABLESIZE */
- #ifdef HAVE_UNISTD_H
- /* thanks -- Colin M. Clark <cmc@srg-ssr.ch> */
- nofiles.rlim_cur = sysconf(_SC_OPEN_MAX);
- if (nofiles.rlim_cur == -1) {
- (void) perror("sysconf");
- exit(1);
- }
- #else /* !HAVE_UNISTD_H */
- nofiles.rlim_cur = getdtablesize();
- #endif /* !HAVE_UNISTD_H */
- #endif /* !HAVE_SETDTABLESIZE */
- #endif /* !RLIMIT_NOFILE */
-
- if (dbg_lvl >= 1)
- (void) fprintf(stderr, "Open file descriptor limit now %d\n",
- nofiles.rlim_cur);
- return nofiles.rlim_cur;
- }
-
- void
- dumplist()
- {
- int i = 0;
- int d;
- struct data **dpp;
- char *dotquad;
-
- (void) fprintf(stdout, "\nexpecting %d hosts\n", nhosts);
-
- for (dpp = &dp; *dpp; dpp = &(*dpp)->datap) {
- (void) fprintf(stdout, "%2d/%2d ", ++i, nhosts);
- (void) fprintf(stdout, "%s %s\n", (*dpp)->host_dup, (*dpp)->host);
- dotquad = inet_ntoa((*dpp)->addr);
- (void) fputs(dotquad, stdout);
- (void) fprintf(stdout, "\t*dpp=0x%08x (*dpp)->datap=0x%08x\n",
- (u_long) (*dpp), (u_long) (*dpp)->datap);
- (void) fputs(dotquad, stdout);
- (void) fprintf(stdout,
- "\tno=%d, nn=%d, clnt_vers=%d, bcst_vers=%d, ok_to_call=%d\n",
- (*dpp)->no,
- (*dpp)->nn,
- (*dpp)->clnt_vers,
- (*dpp)->bcst_vers,
- (*dpp)->ok_to_call);
-
- (void) fputs(dotquad, stdout);
- if ((*dpp)->sn.cp_val) {
- (void) fprintf(stdout, "\tcp_time\t%08x %08x %08x %08x\n",
- (*dpp)->sn.cp_val[CP_USER],
- (*dpp)->sn.cp_val[CP_NICE],
- (*dpp)->sn.cp_val[CP_SYS],
- (*dpp)->sn.cp_val[CP_IDLE]);
- } else {
- (void) fprintf(stdout, "\tcp_val = NULL\n");
- }
-
- (void) fputs(dotquad, stdout);
- (void) fprintf(stdout, "\tavenrun\t%08x %08x %08x\n",
- (*dpp)->sn.avenrun[AV1],
- (*dpp)->sn.avenrun[AV5],
- (*dpp)->sn.avenrun[AV15]);
-
- (void) fputs(dotquad, stdout);
- if ((*dpp)->sn.dk_val) {
- (void) fprintf(stdout, "\tdk_xfer\t%08x %08x %08x %08x\n",
- (*dpp)->sn.dk_val[0],
- (*dpp)->sn.dk_val[1],
- (*dpp)->sn.dk_val[2],
- (*dpp)->sn.dk_val[3]);
- } else {
- (void) fprintf(stdout, "\tdk_val = NULL\n");
- }
-
- for (d = DK_NDRIVE; d < (*dpp)->sn.dk_len; d += 4) {
- int e;
-
- (void) fputs(dotquad, stdout);
- (void) fprintf(stdout, "\t.....dk\t");
- for (e = 0; e < Min((*dpp)->sn.dk_len - d, 4); e++) {
- (void) fprintf(stdout, " %08x", (*dpp)->sn.dk_val[d + e]);
- }
- (void) putc('\n', stdout);
- }
-
- (void) fputs(dotquad, stdout);
- (void) fprintf(stdout, "\tvm\t%08x %08x %08x %08x %08x %08x\n",
- (*dpp)->sn.v_pgpgin,
- (*dpp)->sn.v_pgpgout,
- (*dpp)->sn.v_pswpin,
- (*dpp)->sn.v_pswpout,
- (*dpp)->sn.v_swtch,
- (*dpp)->sn.v_intr);
- (void) fputs(dotquad, stdout);
- (void) fprintf(stdout, "\tif\t%08x %08x %08x %08x %08x\n",
- (*dpp)->sn.if_ipackets,
- (*dpp)->sn.if_ierrors,
- (*dpp)->sn.if_opackets,
- (*dpp)->sn.if_oerrors,
- (*dpp)->sn.if_collisions);
- }
- (void) fprintf(stdout, "end of dump\n");
- }
-
- RETSIGTYPE
- illhdlr()
- {
- (void) fprintf(stderr, "Illegal instruction\n");
- dumplist();
- (void) fprintf(stderr, "exiting from illhdlr\n");
- exit(1);
- }
-
- RETSIGTYPE
- segvhdlr()
- {
- (void) fprintf(stderr, "Segmentation fault\n");
- dumplist();
- (void) fprintf(stderr, "exiting from segvhdlr\n");
- exit(1);
- }
-
- /**
- * line-buffer the output
- * permits "tail -f" of a growing log file or a pipe
- **/
- void
- linebuf_stdout()
- {
- #ifdef HAVE_SETLINEBUF
- (void) setlinebuf(stdout);
- #else /* !HAVE_SETLINEBUF */
- errno = 0;
- #ifdef SETVBUF_REVERSED
- if (setvbuf(stdout, _IOLBF, (char *) NULL, BUFSIZ))
- #else /* !SETVBUF_REVERSED */
- if (setvbuf(stdout, (char *) NULL, _IOLBF, BUFSIZ))
- #endif /* !SETVBUF_REVERSED */
- {
- if (errno)
- perror("setvbuf");
- else
- (void) fprintf(stderr, "setvbuf error\n");
- exit(1);
- }
- #endif /* !HAVE_SETLINEBUF */
- }
-
- /**
- * initialize signal handlers
- * parse options
- * resolve host names
- * loop endlessly. either:
- * do client calls
- * or do broadcasts
- **/
- int
- main(argc, argv)
- int argc;
- char *argv[];
- {
- u_long vers_max;
- u_long nbcst_vers;
- int stdout_is_a_tty;
- int c_seen = 0;
- int do_uptime = 0;
- int n_ofiles;
- int opti;
- int c;
- int i_seen = 0;
- unsigned count = 0;
- unsigned interval = 10;
- unsigned bcst_interval;
- unsigned hdrcnt;
- unsigned telapse;
- unsigned short term_rows;
- char *optstring;
- char *basename;
- struct data **dpp;
- struct datatbl *tbl;
- struct timeval time1, time2;
-
- stdout_is_a_tty = isatty(STDOUT_FILENO);
-
- tbl = NULL;
- if (gettimeofday(&starttime, (struct timezone *) NULL) == -1) {
- perror("gettimeofday");
- exit(1);
- }
- (void) signal(SIGHUP, cleanup);
- (void) signal(SIGINT, cleanup);
- (void) signal(SIGTERM, cleanup);
- (void) signal(SIGILL, illhdlr);
- (void) signal(SIGSEGV, segvhdlr);
-
- linebuf_stdout();
- basename = strrchr(argv[0], '/');
- basename = basename ? ++basename : argv[0];
-
- opterr = 0;
- if (strcmp(basename, "rup") == 0) {
- vers_max = RSTATVERS_TIME;
- optstring = "hltnD";
- while ((c = getopt(argc, argv, optstring)) != -1) {
- switch (c) {
- case 'h':
- opts |= O_SHOST;
- break;
- case 'l':
- opts |= O_SORT | O_RVRS;
- key_ptr = (key *) calloc(1, sizeof(key));
- key_ptr->k_doffset = sn_offset(avenrun[AV1]);
- break;
- case 't':
- opts |= O_SORT;
- key_ptr = (key *) calloc(1, sizeof(key));
- /* sd.boottime is uptime */
- key_ptr->k_doffset = sd_offset(boottime.tv_sec);
- break;
- case 'n':
- opts |= O_NHOST;
- break;
- case 'D':
- opts |= O_DBG;
- dbg_lvl++;
- break;
- case '?':
- msg(rupusagev, stderr);
- exit(1);
- }
- }
- c_seen = 1;
- count = 1;
- do_uptime = 1;
- opts |= O_NCLR; /* never clear the screen in rup mode */
- } else { /* rperf */
- vers_max = RSTATVERS_VAR;
- optstring = "aAcdivhnSTsub1234BDrN";
- while ((c = getopt(argc, argv, optstring)) != -1)
- switch (c) {
- case 'a':
- opts |= O_MOST;
- break;
- case 'A':
- opts |= O_ALL; /* everything! */
- break;
- case 'c':
- opts |= O_CP;
- break;
- case 'd':
- opts |= O_DK;
- break;
- case 'i':
- opts |= O_IF;
- break;
- case 'S':
- opts |= O_TIME;
- break;
- case 'T':
- opts |= O_DATE;
- break;
- case 's':
- opts |= O_SECS;
- break;
- case 'h':
- opts |= O_SHOST;
- break;
- case 'u':
- opts |= O_UP;
- break;
- case 'n':
- opts |= O_NHOST;
- break;
- case 'v':
- opts |= O_VM;
- break;
- case 'b':
- opts |= O_BCST;
- break;
- case '1':
- vers_max = RSTATVERS_ORIG;
- break;
- case '2':
- vers_max = RSTATVERS_SWTCH;
- break;
- case '3':
- vers_max = RSTATVERS_TIME;
- break;
- case '4':
- vers_max = RSTATVERS_VAR;
- break;
- case 'B':
- opts |= O_BARE | O_NCLR;
- break;
- case 'r':
- opts |= O_RVRS;
- break;
- case 'D':
- opts |= O_DBG;
- dbg_lvl++;
- break;
- case 'N':
- opts |= O_NCLR;
- break;
- case '?':
- verbosehelp();
- }
-
- if (!(opts & O_BARE))
- do_uptime = 1;
- }
-
- init_termcap();
-
- n_ofiles = set_max_nofiles();
- {
- /**
- * Estimate size of hash table.
- *
- * The hash table gets filled with the ascii host address, the official
- * host name, and alias host names.
- *
- * Machines with more than one interface get each address stored in the
- * table, as replies are received from them.
- *
- * The table is used to for quick lookup when a broadcast reply is
- * received, and to eliminate duplication for hosts with more than
- * one network interface
- **/
- errno = 0;
- if (!hcreate((unsigned) Max(2 * n_ofiles, 1031 /* big */ ))) {
- if (errno)
- perror("hcreate");
- else
- (void) fprintf(stderr, "Can't hcreate\n");
- exit(1);
- }
- }
-
- if (opts & O_NHOST)
- (void) strcpy(f_h, f_haddr);
-
- opti = optind;
- while (argv[opti]) {
- char *oa;
- long l;
-
- l = strtol(argv[opti], &oa, 0);
- if (argv[opti] == oa || *oa) {
- /* "mml0.meche.rpi.edu" or "128.113.14.20" or "+idle" */
- if (*argv[opti] == '+') {
- char *sortkey;
- key *kp;
-
- sortkey = argv[opti] + sizeof(char);
- for (kp = keys; kp->k_name != NULL; kp++) {
- if (strcmp(sortkey, kp->k_name) == 0) {
- key_ptr = kp;
- break;
- }
- }
- if (!key_ptr) {
- (void) fprintf(stderr, "unknown sort key: %s\n", sortkey);
- msg(keyhelp, stderr);
- exit(1);
- }
- if (vers_max < RSTATVERS_TIME) {
- if (key_ptr->k_noffset == sn_offset(curtime.tv_sec)) {
- (void) fprintf(stderr,
- "Cannot sort by %s in version %d of rstatd\n",
- sortkey, vers_max);
- exit(1);
- }
- }
- if (vers_max == RSTATVERS_ORIG) {
- if (key_ptr->k_noffset == sn_offset(boottime.tv_sec)
- || key_ptr->k_noffset == sn_offset(v_swtch)
- || key_ptr->k_noffset == sn_offset(avenrun[AV1])
- || key_ptr->k_noffset == sn_offset(avenrun[AV5])
- || key_ptr->k_noffset == sn_offset(avenrun[AV15])) {
- (void) fprintf(stderr,
- "Cannot sort by %s in version %d of rstatd\n",
- sortkey, vers_max);
- exit(1);
- }
- }
- opts |= O_SORT;
- } else {
- /* not a sort key. Must be a host name or address */
- mode = MODE_CALL;
- }
- } else {
- /* arg is a decimal number */
- if (!i_seen) {
- if (l <= 0) {
- (void) fprintf(stderr, "%s interval invalid\n",
- l ? "Negative" : "Zero");
- exit(1);
- }
- interval = l;
- i_seen = 1;
- } else if (!c_seen) {
- count = l + 1; /* the user wants l data displays */
- c_seen = 1;
- } else {
- /* third decimal argument */
- (void) fprintf(stderr, "Unknown option %s\n", argv[opti]);
- verbosehelp();
- }
- }
- opti++;
- }
-
-
- if (mode == MODE_CALL) {
- if (opts & O_BCST) {
- (void) fprintf(stderr,
- "Can't use -b and hostname arguments together.\n");
- exit(1);
- }
- if (opts & O_NHOST) {
- (void) fprintf(stderr,
- "Can't use -n and hostname arguments together.\n");
- exit(1);
- }
- if (opts & O_SHOST) {
- (void) fprintf(stderr,
- "Can't use -h and hostname arguments together.\n");
- exit(1);
- }
- if (dbg_lvl >= 1)
- (void) fputs("resolving host names\n", stderr);
- opti = optind;
- dpp = &dp;
-
- while (argv[opti]) {
- char *oa;
- u_long host_address;
-
- (void) strtol(argv[opti], &oa, 0);
- if ((argv[opti] == oa || *oa) && *argv[opti] != '+') {
- /* "mml0.meche.rpi.edu" or "128.113.14.20" */
- struct in_addr addr;
- char *hostname;
- struct hostent *host_entry;
-
- hostname = argv[opti];
- host_entry = gethostbyname(hostname);
- if (!host_entry) { /* maybe he typed an address */
- if (dbg_lvl >= 1)
- (void) fputs("byname failed\n", stderr);
- #ifdef STRUCT_IN_ADDR_INET_ADDR
- /**
- * Data General.
- * thanks mpc@mbs.linet.org (Mark Clements)
- **/
- {
- struct in_addr host_in_addr;
- host_in_addr = inet_addr(hostname);
- host_address = host_in_addr.s_addr;
- }
- #else /* u_long inet_addr(); */
- host_address = inet_addr(hostname);
- #endif /* u_long inet_addr(); */
- if (host_address != -1) {
- host_entry =
- gethostbyaddr((char *) &host_address, 4, AF_INET);
- if (!host_entry && dbg_lvl >= 1)
- (void) fputs("byaddr failed\n", stderr);
- } else if (dbg_lvl >= 1)
- (void) fputs("inet_addr failed\n", stderr);
- }
- if (host_entry) {
- bcopy(host_entry->h_addr,
- (char *) &addr.s_addr,
- host_entry->h_length);
- }
- /**
- * maybe he typed a valid address anyway --
- **/
- if (!host_entry && (host_address != -1))
- addr.s_addr = host_address;
-
- if (host_entry || (host_address != -1)) {
- /* host ok. add to list */
- if (dbg_lvl >= 1)
- (void) fprintf(stderr, "%s\n", inet_ntoa(addr));
- (*dpp) = new_host(&addr, hostname);
- (*dpp)->datap = NULL;
- dpp = &(*dpp)->datap;
- } else {
- (void) fprintf(stderr, "can't get address for %s\n",
- hostname);
- }
- } /* a host argument */
- opti++;
- }
- if (dbg_lvl >= 1)
- (void) fprintf(stderr, "%d hosts\n", nhosts);
- if (!nhosts)
- exit(0);
- }
- switch (mode) {
- case MODE_CALL:
- if (!(opts & O_ALL)) {
- if (nhosts == 1)
- opts |= O_DEFL1;
- else
- opts |= O_DEFL;
- }
- build_title();
- break;
- case MODE_BCST:
- if (!(opts & O_ALL)) {
- opts |= O_DEFL;
- }
- nhosts = 2;
- build_title();
- nhosts = 0;
- break;
- }
-
- if (vers_max == RSTATVERS_ORIG) {
- if (opts & O_UP)
- (void) fprintf(stderr,
- "Warning, no uptime available in version 1 of rstatd\n");
- if (opts & O_CP)
- (void) fprintf(stderr,
- "Warning, no load average available in version 1 of rstatd\n");
- if (opts & O_VM)
- (void) fprintf(stderr,
- "Warning, no v_swtch available in version 1 of rstatd\n");
- }
- nbcst_vers = Max(0, (int) vers_max - (int) RSTATVERS_TIME) + 1;
- bcst_interval = interval / nbcst_vers;
-
- for (hdrcnt = 1;;) { /* main loop */
- thiscount++;
-
- if (gettimeofday(&time1, (struct timezone *) NULL) == -1) {
- perror("gettimeofday");
- exit(1);
- }
- if (dbg_lvl >= 1)
- (void) fprintf(stderr, "thiscount %d\n", thiscount);
-
- if (mode == MODE_BCST && (thiscount == 1 || opts & O_BCST)) {
- do_broadcast(vers_max, bcst_interval);
- }
- if (stdout_is_a_tty && nhosts > 1 && !(opts & O_NCLR))
- clear();
-
- doclnt_calls(vers_max);
-
- if (dbg_lvl >= 3) {
- dumplist();
- (void) fprintf(stderr, "end of debug dump\n");
- }
- delete_zeros();
- compute_data();
- tbl = sort_data(tbl);
- if (stdout_is_a_tty
- && (!(opts & O_NCLR) || mode == MODE_CALL)) {
- check_term(&term_rows, (unsigned short *) NULL);
- if (term_rows)
- nprint = Min(nresp, term_rows - 3);
- } else
- nprint = nresp;
-
- strip_hostnames(tbl);
-
- if (dbg_lvl >= 1)
- (void) fprintf(stderr, "%d host%s\n",
- nhosts, nhosts == 1 ? "" : "s");
-
- if (do_uptime && vers_max > RSTATVERS_ORIG) {
- print_data(tbl, P_UP);
- }
- if (thiscount > 1
- && ((mode == MODE_CALL && (!--hdrcnt || nhosts > 1))
- || (mode == MODE_BCST))) {
- (void) fputs(title1, stdout);
- (void) fputs(title2, stdout);
- hdrcnt = Max(1, term_rows ? term_rows - 2 : 20);
- }
- if (thiscount > 1) {
- print_data(tbl, P_DATA);
- }
- if (c_seen && !--count)
- exit(0);
-
- if (gettimeofday(&time2, (struct timezone *) NULL) == -1) {
- perror("gettimeofday");
- exit(1);
- }
- telapse = time2.tv_sec - time1.tv_sec;
-
- if (interval > telapse)
- (void) sleep(interval - telapse);
-
- if (!(opts & O_BCST) && (mode == MODE_BCST) && thiscount == 1)
- (void) sleep(interval);
- } /* main loop */
- }
-