home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume39 / rperf / part02 < prev    next >
Encoding:
Text File  |  1993-08-30  |  55.8 KB  |  2,130 lines

  1. Newsgroups: comp.sources.misc
  2. From: fitz@rpi.edu (Brian P. Fitzgerald)
  3. Subject: v39i070:  rperf - performance monitoring of network hosts, v2.1, Part02/03
  4. Message-ID: <1993Aug30.211736.20556@sparky.sterling.com>
  5. X-Md4-Signature: f687243d58734e939907ff2b13a0df04
  6. Sender: kent@sparky.sterling.com (Kent Landfield)
  7. Organization: Rensselaer Polytechnic Institute, Troy NY
  8. Date: Mon, 30 Aug 1993 21:17:36 GMT
  9. Approved: kent@sparky.sterling.com
  10.  
  11. Submitted-by: fitz@rpi.edu (Brian P. Fitzgerald)
  12. Posting-number: Volume 39, Issue 70
  13. Archive-name: rperf/part02
  14. Environment: UNIX
  15.  
  16. #! /bin/sh
  17. # This is a shell archive.  Remove anything before this line, then unpack
  18. # it by saving it into a file and typing "sh file".  To overwrite existing
  19. # files, type "sh file -c".  You can also feed this as standard input via
  20. # unshar, or by typing "sh <file", e.g..  The tool that generated this
  21. # shell archive is called "shar", and is available by anonymous ftp
  22. # from ftp.uu.net in subdirectory /usenet/comp.sources.unix, and from many
  23. # other places. Check 'archie' for the latest locations.  If this archive
  24. # is complete, you will see the following message at the end:
  25. #        "End of archive 2 (of 3)."
  26. # Contents:  rperf.c termcap.c
  27. # Wrapped by fitzgb@mml0.meche.rpi.edu on Mon Aug 30 15:01:24 1993
  28. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  29. if test -f 'rperf.c' -a "${1}" != "-c" ; then 
  30.   echo shar: Will not clobber existing file \"'rperf.c'\"
  31. else
  32. echo shar: Extracting \"'rperf.c'\" \(41113 characters\)
  33. sed "s/^X//" >'rperf.c' <<'END_OF_FILE'
  34. X#ifndef lint
  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    *sccsid[] = {
  41. X    "@(#)rperf.c    2.1 8/30/93 (c) Copyright Brian P. Fitzgerald",
  42. X    "Rensselaer Polytechnic Institute"
  43. X};
  44. X#endif
  45. X/**
  46. X
  47. Xrperf.c -- print system performance statistics.
  48. X
  49. Xby Brian P. Fitzgerald
  50. XMechanics of Materials Laboratory
  51. XRensselaer Polytechnic Institute
  52. XTroy, New York
  53. X
  54. Xusage: rperf [ options ] [ interval [ count ] ] [ +sortkey ] [ host ... ]
  55. X       rup [ options ] [ interval ] [ host ... ]
  56. X
  57. XSend comments and bug fixes to fitz@rpi.edu
  58. X
  59. XTested:
  60. XSunOS 4.1.1, 4.1.2, 4.1.3
  61. XIBM AIX 3.1, 3.2
  62. XHP-UX 8.0
  63. XNeXT Mach 20
  64. XAlliant FX/2800
  65. XSGI PI Iris 4.0.1, 4.0.2
  66. XSCO Unix 3.2.2
  67. XMIPS RISCos
  68. XDEC Ultrix 4.2
  69. XESIX
  70. XAmiga 4.0 2.1c
  71. X
  72. XNot supported:
  73. XAIX 1.2.1 on aix370
  74. X
  75. XSend reports of successful compilation on other platforms to
  76. Xfitz@rpi.edu
  77. X
  78. XHistory:
  79. X
  80. X5/6/92    beta    posted to alt.sources
  81. X5/18/92    1.1    Added multiple hosts, uptime display.  Improved output
  82. X        format.
  83. X5/25/92    1.2    Added signal handler.
  84. X
  85. X1/6/93    1.3    Added broadcast mode
  86. X
  87. X2/6/93    1.4    Added output sorting options.
  88. X        Added rup alias.
  89. X
  90. X2/10/93    1.5    Corrected rpc version mismatch.  Now if_opackets right.
  91. X        Plugged some memory leaks.
  92. X
  93. X3/5/93    1.6    Variable number of disks and cpu states.
  94. X        Fixed a line wrap problem.  Added termcap routine.
  95. X
  96. X8/26/93    2.1    posted to comp.sources.misc
  97. X
  98. X**/
  99. X
  100. X#ifdef STDC_HEADERS
  101. X#include <stddef.h>
  102. X#endif
  103. X#include <sys/types.h>
  104. X#include <sys/socket.h>
  105. X#include <netinet/in.h>
  106. X#include <sys/time.h>
  107. X
  108. X#include <time.h>
  109. X
  110. X#include <sys/ioctl.h>
  111. X#ifndef TIOCGWINSZ
  112. X#ifdef HAVE_SYS_TERMIO_H
  113. X#include <sys/termio.h>
  114. X#endif
  115. X#endif
  116. X#ifdef HAVE_SYS_BSD_TTY_H
  117. X#include <sys/bsd_tty.h>
  118. X#endif
  119. X
  120. X#include <arpa/inet.h>
  121. X#include <netdb.h>
  122. X#include <rpc/rpc.h>
  123. X#include <rpc/pmap_clnt.h>
  124. X#include "rstat.h"
  125. X#include <stdio.h>
  126. X#include <signal.h>
  127. X#include <string.h>
  128. X#include <assert.h>
  129. X#include <errno.h>
  130. X
  131. X/* <unistd.h> */
  132. X#define STDOUT_FILENO   1
  133. X
  134. X/* <sys/dk.h> */
  135. X#define CP_USER         0
  136. X#define CP_NICE         1
  137. X#define CP_SYS          2
  138. X#define CP_IDLE         3
  139. X
  140. X/* <sys/ioctl.h> or <sys/ttycom.h> */
  141. Xstruct Winsize {
  142. X    unsigned short  ws_row;    /* rows, in characters */
  143. X    unsigned short  ws_col;    /* columns, in characters */
  144. X    unsigned short  ws_xpixel;    /* horizontal size, pixels - not used */
  145. X    unsigned short  ws_ypixel;    /* vertical size, pixels - not used */
  146. X};
  147. X
  148. X#define O_CP    0x01
  149. X#define O_DK    0x02
  150. X#define O_VM    0x04
  151. X#define O_IF    0x08
  152. X#define O_TIME    0x10
  153. X#define O_DATE    0x20
  154. X#define O_SECS    0x40
  155. X#define O_ALL    ( O_CP | O_DK | O_VM | O_IF )
  156. X#define O_DEFL    ( O_CP | O_VM | O_IF )
  157. X#define O_DEFL1    ( O_CP | O_DK | O_VM | O_IF )
  158. X#define O_UP    0x100
  159. X#define O_BCST    0x200
  160. X#define O_BARE    0x400
  161. X#define O_DBG    0x800
  162. X#define O_SHOST    0x1000
  163. X#define O_NHOST 0x8000
  164. X#define O_SORT 0x10000
  165. X#define O_RVRS 0x20000
  166. X
  167. X#define cpu(dt) (dcpu ? ((dt) * 100 + hdcpu ) / dcpu : 0)
  168. X#define loadav(nrun) ( (float) (nrun) / FSCALE )
  169. X#define delta(x) ((*dpp)->sn.x - (*dpp)->so.x)    /* use this macro with care */
  170. X#define rate(x)    (dt ? ((x) * 1000L + hdt ) / dt : 0)
  171. X
  172. X#ifndef abs
  173. X#define abs(a) ((a)>= 0 ? (a) : -(a))
  174. X#endif /* abs */
  175. X
  176. X#ifndef max
  177. X#define max(a, b) ((a) > (b) ? (a) : (b))
  178. X#endif /* max */
  179. X
  180. X#define RSTATVERS_BCST RSTATVERS_TIME
  181. Xtypedef statstime stats_broadcast;
  182. X#define RSTATVERS_DEFAULT RSTATVERS_VAR
  183. Xtypedef statsvar stats_default;
  184. X
  185. Xchar           *getenv();
  186. Xvoid            exit();
  187. Xlong            strtol();
  188. Xextern char    *strdup();
  189. X
  190. Xstats_default  *from_stats();
  191. Xstats_default  *from_statsswtch();
  192. Xstats_default  *from_statstime();
  193. Xstats_default  *from_statsvar();
  194. X
  195. Xstats_default  *((*stats_convert[]) ()) =
  196. X{
  197. X    from_stats,
  198. X    from_statsswtch,
  199. X    from_statstime,
  200. X    from_statsvar,
  201. X};
  202. X#define STATS_CONVERT(version) (stats_convert[(version)-1])
  203. X
  204. Xbool_t(*xdr_statsproc[]) () =
  205. X{
  206. X    xdr_stats,
  207. X    xdr_statsswtch,
  208. X    xdr_statstime,
  209. X    xdr_statsvar,
  210. X};
  211. X#define XDR_STATSPROC(version) (xdr_statsproc[(version)-1])
  212. X
  213. Xunion stats_all {
  214. X    struct stats    s1;
  215. X    struct statsswtch s2;
  216. X    struct statstime s3;
  217. X    struct statsvar s4;
  218. X};
  219. Xtypedef union stats_all stats_all;
  220. X
  221. Xstruct data {
  222. X    struct data    *datap;
  223. X    unsigned long   nn;
  224. X    unsigned long   no;
  225. X    struct in_addr  addr;
  226. X    char           *host;
  227. X    CLIENT         *cl;
  228. X    u_long          cl_vers;
  229. X    stats_default   sn;
  230. X    stats_default   so;
  231. X    stats_default   sd;        /* delta or rate.  uptime = sd.boottime */
  232. X};
  233. X
  234. Xstruct key {
  235. X    char           *k_name;
  236. X    int             k_offset;
  237. X    int             k_flag;
  238. X    int             k_index;
  239. X};
  240. Xtypedef struct key key;
  241. X
  242. X#define        K_DELTA 0x1    /* need delta before sorting */
  243. X#define        K_ARRAY    0x2    /* the member is an xdr_array */
  244. X
  245. X/* C faq */
  246. X#ifndef offsetof
  247. X#define offsetof(type, mem) ((size_t) \
  248. X        ((char *)&((type *) 0)->mem - (char *)((type *) 0)))
  249. X#endif                /* offsetof */
  250. X#define sd_offset(mem) offsetof(struct data,sd.mem)
  251. X#define sn_offset(mem) offsetof(struct data,sn.mem)
  252. X
  253. X#define AV1    0
  254. X#define AV5    1
  255. X#define AV15    2
  256. X
  257. Xkey             keys[] = {
  258. X    {"avg", sn_offset(avenrun[AV1]), 0, 0},
  259. X    {"ave", sn_offset(avenrun[AV1]), 0, 0},
  260. X    {"loadavg", sn_offset(avenrun[AV1]), 0, 0},
  261. X    {"loadave", sn_offset(avenrun[AV1]), 0, 0},
  262. X    {"avenrun", sn_offset(avenrun[AV1]), 0, 0},
  263. X    {"av1", sn_offset(avenrun[AV1]), 0, 0},
  264. X    {"av5", sn_offset(avenrun[AV5]), 0, 0},
  265. X    {"av15", sn_offset(avenrun[AV15]), 0, 0},
  266. X
  267. X    {"boottime", sn_offset(boottime.tv_sec), 0, 0},
  268. X    {"uptime", sd_offset(boottime.tv_sec), 0, 0},
  269. X
  270. X    {"user", sd_offset(cp_time), K_DELTA | K_ARRAY, 0},
  271. X    {"us", sd_offset(cp_time), K_DELTA | K_ARRAY, 0},
  272. X    {"nice", sd_offset(cp_time), K_DELTA | K_ARRAY, 1},
  273. X    {"ni", sd_offset(cp_time), K_DELTA | K_ARRAY, 1},
  274. X    {"sys", sd_offset(cp_time), K_DELTA | K_ARRAY, 2},
  275. X    {"system", sd_offset(cp_time), K_DELTA | K_ARRAY, 2},
  276. X    {"sy", sd_offset(cp_time), K_DELTA | K_ARRAY, 2},
  277. X    {"idle", sd_offset(cp_time), K_DELTA | K_ARRAY, 3},
  278. X    {"id", sd_offset(cp_time), K_DELTA | K_ARRAY, 3},
  279. X
  280. X    {"intr", sd_offset(v_intr), K_DELTA, 0},
  281. X    {"swtch", sd_offset(v_swtch), K_DELTA, 0},
  282. X    {"cxsw", sd_offset(v_swtch), K_DELTA, 0},
  283. X    {"csw", sd_offset(v_swtch), K_DELTA, 0},
  284. X
  285. X    {"pgpgin", sd_offset(v_pgpgin), K_DELTA, 0},
  286. X    {"pgin", sd_offset(v_pgpgin), K_DELTA, 0},
  287. X    {"pgpgout", sd_offset(v_pgpgout), K_DELTA, 0},
  288. X    {"pgout", sd_offset(v_pgpgout), K_DELTA, 0},
  289. X    {"pgo", sd_offset(v_pgpgout), K_DELTA, 0},
  290. X
  291. X    {"pswpin", sd_offset(v_pswpin), K_DELTA, 0},
  292. X    {"swpin", sd_offset(v_pswpin), K_DELTA, 0},
  293. X    {"swin", sd_offset(v_pswpin), K_DELTA, 0},
  294. X    {"pswpout", sd_offset(v_pswpout), K_DELTA, 0},
  295. X    {"swpout", sd_offset(v_pswpout), K_DELTA, 0},
  296. X    {"swo", sd_offset(v_pswpout), K_DELTA, 0},
  297. X
  298. X    {"dk_xfer", sd_offset(dk_xfer), K_DELTA | K_ARRAY, 0},
  299. X    {"sd0", sd_offset(dk_xfer), K_DELTA | K_ARRAY, 0},
  300. X    {"disk0", sd_offset(dk_xfer), K_DELTA | K_ARRAY, 0},
  301. X    {"d0", sd_offset(dk_xfer), K_DELTA | K_ARRAY, 0},
  302. X    {"sd1", sd_offset(dk_xfer), K_DELTA | K_ARRAY, 1},
  303. X    {"disk1", sd_offset(dk_xfer), K_DELTA | K_ARRAY, 1},
  304. X    {"d1", sd_offset(dk_xfer), K_DELTA | K_ARRAY, 1},
  305. X    {"sd2", sd_offset(dk_xfer), K_DELTA | K_ARRAY, 2},
  306. X    {"disk2", sd_offset(dk_xfer), K_DELTA | K_ARRAY, 2},
  307. X    {"d2", sd_offset(dk_xfer), K_DELTA | K_ARRAY, 2},
  308. X    {"sd3", sd_offset(dk_xfer), K_DELTA | K_ARRAY, 3},
  309. X    {"disk3", sd_offset(dk_xfer), K_DELTA | K_ARRAY, 3},
  310. X    {"d3", sd_offset(dk_xfer), K_DELTA | K_ARRAY, 3},
  311. X
  312. X    {"ipackets", sd_offset(if_ipackets), K_DELTA, 0},
  313. X    {"ipk", sd_offset(if_ipackets), K_DELTA, 0},
  314. X    {"ierrors", sd_offset(if_ierrors), K_DELTA, 0},
  315. X    {"ier", sd_offset(if_ierrors), K_DELTA, 0},
  316. X    {"oerrors", sd_offset(if_oerrors), K_DELTA, 0},
  317. X    {"oer", sd_offset(if_oerrors), K_DELTA, 0},
  318. X    {"opackets", sd_offset(if_opackets), K_DELTA, 0},
  319. X    {"opk", sd_offset(if_opackets), K_DELTA, 0},
  320. X    {"collisions", sd_offset(if_collisions), K_DELTA, 0},
  321. X    {"coll", sd_offset(if_collisions), K_DELTA, 0},
  322. X    {0, 0, 0, 0}
  323. X};
  324. X
  325. Xkey            *key_ptr = NULL;
  326. X
  327. Xstruct datatbl {
  328. X    int             val;
  329. X    struct data    *dp;
  330. X};
  331. X
  332. Xchar           *keyhelp[] = {
  333. X    "The sort keys are:\n",
  334. X    "\n",
  335. X    "loadavg     user      pgpgin      disk0      boottime    ipackets\n",
  336. X    "av1         nice      pgpgout     disk1      uptime      ierrors\n",
  337. X    "av5         sys       pswpin      disk2                  oerrors\n",
  338. X    "av15        idle      pswpout     disk3                  opackets\n",
  339. X    "                      intr                               collisions\n",
  340. X    "                      swtch\n",
  341. X    0
  342. X};
  343. X
  344. X#define    P_DATA    0
  345. X#define    P_UP    1
  346. X
  347. Xstatic struct timeval TIMEOUT = {25, 0};
  348. X
  349. Xstatic struct data *dp;        /* link list head */
  350. Xstatic unsigned nhosts = 0;    /* multiple hosts idea from Larry McVoy */
  351. Xint             h_seen = 0;    /**
  352. X                 * one or more host arguments was supplied.
  353. X                 *  > 0 is client (non-broadcast) mode
  354. X                 * == 0 is broadcast mode
  355. X                 **/
  356. Xstatic bool_t   bcst_timo;
  357. Xlong            opts = 0;
  358. Xstatic unsigned long thiscount = 0;
  359. Xunsigned        nresp = 0;
  360. X
  361. X/* terminal characteristics */
  362. Xint             term_rows;
  363. Xint             term_cols;
  364. X
  365. Xstruct timeval  starttime;
  366. Xstruct timezone tz;
  367. X
  368. Xchar           *f1_cp = "%-15s ";
  369. Xchar           *f2_cp = "%3s %3s %3s %3s ";
  370. Xchar           *fo_cp = "%3d %3d %3d %3d ";
  371. X
  372. Xchar           *f1_av = "%-14s ";
  373. Xchar           *f2_av = "%4s %4s %4s ";
  374. Xchar           *fo_av = "%4.1f %4.1f %4.1f ";
  375. Xchar           *fo_a0 = "%4.2f %4.2f %4.2f ";
  376. X
  377. Xchar           *f1_dk = "%-12s";
  378. Xchar           *f2_dk = "%2s %2s %2s %2s ";
  379. Xchar           *fo_dk = "%2d %2d %2d %2d ";
  380. X
  381. Xchar           *f1_vm = "%2s %2s %2s %2s %3s %3s ";
  382. Xchar           *f2_vm = "%2s %2s %2s %2s %3s %3s ";
  383. Xchar           *fo_vm = "%2u %2u %2u %2u %3u %3u ";
  384. X
  385. Xchar           *f1_if = " %2s %2s %2s %2s %2s";
  386. Xchar           *f2_if = " %2s %2s %2s %2s %2s";
  387. Xchar           *fo_if = " %2d %2d %2d %2d %2d";
  388. X
  389. Xchar           *f_time = "%-9.9s ";
  390. Xchar           *fo_time = "%9d ";
  391. X
  392. Xchar           *f_date = "%-24.24s ";
  393. X
  394. Xchar           *f_secs = "%-5.5s ";
  395. Xchar           *fo_secs = "%5.2f ";
  396. X
  397. Xchar           *f_h = "%12.12s ";
  398. X
  399. Xchar            title1[160];
  400. Xchar            title2[160];
  401. Xchar            ruler[160];
  402. X
  403. Xstruct array {
  404. X    u_int           len;
  405. X    int            *val;
  406. X};
  407. Xtypedef struct array array;
  408. X
  409. X/*
  410. X * allocate an int array struct, size n and from a if non-null
  411. X */
  412. Xvoid
  413. Xcreate_array(a, p, n)
  414. X    array          *a;
  415. X    int            *p;
  416. X    int             n;
  417. X{
  418. X    int             i;
  419. X
  420. X    a->len = n;
  421. X    a->val = (int *) malloc((unsigned) n * sizeof(int));
  422. X    if (a->val == NULL) {
  423. X    perror("malloc");
  424. X    exit(1);
  425. X    }
  426. X    if (p)
  427. X    for (i = 0; i < n; i++)
  428. X        a->val[i] = p[i];
  429. X}
  430. X
  431. X/*
  432. X * convert and store the received data
  433. X */
  434. Xstats_default  *
  435. Xfrom_stats(s)
  436. X    stats_all      *s;
  437. X{
  438. X    static stats_default r;
  439. X
  440. X    bzero((char *) &r, sizeof(r));
  441. X    create_array((array *) & r.cp_time, s->s1.cp_time, CPUSTATES_ORIG);
  442. X    create_array((array *) & r.dk_xfer, s->s1.dk_xfer, DK_NDRIVE_ORIG);
  443. X    r.v_pgpgin = s->s1.v_pgpgin;
  444. X    r.v_pgpgout = s->s1.v_pgpgout;
  445. X    r.v_pswpin = s->s1.v_pswpin;
  446. X    r.v_pswpout = s->s1.v_pswpout;
  447. X    r.v_intr = s->s1.v_intr;
  448. X    r.if_ipackets = s->s1.if_ipackets;
  449. X    r.if_ierrors = s->s1.if_ierrors;
  450. X    r.if_opackets = s->s1.if_opackets;
  451. X    r.if_oerrors = s->s1.if_oerrors;
  452. X    r.if_collisions = s->s1.if_collisions;
  453. X    if (gettimeofday((struct timeval *) & r.curtime,
  454. X             (struct timezone *) NULL) == -1) {
  455. X    perror("gettimeofday");
  456. X    exit(1);
  457. X    }
  458. X    return &r;
  459. X}
  460. X
  461. Xstats_default  *
  462. Xfrom_statsswtch(s)
  463. X    stats_all      *s;
  464. X{
  465. X    static stats_default r;
  466. X    int             i;
  467. X
  468. X    bzero((char *) &r, sizeof(r));
  469. X    create_array((array *) & r.cp_time, s->s2.cp_time, CPUSTATES_ORIG);
  470. X    create_array((array *) & r.dk_xfer, s->s2.dk_xfer, DK_NDRIVE_ORIG);
  471. X    r.v_pgpgin = s->s2.v_pgpgin;
  472. X    r.v_pgpgout = s->s2.v_pgpgout;
  473. X    r.v_pswpin = s->s2.v_pswpin;
  474. X    r.v_pswpout = s->s2.v_pswpout;
  475. X    r.v_intr = s->s2.v_intr;
  476. X    r.if_ipackets = s->s2.if_ipackets;
  477. X    r.if_ierrors = s->s2.if_ierrors;
  478. X    r.if_opackets = s->s2.if_opackets;
  479. X    r.if_oerrors = s->s2.if_oerrors;
  480. X    r.if_collisions = s->s2.if_collisions;
  481. X    r.v_swtch = s->s2.v_swtch;
  482. X    for (i = 0; i < 3; i++)
  483. X    r.avenrun[i] = s->s2.avenrun[i];
  484. X    r.boottime = s->s2.boottime;
  485. X    if (gettimeofday((struct timeval *) & r.curtime,
  486. X             (struct timezone *) NULL) == -1) {
  487. X    perror("gettimeofday");
  488. X    exit(1);
  489. X    }
  490. X    return &r;
  491. X}
  492. X
  493. Xstats_default  *
  494. Xfrom_statstime(s)
  495. X    stats_all      *s;
  496. X{
  497. X    static stats_default r;
  498. X    int             i;
  499. X
  500. X    bzero((char *) &r, sizeof(r));
  501. X    create_array((array *) & r.cp_time, s->s3.cp_time, CPUSTATES_ORIG);
  502. X    create_array((array *) & r.dk_xfer, s->s3.dk_xfer, DK_NDRIVE_ORIG);
  503. X    r.v_pgpgin = s->s3.v_pgpgin;
  504. X    r.v_pgpgout = s->s3.v_pgpgout;
  505. X    r.v_pswpin = s->s3.v_pswpin;
  506. X    r.v_pswpout = s->s3.v_pswpout;
  507. X    r.v_intr = s->s3.v_intr;
  508. X    r.if_ipackets = s->s3.if_ipackets;
  509. X    r.if_ierrors = s->s3.if_ierrors;
  510. X    r.if_opackets = s->s3.if_opackets;
  511. X    r.if_oerrors = s->s3.if_oerrors;
  512. X    r.if_collisions = s->s3.if_collisions;
  513. X    r.v_swtch = s->s3.v_swtch;
  514. X    for (i = 0; i < 3; i++)
  515. X    r.avenrun[i] = s->s3.avenrun[i];
  516. X    r.boottime = s->s3.boottime;
  517. X    r.curtime = s->s3.curtime;
  518. X    return &r;
  519. X}
  520. X
  521. Xstats_default  *
  522. Xfrom_statsvar(s)
  523. X    stats_all      *s;
  524. X{
  525. X    static stats_default r;
  526. X    int             i;
  527. X
  528. X    bzero((char *) &r, sizeof(r));
  529. X    create_array((array *) & r.cp_time, s->s4.cp_time.cp_time_val,
  530. X         (int) s->s4.cp_time.cp_time_len);
  531. X    create_array((array *) & r.dk_xfer, s->s4.dk_xfer.dk_xfer_val,
  532. X         (int) s->s4.dk_xfer.dk_xfer_len);
  533. X    r.v_pgpgin = s->s4.v_pgpgin;
  534. X    r.v_pgpgout = s->s4.v_pgpgout;
  535. X    r.v_pswpin = s->s4.v_pswpin;
  536. X    r.v_pswpout = s->s4.v_pswpout;
  537. X    r.v_intr = s->s4.v_intr;
  538. X    r.if_ipackets = s->s4.if_ipackets;
  539. X    r.if_ierrors = s->s4.if_ierrors;
  540. X    r.if_opackets = s->s4.if_opackets;
  541. X    r.if_oerrors = s->s4.if_oerrors;
  542. X    r.if_collisions = s->s4.if_collisions;
  543. X    r.v_swtch = s->s4.v_swtch;
  544. X    for (i = 0; i < 3; i++)
  545. X    r.avenrun[i] = s->s4.avenrun[i];
  546. X    r.boottime = s->s4.boottime;
  547. X    r.curtime = s->s4.curtime;
  548. X    return &r;
  549. X}
  550. X
  551. X/*
  552. X * free the cp_time and dk_xfer array in a stats_default struct
  553. X */
  554. Xvoid
  555. Xfree_stats(s)
  556. X    stats_default  *s;
  557. X{
  558. X    free((char *) s->cp_time.cp_time_val);
  559. X    free((char *) s->dk_xfer.dk_xfer_val);
  560. X}
  561. X
  562. X/*
  563. X * save the results in a data structure
  564. X */
  565. Xvoid
  566. Xsave_res(d, res)
  567. X    struct data    *d;
  568. X    stats_default  *res;
  569. X{
  570. X    if (d->nn == thiscount)
  571. X    return;            /* duplicate.  ignore */
  572. X    d->no = d->nn;
  573. X    d->nn = thiscount;
  574. X
  575. X    free_stats(&d->so);
  576. X    d->so = d->sn;
  577. X    d->sn = *res;
  578. X    return;
  579. X}
  580. X
  581. X/*
  582. X * handle lack of communication with client.
  583. X */
  584. Xvoid
  585. Xdrop_from_list(dpp)
  586. X    struct data   **dpp;
  587. X{
  588. X    struct data    *tdp;
  589. X
  590. X    if ((*dpp)->cl)
  591. X    clnt_destroy((*dpp)->cl);
  592. X    free((*dpp)->host);
  593. X
  594. X    tdp = *dpp;
  595. X    *dpp = (*dpp)->datap;
  596. X
  597. X    free_stats(&tdp->so);
  598. X    free((char *) tdp);
  599. X    (void) putc('d', stdout);
  600. X    (void) fflush(stdout);
  601. X    nhosts--;
  602. X    return;
  603. X}
  604. X
  605. X/**
  606. X * this function may be called after (*dpp)->addr
  607. X * has been filled with a valid in_addr
  608. X **/
  609. Xint
  610. Xmake_client(dpp)
  611. X    struct data   **dpp;
  612. X{
  613. X    struct sockaddr_in server_addr;
  614. X    struct timeval  p_timo;
  615. X    int             sock = RPC_ANYSOCK;
  616. X
  617. X    p_timo.tv_sec = 3;
  618. X    p_timo.tv_usec = 0;
  619. X
  620. X    server_addr.sin_family = AF_INET;
  621. X    server_addr.sin_port = 0;
  622. X    server_addr.sin_addr = (*dpp)->addr;
  623. X
  624. X    /**
  625. X     * clntudp_create only determines whether the
  626. X     * program is registered.  It does not actually check
  627. X     * whether the host supports the requested version.
  628. X     * see the pamp_getport man page.
  629. X     **/
  630. X    (*dpp)->cl = clntudp_create(&server_addr,
  631. X                RSTATPROG,
  632. X                (*dpp)->cl_vers,
  633. X                p_timo,
  634. X                &sock);
  635. X
  636. X    if ((*dpp)->cl == NULL) {
  637. X    (void) fprintf(stderr, "Can't contact rstatd on %s because%s\n",
  638. X               (*dpp)->host, clnt_spcreateerror(""));
  639. X    return 0;
  640. X    }
  641. X    if (opts & O_DBG) {
  642. X    (void) putc('m', stdout);
  643. X    (void) fflush(stdout);
  644. X    }
  645. X    return 1;
  646. X}
  647. X
  648. X/**
  649. X * for each host on the linked list that still needs data:
  650. X * loop over the rpc prog versions,
  651. X *    starting with the highest known version,
  652. X *    or highest previously successful version
  653. X *        make a client, if necessary
  654. X *        call the client
  655. X **/
  656. Xvoid
  657. Xdoclnt_calls()
  658. X{
  659. X    stats_all       res;
  660. X    stats_default  *sn;
  661. X    static enum clnt_stat clnt_stat;
  662. X    struct data   **dpp;
  663. X    int             good = 0;
  664. X    int             bad = 0;
  665. X    u_long          vers;
  666. X
  667. X    for (dpp = &dp; *dpp;) {
  668. X    if (opts & O_DBG)
  669. X        (void) fprintf(stdout, "%s ", inet_ntoa((*dpp)->addr));
  670. X    if ((*dpp)->nn == thiscount) {
  671. X        dpp = &(*dpp)->datap;
  672. X        if (opts & O_DBG) {
  673. X        (void) fputs("-\n", stdout);
  674. X        }
  675. X        continue;        /* already have data */
  676. X    }
  677. X    if (!(*dpp)->cl_vers)
  678. X        (*dpp)->cl_vers = RSTATVERS_DEFAULT;    /* highest version */
  679. X    bzero((char *) &res, sizeof(res));
  680. X    for (vers = (*dpp)->cl_vers; vers > 0; vers--) {
  681. X        (*dpp)->cl_vers = vers;
  682. X        if (!(*dpp)->cl)
  683. X        if (!make_client(dpp)) {
  684. X            drop_from_list(dpp);
  685. X            bad++;
  686. X            break;    /* vers */
  687. X        }
  688. X        if (opts & O_DBG) {
  689. X        (void) fprintf(stdout, "v%d", vers);
  690. X        (void) fflush(stdout);
  691. X        }
  692. X        clnt_stat = clnt_call((*dpp)->cl,
  693. X                  RSTATPROC_STATS,
  694. X                  xdr_void,
  695. X                  NULL,
  696. X                  XDR_STATSPROC((*dpp)->cl_vers),
  697. X                  &res,
  698. X                  TIMEOUT);
  699. X        if (clnt_stat == RPC_SUCCESS) {
  700. X        sn = STATS_CONVERT((*dpp)->cl_vers) (&res);
  701. X        xdr_free(XDR_STATSPROC((*dpp)->cl_vers), (char *) &res);
  702. X        save_res(*dpp, sn);
  703. X        if (opts & O_DBG) {
  704. X            (void) fputs("c\n", stdout);
  705. X        }
  706. X        good++;
  707. X        dpp = &(*dpp)->datap;
  708. X        break;        /* vers */
  709. X        }
  710. X        if (clnt_stat == RPC_PROGVERSMISMATCH && vers > 1) {
  711. X        if (opts & O_DBG) {
  712. X            (void) fputs("M ", stdout);
  713. X            (void) fflush(stdout);
  714. X        }
  715. X        clnt_destroy((*dpp)->cl);
  716. X        (*dpp)->cl = NULL;
  717. X        continue;    /* vers-- */
  718. X        }
  719. X        (void) fprintf(stderr, "clnt_call: %s %s\n",
  720. X               (*dpp)->host, clnt_sperrno(clnt_stat));
  721. X        drop_from_list(dpp);
  722. X        bad++;
  723. X        break;        /* vers */
  724. X    }            /* for(vers ... */
  725. X    }
  726. X
  727. X    if (opts & O_DBG) {
  728. X    (void) fprintf(stdout, "done clnt calls good=%d bad=%d\n", good, bad);
  729. X    }
  730. X    if (!nhosts)
  731. X    exit(1);
  732. X    return;
  733. X}
  734. X
  735. X/**
  736. X * given an internet address,
  737. X *    get the hostname,
  738. X *    or the ascii internet address
  739. X **/
  740. Xchar           *
  741. Xget_hostname(addr)
  742. X    struct in_addr  addr;
  743. X{
  744. X    struct hostent *host_entry;
  745. X
  746. X    host_entry = NULL;
  747. X    if (opts & O_NHOST) {
  748. X    return inet_ntoa(addr);
  749. X    } else {
  750. X    host_entry = gethostbyaddr((char *) &addr, 4, AF_INET);
  751. X    if (!host_entry && opts & O_DBG)
  752. X        (void) fputs("byaddr failed\n", stdout);
  753. X    return host_entry ? host_entry->h_name : inet_ntoa(addr);
  754. X    }
  755. X}
  756. X
  757. X/*
  758. X * create a new data structure
  759. X */
  760. Xstruct data    *
  761. Xnew_host(addr, hostname)
  762. X    struct in_addr *addr;
  763. X    char           *hostname;
  764. X{
  765. X    struct data    *newdpp;
  766. X
  767. X    newdpp = (struct data *) calloc(1, sizeof(struct data));
  768. X    if (newdpp == NULL) {
  769. X    perror("calloc");
  770. X    exit(1);
  771. X    }
  772. X    newdpp->addr = *addr;
  773. X    newdpp->host = strdup(hostname);
  774. X    if (!newdpp->host) {
  775. X    perror("strdup");
  776. X    exit(1);
  777. X    }
  778. X    nhosts++;
  779. X    if (!h_seen) {
  780. X    (void) putc('+', stdout);
  781. X    (void) fflush(stdout);
  782. X    }
  783. X    return newdpp;
  784. X}
  785. X
  786. X/*
  787. X * handle each reply to the broadcast
  788. X */
  789. Xbool_t
  790. Xeach_result(resp, raddr)
  791. X    stats_broadcast *resp;
  792. X    struct sockaddr_in *raddr;
  793. X{
  794. X    char           *hostname;
  795. X    struct data   **dpp;
  796. X    stats_default  *sn;
  797. X
  798. X    sn = STATS_CONVERT(RSTATVERS_BCST) (resp);
  799. X    xdr_free(XDR_STATSPROC(RSTATVERS_BCST), (char *) resp);
  800. X
  801. X    hostname = NULL;
  802. X    for (dpp = &dp; *dpp; dpp = &(*dpp)->datap) {
  803. X    if (raddr->sin_addr.s_addr == (*dpp)->addr.s_addr) {
  804. X        /* duplicate */
  805. X        save_res(*dpp, sn);
  806. X        (void) putc('.', stdout);
  807. X        (void) fflush(stdout);
  808. X        return bcst_timo;
  809. X    }
  810. X    if (!hostname)
  811. X        hostname = get_hostname(raddr->sin_addr);
  812. X
  813. X    if (opts & O_SHOST ?
  814. X        strcmp(hostname, (*dpp)->host) < 0 :
  815. X        raddr->sin_addr.s_addr < (*dpp)->addr.s_addr) {
  816. X        /* insert */
  817. X        struct data    *tdp;
  818. X        tdp = *dpp;
  819. X        *dpp = new_host(&raddr->sin_addr, hostname);
  820. X        save_res(*dpp, sn);
  821. X        (*dpp)->datap = tdp;
  822. X        return bcst_timo;
  823. X    }
  824. X    }
  825. X    /* append */
  826. X    if (!hostname)
  827. X    hostname = get_hostname(raddr->sin_addr);
  828. X    *dpp = new_host(&raddr->sin_addr, hostname);
  829. X    save_res(*dpp, sn);
  830. X    (*dpp)->datap = NULL;
  831. X    return bcst_timo;
  832. X}
  833. X
  834. X/*
  835. X * handle termination signals
  836. X */
  837. XRETSIGTYPE
  838. Xcleanup()
  839. X{
  840. X    exit(0);            /* flush and close stdout */
  841. X}
  842. X
  843. X/*
  844. X * force end of broadcasting
  845. X */
  846. XRETSIGTYPE
  847. Xbcst_done()
  848. X{
  849. X    bcst_timo = TRUE;
  850. X}
  851. X
  852. X/*
  853. X * see if display will wrap.  Try to fix.
  854. X */
  855. Xchar           *
  856. Xcheckwrap(cols, obuf)
  857. X    int             cols;
  858. X    char           *obuf;
  859. X{
  860. X    int             olen = strlen(obuf);
  861. X    int             rlen = strlen(ruler);
  862. X    char           *rp, *op, *tp, *sp, *cp;
  863. X    int             rpos = 0, opos;
  864. X    int             nsp, err = 0;
  865. X
  866. X    if (olen <= rlen || rlen > cols)
  867. X    return obuf;        /* leave alone */
  868. X
  869. X    if (opts & O_DBG) {
  870. X    (void) fprintf(stdout, "wrap terminal=%d ruler=%d output%d\n",
  871. X               cols, rlen, olen);
  872. X    (void) fputs(ruler, stdout);
  873. X    (void) putc('\n', stdout);
  874. X    }
  875. X    op = obuf;
  876. X    for (rp = ruler; *rp;) {
  877. X    tp = op;
  878. X    for (; *rp && *rp == ' '; rp++);
  879. X    for (; *op && *op == ' '; op++);
  880. X    nsp = op - tp;
  881. X    for (; *rp && *rp != ' '; rp++);
  882. X    for (; *op && *op != ' '; op++);
  883. X
  884. X    if (!*rp || nsp > 1) {
  885. X        rpos = rp - ruler;
  886. X        opos = op - obuf;
  887. X        err = opos - rpos;
  888. X    }
  889. X    if (err > 0) {
  890. X        if (opts & O_DBG) {
  891. X        (void) fputs(obuf, stdout);
  892. X        (void) putc('\n', stdout);
  893. X        (void) fprintf(stdout, "rpos=%d err=%d\n", rpos, err);
  894. X        }
  895. X        for (sp = op; sp != obuf; sp--) {
  896. X        if (*sp == ' ')
  897. X            sp--;
  898. X        if (*sp == ' ') {    /* shift left one char */
  899. X            sp++;
  900. X            for (cp = sp; *cp; cp++)
  901. X            *cp = *(cp + 1);
  902. X            op--;
  903. X            if (!--err)
  904. X            break;
  905. X        }
  906. X        }
  907. X    }
  908. X    rpos = rp - ruler;
  909. X    opos = op - obuf;
  910. X    err = opos - rpos;
  911. X    }
  912. X
  913. X    if (opts & O_DBG)
  914. X    (void) fputs(" . . . . 1 . . . . 2 . . . . 3 . . . . 4 . . . . 5 . . . . 6 . . . . 7 . . . .\n", stdout);
  915. X    return obuf;
  916. X}
  917. X
  918. X/*
  919. X * qsort comparison routine
  920. X */
  921. Xstatic int
  922. Xdatacompare(i, j)
  923. X    struct datatbl *i, *j;
  924. X{
  925. X    return opts & O_RVRS ?
  926. X    i->val - j->val :
  927. X    j->val - i->val;
  928. X}
  929. X
  930. X/*
  931. X * calculate deltas and other items, for later sorting
  932. X */
  933. Xstruct datatbl *
  934. Xcompute_data(tbl)
  935. X    struct datatbl *tbl;
  936. X{
  937. X    struct data   **dpp;
  938. X    int             i;
  939. X    long            dt, hdt;    /* msec */
  940. X    int             dcpu, hdcpu;
  941. X
  942. X    nresp = 0;
  943. X    for (dpp = &dp; *dpp; dpp = &(*dpp)->datap) {
  944. X    /* this data is current */
  945. X    if ((*dpp)->nn == thiscount) {
  946. X
  947. X        (*dpp)->sd.boottime.tv_sec =    /* uptime */
  948. X        (*dpp)->sn.curtime.tv_sec
  949. X        - (*dpp)->sn.boottime.tv_sec;
  950. X
  951. X        nresp++;
  952. X        if ((*dpp)->no) {
  953. X        /* this data is not the first response from that host */
  954. X
  955. X        /* time in milliseconds, since last call */
  956. X        dt = (((*dpp)->sn.curtime.tv_sec -
  957. X               (*dpp)->so.curtime.tv_sec) * 1000000 +
  958. X              ((*dpp)->sn.curtime.tv_usec -
  959. X               (*dpp)->so.curtime.tv_usec) + 500) / 1000;
  960. X        hdt = (dt + 1) / 2;
  961. X
  962. X        /* first reply from aix3.1 may have wrong cp_time[] */
  963. X        dcpu = 0;
  964. X        if (!(*dpp)->sd.cp_time.cp_time_val)
  965. X            create_array((array *) & (*dpp)->sd.cp_time, (int *) NULL,
  966. X                 (int) (*dpp)->sn.cp_time.cp_time_len);
  967. X
  968. X        for (i = 0; i < (*dpp)->sn.cp_time.cp_time_len; i++) {
  969. X            (*dpp)->sd.cp_time.cp_time_val[i]
  970. X            = delta(cp_time.cp_time_val[i]);
  971. X            dcpu += (*dpp)->sd.cp_time.cp_time_val[i];
  972. X        }
  973. X
  974. X        /**
  975. X             * From vmstat.c 5.31 (Berkeley)
  976. X             * We round upward to avoid losing low-frequency events
  977. X             * (i.e., >= 1 per interval but < 1 per second).
  978. X             **/
  979. X        hdcpu = dcpu / 2;
  980. X        for (i = 0; i < (*dpp)->sn.cp_time.cp_time_len; i++)
  981. X            (*dpp)->sd.cp_time.cp_time_val[i]
  982. X            = cpu((*dpp)->sd.cp_time.cp_time_val[i]);
  983. X
  984. X        if (!(*dpp)->sd.dk_xfer.dk_xfer_val)
  985. X            create_array((array *) & (*dpp)->sd.dk_xfer, (int *) NULL,
  986. X                 (int) (*dpp)->sn.dk_xfer.dk_xfer_len);
  987. X
  988. X        for (i = 0; i < (*dpp)->sn.dk_xfer.dk_xfer_len; i++)
  989. X            (*dpp)->sd.dk_xfer.dk_xfer_val[i]
  990. X            = rate(delta(dk_xfer.dk_xfer_val[i]));
  991. X
  992. X        (*dpp)->sd.v_pgpgin = rate(delta(v_pgpgin));
  993. X        (*dpp)->sd.v_pgpgout = rate(delta(v_pgpgout));
  994. X        (*dpp)->sd.v_pswpin = rate(delta(v_pswpin));
  995. X        (*dpp)->sd.v_pswpout = rate(delta(v_pswpout));
  996. X        (*dpp)->sd.v_swtch = rate(delta(v_swtch));
  997. X        /* Why does v_intr count down on aix370? */
  998. X        (*dpp)->sd.v_intr = rate(abs((int) (delta(v_intr))));
  999. X
  1000. X        (*dpp)->sd.if_ipackets = rate(delta(if_ipackets));
  1001. X        (*dpp)->sd.if_ierrors = rate(delta(if_ierrors));
  1002. X        (*dpp)->sd.if_opackets = rate(delta(if_opackets));
  1003. X        (*dpp)->sd.if_oerrors = rate(delta(if_oerrors));
  1004. X        (*dpp)->sd.if_collisions = rate(delta(if_collisions));
  1005. X        }            /* (*dpp)->no */
  1006. X    }            /* (*dpp)->nn == thiscount */
  1007. X    }
  1008. X
  1009. X    if (tbl)
  1010. X    free((char *) tbl);
  1011. X    tbl = (struct datatbl *) malloc(nresp * sizeof(struct datatbl));
  1012. X    if (tbl == NULL) {
  1013. X    perror("malloc");
  1014. X    exit(1);
  1015. X    }
  1016. X    i = 0;
  1017. X    for (dpp = &dp; *dpp; dpp = &(*dpp)->datap) {
  1018. X    if ((*dpp)->nn == thiscount) {
  1019. X
  1020. X        tbl[i].dp = *dpp;
  1021. X        if (opts & O_SORT &&
  1022. X        (thiscount > 1 || !(key_ptr->k_flag & K_DELTA)))
  1023. X        if (key_ptr->k_flag & K_ARRAY) {
  1024. X            array           arr;
  1025. X
  1026. X            arr = *(array *) ((char *) (*dpp) + key_ptr->k_offset);
  1027. X            tbl[i].val = arr.val[key_ptr->k_index];
  1028. X        } else {
  1029. X            tbl[i].val = *(int *) ((char *) (*dpp) + key_ptr->k_offset);
  1030. X        }
  1031. X        i++;
  1032. X    }
  1033. X    }
  1034. X
  1035. X    if (opts & O_SORT)
  1036. X    qsort((char *) tbl, (int) nresp, sizeof(struct datatbl), datacompare);
  1037. X    return tbl;
  1038. X}
  1039. X
  1040. X/*
  1041. X * get screen size from termcap entry
  1042. X */
  1043. Xcheck_termcap()
  1044. X{
  1045. X    char           *term;
  1046. X    static int      status;
  1047. X    static int      seen;
  1048. X    static int      t_rows;
  1049. X    static int      t_cols;
  1050. X    char            termcap_buf[1024];
  1051. X    char           *efmt = "Can't get terminal size because\n%s";
  1052. X
  1053. X    if (seen) {
  1054. X    if (status == 1) {
  1055. X        term_rows = t_rows;
  1056. X        term_cols = t_cols;
  1057. X    }
  1058. X    return;
  1059. X    }
  1060. X    seen = 1;
  1061. X
  1062. X    term = getenv("TERM");
  1063. X    if (!term) {
  1064. X    (void) fprintf(stderr, efmt, "TERM environment variable not set.\n");
  1065. X    return;
  1066. X    }
  1067. X    status = tgetent(termcap_buf, term);
  1068. X    switch (status) {
  1069. X    case -1:
  1070. X    (void) fprintf(stderr, efmt, "can't open termcap file.\n");
  1071. X    return;
  1072. X    case 0:
  1073. X    (void) fprintf(stderr, efmt, "no termcap entry for a ");
  1074. X    (void) fprintf(stderr, "`%s' terminal\n", term);
  1075. X    return;
  1076. X    case 1:
  1077. X    t_rows = tgetnum("li");
  1078. X    if (t_rows == -1)
  1079. X        t_rows = 0;
  1080. X    t_cols = tgetnum("co");
  1081. X    if (t_cols == -1)
  1082. X        t_cols = 0;
  1083. X    term_rows = t_rows;
  1084. X    term_cols = t_cols;
  1085. X    if (opts & O_DBG)
  1086. X        (void) fprintf(stdout, "check_termcap: tgetnum: %d %d\n",
  1087. X               term_rows, term_cols);
  1088. X    }
  1089. X}
  1090. X
  1091. X/*
  1092. X * get terminal size
  1093. X */
  1094. Xvoid
  1095. Xcheck_term()
  1096. X{
  1097. X    struct Winsize  winsize;
  1098. X
  1099. X    winsize.ws_row = 0;
  1100. X    winsize.ws_col = 0;
  1101. X    term_rows = 0;
  1102. X    term_cols = 0;
  1103. X    if (ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *) &winsize) == -1) {
  1104. X    if (opts & O_DBG)
  1105. X        perror("ioctl: TIOCGWINSZ");
  1106. X    return;            /* assume not a terminal */
  1107. X    }
  1108. X    term_rows = winsize.ws_row;
  1109. X    term_cols = winsize.ws_col;
  1110. X    if (term_rows == 0 || term_cols == 0)
  1111. X    check_termcap();
  1112. X}
  1113. X
  1114. X/*
  1115. X * print the statistics or the uptime
  1116. X */
  1117. Xvoid
  1118. Xprint_data(tbl, flag)
  1119. X    struct datatbl *tbl;
  1120. X    int             flag;
  1121. X{
  1122. X    char            obuf[160];
  1123. X    int             i;
  1124. X    long            up, upd, uph, upm;
  1125. X    float           s;
  1126. X
  1127. X    if (opts & O_SECS) {
  1128. X    struct timeval  now;
  1129. X    if (gettimeofday(&now, (struct timezone *) 0) == -1) {
  1130. X        perror("gettimeofday");
  1131. X        exit(1);
  1132. X    }
  1133. X    s = (now.tv_sec - starttime.tv_sec) +
  1134. X        ((now.tv_usec - starttime.tv_usec) + 5000)
  1135. X        / 10000 / 100.;
  1136. X    }
  1137. X    for (i = 0; i < nresp; i++) {
  1138. X    switch (flag) {
  1139. X    case P_DATA:
  1140. X        if (!tbl[i].dp->no)    /* do we have delta? */
  1141. X        break;
  1142. X        obuf[0] = '\0';
  1143. X        if (opts & O_TIME)
  1144. X        (void) sprintf(obuf + strlen(obuf), fo_time,
  1145. X                   tbl[i].dp->sn.curtime.tv_sec);
  1146. X        if (opts & O_DATE) {
  1147. X        char            buf[30];
  1148. X        struct tm      *tp;
  1149. X
  1150. X        tp = localtime((long *) &tbl[i].dp->sn.curtime.tv_sec);
  1151. X        if (!strftime(buf, 30, "%a %b %d %H:%M:%S %Y ", tp)) {
  1152. X            (void) fputs("can't convert date\n", stderr);
  1153. X            exit(1);
  1154. X        }
  1155. X        (void) sprintf(obuf + strlen(obuf), f_date, buf);
  1156. X        }
  1157. X        if (opts & O_SECS)
  1158. X        (void) sprintf(obuf + strlen(obuf), fo_secs, s);
  1159. X        if (nhosts > 1 || !h_seen)
  1160. X        (void) sprintf(obuf + strlen(obuf), f_h, tbl[i].dp->host);
  1161. X        if (opts & O_CP) {
  1162. X        (void) sprintf(obuf + strlen(obuf), fo_cp,
  1163. X                   tbl[i].dp->sd.cp_time.cp_time_val[CP_USER],
  1164. X                   tbl[i].dp->sd.cp_time.cp_time_val[CP_NICE],
  1165. X                   tbl[i].dp->sd.cp_time.cp_time_val[CP_SYS],
  1166. X                   tbl[i].dp->sd.cp_time.cp_time_val[CP_IDLE]);
  1167. X        /* average run queue lengths */
  1168. X        (void) sprintf(obuf + strlen(obuf), fo_av,
  1169. X                   loadav(tbl[i].dp->sn.avenrun[AV1]),
  1170. X                   loadav(tbl[i].dp->sn.avenrun[AV5]),
  1171. X                   loadav(tbl[i].dp->sn.avenrun[AV15]));
  1172. X        }
  1173. X        if (opts & O_DK)
  1174. X        (void) sprintf(obuf + strlen(obuf), fo_dk,
  1175. X                   tbl[i].dp->sd.dk_xfer.dk_xfer_val[0],
  1176. X                   tbl[i].dp->sd.dk_xfer.dk_xfer_val[1],
  1177. X                   tbl[i].dp->sd.dk_xfer.dk_xfer_val[2],
  1178. X                   tbl[i].dp->sd.dk_xfer.dk_xfer_val[3]);
  1179. X
  1180. X        if (opts & O_VM)
  1181. X        (void) sprintf(obuf + strlen(obuf), fo_vm,
  1182. X                   tbl[i].dp->sd.v_pgpgin,
  1183. X                   tbl[i].dp->sd.v_pgpgout,
  1184. X                   tbl[i].dp->sd.v_pswpin,
  1185. X                   tbl[i].dp->sd.v_pswpout,
  1186. X                   tbl[i].dp->sd.v_swtch,
  1187. X                   tbl[i].dp->sd.v_intr);
  1188. X
  1189. X        if (opts & O_IF)
  1190. X        (void) sprintf(obuf + strlen(obuf), fo_if,
  1191. X                   tbl[i].dp->sd.if_ipackets,
  1192. X                   tbl[i].dp->sd.if_ierrors,
  1193. X                   tbl[i].dp->sd.if_opackets,
  1194. X                   tbl[i].dp->sd.if_oerrors,
  1195. X                   tbl[i].dp->sd.if_collisions);
  1196. X
  1197. X        check_term();
  1198. X        (void) fputs(checkwrap(term_cols > 0 ? term_cols - 1 : 0,
  1199. X                   obuf), stdout);
  1200. X        (void) putc('\n', stdout);
  1201. X
  1202. X        if (opts & O_DK) {
  1203. X        int             d, dhigh = -1;
  1204. X        int             moredisks;
  1205. X
  1206. X        for (d = tbl[i].dp->sn.dk_xfer.dk_xfer_len - 1; d >= 0; d--) {
  1207. X            if (tbl[i].dp->sn.dk_xfer.dk_xfer_val[d]) {
  1208. X            dhigh = d;
  1209. X            break;
  1210. X            }
  1211. X        }
  1212. X        moredisks = dhigh - DK_NDRIVE_ORIG + 1;
  1213. X        if (moredisks > 0) {
  1214. X            (void) fprintf(stdout, "%d more disk%s... ",
  1215. X                   moredisks, moredisks == 1 ? "" : "s");
  1216. X            for (d = DK_NDRIVE_ORIG; d <= dhigh; d++)
  1217. X            (void) fprintf(stdout, "%d ",
  1218. X                       tbl[i].dp->sd.dk_xfer.dk_xfer_val[d]);
  1219. X            (void) putc('\n', stdout);
  1220. X        }
  1221. X        }
  1222. X        break;
  1223. X
  1224. X    case P_UP:
  1225. X        if (tbl[i].dp->no)    /* have we already printed the uptime? */
  1226. X        break;
  1227. X        up = tbl[i].dp->sd.boottime.tv_sec;    /* uptime stored here */
  1228. X        upd = up / 86400;
  1229. X        up = abs(up - upd * 86400);
  1230. X        uph = up / 3600;
  1231. X        up -= uph * 3600;
  1232. X        upm = up / 60;
  1233. X        (void) fprintf(stdout, f_h, tbl[i].dp->host);
  1234. X        switch (upd) {
  1235. X        case 0:
  1236. X        (void) fputs("up           ", stdout);
  1237. X        break;
  1238. X        case 1:
  1239. X        (void) fprintf(stdout, "up %3d day,  ", upd);
  1240. X        break;
  1241. X        default:
  1242. X        (void) fprintf(stdout, "up %3d days, ", upd);
  1243. X        break;
  1244. X        }
  1245. X        (void) fprintf(stdout, "%2d:%02d,", uph, upm);
  1246. X        (void) fputs("     load average: ", stdout);
  1247. X        /* average run queue lengths */
  1248. X        (void) fprintf(stdout, fo_a0,
  1249. X               loadav(tbl[i].dp->sn.avenrun[AV1]),
  1250. X               loadav(tbl[i].dp->sn.avenrun[AV5]),
  1251. X               loadav(tbl[i].dp->sn.avenrun[AV15]));
  1252. X        (void) putc('\n', stdout);
  1253. X        break;
  1254. X    }            /* switch (flag) */
  1255. X    }
  1256. X}
  1257. X
  1258. X/*
  1259. X * make the titles for the columns, depending on the options selected
  1260. X */
  1261. Xvoid
  1262. Xbuild_title()
  1263. X{
  1264. X    title1[0] = '\0';
  1265. X    title2[0] = '\0';
  1266. X    ruler[0] = '\0';
  1267. X    if (opts & O_BARE) {
  1268. X    return;
  1269. X    }
  1270. X    if (opts & O_TIME) {
  1271. X    (void) sprintf(title1 + strlen(title1), f_time, "unix time");
  1272. X    (void) sprintf(title2 + strlen(title2), f_time, "(seconds)");
  1273. X    (void) sprintf(ruler + strlen(ruler), fo_time, 100000000);
  1274. X    }
  1275. X    if (opts & O_DATE) {
  1276. X    (void) sprintf(title1 + strlen(title1), f_date, "Date");
  1277. X    (void) sprintf(title2 + strlen(title2), f_date, "(local time)");
  1278. X    (void) sprintf(ruler + strlen(ruler), f_date,
  1279. X               "Thu Jan  1 00:00:00 1970");
  1280. X    }
  1281. X    if (opts & O_SECS) {
  1282. X    (void) sprintf(title1 + strlen(title1), f_secs, "time");
  1283. X    (void) sprintf(title2 + strlen(title2), f_secs, "(sec)");
  1284. X    (void) sprintf(ruler + strlen(ruler), fo_secs, 10.01);
  1285. X    }
  1286. X    if (nhosts > 1) {
  1287. X    (void) sprintf(title1 + strlen(title1), f_h, "");
  1288. X    (void) sprintf(title2 + strlen(title2), f_h, "hostname");
  1289. X    (void) sprintf(ruler + strlen(ruler), f_h,
  1290. X               "127.000.000.001");
  1291. X    }
  1292. X    if (opts & O_CP) {
  1293. X    (void) sprintf(title1 + strlen(title1), f1_cp, "%cpu");
  1294. X    (void) sprintf(title1 + strlen(title1), f1_av, "loadavg (nrun)");
  1295. X    (void) sprintf(title2 + strlen(title2), f2_cp, "us", "ni", "sy", "id");
  1296. X    (void) sprintf(title2 + strlen(title2), f2_av, "1m", "5m", "15m");
  1297. X    (void) sprintf(ruler + strlen(ruler), fo_cp, 100, 100, 100, 100);
  1298. X    (void) sprintf(ruler + strlen(ruler), fo_av, 10.00, 10.00, 10.00);
  1299. X    }
  1300. X    if (opts & O_DK) {
  1301. X    (void) sprintf(title1 + strlen(title1), f1_dk, "disk xfers");
  1302. X    (void) sprintf(title2 + strlen(title2), f2_dk,
  1303. X               "d0", "d1", "d2", "d3");
  1304. X    (void) sprintf(ruler + strlen(ruler), fo_dk, 10, 10, 10, 10);
  1305. X    }
  1306. X    if (opts & O_VM) {
  1307. X    (void) sprintf(title1 + strlen(title1), f1_vm,
  1308. X               "pg", "pg", "sw", "sw", "cx", "in");
  1309. X    (void) sprintf(title2 + strlen(title2), f2_vm,
  1310. X               "in", "o", "in", "o", "sw", "tr");
  1311. X    (void) sprintf(ruler + strlen(ruler), fo_vm, 10, 10, 10, 10, 100, 100);
  1312. X    }
  1313. X    if (opts & O_IF) {
  1314. X    (void) sprintf(title1 + strlen(title1), f1_if,
  1315. X               "i", "i", "o", "o", "co");
  1316. X    (void) sprintf(title2 + strlen(title2), f2_if,
  1317. X               "pk", "er", "pk", "er", "ll");
  1318. X    (void) sprintf(ruler + strlen(ruler), fo_if, 10, 10, 10, 10, 10);
  1319. X    }
  1320. X    (void) sprintf(title1 + strlen(title1), "\n");
  1321. X    (void) sprintf(title2 + strlen(title2), "\n");
  1322. X    return;
  1323. X}
  1324. X
  1325. X/**
  1326. X * initialize signal handlers
  1327. X * parse options
  1328. X * loop endlessly. either:
  1329. X *    resolve host names, do client calls
  1330. X *    or do broadcasts
  1331. X**/
  1332. Xmain(argc, argv)
  1333. X    int             argc;
  1334. X    char           *argv[];
  1335. X{
  1336. X    int             c, do_usage = 0;
  1337. X    int             i_seen = 0;
  1338. X    int             c_seen = 0;
  1339. X    unsigned        interval = 10;
  1340. X    char           *optstring;
  1341. X    char           *basename;
  1342. X    char           *usage;
  1343. X    extern int      opterr, optind;
  1344. X    extern char    *optarg;
  1345. X    int             opti;
  1346. X    unsigned        hdrcnt;
  1347. X    unsigned        count;
  1348. X    struct data   **dpp;
  1349. X    struct datatbl *tbl;
  1350. X
  1351. X    tbl = NULL;
  1352. X    if (gettimeofday(&starttime, &tz) == -1) {
  1353. X    perror("gettimeofday");
  1354. X    exit(1);
  1355. X    }
  1356. X    (void) signal(SIGHUP, cleanup);
  1357. X    (void) signal(SIGINT, cleanup);
  1358. X    (void) signal(SIGTERM, cleanup);
  1359. X
  1360. X#ifdef HAVE_SETLINEBUF
  1361. X    /**
  1362. X     * line-buffer the output
  1363. X     * permits "tail -f" of a growing log file
  1364. X     **/
  1365. X    (void) setlinebuf(stdout);
  1366. X#endif
  1367. X    basename = strrchr(argv[0], '/');
  1368. X    basename = basename ? ++basename : argv[0];
  1369. X
  1370. X    opterr = 1;
  1371. X    if (strcmp(basename, "rup") == 0) {
  1372. X    optstring = "hltn";
  1373. X    usage = "usage: %s [ -%s ] [ interval ] [ host ... ]\n";
  1374. X    while ((c = getopt(argc, argv, optstring)) != -1) {
  1375. X        switch (c) {
  1376. X        case 'h':
  1377. X        opts |= O_SHOST;
  1378. X        break;
  1379. X        case 'l':
  1380. X        opts |= O_SORT | O_RVRS;
  1381. X        key_ptr = (key *) calloc(1, sizeof(key));
  1382. X        key_ptr->k_offset = sn_offset(avenrun[AV1]);
  1383. X        break;
  1384. X        case 't':
  1385. X        opts |= O_SORT;
  1386. X        key_ptr = (key *) calloc(1, sizeof(key));
  1387. X        key_ptr->k_offset = sd_offset(boottime.tv_sec);    /* uptime */
  1388. X        break;
  1389. X        case 'n':
  1390. X        opts |= O_NHOST;
  1391. X        break;
  1392. X        case '?':
  1393. X        do_usage++;
  1394. X        }
  1395. X    }
  1396. X    c_seen = 1;
  1397. X    count = 0;
  1398. X    opts |= O_UP;
  1399. X    } else {            /* rperf */
  1400. X    optstring = "acdivhnSTsbBDr";
  1401. X    usage = "usage: %s [ -%s ] [ interval [ count ] ] [ +sortkey ] [ host ... ]\n";
  1402. X    while ((c = getopt(argc, argv, optstring)) != -1)
  1403. X        switch (c) {
  1404. X        case 'a':
  1405. X        opts |= O_ALL;
  1406. X        break;
  1407. X        case 'c':
  1408. X        opts |= O_CP;
  1409. X        break;
  1410. X        case 'd':
  1411. X        opts |= O_DK;
  1412. X        break;
  1413. X        case 'i':
  1414. X        opts |= O_IF;
  1415. X        break;
  1416. X        case 'S':
  1417. X        opts |= O_TIME;
  1418. X        break;
  1419. X        case 'T':
  1420. X        opts |= O_DATE;
  1421. X        break;
  1422. X        case 's':
  1423. X        opts |= O_SECS;
  1424. X        break;
  1425. X        case 'h':
  1426. X        opts |= O_SHOST;
  1427. X        break;
  1428. X        case 'n':
  1429. X        opts |= O_NHOST;
  1430. X        break;
  1431. X        case 'v':
  1432. X        opts |= O_VM;
  1433. X        break;
  1434. X        case 'b':
  1435. X        opts |= O_BCST;
  1436. X        break;
  1437. X        case 'B':
  1438. X        opts |= O_BARE;
  1439. X        break;
  1440. X        case 'r':
  1441. X        opts |= O_RVRS;
  1442. X        break;
  1443. X        case 'D':
  1444. X        opts |= O_DBG;
  1445. X        break;
  1446. X        case '?':
  1447. X        do_usage++;
  1448. X        }
  1449. X
  1450. X    if (!(opts & O_BARE))
  1451. X        opts |= O_UP;
  1452. X    }
  1453. X    if (opts & O_NHOST)
  1454. X    f_h = "%15.15s ";
  1455. X
  1456. X    opti = optind;
  1457. X    while (argv[opti]) {
  1458. X    char           *oa;
  1459. X    unsigned        l;
  1460. X
  1461. X    l = strtol(argv[opti], &oa, 0);
  1462. X    if (argv[opti] == oa || *oa) {
  1463. X        /* "mml0.meche.rpi.edu" or "128.113.14.20" or "+idle" */
  1464. X        if (*argv[opti] == '+') {
  1465. X        char           *sortkey;
  1466. X        key            *kp;
  1467. X
  1468. X        sortkey = argv[opti] + sizeof(char);
  1469. X        for (kp = keys; kp->k_name != NULL; kp++) {
  1470. X            if (strcmp(sortkey, kp->k_name) == 0) {
  1471. X            key_ptr = kp;
  1472. X            break;
  1473. X            }
  1474. X        }
  1475. X        if (key_ptr) {
  1476. X            opts |= O_SORT;
  1477. X        } else {
  1478. X            int             i;
  1479. X            char           *p;
  1480. X
  1481. X            (void) fprintf(stderr, "unknown sort key: %s\n", sortkey);
  1482. X            for (i = 0; p = keyhelp[i]; i++)
  1483. X            (void) fputs(p, stdout);
  1484. X        }
  1485. X        } else {
  1486. X        h_seen++;
  1487. X        }
  1488. X    } else {
  1489. X        if (!i_seen) {
  1490. X        interval = l;
  1491. X        i_seen++;
  1492. X        } else if (!c_seen) {
  1493. X        count = l;
  1494. X        c_seen++;
  1495. X        }
  1496. X    }
  1497. X    opti++;
  1498. X    }
  1499. X
  1500. X    if (do_usage)
  1501. X    (void) fprintf(stderr, usage, basename, optstring);
  1502. X
  1503. X    if (h_seen) {        /* do client calls */
  1504. X    if (opts & O_DBG)
  1505. X        (void) fputs("resolving host names\n", stderr);
  1506. X    opti = optind;
  1507. X    dpp = &dp;
  1508. X
  1509. X    while (argv[opti]) {
  1510. X        char           *oa;
  1511. X        unsigned long   host_address;
  1512. X
  1513. X        (void) strtol(argv[opti], &oa, 0);
  1514. X        if ((argv[opti] == oa || *oa) && *argv[opti] != '+') {
  1515. X        /* "mml0.meche.rpi.edu" or "128.113.14.20" */
  1516. X        struct in_addr  addr;
  1517. X        char           *hostname;
  1518. X        struct hostent *host_entry;
  1519. X
  1520. X        hostname = argv[opti];
  1521. X        host_entry = gethostbyname(hostname);
  1522. X        if (!host_entry) {    /* maybe he typed an address */
  1523. X            if (opts & O_DBG)
  1524. X            (void) fputs("byname failed\n", stderr);
  1525. X            host_address = inet_addr(hostname);
  1526. X            if (host_address != -1) {
  1527. X            host_entry =
  1528. X                gethostbyaddr((char *) &host_address, 4, AF_INET);
  1529. X            if (!host_entry && opts & O_DBG)
  1530. X                (void) fputs("byaddr failed\n", stderr);
  1531. X            } else if (opts & O_DBG)
  1532. X            (void) fputs("inet_addr failed\n", stderr);
  1533. X        }
  1534. X        if (host_entry) {
  1535. X            bcopy(host_entry->h_addr,
  1536. X              (char *) &addr.s_addr,
  1537. X              host_entry->h_length);
  1538. X        }
  1539. X        /*
  1540. X         * maybe he typed a valid address anyway --
  1541. X         */
  1542. X        if (!host_entry && (host_address != -1))
  1543. X            addr.s_addr = host_address;
  1544. X
  1545. X        if (host_entry || (host_address != -1)) {
  1546. X            /* host ok.  add to list */
  1547. X            if (opts & O_DBG)
  1548. X            (void) fprintf(stdout, "%s\n", inet_ntoa(addr));
  1549. X            (*dpp) = new_host(&addr, hostname);
  1550. X            (*dpp)->datap = NULL;
  1551. X            dpp = &(*dpp)->datap;
  1552. X        } else {
  1553. X            (void) fprintf(stderr, "can't get address for %s\n",
  1554. X                   hostname);
  1555. X        }
  1556. X        }            /* a host argument */
  1557. X        opti++;
  1558. X    }
  1559. X    if (opts & O_DBG)
  1560. X        (void) fprintf(stderr, "%d hosts\n", nhosts);
  1561. X
  1562. X    if (!nhosts)
  1563. X        exit(1);
  1564. X
  1565. X    if (!(opts & O_ALL)) {
  1566. X        if (nhosts == 1)
  1567. X        opts |= O_DEFL1;
  1568. X        else
  1569. X        opts |= O_DEFL;
  1570. X    }
  1571. X    thiscount++;
  1572. X    doclnt_calls();
  1573. X    tbl = compute_data(tbl);
  1574. X
  1575. X    if (opts & O_UP) {
  1576. X        print_data(tbl, P_UP);
  1577. X    }
  1578. X    build_title();
  1579. X
  1580. X    for (hdrcnt = 1;;) {
  1581. X
  1582. X        if (c_seen && !count--)
  1583. X        exit(0);
  1584. X
  1585. X        (void) sleep(interval);
  1586. X
  1587. X        if (!--hdrcnt || nhosts > 1) {
  1588. X        (void) fputs(title1, stdout);
  1589. X        (void) fputs(title2, stdout);
  1590. X        check_term();
  1591. X        hdrcnt = term_rows ? term_rows - 2 : 20;
  1592. X        }
  1593. X        thiscount++;
  1594. X        doclnt_calls();
  1595. X        tbl = compute_data(tbl);
  1596. X        if (opts & O_DBG)
  1597. X        (void) fprintf(stdout,
  1598. X                 "%d host%s\n", nhosts, nhosts == 1 ? "" : "s");
  1599. X        print_data(tbl, P_DATA);
  1600. X    }
  1601. X
  1602. X    } else {            /* do broadcasts */
  1603. X    if (!(opts & O_ALL)) {
  1604. X        opts |= O_DEFL;
  1605. X    }
  1606. X    nhosts = 2;
  1607. X    build_title();
  1608. X    nhosts = 0;
  1609. X
  1610. X    for (;;) {
  1611. X        thiscount++;
  1612. X
  1613. X        if (thiscount == 1 || opts & O_BCST) {
  1614. X        stats_broadcast resbuf;
  1615. X        static enum clnt_stat clnt_stat;
  1616. X
  1617. X        (void) signal(SIGALRM, bcst_done);
  1618. X        (void) alarm(interval);    /* broadcast interval.  >54 ignored */
  1619. X        bcst_timo = FALSE;
  1620. X        (void) fputs("broadcasting ", stdout);
  1621. X        (void) fflush(stdout);
  1622. X        bzero((char *) &resbuf, sizeof resbuf);
  1623. X        clnt_stat = clnt_broadcast(RSTATPROG,
  1624. X                       RSTATVERS_BCST,
  1625. X                       RSTATPROC_STATS,
  1626. X                       xdr_void,
  1627. X                       (char *) NULL,
  1628. X                       XDR_STATSPROC(RSTATVERS_BCST),
  1629. X                       (char *) &resbuf,
  1630. X                       each_result);
  1631. X        if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT) {
  1632. X            (void) fprintf(stderr, "\nclnt_broadcast: %s\n",
  1633. X                   clnt_sperrno(clnt_stat));
  1634. X            exit(1);
  1635. X        }
  1636. X        (void) putc('\n', stdout);
  1637. X        }            /* thiscount == 1 || opts & O_BCST */
  1638. X        doclnt_calls();
  1639. X        tbl = compute_data(tbl);
  1640. X        if (opts & O_DBG)
  1641. X        (void) fprintf(stdout,
  1642. X                 "%d host%s\n", nhosts, nhosts == 1 ? "" : "s");
  1643. X
  1644. X        if (opts & O_UP) {
  1645. X        print_data(tbl, P_UP);
  1646. X        }
  1647. X        if (thiscount > 1) {
  1648. X        (void) fputs(title1, stdout);
  1649. X        (void) fputs(title2, stdout);
  1650. X        print_data(tbl, P_DATA);
  1651. X        }
  1652. X        if (c_seen && !count--)
  1653. X        exit(0);
  1654. X
  1655. X        if (!(opts & O_BCST))
  1656. X        (void) sleep(interval);
  1657. X    }
  1658. X    }
  1659. X}
  1660. END_OF_FILE
  1661. if test 41113 -ne `wc -c <'rperf.c'`; then
  1662.     echo shar: \"'rperf.c'\" unpacked with wrong size!
  1663. fi
  1664. # end of 'rperf.c'
  1665. fi
  1666. if test -f 'termcap.c' -a "${1}" != "-c" ; then 
  1667.   echo shar: Will not clobber existing file \"'termcap.c'\"
  1668. else
  1669. echo shar: Extracting \"'termcap.c'\" \(11444 characters\)
  1670. sed "s/^X//" >'termcap.c' <<'END_OF_FILE'
  1671. X/*-
  1672. X * Copyright (c) 1980 The Regents of the University of California.
  1673. X * All rights reserved.
  1674. X *
  1675. X * Redistribution and use in source and binary forms, with or without
  1676. X * modification, are permitted provided that the following conditions
  1677. X * are met:
  1678. X * 1. Redistributions of source code must retain the above copyright
  1679. X *    notice, this list of conditions and the following disclaimer.
  1680. X * 2. Redistributions in binary form must reproduce the above copyright
  1681. X *    notice, this list of conditions and the following disclaimer in the
  1682. X *    documentation and/or other materials provided with the distribution.
  1683. X * 3. All advertising materials mentioning features or use of this software
  1684. X *    must display the following acknowledgement:
  1685. X *    This product includes software developed by the University of
  1686. X *    California, Berkeley and its contributors.
  1687. X * 4. Neither the name of the University nor the names of its contributors
  1688. X *    may be used to endorse or promote products derived from this software
  1689. X *    without specific prior written permission.
  1690. X *
  1691. X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  1692. X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  1693. X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  1694. X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  1695. X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  1696. X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  1697. X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  1698. X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  1699. X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  1700. X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  1701. X * SUCH DAMAGE.
  1702. X */
  1703. X
  1704. X#ifndef lint
  1705. Xstatic char     sccsid[] = "@(#)termcap.c    5.5 (Berkeley) 6/1/90";
  1706. X#endif                /* not lint */
  1707. X
  1708. X#define    BUFSIZ        1024
  1709. X#define MAXHOP        32    /* max number of tc= indirections */
  1710. X#define    PBUFSIZ        512    /* max length of filename path */
  1711. X#define    PVECSIZ        32    /* max number of names in path */
  1712. X
  1713. X#include <string.h>
  1714. X#include <ctype.h>
  1715. X#include "pathnames.h"
  1716. X
  1717. X/*-
  1718. X * termcap - routines for dealing with the terminal capability data base
  1719. X *
  1720. X * BUG:        Should use a "last" pointer in tbuf, so that searching
  1721. X *        for capabilities alphabetically would not be a n**2/2
  1722. X *        process when large numbers of capabilities are given.
  1723. X * Note:    If we add a last pointer now we will screw up the
  1724. X *        tc capability. We really should compile termcap.
  1725. X *
  1726. X * Essentially all the work here is scanning and decoding escapes
  1727. X * in string capabilities.  We don't use stdio because the editor
  1728. X * doesn't, and because living w/o it is not hard.
  1729. X */
  1730. X
  1731. Xstatic char    *tbuf;
  1732. Xstatic int      hopcount;    /* detect infinite loops in termcap, init 0 */
  1733. Xstatic char     pathbuf[PBUFSIZ];    /* holds raw path of filenames */
  1734. Xstatic char    *pathvec[PVECSIZ];    /* to point to names in pathbuf */
  1735. Xstatic char   **pvec;        /* holds usable tail of path vector */
  1736. Xchar           *tskip();
  1737. Xchar           *tgetstr();
  1738. Xchar           *tdecode();
  1739. Xchar           *getenv();
  1740. X
  1741. X/*
  1742. X * Get an entry for terminal name in buffer bp from the termcap file.
  1743. X */
  1744. Xtgetent(bp, name)
  1745. X    char           *bp, *name;
  1746. X{
  1747. X    register char  *p;
  1748. X    register char  *cp;
  1749. X    register int    c;
  1750. X    char           *home, *termpath;
  1751. X    char          **fname = pathvec;
  1752. X
  1753. X    pvec = pathvec;
  1754. X    tbuf = bp;
  1755. X    p = pathbuf;
  1756. X    cp = getenv("TERMCAP");
  1757. X    /*-
  1758. X     * TERMCAP can have one of two things in it. It can be the
  1759. X     * name of a file to use instead of /etc/termcap. In this
  1760. X     * case it better start with a "/". Or it can be an entry to
  1761. X     * use so we don't have to read the file. In this case it
  1762. X     * has to already have the newlines crunched out.  If TERMCAP
  1763. X     * does not hold a file name then a path of names is searched
  1764. X     * instead.  The path is found in the TERMPATH variable, or
  1765. X     * becomes "$HOME/.termcap /etc/termcap" if no TERMPATH exists.
  1766. X     */
  1767. X    if (!cp || *cp != '/') {    /* no TERMCAP or it holds an entry */
  1768. X    if (termpath = getenv("TERMPATH"))
  1769. X        (void) strncpy(pathbuf, termpath, PBUFSIZ);
  1770. X    else {
  1771. X        if (home = getenv("HOME")) {    /* set up default */
  1772. X        p += strlen(home);    /* path, looking in */
  1773. X        (void) strcpy(pathbuf, home);    /* $HOME first */
  1774. X        *p++ = '/';
  1775. X        }            /* if no $HOME look in current directory */
  1776. X        (void) strncpy(p, _PATH_DEF, PBUFSIZ - (p - pathbuf));
  1777. X    }
  1778. X    } else            /* user-defined name in TERMCAP */
  1779. X    (void) strncpy(pathbuf, cp, PBUFSIZ);    /* still can be tokenized */
  1780. X
  1781. X    *fname++ = pathbuf;        /* tokenize path into vector of names */
  1782. X    while (*++p)
  1783. X    if (*p == ' ' || *p == ':') {
  1784. X        *p = '\0';
  1785. X        while (*++p)
  1786. X        if (*p != ' ' && *p != ':')
  1787. X            break;
  1788. X        if (*p == '\0')
  1789. X        break;
  1790. X        *fname++ = p;
  1791. X        if (fname >= pathvec + PVECSIZ) {
  1792. X        fname--;
  1793. X        break;
  1794. X        }
  1795. X    }
  1796. X    *fname = (char *) 0;    /* mark end of vector */
  1797. X    if (cp && *cp && *cp != '/') {
  1798. X    tbuf = cp;
  1799. X    c = tnamatch(name);
  1800. X    tbuf = bp;
  1801. X    if (c) {
  1802. X        (void) strcpy(bp, cp);
  1803. X        return (tnchktc());
  1804. X    }
  1805. X    }
  1806. X    return (tfindent(bp, name));/* find terminal entry in path */
  1807. X}
  1808. X
  1809. X/*-
  1810. X * tfindent - reads through the list of files in pathvec as if they were one
  1811. X * continuous file searching for terminal entries along the way.  It will
  1812. X * participate in indirect recursion if the call to tnchktc() finds a tc=
  1813. X * field, which is only searched for in the current file and files ocurring
  1814. X * after it in pathvec.  The usable part of this vector is kept in the global
  1815. X * variable pvec.  Terminal entries may not be broken across files.  Parse is
  1816. X * very rudimentary; we just notice escaped newlines.
  1817. X */
  1818. Xtfindent(bp, name)
  1819. X    char           *bp, *name;
  1820. X{
  1821. X    register char  *cp;
  1822. X    register int    c;
  1823. X    register int    i, cnt;
  1824. X    char            ibuf[BUFSIZ];
  1825. X    int             opencnt = 0;
  1826. X    int             tf;
  1827. X
  1828. X    tbuf = bp;
  1829. Xnextfile:
  1830. X    i = cnt = 0;
  1831. X    while (*pvec && (tf = open(*pvec, 0)) < 0)
  1832. X    pvec++;
  1833. X    if (!*pvec)
  1834. X    return (opencnt ? 0 : -1);
  1835. X    opencnt++;
  1836. X    for (;;) {
  1837. X    cp = bp;
  1838. X    for (;;) {
  1839. X        if (i == cnt) {
  1840. X        cnt = read(tf, ibuf, BUFSIZ);
  1841. X        if (cnt <= 0) {
  1842. X            (void) close(tf);
  1843. X            pvec++;
  1844. X            goto nextfile;
  1845. X        }
  1846. X        i = 0;
  1847. X        }
  1848. X        c = ibuf[i++];
  1849. X        if (c == '\n') {
  1850. X        if (cp > bp && cp[-1] == '\\') {
  1851. X            cp--;
  1852. X            continue;
  1853. X        }
  1854. X        break;
  1855. X        }
  1856. X        if (cp >= bp + BUFSIZ) {
  1857. X        (void) write(2, "Termcap entry too long\n", 23);
  1858. X        break;
  1859. X        } else
  1860. X        *cp++ = c;
  1861. X    }
  1862. X    *cp = 0;
  1863. X
  1864. X    /*
  1865. X     * The real work for the match.
  1866. X     */
  1867. X    if (tnamatch(name)) {
  1868. X        (void) close(tf);
  1869. X        return (tnchktc());
  1870. X    }
  1871. X    }
  1872. X}
  1873. X
  1874. X/*-
  1875. X * tnchktc: check the last entry, see if it's tc=xxx. If so,
  1876. X * recursively find xxx and append that entry (minus the names)
  1877. X * to take the place of the tc=xxx entry. This allows termcap
  1878. X * entries to say "like an HP2621 but doesn't turn on the labels".
  1879. X * Note that this works because of the left to right scan.
  1880. X */
  1881. Xtnchktc()
  1882. X{
  1883. X    register char  *p, *q;
  1884. X    char            tcname[16];    /* name of similar terminal */
  1885. X    char            tcbuf[BUFSIZ];
  1886. X    char           *holdtbuf = tbuf;
  1887. X    int             l;
  1888. X
  1889. X    p = tbuf + strlen(tbuf) - 2;/* before the last colon */
  1890. X    while (*--p != ':')
  1891. X    if (p < tbuf) {
  1892. X        (void) write(2, "Bad termcap entry\n", 18);
  1893. X        return (0);
  1894. X    }
  1895. X    p++;
  1896. X    /* p now points to beginning of last field */
  1897. X    if (p[0] != 't' || p[1] != 'c')
  1898. X    return (1);
  1899. X    (void) strcpy(tcname, p + 3);
  1900. X    q = tcname;
  1901. X    while (*q && *q != ':')
  1902. X    q++;
  1903. X    *q = 0;
  1904. X    if (++hopcount > MAXHOP) {
  1905. X    (void) write(2, "Infinite tc= loop\n", 18);
  1906. X    return (0);
  1907. X    }
  1908. X    if (tfindent(tcbuf, tcname) != 1) {
  1909. X    hopcount = 0;        /* unwind recursion */
  1910. X    return (0);
  1911. X    }
  1912. X    for (q = tcbuf; *q != ':'; q++);
  1913. X    l = p - holdtbuf + strlen(q);
  1914. X    if (l > BUFSIZ) {
  1915. X    (void) write(2, "Termcap entry too long\n", 23);
  1916. X    q[BUFSIZ - (p - tbuf)] = 0;
  1917. X    }
  1918. X    (void) strcpy(p, q + 1);
  1919. X    tbuf = holdtbuf;
  1920. X    hopcount = 0;        /* unwind recursion */
  1921. X    return (1);
  1922. X}
  1923. X
  1924. X/*-
  1925. X * Tnamatch deals with name matching.  The first field of the termcap
  1926. X * entry is a sequence of names separated by |'s, so we compare
  1927. X * against each such name.  The normal : terminator after the last
  1928. X * name (before the first field) stops us.
  1929. X */
  1930. Xtnamatch(np)
  1931. X    char           *np;
  1932. X{
  1933. X    register char  *Np, *Bp;
  1934. X
  1935. X    Bp = tbuf;
  1936. X    if (*Bp == '#')
  1937. X    return (0);
  1938. X    for (;;) {
  1939. X    for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
  1940. X        continue;
  1941. X    if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
  1942. X        return (1);
  1943. X    while (*Bp && *Bp != ':' && *Bp != '|')
  1944. X        Bp++;
  1945. X    if (*Bp == 0 || *Bp == ':')
  1946. X        return (0);
  1947. X    Bp++;
  1948. X    }
  1949. X}
  1950. X
  1951. X/*-
  1952. X * Skip to the next field.  Notice that this is very dumb, not
  1953. X * knowing about \: escapes or any such.  If necessary, :'s can be put
  1954. X * into the termcap file in octal.
  1955. X */
  1956. Xstatic char    *
  1957. Xtskip(bp)
  1958. X    register char  *bp;
  1959. X{
  1960. X
  1961. X    while (*bp && *bp != ':')
  1962. X    bp++;
  1963. X    if (*bp == ':')
  1964. X    bp++;
  1965. X    return (bp);
  1966. X}
  1967. X
  1968. X/*-
  1969. X * Return the (numeric) option id.
  1970. X * Numeric options look like
  1971. X *    li#80
  1972. X * i.e. the option string is separated from the numeric value by
  1973. X * a # character.  If the option is not found we return -1.
  1974. X * Note that we handle octal numbers beginning with 0.
  1975. X */
  1976. Xtgetnum(id)
  1977. X    char           *id;
  1978. X{
  1979. X    register int    i, base;
  1980. X    register char  *bp = tbuf;
  1981. X
  1982. X    for (;;) {
  1983. X    bp = tskip(bp);
  1984. X    if (*bp == 0)
  1985. X        return (-1);
  1986. X    if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
  1987. X        continue;
  1988. X    if (*bp == '@')
  1989. X        return (-1);
  1990. X    if (*bp != '#')
  1991. X        continue;
  1992. X    bp++;
  1993. X    base = 10;
  1994. X    if (*bp == '0')
  1995. X        base = 8;
  1996. X    i = 0;
  1997. X    while (isdigit(*bp))
  1998. X        i *= base, i += *bp++ - '0';
  1999. X    return (i);
  2000. X    }
  2001. X}
  2002. X
  2003. X/*-
  2004. X * Handle a flag option.
  2005. X * Flag options are given "naked", i.e. followed by a : or the end
  2006. X * of the buffer.  Return 1 if we find the option, or 0 if it is
  2007. X * not given.
  2008. X */
  2009. Xtgetflag(id)
  2010. X    char           *id;
  2011. X{
  2012. X    register char  *bp = tbuf;
  2013. X
  2014. X    for (;;) {
  2015. X    bp = tskip(bp);
  2016. X    if (!*bp)
  2017. X        return (0);
  2018. X    if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
  2019. X        if (!*bp || *bp == ':')
  2020. X        return (1);
  2021. X        else if (*bp == '@')
  2022. X        return (0);
  2023. X    }
  2024. X    }
  2025. X}
  2026. X
  2027. X/*-
  2028. X * Get a string valued option.
  2029. X * These are given as
  2030. X *    cl=^Z
  2031. X * Much decoding is done on the strings, and the strings are
  2032. X * placed in area, which is a ref parameter which is updated.
  2033. X * No checking on area overflow.
  2034. X */
  2035. Xchar           *
  2036. Xtgetstr(id, area)
  2037. X    char           *id, **area;
  2038. X{
  2039. X    register char  *bp = tbuf;
  2040. X
  2041. X    for (;;) {
  2042. X    bp = tskip(bp);
  2043. X    if (!*bp)
  2044. X        return (0);
  2045. X    if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
  2046. X        continue;
  2047. X    if (*bp == '@')
  2048. X        return (0);
  2049. X    if (*bp != '=')
  2050. X        continue;
  2051. X    bp++;
  2052. X    return (tdecode(bp, area));
  2053. X    }
  2054. X}
  2055. X
  2056. X/*-
  2057. X * Tdecode does the grung work to decode the
  2058. X * string capability escapes.
  2059. X */
  2060. Xstatic char    *
  2061. Xtdecode(str, area)
  2062. X    register char  *str;
  2063. X    char          **area;
  2064. X{
  2065. X    register char  *cp;
  2066. X    register int    c;
  2067. X    register char  *dp;
  2068. X    int             i;
  2069. X
  2070. X    cp = *area;
  2071. X    while ((c = *str++) && c != ':') {
  2072. X    switch (c) {
  2073. X
  2074. X    case '^':
  2075. X        c = *str++ & 037;
  2076. X        break;
  2077. X
  2078. X    case '\\':
  2079. X        dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
  2080. X        c = *str++;
  2081. X    nextc:
  2082. X        if (*dp++ == c) {
  2083. X        c = *dp++;
  2084. X        break;
  2085. X        }
  2086. X        dp++;
  2087. X        if (*dp)
  2088. X        goto nextc;
  2089. X        if (isdigit(c)) {
  2090. X        c -= '0', i = 2;
  2091. X        do
  2092. X            c <<= 3, c |= *str++ - '0';
  2093. X        while (--i && isdigit(*str));
  2094. X        }
  2095. X        break;
  2096. X    }
  2097. X    *cp++ = c;
  2098. X    }
  2099. X    *cp++ = 0;
  2100. X    str = *area;
  2101. X    *area = cp;
  2102. X    return (str);
  2103. X}
  2104. END_OF_FILE
  2105. if test 11444 -ne `wc -c <'termcap.c'`; then
  2106.     echo shar: \"'termcap.c'\" unpacked with wrong size!
  2107. fi
  2108. # end of 'termcap.c'
  2109. fi
  2110. echo shar: End of archive 2 \(of 3\).
  2111. cp /dev/null ark2isdone
  2112. MISSING=""
  2113. for I in 1 2 3 ; do
  2114.     if test ! -f ark${I}isdone ; then
  2115.     MISSING="${MISSING} ${I}"
  2116.     fi
  2117. done
  2118. if test "${MISSING}" = "" ; then
  2119.     echo You have unpacked all 3 archives.
  2120.     echo "Now do 'sh ./configure'"
  2121.     rm -f ark[1-9]isdone
  2122. else
  2123.     echo You still need to unpack the following archives:
  2124.     echo "        " ${MISSING}
  2125. fi
  2126. ##  End of shell archive.
  2127. exit 0
  2128.  
  2129. exit 0 # Just in case...
  2130.