home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / unix / volume13 / rstat < prev    next >
Encoding:
Text File  |  1988-09-11  |  40.7 KB  |  1,823 lines

  1. Subject:  v13i031:  Remote statistics server
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Dave Curry <davy@intrepid.ecn.purdue.edu>
  7. Posting-number: Volume 13, Issue 31
  8. Archive-name: rstat
  9.  
  10. This is a remote statistics server for BSD.  With it you can write
  11. survey programs to collect statistics on things like load averages,
  12. number of users, uptime, and general network statistics from remote
  13. machines.  It implements the server described by Dave Mills in RFC996,
  14. "Statistics Server", February 1987.
  15.  
  16. It has been tested on a Vax-11/780 running 4.3BSD, a Gould PN9080
  17. running UTX/32 2.0 (4.3BSD), a Sun 3/180 and a Sun 3/50 running Sun
  18. 3.3 (4.2BSD), and a CCI 6/32 running 4.3BSD.  It should work equally
  19. well under 4.2BSD.  (Note: on real new 4.3BSD, like on the CCI 6/32,
  20. change "sys/dk.h" to "sys/dkstat.h" in getcpustats.c - I wish Berkeley
  21. would make up their minds!)
  22.  
  23. # This is a shell archive.  Save this into a file, edit it
  24. # and delete all lines above this comment.  Then give this
  25. # file to sh by executing the command "sh file".  The files
  26. # will be extracted into the current directory owned by
  27. # you with default permissions.
  28. #
  29. # The files contained herein are:
  30. #          README       Makefile        stats.1      statsrv.8
  31. #         stats.h  dg_sendrecv.c  getcpustats.c getloadstats.c
  32. #   getnetstats.cgettablestats.c gettimestats.c getuserstats.c
  33. #   st_sendrecv.c        stats.c      statsrv.c         tester
  34. #             rfc
  35. #
  36. echo 'x - README'
  37. sed 's/^X//' <<'________This_Is_The_END________' >>README
  38. XThis is a remote statistics server as described in RFC996, "Statistics
  39. XServer", D. L. Mills, February 1987.  With it, you can collect things
  40. Xlike load averages, number of users, uptime, and network statistics
  41. Xfrom remote machines easily.
  42. X
  43. XIt has been tested on a Vax-11/780 running 4.3BSD, a Gould PN9080
  44. Xrunning UTX/32 2.0 (4.3BSD), a Sun 3/180 and a Sun 3/50 running Sun
  45. X3.3 (4.2BSD), a CCI 6/32 running 4.3BSD, and a Sequent running Dynix.
  46. XIt should work equally well under 4.2BSD.  (Note: on real new 4.3BSD,
  47. Xlike on the CCI 6/32, change "sys/dk.h" to "sys/dkstat.h" in
  48. Xgetcpustats.c - I wish Berkeley would make up their minds!)
  49. X
  50. XOn Suns, you will want to edit "Makefile" and add "-fswitch" to CFLAGS,
  51. Xand change the install for "statsrv" to put it in "/usr/etc/in.statsrv".
  52. XAfter you have made and installed the programs, edit "/etc/inetd.conf"
  53. Xand add the lines:
  54. X
  55. Xstatsrv    stream    tcp    nowait    root    /etc/statsrv    statsrv
  56. Xstatsrv    dgram    udp    wait    root    /etc/statsrv    statsrv
  57. X
  58. XThen kill -1 inetd.  On Suns, instead of "/etc/inetd.conf", edit
  59. X"/etc/servers" and add the lines:
  60. X
  61. Xstatsrv    tcp    /usr/etc/in.statsrv
  62. Xstatsrv    udp    /usr/etc/in.statsrv
  63. X
  64. XThen kill inetd and restart it.
  65. X
  66. XIf you don't keep up with the NIC, you may need to add the following
  67. Xlines to "/etc/services":
  68. X
  69. Xstatsrv        133/tcp        # statistics server
  70. Xstatsrv        133/udp
  71. X
  72. XGood luck.
  73. X
  74. XDave Curry
  75. XPurdue University
  76. XEngineering Computer Network
  77. Xdavy@intrepid.ecn.purdue.edu
  78. X{ihnp4, rutgers, iuvax}!pur-ee!davy
  79. ________This_Is_The_END________
  80. echo 'x - Makefile'
  81. sed 's/^X//' <<'________This_Is_The_END________' >>Makefile
  82. X#
  83. X# $Header: /ecn1/src/ecn/statsrv/RCS/Makefile,v 1.3 87/12/08 14:39:43 davy Exp $
  84. X#
  85. X# Makefile for stats and statsrv.
  86. X#
  87. X# David A. Curry
  88. X# Purdue University
  89. X# Engineering Computer Network
  90. X# davy@intrepid.ecn.purdue.edu
  91. X# October, 1987
  92. X#
  93. X# $Log:    Makefile,v $
  94. X# Revision 1.3  87/12/08  14:39:43  davy
  95. X# Added lines for gettablestats.c.
  96. X# 
  97. X# Revision 1.2  87/10/29  14:23:50  davy
  98. X# Updated dependencies.
  99. X# 
  100. X# Revision 1.1  87/10/17  21:00:57  davy
  101. X# Initial revision
  102. X# 
  103. X#
  104. XCFLAGS=    -O
  105. XDESTDIR=
  106. X
  107. XSTATS=    stats.o dg_sendrecv.o st_sendrecv.o
  108. XSTATSRV=statsrv.o dg_sendrecv.o st_sendrecv.o getcpustats.o getloadstats.o \
  109. X    getnetstats.o gettablestats.o gettimestats.o getuserstats.o
  110. X
  111. Xall: stats statsrv
  112. X
  113. Xstats: $(STATS)
  114. X    $(CC) $(CFLAGS) -o stats $(STATS)
  115. X
  116. Xstatsrv: $(STATSRV)
  117. X    $(CC) $(CFLAGS) -o statsrv $(STATSRV)
  118. X
  119. Xinstall: all
  120. X    install -c -s stats $(DESTDIR)/usr/ecn/stats
  121. X    install -c -s statsrv $(DESTDIR)/etc/statsrv
  122. X
  123. Xtags:
  124. X    @ctags *.c > tags
  125. X
  126. Xclean:
  127. X    rm -f a.out core *.o
  128. X
  129. Xzap: clean
  130. X    rm -f stats statsrv
  131. X
  132. Xstats.o: stats.c stats.h
  133. Xdg_sendrecv.o: dg_sendrecv.c stats.h
  134. Xst_sendrecv.o: st_sendrecv.c stats.h
  135. Xgetcpustats.o: getcpustats.c stats.h
  136. Xgetnetstats.o: getnetstats.c
  137. Xgetloadstats.o: getloadstats.c stats.h
  138. Xgettimestats.o: gettimestats.c stats.h
  139. Xgetuserstats.o: getuserstats.c stats.h
  140. Xgettablestats.o: gettablestats.c
  141. ________This_Is_The_END________
  142. echo 'x - stats.1'
  143. sed 's/^X//' <<'________This_Is_The_END________' >>stats.1
  144. X.TH STATS 1 "17 October 1987" ECN
  145. X.SH NAME
  146. Xstats \- gather remote statistics
  147. X.SH SYNOPSIS
  148. X.B stats
  149. X[
  150. X.B \-d
  151. X]
  152. X.I hostname
  153. X.I statname
  154. X[
  155. X.IR statname ...
  156. X]
  157. X.SH DESCRIPTION
  158. X.PP
  159. X.B Stats
  160. Xis used to gather statistics from remote hosts by connecting to a
  161. Xstatistics server on internet port 133 (see
  162. X.BR statsrv (8)).
  163. XStatistics names are based on the remote host's command language,
  164. Xtry using the ``help'' statistic to get a list.
  165. X.PP
  166. XBy default,
  167. X.B stats
  168. Xuses a stream (\s-1TCP\s0) connection;
  169. Xif the
  170. X.B \-d
  171. Xflag is given as the first argument,
  172. Xdatagrams (\s-1UDP\s0) will be used instead.
  173. XNot all statistics servers support stream connections.
  174. X.SH SEE ALSO
  175. X.BR statsrv (8)
  176. X.br
  177. X\s-1RFC996\s0,
  178. X.IR "Statistics Server" ,
  179. XD. L. Mills,
  180. XFebruary 1987.
  181. X.SH AUTHOR
  182. XDavid A. Curry,
  183. XPurdue University Engineering Computer Network
  184. ________This_Is_The_END________
  185. echo 'x - statsrv.8'
  186. sed 's/^X//' <<'________This_Is_The_END________' >>statsrv.8
  187. X.TH STATSRV 8 "8 December 1987" ECN
  188. X.SH NAME
  189. Xstatsrv \- statistics server
  190. X.SH SYNOPSIS
  191. X.B statsrv
  192. X.SH DESCRIPTION
  193. X.PP
  194. X.B Statsrv
  195. Xis invoked by
  196. X.BR inetd (8)
  197. Xwhen connections or datagrams arrive on internet port 133.
  198. XIt understands both stream (\s-1TCP\s0) and datagram (\s-1UDP\s0)
  199. Xconnections.
  200. X.PP
  201. X.B Statsrv
  202. Xreads null-terminated strings requesting statistics,
  203. Xand returns null-terminated strings suitable for printing on a terminal
  204. Xor line printer.
  205. XThe special statistic name ``help'' may be sent to request a list of
  206. Xknown commands.
  207. XAs of this writing,
  208. Xthe known commands are:
  209. X.IP \fBactusers\fP \w'boottimeXX'u
  210. XThe number of active users (those users idle less than one hour)
  211. Xis returned.
  212. X.IP \fBboottime\fP \w'boottimeXX'u
  213. XThe time the system was last booted is returned.
  214. X.IP \fBcpu\fP \w'boottimeXX'u
  215. XThe cpu utilization,
  216. Xbroken down into percentages of user,
  217. Xnice,
  218. Xsystem,
  219. Xand idle time,
  220. Xis returned.
  221. X.IP \fBdate\fP \w'boottimeXX'u
  222. XThe current date is returned.
  223. X.IP \fBhelp\fP \w'boottimeXX'u
  224. XA list of known commands,
  225. Xseparated by newlines,
  226. Xis returned.
  227. X.IP \fBloadav\fP \w'boottimeXX'u
  228. XThe one-minute load average,
  229. Xan average of the number of runnable jobs,
  230. Xis returned.
  231. X.IP \fBmbufs\fP \w'boottimeXX'u
  232. XA summary of network buffer (mbufs) utilization is returned.
  233. XThis is the output from
  234. X.BR "netstat \-m" .
  235. X.IP \fBpackets\fP \w'boottimeXX'u
  236. XA summary of input and output packets on the network interfaces is
  237. Xreturned.
  238. XThis is the output from
  239. X.BR "netstat \-i" .
  240. X.IP \fBproto\fP \w'boottimeXX'u
  241. XA summary of various network protocol information is returned.
  242. XThis is the output from
  243. X.BR "netstat -s" .
  244. XUsually,
  245. Xthis statistic is too long to fit into a datagram.
  246. X.IP \fBtables\fP \w'boottimeXX'u
  247. XA summary of the utilization of various internal system tables.
  248. XThis is the output from
  249. X.BR "pstat -T" .
  250. X.IP \fBtime\fP \w'boottimeXX'u
  251. XThe current time is returned.
  252. X.IP \fBuptime\fP \w'boottimeXX'u
  253. XThe amount of time the system has been up is returned.
  254. X.IP \fBusers\fP \w'boottimeXX'u
  255. XThe number of users logged in is returned.
  256. X.IP \fBwho\fP \w'boottimeXX'u
  257. XA list of all logged in users.
  258. XThis list is contained on a single line,
  259. Xwith login names separated from each other by a space character.
  260. XOccasionally the output from this statistic will be too long to fit
  261. Xinto a datagram.
  262. X.SH SEE ALSO
  263. X.BR netstat (1),
  264. X.BR stats (1)
  265. X.br
  266. X\s-1RFC996\s0,
  267. X.IR "Statistics Server" ,
  268. XD. L. Mills,
  269. XFebruary 1987
  270. X.SH AUTHOR
  271. XDavid A. Curry,
  272. XPurdue University Engineering Computer Network
  273. ________This_Is_The_END________
  274. echo 'x - stats.h'
  275. sed 's/^X//' <<'________This_Is_The_END________' >>stats.h
  276. X/*
  277. X * $Header: /ecn1/src/ecn/statsrv/RCS/stats.h,v 1.1 87/10/17 21:01:03 davy Exp Locker: davy $
  278. X *
  279. X * stats.h - definitions for statistics server
  280. X *
  281. X * David A. Curry
  282. X * Purdue University
  283. X * Engineering Computer Network
  284. X * davy@intrepid.ecn.purdue.edu
  285. X * October, 1987
  286. X *
  287. X * $Log:    stats.h,v $
  288. X * Revision 1.1  87/10/17  21:01:03  davy
  289. X * Initial revision
  290. X * 
  291. X */
  292. X
  293. X#define SERVNAME    "statsrv"    /* name of our service        */
  294. X#define MAXDGRAM    576        /* maximum size of a datagram    */
  295. X
  296. X#define KMEM        "/dev/kmem"    /* path to kernel memory    */
  297. X
  298. X#if vax || sun || gould || tahoe
  299. X#define VMUNIX        "/vmunix"    /* path to kernel        */
  300. X#endif
  301. X#if sequent
  302. X#define VMUNIX        "/dynix"
  303. X#endif
  304. X
  305. X/*
  306. X * For 4.2BSD syslogs.
  307. X */
  308. X#ifndef LOG_DAEMON
  309. X#define LOG_DAEMON    (3<<3)
  310. X#endif
  311. X
  312. Xextern int st_send(), st_recv();    /* stream send/recv functions    */
  313. Xextern int dg_send(), dg_recv();    /* datagram send/recv functions    */
  314. ________This_Is_The_END________
  315. echo 'x - dg_sendrecv.c'
  316. sed 's/^X//' <<'________This_Is_The_END________' >>dg_sendrecv.c
  317. X#ifndef lint
  318. Xstatic char *RCSid = "$Header: /ecn1/src/ecn/statsrv/RCS/dg_sendrecv.c,v 1.1 87/10/17 21:01:12 davy Exp $";
  319. X#endif
  320. X/*
  321. X * dg_sendrecv.c - datagram send/recv functions
  322. X *
  323. X * David A. Curry
  324. X * Purdue University
  325. X * Engineering Computer Network
  326. X * davy@intrepid.ecn.purdue.edu
  327. X * October, 1987
  328. X *
  329. X * $Log:    dg_sendrecv.c,v $
  330. X * Revision 1.1  87/10/17  21:01:12  davy
  331. X * Initial revision
  332. X * 
  333. X */
  334. X#include <sys/param.h>
  335. X#include <sys/socket.h>
  336. X#include <netinet/in.h>
  337. X#include <syslog.h>
  338. X#include <stdio.h>
  339. X
  340. X#include "stats.h"
  341. X
  342. Xextern char    *pname;            /* program name            */
  343. Xextern short    server;            /* 1 if server, 0 if client    */
  344. Xextern struct     sockaddr_in sin;    /* address of remote host    */
  345. X
  346. X/*
  347. X * dg_send - send buf as a datagram to the address in sin~r on socket s.
  348. X */
  349. Xdg_send(s, buf)
  350. Xchar *buf;
  351. Xint s;
  352. X{
  353. X    register int cnt;
  354. X
  355. X    /*
  356. X     * We want the length including the null.
  357. X     */
  358. X    cnt = strlen(buf) + 1;
  359. X
  360. X    /*
  361. X     * According to RFC996, can be no larger than MAXDGRAM.
  362. X     */
  363. X    if (cnt > MAXDGRAM) {
  364. X        if (server) {
  365. X            strcpy(buf, "output length too long for datagram.\n");
  366. X            cnt = strlen(buf) + 1;
  367. X        }
  368. X        else {
  369. X            fprintf(stderr, "%s: string too long for datagram.\n", pname);
  370. X            exit(1);
  371. X        }
  372. X    }
  373. X
  374. X    /*
  375. X     * Send the datagram.
  376. X     */
  377. X    if (sendto(s, buf, cnt, 0, &sin, sizeof(struct sockaddr_in)) < 0) {
  378. X        if (server)
  379. X            syslog(LOG_ERR, "sendto: %m");
  380. X        else
  381. X            error("sendto");
  382. X        exit(1);
  383. X    }
  384. X}
  385. X
  386. X/*
  387. X * dg_recv - receive a datagram of maximum size cnt into buf from the address
  388. X *         in sin on socket s.
  389. X */
  390. Xdg_recv(s, buf, cnt)
  391. Xint s, cnt;
  392. Xchar *buf;
  393. X{
  394. X    int len;
  395. X
  396. X    len = sizeof(struct sockaddr_in);
  397. X
  398. X    /*
  399. X     * Receive the datagram.
  400. X     */
  401. X    if (recvfrom(s, buf, cnt, 0, &sin, &len) < 0) {
  402. X        if (server)
  403. X            syslog(LOG_ERR, "recvfrom: %m");
  404. X        else
  405. X            error("recvfrom");
  406. X        exit(1);
  407. X    }
  408. X}
  409. ________This_Is_The_END________
  410. echo 'x - getcpustats.c'
  411. sed 's/^X//' <<'________This_Is_The_END________' >>getcpustats.c
  412. X#ifndef lint
  413. Xstatic char *RCSid = "$Header: /ecn1/src/ecn/statsrv/RCS/getcpustats.c,v 1.2 87/10/29 14:24:02 davy Exp $";
  414. X#endif
  415. X/*
  416. X * getcpustats - get cpu usage statistics
  417. X *
  418. X * David A. Curry
  419. X * Purdue University
  420. X * Engineering Computer Network
  421. X * davy@intrepid.ecn.purdue.edu
  422. X * October, 1987
  423. X *
  424. X * $Log:    getcpustats.c,v $
  425. X * Revision 1.2  87/10/29  14:24:02  davy
  426. X * Modified to use VMUNIX and KMEM instead of hard-coded paths.
  427. X * 
  428. X * Revision 1.1  87/10/17  21:01:18  davy
  429. X * Initial revision
  430. X * 
  431. X */
  432. X#include <sys/param.h>
  433. X#include <sys/file.h>
  434. X#include <sys/dk.h>
  435. X#include <syslog.h>
  436. X#include <nlist.h>
  437. X#include <stdio.h>
  438. X#include "stats.h"
  439. X
  440. Xstatic struct nlist nl[] = {
  441. X#define X_CPTIME    0
  442. X    {    "_cp_time"    },
  443. X    {    0        }
  444. X};
  445. X
  446. Xextern    int (*fn_recv)(), (*fn_send)();    /* send/recv functions        */
  447. X
  448. X/*
  449. X * getcpustats - get cpu usage statistics
  450. X */
  451. Xgetcpustats(name)
  452. Xchar *name;
  453. X{
  454. X    int kmem;
  455. X    double f;
  456. X    register int i;
  457. X    double percent();
  458. X    char buf[BUFSIZ];
  459. X    int user, nice, sys, idle;
  460. X    long times1[CPUSTATES], times2[CPUSTATES];
  461. X
  462. X    /*
  463. X     * Open kernel memory.
  464. X     */
  465. X    if ((kmem = open(KMEM, O_RDONLY)) < 0) {
  466. X        syslog(LOG_ERR, "open: %s: %m", KMEM);
  467. X        exit(1);
  468. X    }
  469. X
  470. X    /*
  471. X     * Read kernel namelist.
  472. X     */
  473. X    if ((nlist(VMUNIX, nl) < 0) || (nl[0].n_type == 0)) {
  474. X        syslog(LOG_ERR, "%s: no namelist", VMUNIX);
  475. X        exit(1);
  476. X    }
  477. X
  478. X    /*
  479. X     * Read the first set of usage stats.
  480. X     */
  481. X    lseek(kmem, (long) nl[X_CPTIME].n_value, L_SET);
  482. X    read(kmem, (char *) times1, sizeof(times1));
  483. X
  484. X    /*
  485. X     * Give it a time interval.
  486. X     */
  487. X    sleep(1);
  488. X
  489. X    /*
  490. X     * Read the second set of usage stats.
  491. X     */
  492. X    lseek(kmem, (long) nl[X_CPTIME].n_value, L_SET);
  493. X    read(kmem, (char *) times2, sizeof(times2));
  494. X
  495. X    /*
  496. X     * Calculate change.
  497. X     */
  498. X    for (i=0; i < CPUSTATES; i++)
  499. X        times2[i] -= times1[i];
  500. X
  501. X    /*
  502. X     * Calculate times.
  503. X     */
  504. X    for (i=0; i < CPUSTATES; i++) {
  505. X        f = percent(i, times2);
  506. X
  507. X        /*
  508. X         * Save results.  This is risky, and assumes the order
  509. X         * is as given.  Check sys/dk.h if you think it's wrong
  510. X         * on your system.
  511. X         */
  512. X        switch (i) {
  513. X        case 0:
  514. X            user = (int) f;
  515. X            break;
  516. X        case 1:
  517. X            nice = (int) f;
  518. X            break;
  519. X        case 2:
  520. X            sys = (int) f;
  521. X            break;
  522. X        case 3:
  523. X            idle = (int) f;
  524. X            break;
  525. X        }
  526. X    }
  527. X
  528. X    sprintf(buf, "user %d%% nice %d%% sys %d%% idle %d%%\n", user, nice, sys, idle);
  529. X    (*fn_send)(0, buf);
  530. X    close(kmem);
  531. X}
  532. X
  533. X/*
  534. X * percent - figure what percentage of time is used by row.
  535. X */
  536. Xstatic double percent(row, times)
  537. Xlong *times;
  538. Xint row;
  539. X{
  540. X    double t;
  541. X    register int i;
  542. X
  543. X    t = 0.0;
  544. X    for (i=0; i < CPUSTATES; i++)
  545. X        t += times[i];
  546. X
  547. X    if (t == 0.0)
  548. X        t = 1.0;
  549. X
  550. X    return(times[row] * 100.0 / t);
  551. X}
  552. ________This_Is_The_END________
  553. echo 'x - getloadstats.c'
  554. sed 's/^X//' <<'________This_Is_The_END________' >>getloadstats.c
  555. X#ifndef lint
  556. Xstatic char *RCSid = "$Header: /ecn1/src/ecn/statsrv/RCS/getloadstats.c,v 1.2 87/10/29 14:24:54 davy Exp $";
  557. X#endif
  558. X/*
  559. X * getloadstats - get load average statistics
  560. X *
  561. X * David A. Curry
  562. X * Purdue University
  563. X * Engineering Computer Network
  564. X * davy@intrepid.ecn.purdue.edu
  565. X * October, 1987
  566. X *
  567. X * $Log:    getloadstats.c,v $
  568. X * Revision 1.2  87/10/29  14:24:54  davy
  569. X * Modified to use VMUNIX and KMEM instead of hard-coded paths.
  570. X * 
  571. X * Revision 1.1  87/10/17  21:01:23  davy
  572. X * Initial revision
  573. X * 
  574. X */
  575. X#include <sys/param.h>
  576. X#include <sys/file.h>
  577. X#include <syslog.h>
  578. X#include <nlist.h>
  579. X#include <stdio.h>
  580. X#include "stats.h"
  581. X
  582. Xstatic struct nlist nl[] = {
  583. X#define X_AVENRUN    0
  584. X    {    "_avenrun"    },
  585. X    {    0        }
  586. X};
  587. X
  588. Xextern    int (*fn_recv)(), (*fn_send)();    /* send/recv functions        */
  589. X
  590. X/*
  591. X * getloadstats - get load average statistics
  592. X */
  593. Xgetloadstats(name)
  594. Xchar *name;
  595. X{
  596. X    int kmem;
  597. X    char buf[BUFSIZ];
  598. X#ifdef sun
  599. X    long avenrun[3];
  600. X#else
  601. X    double avenrun[3];
  602. X#endif
  603. X
  604. X    /*
  605. X     * Open kernel memory.
  606. X     */
  607. X    if ((kmem = open(KMEM, O_RDONLY)) < 0) {
  608. X        syslog(LOG_ERR, "open: %s: %m", KMEM);
  609. X        exit(1);
  610. X    }
  611. X
  612. X    /*
  613. X     * Read kernel namelist.
  614. X     */
  615. X    if ((nlist(VMUNIX, nl) < 0) || (nl[0].n_type == 0)) {
  616. X        syslog(LOG_ERR, "%s: no namelist", VMUNIX);
  617. X        exit(1);
  618. X    }
  619. X
  620. X    /*
  621. X     * Read the load averages.
  622. X     */
  623. X    lseek(kmem, (long) nl[X_AVENRUN].n_value, L_SET);
  624. X    read(kmem, (char *) avenrun, sizeof(avenrun));
  625. X
  626. X    /*
  627. X     * Return the one-minute load average.
  628. X     */
  629. X#ifdef sun
  630. X    sprintf(buf, "%.2f\n", (double) avenrun[0] / FSCALE);
  631. X#else
  632. X    sprintf(buf, "%.2f\n", avenrun[0]);
  633. X#endif
  634. X
  635. X    (*fn_send)(0, buf);
  636. X    close(kmem);
  637. X}
  638. ________This_Is_The_END________
  639. echo 'x - getnetstats.c'
  640. sed 's/^X//' <<'________This_Is_The_END________' >>getnetstats.c
  641. X#ifndef lint
  642. Xstatic char *RCSid = "$Header: /ecn1/src/ecn/statsrv/RCS/getnetstats.c,v 1.1 87/10/17 21:01:29 davy Exp $";
  643. X#endif
  644. X/*
  645. X * getnetstats - get network statistics
  646. X *
  647. X * David A. Curry
  648. X * Purdue University
  649. X * Engineering Computer Network
  650. X * davy@intrepid.ecn.purdue.edu
  651. X * October, 1987
  652. X *
  653. X * $Log:    getnetstats.c,v $
  654. X * Revision 1.1  87/10/17  21:01:29  davy
  655. X * Initial revision
  656. X * 
  657. X */
  658. X#include <sys/param.h>
  659. X#include <syslog.h>
  660. X#include <stdio.h>
  661. X
  662. X#define NETSTAT        "/usr/ucb/netstat"
  663. X
  664. Xextern    int (*fn_recv)(), (*fn_send)();    /* send/recv functions        */
  665. X
  666. X/*
  667. X * getnetstats - get network statistic
  668. X */
  669. Xgetnetstats(name)
  670. Xchar *name;
  671. X{
  672. X    int pid;
  673. X    int pf[2];
  674. X    char *flag;
  675. X    register int cnt;
  676. X    char buf[10 * BUFSIZ];
  677. X    register char *s, *ebuf;
  678. X
  679. X    /*
  680. X     * Different stats get different flags.
  681. X     */
  682. X    if (!strcmp(name, "mbufs"))
  683. X        flag = "-m";
  684. X    else if (!strcmp(name, "packets"))
  685. X        flag = "-i";
  686. X    else if (!strcmp(name, "proto"))
  687. X        flag = "-s";
  688. X
  689. X    if (pipe(pf) < 0) {
  690. X        syslog(LOG_ERR, "pipe: %m");
  691. X        exit(1);
  692. X    }
  693. X
  694. X    /*
  695. X     * Start a child.
  696. X     */
  697. X    if ((pid = vfork()) < 0) {
  698. X        syslog(LOG_ERR, "fork: %m");
  699. X        exit(1);
  700. X    }
  701. X
  702. X    /*
  703. X     * Run the command.
  704. X     */
  705. X    if (pid == 0) {
  706. X        close(pf[0]);
  707. X
  708. X        dup2(pf[1], 1);
  709. X        close(pf[1]);
  710. X
  711. X        execl(NETSTAT, "netstat", flag, 0);
  712. X        syslog(LOG_ERR, "exec: %m");
  713. X        exit(1);
  714. X    }
  715. X
  716. X    close(pf[1]);
  717. X
  718. X    /*
  719. X     * Read from the pipe.
  720. X     */
  721. X    s = buf;
  722. X    ebuf = &buf[sizeof(buf) - 1];
  723. X    while ((cnt = read(pf[0], s, (int) (ebuf - s))) > 0) {
  724. X        s += cnt;
  725. X
  726. X        if (s > ebuf) {
  727. X            syslog(LOG_ERR, "output from %s %s too big", NETSTAT, flag);
  728. X            s = ebuf;
  729. X            break;
  730. X        }
  731. X    }
  732. X
  733. X    *s = '\0';
  734. X    (*fn_send)(0, buf);
  735. X
  736. X    close(pf[0]);
  737. X
  738. X    /*
  739. X     * Pick up the child.
  740. X     */
  741. X    while (wait((int *) 0) >= 0)
  742. X        ;
  743. X}
  744. ________This_Is_The_END________
  745. echo 'x - gettablestats.c'
  746. sed 's/^X//' <<'________This_Is_The_END________' >>gettablestats.c
  747. X#ifndef lint
  748. Xstatic char *RCSid = "$Header: /ecn1/src/ecn/statsrv/RCS/gettablestats.c,v 1.1 87/12/08 14:40:03 davy Exp $";
  749. X#endif
  750. X/*
  751. X * gettablestats - get internal table statistics
  752. X *
  753. X * David A. Curry
  754. X * Purdue University
  755. X * Engineering Computer Network
  756. X * davy@intrepid.ecn.purdue.edu
  757. X * December, 1987
  758. X *
  759. X * $Log:    gettablestats.c,v $
  760. X * Revision 1.1  87/12/08  14:40:03  davy
  761. X * Initial revision
  762. X * 
  763. X */
  764. X#include <sys/param.h>
  765. X#include <syslog.h>
  766. X#include <stdio.h>
  767. X
  768. X#define PSTAT        "/etc/pstat"
  769. X
  770. Xextern    int (*fn_recv)(), (*fn_send)();    /* send/recv functions        */
  771. X
  772. X/*
  773. X * gettablestats - get internal table statistics
  774. X */
  775. Xgettablestats(name)
  776. Xchar *name;
  777. X{
  778. X    int pid;
  779. X    int pf[2];
  780. X    char *flag;
  781. X    register int cnt;
  782. X    char buf[10 * BUFSIZ];
  783. X    register char *s, *ebuf;
  784. X
  785. X    /*
  786. X     * Different stats get different flags.
  787. X     */
  788. X    if (!strcmp(name, "tables"))
  789. X        flag = "-T";
  790. X
  791. X    if (pipe(pf) < 0) {
  792. X        syslog(LOG_ERR, "pipe: %m");
  793. X        exit(1);
  794. X    }
  795. X
  796. X    /*
  797. X     * Start a child.
  798. X     */
  799. X    if ((pid = vfork()) < 0) {
  800. X        syslog(LOG_ERR, "fork: %m");
  801. X        exit(1);
  802. X    }
  803. X
  804. X    /*
  805. X     * Run the command.
  806. X     */
  807. X    if (pid == 0) {
  808. X        close(pf[0]);
  809. X
  810. X        dup2(pf[1], 1);
  811. X        close(pf[1]);
  812. X
  813. X        execl(PSTAT, "pstat", flag, 0);
  814. X        syslog(LOG_ERR, "exec: %m");
  815. X        exit(1);
  816. X    }
  817. X
  818. X    close(pf[1]);
  819. X
  820. X    /*
  821. X     * Read from the pipe.
  822. X     */
  823. X    s = buf;
  824. X    ebuf = &buf[sizeof(buf) - 1];
  825. X    while ((cnt = read(pf[0], s, (int) (ebuf - s))) > 0) {
  826. X        s += cnt;
  827. X
  828. X        if (s > ebuf) {
  829. X            syslog(LOG_ERR, "output from %s %s too big", PSTAT, flag);
  830. X            s = ebuf;
  831. X            break;
  832. X        }
  833. X    }
  834. X
  835. X    *s = '\0';
  836. X    (*fn_send)(0, buf);
  837. X
  838. X    close(pf[0]);
  839. X
  840. X    /*
  841. X     * Pick up the child.
  842. X     */
  843. X    while (wait((int *) 0) >= 0)
  844. X        ;
  845. X}
  846. ________This_Is_The_END________
  847. echo 'x - gettimestats.c'
  848. sed 's/^X//' <<'________This_Is_The_END________' >>gettimestats.c
  849. X#ifndef lint
  850. Xstatic char *RCSid = "$Header: /ecn1/src/ecn/statsrv/RCS/gettimestats.c,v 1.3 87/10/29 15:03:57 davy Exp $";
  851. X#endif
  852. X/*
  853. X * gettimestats - get time-related statistics
  854. X *
  855. X * David A. Curry
  856. X * Purdue University
  857. X * Engineering Computer Network
  858. X * davy@intrepid.ecn.purdue.edu
  859. X * October, 1987
  860. X *
  861. X * $Log:    gettimestats.c,v $
  862. X * Revision 1.3  87/10/29  15:03:57  davy
  863. X * Fixed bug with timezone printing.
  864. X * 
  865. X * Revision 1.2  87/10/29  14:25:03  davy
  866. X * Modified to use VMUNIX and KMEM instead of hard-coded paths.
  867. X * 
  868. X * Revision 1.1  87/10/17  21:01:34  davy
  869. X * Initial revision
  870. X * 
  871. X */
  872. X#include <sys/param.h>
  873. X#include <sys/file.h>
  874. X#include <sys/time.h>
  875. X#include <syslog.h>
  876. X#include <nlist.h>
  877. X#include <stdio.h>
  878. X#include "stats.h"
  879. X
  880. Xstatic struct nlist nl[] = {
  881. X#define X_BOOTTIME    0
  882. X    {    "_boottime"    },
  883. X    {    0        }
  884. X};
  885. X
  886. Xextern    int (*fn_recv)(), (*fn_send)();    /* send/recv functions        */
  887. X
  888. X/*
  889. X * gettimestats - get time-related statistics
  890. X */
  891. Xgettimestats(name)
  892. Xchar *name;
  893. X{
  894. X    int kmem;
  895. X    struct timezone tz;
  896. X    struct timeval curtime, boottime;
  897. X
  898. X    /*
  899. X     * Get current date and time.
  900. X     */
  901. X    gettimeofday(&curtime, &tz);
  902. X
  903. X    /*
  904. X     * If we're doing "date" or "time", we just print
  905. X     * out the current date and time.
  906. X     */
  907. X    if (!strcmp(name, "date") || !strcmp(name, "time")) {
  908. X        prdate(&curtime, &tz);
  909. X        return;
  910. X    }
  911. X
  912. X    /*
  913. X     * Open kernel memory.
  914. X     */
  915. X    if ((kmem = open(KMEM, O_RDONLY)) < 0) {
  916. X        syslog(LOG_ERR, "open: %s: %m", KMEM);
  917. X        exit(1);
  918. X    }
  919. X
  920. X    /*
  921. X     * Read kernel namelist.
  922. X     */
  923. X    if ((nlist(VMUNIX, nl) < 0) || (nl[0].n_type == 0)) {
  924. X        syslog(LOG_ERR, "%s: no namelist", VMUNIX);
  925. X        exit(1);
  926. X    }
  927. X
  928. X    /*
  929. X     * Read the boot time.
  930. X     */
  931. X    lseek(kmem, (long) nl[X_BOOTTIME].n_value, L_SET);
  932. X    read(kmem, (char *) &boottime, sizeof(boottime));
  933. X
  934. X    /*
  935. X     * For "boottime" we just print the boot time, for
  936. X     * "uptime" we print the time up.
  937. X     */
  938. X    if (!strcmp(name, "boottime")) {
  939. X        prdate(&boottime, &tz);
  940. X    }
  941. X    else {
  942. X        curtime.tv_sec -= boottime.tv_sec;
  943. X        prtime(&curtime);
  944. X    }
  945. X
  946. X    close(kmem);
  947. X}
  948. X
  949. X/*
  950. X * prdate - print date and time
  951. X */
  952. Xstatic prdate(tv, tz)
  953. Xstruct timezone *tz;
  954. Xstruct timeval *tv;
  955. X{
  956. X    char buf[64];
  957. X    struct tm *tm;
  958. X    struct tm *localtime();
  959. X    register char *ap, *tzn;
  960. X    char *asctime(), *timezone();
  961. X
  962. X    tm = localtime(&tv->tv_sec);
  963. X
  964. X    ap = asctime(tm);
  965. X    tzn = timezone(tz->tz_minuteswest, tm->tm_isdst);
  966. X
  967. X    /*
  968. X     * Date and time.
  969. X     */
  970. X    strncpy(buf, ap, 20);
  971. X    buf[20] = '\0';
  972. X
  973. X    /*
  974. X     * Timezone.
  975. X     */
  976. X    if (tzn)
  977. X        strcat(buf, tzn);
  978. X
  979. X    /*
  980. X     * Year.
  981. X     */
  982. X    strcat(buf, ap+19);
  983. X
  984. X    (*fn_send)(0, buf);
  985. X}
  986. X
  987. X/*
  988. X * prtime - print time as days, hours, minutes, seconds.
  989. X */
  990. Xstatic prtime(tv)
  991. Xstruct timeval *tv;
  992. X{
  993. X    char tmp[32], buf[128];
  994. X
  995. X    *buf = '\0';
  996. X
  997. X    if (tv->tv_sec >= 86400) {
  998. X        sprintf(tmp, "%d days ", tv->tv_sec / 86400);
  999. X        tv->tv_sec %= 86400;
  1000. X        strcat(buf, tmp);
  1001. X    }
  1002. X
  1003. X    if (tv->tv_sec >= 3600) {
  1004. X        sprintf(tmp, "%d hours ", tv->tv_sec / 3600);
  1005. X        tv->tv_sec %= 3600;
  1006. X        strcat(buf, tmp);
  1007. X    }
  1008. X
  1009. X    if (tv->tv_sec >= 60) {
  1010. X        sprintf(tmp, "%d minutes ", tv->tv_sec / 60);
  1011. X        tv->tv_sec %= 60;
  1012. X        strcat(buf, tmp);
  1013. X    }
  1014. X
  1015. X    if (tv->tv_sec) {
  1016. X        sprintf(tmp, "%d seconds", tv->tv_sec);
  1017. X        strcat(buf, tmp);
  1018. X    }
  1019. X
  1020. X    strcat(buf, "\n");
  1021. X    (*fn_send)(0, buf);
  1022. X}
  1023. ________This_Is_The_END________
  1024. echo 'x - getuserstats.c'
  1025. sed 's/^X//' <<'________This_Is_The_END________' >>getuserstats.c
  1026. X#ifndef lint
  1027. Xstatic char *RCSid = "$Header: /ecn1/src/ecn/statsrv/RCS/getuserstats.c,v 1.3 87/12/08 14:39:06 davy Exp $";
  1028. X#endif
  1029. X/*
  1030. X * getuserstats - get user statistics
  1031. X *
  1032. X * David A. Curry
  1033. X * Purdue University
  1034. X * Engineering Computer Network
  1035. X * davy@intrepid.ecn.purdue.edu
  1036. X * October, 1987
  1037. X *
  1038. X * $Log:    getuserstats.c,v $
  1039. X * Revision 1.3  87/12/08  14:39:06  davy
  1040. X * Added code for the "who" statistic.
  1041. X * 
  1042. X * Revision 1.2  87/10/29  14:24:36  davy
  1043. X * Modified to use UTMP instead of hard-coded path.
  1044. X * 
  1045. X * Revision 1.1  87/10/17  21:01:40  davy
  1046. X * Initial revision
  1047. X * 
  1048. X */
  1049. X#include <sys/param.h>
  1050. X#include <sys/stat.h>
  1051. X#include <sys/time.h>
  1052. X#include <syslog.h>
  1053. X#include <stdio.h>
  1054. X#include <utmp.h>
  1055. X
  1056. X#define WHO        0
  1057. X#define USERS        1
  1058. X#define ACTUSERS    2
  1059. X
  1060. X#define UTMP        "/etc/utmp"
  1061. X#define USERBUFSIZE    2048        /* 256 8-char logins        */
  1062. X
  1063. Xextern    int (*fn_recv)(), (*fn_send)();    /* send/recv functions        */
  1064. X
  1065. X/*
  1066. X * getuserstats - get user statistics
  1067. X */
  1068. Xgetuserstats(name)
  1069. Xchar *name;
  1070. X{
  1071. X    FILE *fp;
  1072. X    char buf[32];
  1073. X    struct utmp ut;
  1074. X    struct stat st;
  1075. X    struct timeval tv;
  1076. X    register int cnt, mode;
  1077. X    char userbuf[USERBUFSIZE];
  1078. X
  1079. X    /*
  1080. X     * "actusers" means we only want active users.
  1081. X     * "who" means we want user names.
  1082. X     */
  1083. X    if (!strcmp(name, "actusers"))
  1084. X        mode = ACTUSERS;
  1085. X    else if (!strcmp(name, "users"))
  1086. X        mode = USERS;
  1087. X    else
  1088. X        mode = WHO;
  1089. X
  1090. X    if ((fp = fopen(UTMP, "r")) == NULL) {
  1091. X        syslog(LOG_ERR, "cannot open %s", UTMP);
  1092. X        exit(1);
  1093. X    }
  1094. X
  1095. X    *userbuf = NULL;
  1096. X    gettimeofday(&tv, (struct timeval *) 0);
  1097. X
  1098. X    /*
  1099. X     * For each user...
  1100. X     */
  1101. X    cnt = 0;
  1102. X    while (fread(&ut, sizeof(struct utmp), 1, fp) == 1) {
  1103. X        /*
  1104. X         * Not logged in.
  1105. X         */
  1106. X        if (ut.ut_name[0] == NULL)
  1107. X            continue;
  1108. X
  1109. X        /*
  1110. X         * For active users, see how long he's been idle.
  1111. X         */
  1112. X        if (mode == ACTUSERS) {
  1113. X            sprintf(buf, "/dev/%.8s", ut.ut_line);
  1114. X
  1115. X            if (stat(buf, &st) < 0)
  1116. X                continue;
  1117. X
  1118. X            /*
  1119. X             * If idle less than 1 hour, he's active.
  1120. X             */
  1121. X            if ((tv.tv_sec - st.st_atime) < 3600)
  1122. X                cnt++;
  1123. X        }
  1124. X        else {
  1125. X            /*
  1126. X             * Copy the login name if needed.
  1127. X             */
  1128. X            if (mode == WHO) {
  1129. X                sprintf(buf, "%.8s ", ut.ut_name);
  1130. X                strcat(userbuf, buf);
  1131. X            }
  1132. X
  1133. X            cnt++;
  1134. X        }
  1135. X    }
  1136. X
  1137. X    /*
  1138. X     * Send the appropriate buffer.
  1139. X     */
  1140. X    if (mode == WHO) {
  1141. X        strcat(userbuf, "\n");
  1142. X        (*fn_send)(0, userbuf);
  1143. X    }
  1144. X    else {
  1145. X        sprintf(buf, "%d\n", cnt);
  1146. X        (*fn_send)(0, buf);
  1147. X    }
  1148. X
  1149. X    fclose(fp);
  1150. X}
  1151. ________This_Is_The_END________
  1152. echo 'x - st_sendrecv.c'
  1153. sed 's/^X//' <<'________This_Is_The_END________' >>st_sendrecv.c
  1154. X#ifndef lint
  1155. Xstatic char *RCSid = "$Header: /ecn1/src/ecn/statsrv/RCS/st_sendrecv.c,v 1.2 87/10/19 08:37:02 davy Exp $";
  1156. X#endif
  1157. X/*
  1158. X * st_sendrecv.c - stream send/recv functions
  1159. X *
  1160. X * David A. Curry
  1161. X * Purdue University
  1162. X * Engineering Computer Network
  1163. X * davy@intrepid.ecn.purdue.edu
  1164. X * October, 1987
  1165. X *
  1166. X * $Log:    st_sendrecv.c,v $
  1167. X * Revision 1.2  87/10/19  08:37:02  davy
  1168. X * Fixed to catch end of file on socket.
  1169. X * 
  1170. X * Revision 1.1  87/10/17  21:01:46  davy
  1171. X * Initial revision
  1172. X * 
  1173. X */
  1174. X#include <sys/param.h>
  1175. X#include <sys/socket.h>
  1176. X#include <netinet/in.h>
  1177. X#include <syslog.h>
  1178. X#include <stdio.h>
  1179. X
  1180. X#include "stats.h"
  1181. X
  1182. Xextern char    *pname;
  1183. Xextern short    server;
  1184. X
  1185. X/*
  1186. X * st_send - send buf on the socket s.
  1187. X */
  1188. Xst_send(s, buf)
  1189. Xchar *buf;
  1190. Xint s;
  1191. X{
  1192. X    register int cnt;
  1193. X
  1194. X    /*
  1195. X     * We want the length including the null.
  1196. X     */
  1197. X    cnt = strlen(buf) + 1;
  1198. X
  1199. X    /*
  1200. X     * Send the buffer.
  1201. X     */
  1202. X    if (send(s, buf, cnt, 0) < 0) {
  1203. X        if (server)
  1204. X            syslog(LOG_ERR, "send: %m");
  1205. X        else
  1206. X            error("send");
  1207. X        exit(1);
  1208. X    }
  1209. X}
  1210. X
  1211. X/*
  1212. X * st_recv - receive data of maximum length cnt into the buffer buf on
  1213. X *         socket s.  err describes what we're expecting for the error
  1214. X *         message.
  1215. X */
  1216. Xst_recv(s, buf, cnt, err)
  1217. Xchar *buf, *err;
  1218. Xint s, cnt;
  1219. X{
  1220. X    char c;
  1221. X    register int n;
  1222. X
  1223. X    /*
  1224. X     * Receive a character at a time up to a null.
  1225. X     */
  1226. X    do {
  1227. X        if ((n = recv(s, &c, sizeof(char), 0)) < 0) {
  1228. X            if (server)
  1229. X                syslog(LOG_ERR, "recv: %m");
  1230. X            else
  1231. X                error("recv");
  1232. X            exit(1);
  1233. X        }
  1234. X
  1235. X        /*
  1236. X         * End of file.
  1237. X         */
  1238. X        if (n == 0)
  1239. X            exit(0);
  1240. X
  1241. X        if (--cnt < 0) {
  1242. X            if (server)
  1243. X                syslog(LOG_ERR, "%s too long", err);
  1244. X            else
  1245. X                fprintf(stderr, "%s: %s too long.\n", pname, err);
  1246. X            exit(1);
  1247. X        }
  1248. X
  1249. X        *buf++ = c;
  1250. X    } while (c != '\0');
  1251. X}
  1252. ________This_Is_The_END________
  1253. echo 'x - stats.c'
  1254. sed 's/^X//' <<'________This_Is_The_END________' >>stats.c
  1255. X#ifndef lint
  1256. Xstatic char *RCSid = "$Header: /ecn1/src/ecn/statsrv/RCS/stats.c,v 1.1 87/10/17 21:01:52 davy Exp $";
  1257. X#endif
  1258. X/*
  1259. X * stats - retrieve statistics from the statistics server
  1260. X *
  1261. X * Usage:    stats [-d] host statname [statname...]
  1262. X *
  1263. X * The STATSRV protocol is described in RFC996, "Statistics Server",
  1264. X * D.L. Mills, February 1987.
  1265. X *
  1266. X * David A. Curry
  1267. X * Purdue University
  1268. X * Engineering Computer Network
  1269. X * davy@intrepid.ecn.purdue.edu
  1270. X * October, 1987
  1271. X *
  1272. X * $Log:    stats.c,v $
  1273. X * Revision 1.1  87/10/17  21:01:52  davy
  1274. X * Initial revision
  1275. X * 
  1276. X */
  1277. X#include <sys/param.h>
  1278. X#include <sys/socket.h>
  1279. X#include <netinet/in.h>
  1280. X#include <netdb.h>
  1281. X#include <stdio.h>
  1282. X
  1283. X#include "stats.h"
  1284. X
  1285. Xchar    *pname;                /* program name            */
  1286. Xshort    server = 0;            /* indicates we aren't server    */
  1287. Xstruct    sockaddr_in sin;        /* address of remote host    */
  1288. Xint    (*fn_send)(), (*fn_recv)();    /* send/recv functions        */
  1289. X
  1290. Xmain(argc, argv)
  1291. Xint argc;
  1292. Xchar **argv;
  1293. X{
  1294. X    int socktype;
  1295. X    register int s;
  1296. X    char buf[10240];
  1297. X    struct hostent *hp;
  1298. X    struct servent *sp;
  1299. X    char *host, *servtype;
  1300. X    struct hostent *gethostbyname();
  1301. X    struct servent *getservbyname();
  1302. X
  1303. X    pname = *argv;
  1304. X
  1305. X    /*
  1306. X     * Set up to use TCP stream sockets.
  1307. X     */
  1308. X    servtype = "tcp";
  1309. X    fn_recv = st_recv;
  1310. X    fn_send = st_send;
  1311. X    socktype = SOCK_STREAM;
  1312. X
  1313. X    /*
  1314. X     * Check arguments.
  1315. X     */
  1316. Xargchk:    if (argc < 3) {
  1317. X        fprintf(stderr, "Usage: %s [-d] host statname [statname...]\n", pname);
  1318. X        fprintf(stderr, "    use the \"help\" statistic for more info.\n");
  1319. X        exit(1);
  1320. X    }
  1321. X
  1322. X    /*
  1323. X     * -d indicates use datagrams; set up to use
  1324. X     * datagram sockets and then go recheck the
  1325. X     * argument list.
  1326. X     */
  1327. X    if (!strcmp(*++argv, "-d")) {
  1328. X        socktype = SOCK_DGRAM;
  1329. X        fn_recv = dg_recv;
  1330. X        fn_send = dg_send;
  1331. X        servtype = "udp";
  1332. X        argc--;
  1333. X
  1334. X        goto argchk;
  1335. X    }
  1336. X
  1337. X    /*
  1338. X     * Host is first argument.
  1339. X     */
  1340. X    argc--;
  1341. X    host = *argv;
  1342. X
  1343. X    /*
  1344. X     * Get a socket.
  1345. X     */
  1346. X    if ((s = socket(AF_INET, socktype, 0)) < 0) {
  1347. X        error("socket");
  1348. X        exit(1);
  1349. X    }
  1350. X
  1351. X    /*
  1352. X     * Look up the host's address.
  1353. X     */
  1354. X    if ((hp = gethostbyname(host)) == NULL) {
  1355. X        fprintf(stderr, "%s: %s: host unknown.\n", pname, host);
  1356. X        exit(1);
  1357. X    }
  1358. X
  1359. X    /*
  1360. X     * Look up the port the server lives on.
  1361. X     */
  1362. X    if ((sp = getservbyname(SERVNAME, servtype)) == NULL) {
  1363. X        fprintf(stderr, "%s: %s/%s: service unknown.\n", pname, SERVNAME, servtype);
  1364. X        exit(1);
  1365. X    }
  1366. X
  1367. X    /*
  1368. X     * Build the server's address.
  1369. X     */
  1370. X    sin.sin_port = sp->s_port;
  1371. X    sin.sin_family = hp->h_addrtype;
  1372. X    bcopy(hp->h_addr, &sin.sin_addr, sizeof(sin.sin_addr));
  1373. X
  1374. X    /*
  1375. X     * If we're using a stream socket, connect to
  1376. X     * the remote host.
  1377. X     */
  1378. X    if (socktype == SOCK_STREAM) {
  1379. X        if (connect(s, &sin, sizeof(struct sockaddr_in)) < 0) {
  1380. X            error("connect");
  1381. X            exit(1);
  1382. X        }
  1383. X    }
  1384. X
  1385. X    /*
  1386. X     * For each statistic requested...
  1387. X     */
  1388. X    while (--argc) {
  1389. X        /*
  1390. X         * Send the name of the statistic to the
  1391. X         * server.
  1392. X         */
  1393. X        (*fn_send)(s, *++argv);
  1394. X
  1395. X        /*
  1396. X         * Wait for a response.
  1397. X         */
  1398. X        (*fn_recv)(s, buf, sizeof(buf), "response");
  1399. X
  1400. X        /*
  1401. X         * Print what we got.
  1402. X         */
  1403. X        fputs(buf, stdout);
  1404. X    }
  1405. X
  1406. X    exit(0);
  1407. X}
  1408. X
  1409. X/*
  1410. X * error - print program name and error message.
  1411. X */
  1412. Xerror(s)
  1413. X{
  1414. X    fprintf(stderr, "%s: ", pname);
  1415. X    perror(s);
  1416. X}
  1417. ________This_Is_The_END________
  1418. echo 'x - statsrv.c'
  1419. sed 's/^X//' <<'________This_Is_The_END________' >>statsrv.c
  1420. X#ifndef lint
  1421. Xstatic char *RCSid = "$Header: /ecn1/src/ecn/statsrv/RCS/statsrv.c,v 1.2 87/12/08 14:39:23 davy Exp $";
  1422. X#endif
  1423. X/*
  1424. X * statsrv - statistics server
  1425. X *
  1426. X * Statsrv is invoked via inetd(8).  Place the following lines in your
  1427. X * inetd.conf file (statsrv is port 133 for both udp and tcp):
  1428. X *
  1429. X * statsrv    stream    tcp    nowait    root    /etc/statsrv    statsrv
  1430. X * statsrv    dgram    udp    wait    root    /etc/statsrv    statsrv
  1431. X *
  1432. X * The STATSRV protocol is described in RFC996, "Statistics Server",
  1433. X * D.L. Mills, February 1987.
  1434. X *
  1435. X * David A. Curry
  1436. X * Purdue University
  1437. X * Engineering Computer Network
  1438. X * davy@intrepid.ecn.purdue.edu
  1439. X * October, 1987
  1440. X *
  1441. X * $Log:    statsrv.c,v $
  1442. X * Revision 1.2  87/12/08  14:39:23  davy
  1443. X * Added lines for the "tables" and "who" commands.
  1444. X * 
  1445. X * Revision 1.1  87/10/17  21:01:57  davy
  1446. X * Initial revision
  1447. X * 
  1448. X */
  1449. X#include <sys/param.h>
  1450. X#include <sys/socket.h>
  1451. X#include <netinet/in.h>
  1452. X#include <syslog.h>
  1453. X#include <errno.h>
  1454. X#include <ctype.h>
  1455. X#include <stdio.h>
  1456. X
  1457. X#include "stats.h"
  1458. X
  1459. X/*
  1460. X * One of these for each statistic we understand.
  1461. X */
  1462. Xstruct statistic {
  1463. X    char    *st_name;
  1464. X    int    (*st_func)();
  1465. X};
  1466. X
  1467. X/*
  1468. X * Functions which do the statistics.
  1469. X */
  1470. Xextern int liststats();
  1471. Xextern int getcpustats();
  1472. Xextern int getnetstats();
  1473. Xextern int getloadstats();
  1474. Xextern int getuserstats();
  1475. Xextern int gettimestats();
  1476. Xextern int gettablestats();
  1477. X
  1478. X/*
  1479. X * Statistics we understand.
  1480. X */
  1481. Xstatic struct statistic stats[] = {
  1482. X    {    "actusers",    getuserstats    },
  1483. X    {    "boottime",    gettimestats    },
  1484. X    {    "cpu",        getcpustats    },
  1485. X    {    "date",        gettimestats    },
  1486. X    {    "help",        liststats    },
  1487. X    {    "loadav",    getloadstats    },
  1488. X    {    "mbufs",    getnetstats    },
  1489. X    {    "packets",    getnetstats    },
  1490. X    {    "proto",    getnetstats    },
  1491. X    {    "tables",    gettablestats    },
  1492. X    {    "time",        gettimestats    },
  1493. X    {    "uptime",    gettimestats    },
  1494. X    {    "users",    getuserstats    },
  1495. X    {    "who",        getuserstats    },
  1496. X    {    0,        0        }
  1497. X};
  1498. X    
  1499. Xchar    *pname;                /* program name            */
  1500. Xshort    server = 1;            /* indicates we're the server    */
  1501. Xstruct    sockaddr_in sin;        /* address of remote host    */
  1502. Xint    (*fn_recv)(), (*fn_send)();    /* send/recv functions        */
  1503. X
  1504. Xextern    int errno;
  1505. X
  1506. Xmain(argc, argv)
  1507. Xint argc;
  1508. Xchar **argv;
  1509. X{
  1510. X    char *rindex();
  1511. X    char buf[BUFSIZ];
  1512. X    register char *s;
  1513. X    int len, socktype;
  1514. X    register struct statistic *st;
  1515. X
  1516. X    /*
  1517. X     * Get program name.
  1518. X     */
  1519. X    if ((pname = rindex(*argv, '/')) == NULL)
  1520. X        pname = *argv;
  1521. X    else
  1522. X        pname++;
  1523. X
  1524. X    /*
  1525. X     * Set up syslog.
  1526. X     */
  1527. X    openlog(pname, LOG_PID, LOG_DAEMON);
  1528. X
  1529. X    /*
  1530. X     * Set up to run on stream sockets.
  1531. X     */
  1532. X    fn_recv = st_recv;
  1533. X    fn_send = st_send;
  1534. X    socktype = SOCK_STREAM;
  1535. X
  1536. X    /*
  1537. X     * Figure out if we're on a stream or datagram socket.  If
  1538. X     * we are on a datagram socket, we have no peer, and we
  1539. X     * will get an ENOTCONN error.
  1540. X     */
  1541. X    len = sizeof(struct sockaddr_in);
  1542. X    if (getpeername(0, &sin, &len) < 0) {
  1543. X        /*
  1544. X         * Datagram socket.
  1545. X         */
  1546. X        if (errno == ENOTCONN) {
  1547. X            socktype = SOCK_DGRAM;
  1548. X            fn_recv = dg_recv;
  1549. X            fn_send = dg_send;
  1550. X        }
  1551. X        else {
  1552. X            syslog(LOG_ERR, "getpeername: %m");
  1553. X            exit(1);
  1554. X        }
  1555. X    }
  1556. X
  1557. X    /*
  1558. X     * Forever...
  1559. X     */
  1560. Xtop:    for (;;) {
  1561. X        /*
  1562. X         * Get a statistic request from the remote host.
  1563. X         */
  1564. X        (*fn_recv)(0, buf, sizeof(buf), "statname");
  1565. X
  1566. X        /*
  1567. X         * Convert to lower case.
  1568. X         */
  1569. X        for (s = buf; *s; s++) {
  1570. X            if (isupper(*s))
  1571. X                *s = tolower(*s);
  1572. X        }
  1573. X
  1574. X        /*
  1575. X         * Look up the statistic and run the
  1576. X         * function.
  1577. X         */
  1578. X        for (st = stats; st->st_name; st++) {
  1579. X            if (!strcmp(st->st_name, buf)) {
  1580. X                (*(st->st_func))(buf);
  1581. X
  1582. X                /*
  1583. X                 * Only one statistic per datagram.
  1584. X                 */
  1585. X                if (socktype == SOCK_DGRAM)
  1586. X                    exit(0);
  1587. X
  1588. X                goto top;
  1589. X            }
  1590. X        }
  1591. X
  1592. X        /*
  1593. X         * Unknown statistic.
  1594. X         */
  1595. X        (*fn_send)(0, "unknown command - use \"help\" for list.\n");
  1596. X        exit(1);
  1597. X    }
  1598. X}
  1599. X
  1600. X/*
  1601. X * liststats - list statistics we know about.
  1602. X */
  1603. Xliststats(name)
  1604. Xchar *name;
  1605. X{
  1606. X    char buf[BUFSIZ];
  1607. X    register struct statistic *st;
  1608. X
  1609. X    *buf = '\0';
  1610. X
  1611. X    for (st = stats; st->st_name; st++) {
  1612. X        strcat(buf, st->st_name);
  1613. X        strcat(buf, "\n");
  1614. X    }
  1615. X
  1616. X    (*fn_send)(0, buf);
  1617. X}
  1618. X
  1619. X/*
  1620. X * error - print program name and error message.
  1621. X */
  1622. Xerror(s)
  1623. X{
  1624. X    fprintf(stderr, "%s: ", pname);
  1625. X    perror(s);
  1626. X}
  1627. ________This_Is_The_END________
  1628. echo 'x - tester'
  1629. sed 's/^X//' <<'________This_Is_The_END________' >>tester
  1630. X#!/bin/csh -f
  1631. X
  1632. Xset hostname = `hostname`
  1633. X
  1634. Xforeach i (actusers boottime cpu date help loadav mbufs packets proto \
  1635. X       tables time uptime users who)
  1636. X    echo "--------- $i (stream) ---------"
  1637. X    stats $hostname $i
  1638. X    echo "--------- $i (datagram) ---------"
  1639. X    stats -d $hostname $i
  1640. Xend
  1641. X
  1642. ________This_Is_The_END________
  1643. echo 'x - rfc'
  1644. sed 's/^X//' <<'________This_Is_The_END________' >>rfc
  1645. X
  1646. XNetwork Working Group                                         D.L. Mills
  1647. XRequest for Comments: 996                         University of Delaware
  1648. X                                                           February 1987
  1649. X
  1650. X
  1651. X                           Statistics Server
  1652. X
  1653. XSTATUS OF THIS MEMO
  1654. X
  1655. X   This RFC specifies a standard for the ARPA Internet community. Hosts
  1656. X   and gateways on the DARPA Internet that choose to implement a remote
  1657. X   statistics monitoring facility may use this protocol to send
  1658. X   statistics data upon request to a monitoring center or debugging
  1659. X   host.  Distribution of this memo is unlimited.
  1660. X
  1661. XDISCUSSION
  1662. X
  1663. X   Many host and gateway implementations include a facility which
  1664. X   records traffic statistics, such as packet counters, error counters
  1665. X   and significant event counters for debugging and performance
  1666. X   evluation.  Simple data-access and formatting programs can be used to
  1667. X   display these statistics along with the status of connections, etc.
  1668. X   Several operating systems, including the various Unix systems and
  1669. X   Fuzzball systems, already provide extensive facilities to capture and
  1670. X   display these data for local users and/or operators.
  1671. X
  1672. X   In many instances it is highly useful to observe statistics data on
  1673. X   remote hosts and gateways from a monitoring center or debugging host.
  1674. X   Indeed, several protocols have been implemented and used expressly
  1675. X   for this purpose [1-6]. In many cases the data can be retrieved using
  1676. X   conventional services such as remote login or even file transfer.
  1677. X   However, use of these heavyweight mechanisms is awkward and intrusive
  1678. X   if conducted on a regular, frequent basis and may involve substantial
  1679. X   intrusion in the operating system if retrofitted to existing systems.
  1680. X
  1681. X   The Statistics Server (STATSRV) protocol is intended as a lightweight
  1682. X   mechanism similar in spirit to NETSTAT [7] and complementary to it.
  1683. X   STATSRV is designed to capture statistics data with minimal intrusion
  1684. X   on existing systems or networks. It is intended for use with existing
  1685. X   hosts and gateways primarily for casual monitoring and debugging
  1686. X   purposes. It is not intended as a full-function monitoring protocol
  1687. X   [1,5,6] providing detailed, standardized reports suitable for machine
  1688. X   analysis, for example, but could be useful in exploratory development
  1689. X   leading to enduring systems of this type.
  1690. X
  1691. X   The STATSRV model is based on the native host command language used
  1692. X   for statistics monitoring and display. The client sends a null-
  1693. X   terminated ASCII command to the server, which then responds with a
  1694. X   null-terminated ASCII response suitable for a printer or CRT display.
  1695. X   Although in principle STATSRV could be used over TCP, it is less
  1696. X   intrusive and more efficient to use it over UDP. In the case of UDP,
  1697. X
  1698. X
  1699. X
  1700. XD. L. Mills                                                     [Page 1]
  1701. X
  1702. XRFC 996                                                    February 1987
  1703. X
  1704. X
  1705. X   commands and responses must fit into a single 576-octet IP datagram.
  1706. X   In both UDP and TCP the assigned port number is 133 (decimal).
  1707. X
  1708. X   As is conventional in other lightweight services of this type
  1709. X   (NETSTAT, FINGER, etc.), there is no provision for access control or
  1710. X   authentication in STATSRV. If necessary, each command could include a
  1711. X   password or other mechanism to discourage casual abuse.
  1712. X
  1713. XEXAMPLE
  1714. X
  1715. X   The Fuzzball system includes many local commands to display internal
  1716. X   data structures, including one that produces the following billboard
  1717. X   for each network device, in this case "dm0" on host "udel2.udel.edu":
  1718. X
  1719. X        Process type: 000027  options: 040000
  1720. X        Subnet: DMV  status: 376  hello: 15  timeout: 2000
  1721. X        Foreign address: [192.5.39.87]  max size: 576
  1722. X        Input packets      3645    Output packets  3690
  1723. X          bad format       0       ICMP msgs       0
  1724. X          bad checksum     0       Input errors    0
  1725. X          returned         0       Output errors   0
  1726. X          dropped          2       No buffer       0
  1727. X          HELLO msgs       2286    Preempted       0
  1728. X
  1729. X   The same billboard is returned as a null-terminated ASCII string in a
  1730. X   UDP datagram by sending the null-terminated ASCII command "dm0" in a
  1731. X   UDP datagram to the host. Similar billboards can be produced for most
  1732. X   processes in the system. Unix programs and shell scripts have been
  1733. X   built which send commands like these to selected hosts on a periodic
  1734. X   basis in order to construct a simple, ad-hoc monitoring facility.
  1735. X
  1736. XREFERENCES
  1737. X
  1738. X   [1]  Flood Page, D.,"Gateway Monitoring Protocol", DARPA Network
  1739. X        Working Group Report IEN-131, Bolt Beranek and Newman, February
  1740. X        1980.
  1741. X
  1742. X   [2]  Flood Page, D., "The CMCC Terminal Process", DARPA Network
  1743. X        Working Group Report IEN-132, Bolt Beranek and Newman, February
  1744. X        1980.
  1745. X
  1746. X   [3]  Flood Page, D., "CMCC Performance Measurement Message Formats",
  1747. X        DARPA Network Working Group Report IEN-157, Bolt Beranek and
  1748. X        Newman, September 1980.
  1749. X
  1750. X   [4]  Jones, R.G., " A Proposal for Simple Measurement Support for
  1751. X        Users", DARPA Network Working Group Report IEN-161, University
  1752. X        College London, November 1980.
  1753. X
  1754. X
  1755. X
  1756. X
  1757. X
  1758. X
  1759. XD. L. Mills                                                     [Page 2]
  1760. X
  1761. XRFC 996                                                    February 1987
  1762. X
  1763. X
  1764. X   [5]  Littauer, B.M., A.J. Huang and R.M. Hinden," A Host Monitoring
  1765. X        Protocol", DARPA Network Working Group Report IEN-197, Bolt
  1766. X        Beranek and Newman, September 1981.
  1767. X
  1768. X   [6]  Hinden, R.M.," A Host Monitoring Protocol", DARPA Network
  1769. X        Working Group Report RFC-869, BBN Communications Corporation,
  1770. X        December 1983.
  1771. X
  1772. X   [7]  Reynolds, J.K., and J. Postel, "Assigned Numbers", DARPA Network
  1773. X        Working Group Report RFC-990, USC Information Sciences
  1774. X        Institute, November 1986.
  1775. X
  1776. X
  1777. X
  1778. X
  1779. X
  1780. X
  1781. X
  1782. X
  1783. X
  1784. X
  1785. X
  1786. X
  1787. X
  1788. X
  1789. X
  1790. X
  1791. X
  1792. X
  1793. X
  1794. X
  1795. X
  1796. X
  1797. X
  1798. X
  1799. X
  1800. X
  1801. X
  1802. X
  1803. X
  1804. X
  1805. X
  1806. X
  1807. X
  1808. X
  1809. X
  1810. X
  1811. X
  1812. X
  1813. X
  1814. X
  1815. X
  1816. X
  1817. X
  1818. XD. L. Mills                                                     [Page 3]
  1819. X
  1820. ________This_Is_The_END________
  1821. exit
  1822.  
  1823.