PATCH TO FIX NETSTAT BUILDS AND ADD RWHO, RWHOD AND RUPTIME
authorKarl Lehenbauer <karl@NeoSoft.com>
Tue, 9 Mar 1993 00:00:00 +0000 (00:00 +0000)
committerKarl Lehenbauer <karl@NeoSoft.com>
Tue, 9 Mar 1993 00:00:00 +0000 (00:00 +0000)
Karl Lehenbauer:
The rwho and ruptime commands and the rwho daemon (rwhod) were not
shipped with 386BSD 0.1.  These commands, if rwhod is enabled,
let you see uptime and who information for machines on your LAN.

It can cause a lot of overhead if there are a lot of machines on your
LAN.  A forthcoming multicast version will have much lower overhead.

This patch creates the necessary files to build these commands, along
with manpages of course.

All I did was grab them off of uunet, stick them in the right place, and
compile.  No changes were required.

Rodney W. Grimes:

To build,

1.  cd to /usr/src/usr.sbin/rwhod and do a "make obj", "make" and "make install"
2.  cd to /usr/src/usr.bin/rwho and do a "make obj", "make" and "make install"
3.  cd to /usr/src/usr.bin/ruptime and do a "make obj", "make" and "make install"
4.  set rwhod to YES in /etc/netstart.
5.  reboot

I added the fixes for the top level make files so that these get compiled on
complete builds.  Also added netstat to the top level makefile.

AUTHOR: Karl Lehenbauer (karl@NeoSoft.com)
AUTHOR: Rodney W. Grimes (rgrimes@agora.rain.com)
386BSD-Patchkit: patch00087

usr/src/usr.bin/Makefile
usr/src/usr.bin/ruptime/Makefile [new file with mode: 0644]
usr/src/usr.bin/ruptime/ruptime.1 [new file with mode: 0644]
usr/src/usr.bin/ruptime/ruptime.c [new file with mode: 0644]
usr/src/usr.bin/rwho/Makefile [new file with mode: 0644]
usr/src/usr.bin/rwho/rwho.1 [new file with mode: 0644]
usr/src/usr.bin/rwho/rwho.c [new file with mode: 0644]
usr/src/usr.sbin/Makefile
usr/src/usr.sbin/rwhod/Makefile [new file with mode: 0644]
usr/src/usr.sbin/rwhod/rwhod.8 [new file with mode: 0644]
usr/src/usr.sbin/rwhod/rwhod.c [new file with mode: 0644]

index f4263f2..021b2ce 100644 (file)
@@ -1,4 +1,13 @@
 #      @(#)Makefile    5.8.1.1 (Berkeley) 5/8/91
 #      @(#)Makefile    5.8.1.1 (Berkeley) 5/8/91
+#
+# PATCHES MAGIC                LEVEL   PATCH THAT GOT US HERE
+# --------------------         -----   ----------------------
+# CURRENT PATCH LEVEL:         1       00087
+# --------------------         -----   ----------------------
+#
+# 09 Mar 93    Rodney W. Grimes        Added netstat, rwho, and ruptime
+#                                      to SUBDIR
+#
 
 SUBDIR=        ar awk biff basename cal calendar \
        checknr chpass cksum cmp col colcrt colrm column comm compress \
 
 SUBDIR=        ar awk biff basename cal calendar \
        checknr chpass cksum cmp col colcrt colrm column comm compress \
@@ -7,9 +16,9 @@ SUBDIR=        ar awk biff basename cal calendar \
        g++ gas gcc gdb grep groff groups head hexdump id join \
        ktrace last ld leave lex locate lock logger \
        login logname lorder m4 machine mail make man mesg mkdep mkfifo \
        g++ gas gcc gdb grep groff groups head hexdump id join \
        ktrace last ld leave lex locate lock logger \
        login logname lorder m4 machine mail make man mesg mkdep mkfifo \
-       mkstr more nfsstat nice nm nohup pagesize \
+       mkstr more netstat nfsstat nice nm nohup pagesize \
        passwd paste pr printenv printf ranlib rcs \
        passwd paste pr printenv printf ranlib rcs \
-       rdist renice rlogin rsh script sed \
+       rdist renice rlogin rsh ruptime rwho script sed \
        shar showmount size soelim sort split strings \
        strip su symorder tail talk tar tee telnet tftp time \
        tip tn3270 touch tput tr true tsort tty ul unexpand unifdef uniq \
        shar showmount size soelim sort split strings \
        strip su symorder tail talk tar tee telnet tftp time \
        tip tn3270 touch tput tr true tsort tty ul unexpand unifdef uniq \
diff --git a/usr/src/usr.bin/ruptime/Makefile b/usr/src/usr.bin/ruptime/Makefile
new file mode 100644 (file)
index 0000000..58ee4e5
--- /dev/null
@@ -0,0 +1,5 @@
+#      @(#)Makefile    5.3 (Berkeley) 5/11/90
+
+PROG=  ruptime
+
+.include <bsd.prog.mk>
diff --git a/usr/src/usr.bin/ruptime/ruptime.1 b/usr/src/usr.bin/ruptime/ruptime.1
new file mode 100644 (file)
index 0000000..93d25c7
--- /dev/null
@@ -0,0 +1,81 @@
+.\" Copyright (c) 1983, 1990 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"    This product includes software developed by the University of
+.\"    California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)ruptime.1  6.9 (Berkeley) 4/23/91
+.\"
+.Dd April 23, 1991
+.Dt RUPTIME 1
+.Os BSD 4.2
+.Sh NAME
+.Nm ruptime
+.Nd show host status of local machines
+.Sh SYNOPSIS
+.Nm ruptime
+.Op Fl alrtu
+.Sh DESCRIPTION
+.Nm Ruptime
+gives a status line like
+.Ar uptime
+for each machine on the local network; these are formed from packets
+broadcast by each host on the network once a minute.
+.Pp
+Machines for which no status report has been received for 11
+minutes are shown as being down.
+.Pp
+Options:
+.Bl -tag -width Ds
+.It Fl a
+Users idle an hour or more are not counted unless the
+.Fl a
+flag is given.
+.It Fl l
+Sort by load average.
+.It Fl r
+Reverses the sort order.
+.It Fl t
+Sort by uptime.
+.It Fl u
+Sort by number of users.
+.El
+.Pp
+The default listing is sorted by host name.
+.Sh FILES
+.Bl -tag -width /usr/var/rwho/whod.* -compact
+.It Pa /usr/var/rwho/whod.*
+data files
+.El
+.Sh SEE ALSO
+.Xr rwho 1
+.Xr uptime 1
+.Sh HISTORY
+.Nm Ruptime
+appeared in
+.Bx 4.2 .
diff --git a/usr/src/usr.bin/ruptime/ruptime.c b/usr/src/usr.bin/ruptime/ruptime.c
new file mode 100644 (file)
index 0000000..6b58055
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 1983 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1983 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)ruptime.c  5.8 (Berkeley) 7/21/90";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <sys/file.h>
+#include <sys/errno.h>
+#include <protocols/rwhod.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+size_t nhosts, hspace = 20;
+struct hs {
+       struct  whod *hs_wd;
+       int     hs_nusers;
+} *hs;
+struct whod awhod;
+
+#define        ISDOWN(h)               (now - (h)->hs_wd->wd_recvtime > 11 * 60)
+#define        WHDRSIZE        (sizeof (awhod) - sizeof (awhod.wd_we))
+
+time_t now;
+int rflg = 1;
+int hscmp(), ucmp(), lcmp(), tcmp();
+
+main(argc, argv)
+       int argc;
+       char **argv;
+{
+       extern char *optarg;
+       extern int optind;
+       register struct hs *hsp;
+       register struct whod *wd;
+       register struct whoent *we;
+       register DIR *dirp;
+       struct direct *dp;
+       int aflg, cc, ch, f, i, maxloadav;
+       char buf[sizeof(struct whod)];
+       int (*cmp)() = hscmp;
+       time_t time();
+       char *interval();
+
+       aflg = 0;
+       while ((ch = getopt(argc, argv, "alrut")) != EOF)
+               switch((char)ch) {
+               case 'a':
+                       aflg = 1;
+                       break;
+               case 'l':
+                       cmp = lcmp;
+                       break;
+               case 'r':
+                       rflg = -1;
+                       break;
+               case 't':
+                       cmp = tcmp;
+                       break;
+               case 'u':
+                       cmp = ucmp;
+                       break;
+               default: 
+                       (void)fprintf(stderr, "usage: ruptime [-alrut]\n");
+                       exit(1);
+               }
+
+       if (chdir(_PATH_RWHODIR) || (dirp = opendir(".")) == NULL) {
+               (void)fprintf(stderr, "ruptime: %s: %s.\n",
+                   _PATH_RWHODIR, strerror(errno));
+               exit(1);
+       }
+       morehosts();
+       hsp = hs;
+       maxloadav = -1;
+       while (dp = readdir(dirp)) {
+               if (dp->d_ino == 0 || strncmp(dp->d_name, "whod.", 5))
+                       continue;
+               if ((f = open(dp->d_name, O_RDONLY, 0)) < 0) {
+                       (void)fprintf(stderr, "ruptime: %s: %s\n",
+                           dp->d_name, strerror(errno));
+                       continue;
+               }
+               cc = read(f, buf, sizeof(struct whod));
+               (void)close(f);
+               if (cc < WHDRSIZE)
+                       continue;
+               if (nhosts == hspace) {
+                       morehosts();
+                       hsp = hs + nhosts;
+               }
+               /* NOSTRICT */
+               hsp->hs_wd = malloc((size_t)WHDRSIZE);
+               wd = (struct whod *)buf;
+               bcopy((char *)wd, (char *)hsp->hs_wd, (size_t)WHDRSIZE);
+               hsp->hs_nusers = 0;
+               for (i = 0; i < 2; i++)
+                       if (wd->wd_loadav[i] > maxloadav)
+                               maxloadav = wd->wd_loadav[i];
+               we = (struct whoent *)(buf+cc);
+               while (--we >= wd->wd_we)
+                       if (aflg || we->we_idle < 3600)
+                               hsp->hs_nusers++;
+               nhosts++;
+               hsp++;
+       }
+       if (!nhosts) {
+               (void)printf("ruptime: no hosts in %s.\n", _PATH_RWHODIR);
+               exit(1);
+       }
+       qsort((char *)hs, nhosts, sizeof (hs[0]), cmp);
+       (void)time(&now);
+       for (i = 0; i < nhosts; i++) {
+               hsp = &hs[i];
+               if (ISDOWN(hsp)) {
+                       (void)printf("%-12.12s%s\n", hsp->hs_wd->wd_hostname,
+                           interval(now - hsp->hs_wd->wd_recvtime, "down"));
+                       continue;
+               }
+               (void)printf(
+                   "%-12.12s%s,  %4d user%s  load %*.2f, %*.2f, %*.2f\n",
+                   hsp->hs_wd->wd_hostname,
+                   interval((time_t)hsp->hs_wd->wd_sendtime -
+                       (time_t)hsp->hs_wd->wd_boottime, "  up"),
+                   hsp->hs_nusers,
+                   hsp->hs_nusers == 1 ? ", " : "s,",
+                   maxloadav >= 1000 ? 5 : 4,
+                       hsp->hs_wd->wd_loadav[0] / 100.0,
+                   maxloadav >= 1000 ? 5 : 4,
+                       hsp->hs_wd->wd_loadav[1] / 100.0,
+                   maxloadav >= 1000 ? 5 : 4,
+                       hsp->hs_wd->wd_loadav[2] / 100.0);
+               free((void *)hsp->hs_wd);
+       }
+       exit(0);
+}
+
+char *
+interval(tval, updown)
+       time_t tval;
+       char *updown;
+{
+       static char resbuf[32];
+       int days, hours, minutes;
+
+       if (tval < 0 || tval > 365*24*60*60) {
+               (void)sprintf(resbuf, "   %s ??:??", updown);
+               return(resbuf);
+       }
+       minutes = (tval + 59) / 60;             /* round to minutes */
+       hours = minutes / 60; minutes %= 60;
+       days = hours / 24; hours %= 24;
+       if (days)
+               (void)sprintf(resbuf, "%s %2d+%02d:%02d",
+                   updown, days, hours, minutes);
+       else
+               (void)sprintf(resbuf, "%s    %2d:%02d",
+                   updown, hours, minutes);
+       return(resbuf);
+}
+
+/* alphabetical comparison */
+hscmp(a1, a2)
+       void *a1, *a2;
+{
+       struct hs *h1 = a1, *h2 = a2;
+
+       return(rflg * strcmp(h1->hs_wd->wd_hostname, h2->hs_wd->wd_hostname));
+}
+
+/* load average comparison */
+lcmp(a1, a2)
+       void *a1, *a2;
+{
+       register struct hs *h1 = a1, *h2 = a2;
+
+       if (ISDOWN(h1))
+               if (ISDOWN(h2))
+                       return(tcmp(a1, a2));
+               else
+                       return(rflg);
+       else if (ISDOWN(h2))
+               return(-rflg);
+       else
+               return(rflg *
+                       (h2->hs_wd->wd_loadav[0] - h1->hs_wd->wd_loadav[0]));
+}
+
+/* number of users comparison */
+ucmp(a1, a2)
+       void *a1, *a2;
+{
+       register struct hs *h1 = a1, *h2 = a2;
+
+       if (ISDOWN(h1))
+               if (ISDOWN(h2))
+                       return(tcmp(a1, a2));
+               else
+                       return(rflg);
+       else if (ISDOWN(h2))
+               return(-rflg);
+       else
+               return(rflg * (h2->hs_nusers - h1->hs_nusers));
+}
+
+/* uptime comparison */
+tcmp(a1, a2)
+       void *a1, *a2;
+{
+       register struct hs *h1 = a1, *h2 = a2;
+
+       return(rflg * (
+               (ISDOWN(h2) ? h2->hs_wd->wd_recvtime - now
+                         : h2->hs_wd->wd_sendtime - h2->hs_wd->wd_boottime)
+               -
+               (ISDOWN(h1) ? h1->hs_wd->wd_recvtime - now
+                         : h1->hs_wd->wd_sendtime - h1->hs_wd->wd_boottime)
+       ));
+}
+
+morehosts()
+{
+       hs = realloc((char *)hs, (hspace *= 2) * sizeof(*hs));
+       if (hs == NULL) {
+               (void)fprintf(stderr, "ruptime: %s.\n", strerror(ENOMEM));
+               exit(1);
+       }
+}
diff --git a/usr/src/usr.bin/rwho/Makefile b/usr/src/usr.bin/rwho/Makefile
new file mode 100644 (file)
index 0000000..e7454dd
--- /dev/null
@@ -0,0 +1,5 @@
+#      @(#)Makefile    5.3 (Berkeley) 5/11/90
+
+PROG=  rwho
+
+.include <bsd.prog.mk>
diff --git a/usr/src/usr.bin/rwho/rwho.1 b/usr/src/usr.bin/rwho/rwho.1
new file mode 100644 (file)
index 0000000..0c71502
--- /dev/null
@@ -0,0 +1,80 @@
+.\" Copyright (c) 1983, 1990 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"    This product includes software developed by the University of
+.\"    California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)rwho.1     6.7 (Berkeley) 4/23/91
+.\"
+.Dd April 23, 1991
+.Dt RWHO 1
+.Os BSD 4.2
+.Sh NAME
+.Nm rwho
+.Nd who is logged in on local machines
+.Sh SYNOPSIS
+.Nm rwho
+.Op Fl a
+.Sh DESCRIPTION
+The
+.Nm rwho
+command produces output similar to
+.Xr who ,
+but for all machines on the local network.
+If no report has been
+received from a machine for 5 minutes then
+.Nm rwho
+assumes the machine is down, and does not report users last known
+to be logged into that machine.
+.Pp
+If a users hasn't typed to the system for a minute or more, then
+.Nm rwho
+reports this idle time.  If a user hasn't typed to the system for
+an hour or more, then
+the user will be omitted from the output of
+.Nm rwho
+unless the
+.Fl a
+flag is given.
+.Sh FILES
+.Bl -tag -width /var/spool/rwho/rhowd.* -compact
+.It Pa /var/spool/rwho/whod.*
+information about other machines
+.El
+.Sh SEE ALSO
+.Xr ruptime 1 ,
+.Xr rwhod 8
+.Sh HISTORY
+The
+.Nm rwho
+command
+appeared in
+.Bx 4.3 .
+.Sh BUGS
+This is unwieldy when the number of machines
+on the local net is large.
diff --git a/usr/src/usr.bin/rwho/rwho.c b/usr/src/usr.bin/rwho/rwho.c
new file mode 100644 (file)
index 0000000..a744340
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 1983 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1983 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)rwho.c     5.5 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <sys/file.h>
+#include <protocols/rwhod.h>
+#include <stdio.h>
+
+DIR    *dirp;
+
+struct whod wd;
+int    utmpcmp();
+#define        NUSERS  1000
+struct myutmp {
+       char    myhost[MAXHOSTNAMELEN];
+       int     myidle;
+       struct  outmp myutmp;
+} myutmp[NUSERS];
+int    nusers;
+
+#define        WHDRSIZE        (sizeof (wd) - sizeof (wd.wd_we))
+/* 
+ * this macro should be shared with ruptime.
+ */
+#define        down(w,now)     ((now) - (w)->wd_recvtime > 11 * 60)
+
+char   *ctime(), *strcpy();
+time_t now;
+int    aflg;
+
+main(argc, argv)
+       int argc;
+       char **argv;
+{
+       extern char *optarg;
+       extern int optind;
+       int ch;
+       struct direct *dp;
+       int cc, width;
+       register struct whod *w = &wd;
+       register struct whoent *we;
+       register struct myutmp *mp;
+       int f, n, i;
+       time_t time();
+
+       while ((ch = getopt(argc, argv, "a")) != EOF)
+               switch((char)ch) {
+               case 'a':
+                       aflg = 1;
+                       break;
+               case '?':
+               default:
+                       fprintf(stderr, "usage: rwho [-a]\n");
+                       exit(1);
+               }
+       if (chdir(_PATH_RWHODIR) || (dirp = opendir(".")) == NULL) {
+               perror(_PATH_RWHODIR);
+               exit(1);
+       }
+       mp = myutmp;
+       (void)time(&now);
+       while (dp = readdir(dirp)) {
+               if (dp->d_ino == 0 || strncmp(dp->d_name, "whod.", 5))
+                       continue;
+               f = open(dp->d_name, O_RDONLY);
+               if (f < 0)
+                       continue;
+               cc = read(f, (char *)&wd, sizeof (struct whod));
+               if (cc < WHDRSIZE) {
+                       (void) close(f);
+                       continue;
+               }
+               if (down(w,now)) {
+                       (void) close(f);
+                       continue;
+               }
+               cc -= WHDRSIZE;
+               we = w->wd_we;
+               for (n = cc / sizeof (struct whoent); n > 0; n--) {
+                       if (aflg == 0 && we->we_idle >= 60*60) {
+                               we++;
+                               continue;
+                       }
+                       if (nusers >= NUSERS) {
+                               printf("too many users\n");
+                               exit(1);
+                       }
+                       mp->myutmp = we->we_utmp; mp->myidle = we->we_idle;
+                       (void) strcpy(mp->myhost, w->wd_hostname);
+                       nusers++; we++; mp++;
+               }
+               (void) close(f);
+       }
+       qsort((char *)myutmp, nusers, sizeof (struct myutmp), utmpcmp);
+       mp = myutmp;
+       width = 0;
+       for (i = 0; i < nusers; i++) {
+               int j = strlen(mp->myhost) + 1 + strlen(mp->myutmp.out_line);
+               if (j > width)
+                       width = j;
+               mp++;
+       }
+       mp = myutmp;
+       for (i = 0; i < nusers; i++) {
+               char buf[BUFSIZ];
+               (void)sprintf(buf, "%s:%s", mp->myhost, mp->myutmp.out_line);
+               printf("%-8.8s %-*s %.12s",
+                  mp->myutmp.out_name,
+                  width,
+                  buf,
+                  ctime((time_t *)&mp->myutmp.out_time)+4);
+               mp->myidle /= 60;
+               if (mp->myidle) {
+                       if (aflg) {
+                               if (mp->myidle >= 100*60)
+                                       mp->myidle = 100*60 - 1;
+                               if (mp->myidle >= 60)
+                                       printf(" %2d", mp->myidle / 60);
+                               else
+                                       printf("   ");
+                       } else
+                               printf(" ");
+                       printf(":%02d", mp->myidle % 60);
+               }
+               printf("\n");
+               mp++;
+       }
+       exit(0);
+}
+
+utmpcmp(u1, u2)
+       struct myutmp *u1, *u2;
+{
+       int rc;
+
+       rc = strncmp(u1->myutmp.out_name, u2->myutmp.out_name, 8);
+       if (rc)
+               return (rc);
+       rc = strncmp(u1->myhost, u2->myhost, 8);
+       if (rc)
+               return (rc);
+       return (strncmp(u1->myutmp.out_line, u2->myutmp.out_line, 8));
+}
index 79d7d7a..47274e1 100644 (file)
@@ -1,8 +1,17 @@
 #      @(#)Makefile    5.6.1.2 (Berkeley) 5/8/91
 #      @(#)Makefile    5.6.1.2 (Berkeley) 5/8/91
+#
+# PATCHES MAGIC                LEVEL   PATCH THAT GOT US HERE
+# --------------------         -----   ----------------------
+# CURRENT PATCH LEVEL:         1       00087
+# --------------------         -----   ----------------------
+#
+# 09 Mar 93    Rodney W. Grimes        Added rwhod to SUBDIR, moved portmap
+#                                      into alphabetic order.
+#
 
 SUBDIR=        arp chown chroot config dbsym dev_mkdb diskpart \
        inetd kvm_mkdb lpr \
 
 SUBDIR=        arp chown chroot config dbsym dev_mkdb diskpart \
        inetd kvm_mkdb lpr \
-       portmap mtree named pwd_mkdb rmt \
+       mtree named portmap pwd_mkdb rmt rwhod\
        sendmail sliplogin syslogd timed traceroute update vipw
 
 .if   make(clean) || make(cleandir)
        sendmail sliplogin syslogd timed traceroute update vipw
 
 .if   make(clean) || make(cleandir)
diff --git a/usr/src/usr.sbin/rwhod/Makefile b/usr/src/usr.sbin/rwhod/Makefile
new file mode 100644 (file)
index 0000000..607c2ca
--- /dev/null
@@ -0,0 +1,8 @@
+#      @(#)Makefile    5.3 (Berkeley) 5/11/90
+
+PROG=  rwhod
+MAN8=  rwhod.0
+DPADD= ${LIBUTIL}
+LDADD= -lutil
+
+.include <bsd.prog.mk>
diff --git a/usr/src/usr.sbin/rwhod/rwhod.8 b/usr/src/usr.sbin/rwhod/rwhod.8
new file mode 100644 (file)
index 0000000..ad80f2c
--- /dev/null
@@ -0,0 +1,146 @@
+.\" Copyright (c) 1983, 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"    This product includes software developed by the University of
+.\"    California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)rwhod.8    6.5 (Berkeley) 3/16/91
+.\"
+.Dd March 16, 1991
+.Dt RWHOD 8
+.Os BSD 4.2
+.Sh NAME
+.Nm rwhod
+.Nd system status server
+.Sh SYNOPSIS
+.Nm rwhod
+.Sh DESCRIPTION
+.Nm Rwhod
+is the server which maintains the database used by the
+.Xr rwho 1
+and
+.Xr ruptime 1
+programs.  Its operation is predicated on the ability to
+.Em broadcast
+messages on a network.
+.Pp
+.Nm Rwhod
+operates as both a producer and consumer of status information.
+As a producer of information it periodically
+queries the state of the system and constructs
+status messages which are broadcast on a network.
+As a consumer of information, it listens for other
+.Nm rwhod
+servers' status messages, validating them, then recording
+them in a collection of files located in the directory
+.Pa /var/rwho .
+.Pp
+The server transmits and receives messages at the port indicated
+in the ``rwho'' service specification; see 
+.Xr services 5 .
+The messages sent and received, are of the form:
+.Bd -literal -offset indent
+struct outmp {
+       char    out_line[8];            /* tty name */
+       char    out_name[8];            /* user id */
+       long    out_time;               /* time on */
+};
+
+struct whod {
+       char    wd_vers;
+       char    wd_type;
+       char    wd_fill[2];
+       int     wd_sendtime;
+       int     wd_recvtime;
+       char    wd_hostname[32];
+       int     wd_loadav[3];
+       int     wd_boottime;
+       struct  whoent {
+               struct  outmp we_utmp;
+               int     we_idle;
+       } wd_we[1024 / sizeof (struct whoent)];
+};
+.Ed
+.Pp
+All fields are converted to network byte order prior to
+transmission.  The load averages are as calculated by the
+.Xr w 1
+program, and represent load averages over the 5, 10, and 15 minute 
+intervals prior to a server's transmission; they are multiplied by 100
+for representation in an integer.  The host name
+included is that returned by the
+.Xr gethostname 2
+system call, with any trailing domain name omitted.
+The array at the end of the message contains information about
+the users logged in to the sending machine.  This information 
+includes the contents of the 
+.Xr utmp 5
+entry for each non-idle terminal line and a value indicating the
+time in seconds since a character was last received on the terminal line.
+.Pp
+Messages received by the
+.Xr rwho
+server are discarded unless they originated at an
+.Xr rwho
+server's port.  In addition, if the host's name, as specified
+in the message, contains any unprintable
+.Tn ASCII
+characters, the
+message is discarded.  Valid messages received by
+.Nm rwhod
+are placed in files named
+.Pa whod.hostname
+in the directory
+.Pa /var/rwho .
+These files contain only the most recent message, in the
+format described above.
+.Pp
+Status messages are generated approximately once every
+3 minutes.
+.Nm Rwhod
+performs an
+.Xr nlist 3
+on
+.Pa /vmunix
+every 30 minutes to guard against
+the possibility that this file is not the system
+image currently operating.
+.Sh SEE ALSO
+.Xr rwho 1 ,
+.Xr ruptime 1
+.Sh BUGS
+There should be a way to relay status information between networks. 
+Status information should be sent only upon request rather than continuously.
+People often interpret the server dying
+or network communtication failures
+as a machine going down.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/usr/src/usr.sbin/rwhod/rwhod.c b/usr/src/usr.sbin/rwhod/rwhod.c
new file mode 100644 (file)
index 0000000..41dfc20
--- /dev/null
@@ -0,0 +1,532 @@
+/*
+ * Copyright (c) 1983 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1983 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)rwhod.c    5.20 (Berkeley) 3/2/91";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/signal.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <nlist.h>
+#include <errno.h>
+#include <utmp.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <syslog.h>
+#include <protocols/rwhod.h>
+#include <stdio.h>
+#include <paths.h>
+
+/*
+ * Alarm interval. Don't forget to change the down time check in ruptime
+ * if this is changed.
+ */
+#define AL_INTERVAL (3 * 60)
+
+struct sockaddr_in sin;
+
+char   myname[MAXHOSTNAMELEN];
+
+struct nlist nl[] = {
+#define        NL_BOOTTIME     0
+       { "_boottime" },
+       0
+};
+
+/*
+ * We communicate with each neighbor in
+ * a list constructed at the time we're
+ * started up.  Neighbors are currently
+ * directly connected via a hardware interface.
+ */
+struct neighbor {
+       struct  neighbor *n_next;
+       char    *n_name;                /* interface name */
+       char    *n_addr;                /* who to send to */
+       int     n_addrlen;              /* size of address */
+       int     n_flags;                /* should forward?, interface flags */
+};
+
+struct neighbor *neighbors;
+struct whod mywd;
+struct servent *sp;
+int    s, utmpf, kmemf = -1;
+
+#define        WHDRSIZE        (sizeof (mywd) - sizeof (mywd.wd_we))
+
+extern int errno;
+char   *strcpy(), *malloc();
+long   lseek();
+void   getkmem(), onalrm();
+struct in_addr inet_makeaddr();
+
+main()
+{
+       struct sockaddr_in from;
+       struct stat st;
+       char path[64];
+       int on = 1;
+       char *cp, *index(), *strerror();
+
+       if (getuid()) {
+               fprintf(stderr, "rwhod: not super user\n");
+               exit(1);
+       }
+       sp = getservbyname("who", "udp");
+       if (sp == 0) {
+               fprintf(stderr, "rwhod: udp/who: unknown service\n");
+               exit(1);
+       }
+#ifndef DEBUG
+       daemon(1, 0);
+#endif
+       if (chdir(_PATH_RWHODIR) < 0) {
+               (void)fprintf(stderr, "rwhod: %s: %s\n",
+                   _PATH_RWHODIR, strerror(errno));
+               exit(1);
+       }
+       (void) signal(SIGHUP, getkmem);
+       openlog("rwhod", LOG_PID, LOG_DAEMON);
+       /*
+        * Establish host name as returned by system.
+        */
+       if (gethostname(myname, sizeof (myname) - 1) < 0) {
+               syslog(LOG_ERR, "gethostname: %m");
+               exit(1);
+       }
+       if ((cp = index(myname, '.')) != NULL)
+               *cp = '\0';
+       strncpy(mywd.wd_hostname, myname, sizeof (myname) - 1);
+       utmpf = open(_PATH_UTMP, O_RDONLY|O_CREAT, 0644);
+       if (utmpf < 0) {
+               syslog(LOG_ERR, "%s: %m", _PATH_UTMP);
+               exit(1);
+       }
+       getkmem();
+       if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+               syslog(LOG_ERR, "socket: %m");
+               exit(1);
+       }
+       if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
+               syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
+               exit(1);
+       }
+       sin.sin_family = AF_INET;
+       sin.sin_port = sp->s_port;
+       if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
+               syslog(LOG_ERR, "bind: %m");
+               exit(1);
+       }
+       if (!configure(s))
+               exit(1);
+       signal(SIGALRM, onalrm);
+       onalrm();
+       for (;;) {
+               struct whod wd;
+               int cc, whod, len = sizeof (from);
+
+               cc = recvfrom(s, (char *)&wd, sizeof (struct whod), 0,
+                       (struct sockaddr *)&from, &len);
+               if (cc <= 0) {
+                       if (cc < 0 && errno != EINTR)
+                               syslog(LOG_WARNING, "recv: %m");
+                       continue;
+               }
+               if (from.sin_port != sp->s_port) {
+                       syslog(LOG_WARNING, "%d: bad from port",
+                               ntohs(from.sin_port));
+                       continue;
+               }
+               if (wd.wd_vers != WHODVERSION)
+                       continue;
+               if (wd.wd_type != WHODTYPE_STATUS)
+                       continue;
+               if (!verify(wd.wd_hostname)) {
+                       syslog(LOG_WARNING, "malformed host name from %x",
+                               from.sin_addr);
+                       continue;
+               }
+               (void) sprintf(path, "whod.%s", wd.wd_hostname);
+               /*
+                * Rather than truncating and growing the file each time,
+                * use ftruncate if size is less than previous size.
+                */
+               whod = open(path, O_WRONLY | O_CREAT, 0644);
+               if (whod < 0) {
+                       syslog(LOG_WARNING, "%s: %m", path);
+                       continue;
+               }
+#if ENDIAN != BIG_ENDIAN
+               {
+                       int i, n = (cc - WHDRSIZE)/sizeof(struct whoent);
+                       struct whoent *we;
+
+                       /* undo header byte swapping before writing to file */
+                       wd.wd_sendtime = ntohl(wd.wd_sendtime);
+                       for (i = 0; i < 3; i++)
+                               wd.wd_loadav[i] = ntohl(wd.wd_loadav[i]);
+                       wd.wd_boottime = ntohl(wd.wd_boottime);
+                       we = wd.wd_we;
+                       for (i = 0; i < n; i++) {
+                               we->we_idle = ntohl(we->we_idle);
+                               we->we_utmp.out_time =
+                                   ntohl(we->we_utmp.out_time);
+                               we++;
+                       }
+               }
+#endif
+               (void) time((time_t *)&wd.wd_recvtime);
+               (void) write(whod, (char *)&wd, cc);
+               if (fstat(whod, &st) < 0 || st.st_size > cc)
+                       ftruncate(whod, cc);
+               (void) close(whod);
+       }
+}
+
+/*
+ * Check out host name for unprintables
+ * and other funnies before allowing a file
+ * to be created.  Sorry, but blanks aren't allowed.
+ */
+verify(name)
+       register char *name;
+{
+       register int size = 0;
+
+       while (*name) {
+               if (!isascii(*name) || !(isalnum(*name) || ispunct(*name)))
+                       return (0);
+               name++, size++;
+       }
+       return (size > 0);
+}
+
+int    utmptime;
+int    utmpent;
+int    utmpsize = 0;
+struct utmp *utmp;
+int    alarmcount;
+
+void
+onalrm()
+{
+       register struct neighbor *np;
+       register struct whoent *we = mywd.wd_we, *wlast;
+       register int i;
+       struct stat stb;
+       int cc;
+       double avenrun[3];
+       time_t now = time((time_t *)NULL);
+       char *strerror();
+
+       if (alarmcount % 10 == 0)
+               getkmem();
+       alarmcount++;
+       (void) fstat(utmpf, &stb);
+       if ((stb.st_mtime != utmptime) || (stb.st_size > utmpsize)) {
+               utmptime = stb.st_mtime;
+               if (stb.st_size > utmpsize) {
+                       utmpsize = stb.st_size + 10 * sizeof(struct utmp);
+                       if (utmp)
+                               utmp = (struct utmp *)realloc(utmp, utmpsize);
+                       else
+                               utmp = (struct utmp *)malloc(utmpsize);
+                       if (! utmp) {
+                               fprintf(stderr, "rwhod: malloc failed\n");
+                               utmpsize = 0;
+                               goto done;
+                       }
+               }
+               (void) lseek(utmpf, (long)0, L_SET);
+               cc = read(utmpf, (char *)utmp, stb.st_size);
+               if (cc < 0) {
+                       fprintf(stderr, "rwhod: %s: %s\n",
+                           _PATH_UTMP, strerror(errno));
+                       goto done;
+               }
+               wlast = &mywd.wd_we[1024 / sizeof (struct whoent) - 1];
+               utmpent = cc / sizeof (struct utmp);
+               for (i = 0; i < utmpent; i++)
+                       if (utmp[i].ut_name[0]) {
+                               bcopy(utmp[i].ut_line, we->we_utmp.out_line,
+                                  sizeof (utmp[i].ut_line));
+                               bcopy(utmp[i].ut_name, we->we_utmp.out_name,
+                                  sizeof (utmp[i].ut_name));
+                               we->we_utmp.out_time = htonl(utmp[i].ut_time);
+                               if (we >= wlast)
+                                       break;
+                               we++;
+                       }
+               utmpent = we - mywd.wd_we;
+       }
+
+       /*
+        * The test on utmpent looks silly---after all, if no one is
+        * logged on, why worry about efficiency?---but is useful on
+        * (e.g.) compute servers.
+        */
+       if (utmpent && chdir(_PATH_DEV)) {
+               syslog(LOG_ERR, "chdir(%s): %m", _PATH_DEV);
+               exit(1);
+       }
+       we = mywd.wd_we;
+       for (i = 0; i < utmpent; i++) {
+               if (stat(we->we_utmp.out_line, &stb) >= 0)
+                       we->we_idle = htonl(now - stb.st_atime);
+               we++;
+       }
+       (void) getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0]));
+       for (i = 0; i < 3; i++)
+               mywd.wd_loadav[i] = htonl((u_long)(avenrun[i] * 100));
+       cc = (char *)we - (char *)&mywd;
+       mywd.wd_sendtime = htonl(time(0));
+       mywd.wd_vers = WHODVERSION;
+       mywd.wd_type = WHODTYPE_STATUS;
+       for (np = neighbors; np != NULL; np = np->n_next)
+               (void) sendto(s, (char *)&mywd, cc, 0,
+                       (struct sockaddr *)np->n_addr, np->n_addrlen);
+       if (utmpent && chdir(_PATH_RWHODIR)) {
+               syslog(LOG_ERR, "chdir(%s): %m", _PATH_RWHODIR);
+               exit(1);
+       }
+done:
+       (void) alarm(AL_INTERVAL);
+}
+
+void
+getkmem()
+{
+       static ino_t vmunixino;
+       static time_t vmunixctime;
+       struct stat sb;
+
+       if (stat(_PATH_UNIX, &sb) < 0) {
+               if (vmunixctime)
+                       return;
+       } else {
+               if (sb.st_ctime == vmunixctime && sb.st_ino == vmunixino)
+                       return;
+               vmunixctime = sb.st_ctime;
+               vmunixino= sb.st_ino;
+       }
+       if (kmemf >= 0)
+               (void) close(kmemf);
+loop:
+       if (nlist(_PATH_UNIX, nl)) {
+               syslog(LOG_WARNING, "%s: namelist botch", _PATH_UNIX);
+               sleep(300);
+               goto loop;
+       }
+       kmemf = open(_PATH_KMEM, O_RDONLY, 0);
+       if (kmemf < 0) {
+               syslog(LOG_ERR, "%s: %m", _PATH_KMEM);
+               exit(1);
+       }
+       (void) lseek(kmemf, (long)nl[NL_BOOTTIME].n_value, L_SET);
+       (void) read(kmemf, (char *)&mywd.wd_boottime,
+           sizeof (mywd.wd_boottime));
+       mywd.wd_boottime = htonl(mywd.wd_boottime);
+}
+
+/*
+ * Figure out device configuration and select
+ * networks which deserve status information.
+ */
+configure(s)
+       int s;
+{
+       char buf[BUFSIZ], *cp, *cplim;
+       struct ifconf ifc;
+       struct ifreq ifreq, *ifr;
+       struct sockaddr_in *sin;
+       register struct neighbor *np;
+
+       ifc.ifc_len = sizeof (buf);
+       ifc.ifc_buf = buf;
+       if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
+               syslog(LOG_ERR, "ioctl (get interface configuration)");
+               return (0);
+       }
+       ifr = ifc.ifc_req;
+#ifdef AF_LINK
+#define max(a, b) (a > b ? a : b)
+#define size(p)        max((p).sa_len, sizeof(p))
+#else
+#define size(p) (sizeof (p))
+#endif
+       cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */
+       for (cp = buf; cp < cplim;
+                       cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) {
+               ifr = (struct ifreq *)cp;
+               for (np = neighbors; np != NULL; np = np->n_next)
+                       if (np->n_name &&
+                           strcmp(ifr->ifr_name, np->n_name) == 0)
+                               break;
+               if (np != NULL)
+                       continue;
+               ifreq = *ifr;
+               np = (struct neighbor *)malloc(sizeof (*np));
+               if (np == NULL)
+                       continue;
+               np->n_name = malloc(strlen(ifr->ifr_name) + 1);
+               if (np->n_name == NULL) {
+                       free((char *)np);
+                       continue;
+               }
+               strcpy(np->n_name, ifr->ifr_name);
+               np->n_addrlen = sizeof (ifr->ifr_addr);
+               np->n_addr = malloc(np->n_addrlen);
+               if (np->n_addr == NULL) {
+                       free(np->n_name);
+                       free((char *)np);
+                       continue;
+               }
+               bcopy((char *)&ifr->ifr_addr, np->n_addr, np->n_addrlen);
+               if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
+                       syslog(LOG_ERR, "ioctl (get interface flags)");
+                       free((char *)np);
+                       continue;
+               }
+               if ((ifreq.ifr_flags & IFF_UP) == 0 ||
+                   (ifreq.ifr_flags & (IFF_BROADCAST|IFF_POINTOPOINT)) == 0) {
+                       free((char *)np);
+                       continue;
+               }
+               np->n_flags = ifreq.ifr_flags;
+               if (np->n_flags & IFF_POINTOPOINT) {
+                       if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
+                               syslog(LOG_ERR, "ioctl (get dstaddr)");
+                               free((char *)np);
+                               continue;
+                       }
+                       /* we assume addresses are all the same size */
+                       bcopy((char *)&ifreq.ifr_dstaddr,
+                         np->n_addr, np->n_addrlen);
+               }
+               if (np->n_flags & IFF_BROADCAST) {
+                       if (ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
+                               syslog(LOG_ERR, "ioctl (get broadaddr)");
+                               free((char *)np);
+                               continue;
+                       }
+                       /* we assume addresses are all the same size */
+                       bcopy((char *)&ifreq.ifr_broadaddr,
+                         np->n_addr, np->n_addrlen);
+               }
+               /* gag, wish we could get rid of Internet dependencies */
+               sin = (struct sockaddr_in *)np->n_addr;
+               sin->sin_port = sp->s_port;
+               np->n_next = neighbors;
+               neighbors = np;
+       }
+       return (1);
+}
+
+#ifdef DEBUG
+sendto(s, buf, cc, flags, to, tolen)
+       int s;
+       char *buf;
+       int cc, flags;
+       char *to;
+       int tolen;
+{
+       register struct whod *w = (struct whod *)buf;
+       register struct whoent *we;
+       struct sockaddr_in *sin = (struct sockaddr_in *)to;
+       char *interval();
+
+       printf("sendto %x.%d\n", ntohl(sin->sin_addr), ntohs(sin->sin_port));
+       printf("hostname %s %s\n", w->wd_hostname,
+          interval(ntohl(w->wd_sendtime) - ntohl(w->wd_boottime), "  up"));
+       printf("load %4.2f, %4.2f, %4.2f\n",
+           ntohl(w->wd_loadav[0]) / 100.0, ntohl(w->wd_loadav[1]) / 100.0,
+           ntohl(w->wd_loadav[2]) / 100.0);
+       cc -= WHDRSIZE;
+       for (we = w->wd_we, cc /= sizeof (struct whoent); cc > 0; cc--, we++) {
+               time_t t = ntohl(we->we_utmp.out_time);
+               printf("%-8.8s %s:%s %.12s",
+                       we->we_utmp.out_name,
+                       w->wd_hostname, we->we_utmp.out_line,
+                       ctime(&t)+4);
+               we->we_idle = ntohl(we->we_idle) / 60;
+               if (we->we_idle) {
+                       if (we->we_idle >= 100*60)
+                               we->we_idle = 100*60 - 1;
+                       if (we->we_idle >= 60)
+                               printf(" %2d", we->we_idle / 60);
+                       else
+                               printf("   ");
+                       printf(":%02d", we->we_idle % 60);
+               }
+               printf("\n");
+       }
+}
+
+char *
+interval(time, updown)
+       int time;
+       char *updown;
+{
+       static char resbuf[32];
+       int days, hours, minutes;
+
+       if (time < 0 || time > 3*30*24*60*60) {
+               (void) sprintf(resbuf, "   %s ??:??", updown);
+               return (resbuf);
+       }
+       minutes = (time + 59) / 60;             /* round to minutes */
+       hours = minutes / 60; minutes %= 60;
+       days = hours / 24; hours %= 24;
+       if (days)
+               (void) sprintf(resbuf, "%s %2d+%02d:%02d",
+                   updown, days, hours, minutes);
+       else
+               (void) sprintf(resbuf, "%s    %2d:%02d",
+                   updown, hours, minutes);
+       return (resbuf);
+}
+#endif