RWHO-MULTINET.BCKRWHO-MULTINET.BCK=BACKUP/NOASSIST [.RWHOD]*.* RWHO-MULTINET.BCK/SAVE/BLOCK=8192 TERRY sPg^V5.5 _SPCVXA:: 'u _$1$DUA2: V5.5-2  (*[SYSPROG.TERRY.TMP.RWHOD]AAAREADME.TXT;8+,/M. / 4O j-J0123KPWO 56f^7BD=f^89GHJ+ Read this before using the RWHO server!!!BASIC INSTALLATION:-------------------N This is a port of the Unix ruptime/rwho/rwhod components to VMS under TGV's MMultiNet TCP/IP package. You may want to make a number of configuration editsbefore installing (see below).K First, define a cluster-wide (if you have a VAXcluster) location to storeJall of the WHOD.* files. The default configuration stores the files in theLdirectory pointed to by the logical SYS$TOOLS:. Define this location, either>as a logical or as a hard-coded disk/directory spec in CONF.H.L Next, if you will have more than 128 hosts supplying RWHO data, change theJdefinition of MAXWLD in CONF.H to the number of hosts you want to support.E Now use the MAKE.COM command file to compile and link the programs.M Select one VAXcluster node to be the "master" node. This node will maintainJthe WHOD.* files for the entire cluster. Note that while there is a masterNnode, all cluster nodes need to run the server if you want to see their statusin the rwho/ruptime displays.L Edit the two command files, START_RWHO_DAEMON.COM and EXEC_RWHO_DAEMON.COMMto specify the location you want to use for the executables and the log file.KAlso, edit the EXEC_RWHO_DAEMON.COM file to contain the name of your masternode (replacing SPCVXA).M Copy the .EXE files, START_RWHO_DAEMON, and EXEC_RWHO_DAEMON to the locationLyou selected in the paragraph above. RWHOD.EXE and the .COM files should notMbe world readable or executable, and RWHO and RUPTIME probably should be, de-$pending on your local site policies.N Add the following lines to either the system-wide login command file or yourJpersonal LOGIN.COM (where "location" is the locattion of the executables):$ RWHO :== $location:RWHOD.EXE$$ RUP*TIME :== $location:RUPTIME.EXE Lastly, add the command:!$ @location:START_RWHO_DAEMON.COM< to your SYSTARTUP_V5.COM somewhere _after_ UCX is started.K The next time your system boots, you'll have an RWHOD server running. You#can also start it up now by saying:!$ @location:START_RWHO_DAEMON.COMK Additional documentation is available in the files RWHO.DOC, RUPTIME.DOC,Gand RWHOD.DOC. These are preformatted versions of the Unix "man" pages.GETTING FANCY:--------------K VMS has no native concept of "load average". However, MultiNet provides aMload average pseudo-driver as part of the package. It is loaded automaticallywhen MultiNet is started.J Similarly, VMS doesn't do a good job keeping track of idle times on ter-Mminals. VMS manages to do this for older terminals, but not for newer pseudo-Ldevices like LAT ports. Again, the TGV folks have provided a work-around forKthis problem, which is included in this kit and built when you executed theMAKE.COM file.M To use it, add the following to your system startup file (SYSTARTUP_V5.COM)#somewhere _after_ you start DECnet:$ RUN location:IDLE-MONN The program will appear to have exited immediately, but the terminal driversNwill now properly be counting idle time. Note that with this mod, idle time isMcounted as "number of seconds since anything happened on this terminal". ThisOmeans that a message (for example, a new mail notification) on an otherwise un-+attended terminal will reset the idle time.O The RWHO server will run without either of these options, but will report the load average and idle time as 0.N You can get lots of debugging output by adding the -d flag to the command to start RWHOD.#CHANGES SINCE THE PREVIOUS RELEASE:#-----------------------------------.1) Based on the 4.4BSD rwho/ruptime/rwhod codeI2) This is a native MultiNet port instead of using UCX compatibility mode;3) Network interfaces automatically detected and configured34) GMT offset automatically detected and configuredF5) The code should work across timezone changes in the spring and fall.6) Configuration consolidated into CONF.H file+7) Maximum number of hosts now configurable8) Logging cleaned upE9) Logging is now configurable at run-time (in START_RWHO_DAEMON.COM)>10) Debugging now a run-time (rather than compile-time) option.11) Host uptime in days is now a 3-digit field6 Terry Kennedy Operations Manager, Academic Computing= terry@spcvxa.bitnet St. Peter's College, Jersey City, NJ USA% terry@spcvxa.spc.edu +1 201 915 9381!*[SYSPROG.TERRY.TMP.RWHOD]CONF.H;4+, ./ 4N-J0123KPWO56B]7bze^89GHJ/*3 * 21-Nov-1993 - tmk - Add this configuration file. *//*M * Location of the temporary data files. If you don't like user logicals withJ * "SYS$" in them, change this. If you have a RAM disk, you can point this+ * logical there for some performance gain. */#define WHODLOC "sys$tools:"/*N * Maximum number of hosts you are going to keep track of. 128 is a reasonableK * upper number and doesn't take too much memory. If you have more than 128L * hosts, you'd probably not want to run rwho because of the broadcast over- * head anyway. */#define MAXWLD 128/*M * Comment out the following define if you don't want to handle idle times in9 * the server. Why you'd want to omit this, I don't know. */ #define IDLE/*[SYSPROG.TERRY.TMP.RWHOD]EXEC_RWHO_DAEMON.COM;4+,-Z./ 4Ah-J0123KPWO56b^7Be^89GHJ$ ! EXEC_RWHO_DAEMON.COM!$ ! Start up the UCX rwho daemon.$ ! $ rwhod :== $sys$tools:rwhod.exe9$ if f$getsyi("nodename") .eqs. "SPCVXA" then goto master$ rwhod $ goto exit$master:A$ ! If you don't want to remove rwho reports from deceased hosts,#$ ! comment out the following line:$ delete sys$tools:whod.*;* $ rwhod -m$exit:$ exit$*[SYSPROG.TERRY.TMP.RWHOD]GETOPT.C;11+,;.7. / 4N o-J0123KPWO 56S ^7 #include #include #ifdef VMS #define index strchr #define rindex strrchr #endif /* VMS */ /* * get option letter from argument vector */ int opterr = 1, /* if error message should be printed */ optind = 1, /* index into parent argv vector */ optopt, /* character checked for validity */ optreset; /* reset getopt */ char *optarg; /* argument associated with option */ #define BADCH (int)'?' #define BADARG (int)':' #define EMSG "" int getopt(nargc, nargv, ostr) int nargc; char * const *nargv; const char *ostr; { static char *place = EMSG; /* option letter processing */ register char *oli; /* option letter list index */ char *p; if (optreset || !*place) { /* update scanning pointer */ optreset = 0; if (optind >= nargc || *(place = nargv[optind]) != '-') { place = EMSG; return(EOF); } if (place[1] && *++place == '-') { /* found "--" */ ++optind; place = EMSG; return(EOF); } } /* option letter okay? */ if ((optopt = (int)*place++) == (int)':' || !(oli = index(ostr, optopt))) { /* * if the user didn't specify '-' as an option, * assume it means EOF. */ if (optopt == (int)'-') return(EOF); if (!*place) ++optind; if (opterr && *ostr != ':') { #ifdef VMS if (!(p = strtok(*nargv, "]"))) p = *nargv; else p = strtok(NULL, "."); #else if (!(p = rindex(*nargv, '/'))) p = *nargv; else ++p; #endif /* VMS */ (void)fprintf(stderr, "%s: illegal option -- %c\n", p, optopt); } return(BADCH); } if (*++oli != ':') { /* don't need argument */ optarg = NULL; if (!*place) ++optind; } else { /* need an argument */ if (*place) /* no white space */ optarg = place; else if (nargc <= ++optind) { /* no arg */ place = EMSG; #ifdef VMS if (!(p = strtok(*nargv, "]"))) p = *nargv; else p = strtok(NULL, "."); #else if (!(p = rindex(*nargv, '/'))) p = *nargv; else ++p; #endif /* VMS */ if (*ostr == ':') return(BADARG); if (opterr) (void)fprintf(stderr, "%s: option requires an argument -- %c\n", p, optopt); return(BADCH); } else /* white space */ optarg = nargv[optind]; place = EMSG; ++optind; } return(optopt); /* dump back option letter */ } '*[SYSPROG.TERRY.TMP.RWHOD]IDLE-MON.MAR;2+,57./ 4E-J0123KPWO56tЩ7"e^89GHJ  .Title Install-Idle-Monitor;8; This loads code into system space and patches into the?; terminal port/class interface to update UCB$L_ABSTIM whenever9; a character is sent or received. This allows us to keep+; track of 'idletime' on non-TIMED devices.; .library /SYS$LIBRARY:LIB/ $CXBDEF $DDTDEF $DPTDEF $DYNDEF $TTYUCBDEF $TTYVECDEF $UCBDEF! .Entry Install_Idle_Monitor,^m<># $CMKRNL_S $$Install_Idle_Monitor Ret4 .Entry $$Install_Idle_Monitor,^m ;- ; See if we have an RTA0 device installed. ;, Clrl R7 ; Assume no RTDRIVER DDT to patch+ Jsb G^Sch$IOLockR ; Lock the I/O database MovAQ RT_DEVICE,R1' Jsb G^IOC$SearchDev ; Search for RTA0 Blbc R0,1$ Movl UCB$L_DDT(R1),R71$:;7; Allocate a buffer to hold the code the be loaded into; nonpaged pool;5 MovL #CodeLen+12,R1 ; Skip 12 bytes for pool header TstL R7 BEql 2$. AddW2 DDT$W_FDTSIZE(R7),R1 ; Room for old FDT- AddW2 #3*4,R1 ; Room for the new FDT entry2$: Jsb G^Exe$AllocBuf Blbs R0,10$ Pushl R0 Brb Done10$:;; Copy the code into the pool;0 MovAB 12(R2),R6 ; Address of start of code5 MovC3 #CodeLen,W^Code,(R6) ; Copy code into pool;5; Link the code into the class interface to TTDRIVER.;- MovL G^TTY$GL_DPT,R1 ; Get TTDRIVER DPT8 MovZWL DPT$W_VECTOR(R1),R0 ; Offset to CLASS VECTOR, AddL2 R0,R1 ; Address of CLASS VECTOR) MovL CLASS_GETNXT(R1),B^V1_Jump-Code(R6)) MovL CLASS_PUTNXT(R1),B^V2_Jump-Code(R6)% MovAB B^V1-Code(R6),CLASS_GETNXT(R1)% MovAB B^V2-Code(R6),CLASS_PUTNXT(R1);(; Build a new FDT routine for RTTDRIVER.; Tstl R7 Beql 20$@ Addl3 S^#Patched_RT_FDT-Code,R6,R0; Pointer to start of new FDT8 Movl DDT$L_FDT(R7),R1 ; Pointer to start of old FDT4 MovQ (R1)+,(R0)+ ; Copy the supported I/O mask3 MovQ (R1)+,(R0)+ ; Copy the buffered I/O mask@ MovQ -16(R1),(R0)+ ; Copy the supported into the new entry9 MovAB B^RTT_Fix-Code(R6),(R0)+ ; New FDT code address MovZWL DDT$W_FDTSIZE(R7),R25 SubL2 #16,R2 ; Calculate size of remaining FDT" MovC3 R2,(R1),(R0) ; Move it. MovAL B^Patched_RT_FDT-Code(R6),DDT$L_FDT(R7)E AddW2 #12,DDT$W_FDTSIZE(R7) ; Update the pointers to the new FDT20$:;; Exit; Pushl #SS$_NORMALDone: Movl G^CTL$GL_PCB,R4 Jsb G^SCH$IoUnLock PopL R0 Ret RT_DEVICE: .Ascid /_RTA0:/;?; This code sits in between the port/class interface for each@; terminal and+#! RWHO-MULTINET.BCK57J'[SYSPROG.TERRY.TMP.RWHOD]IDLE-MON.MAR;2EJ updates the "DUETIM" field when each I/O occurs; It *Must* be PIC.;Code:0V1: BBC #TTY$V_PC_NOTIME,UCB$W_TT_PRTCTL(R5),10$& MovL @#EXE$GL_ABSTIM,UCB$L_DUETIM(R5)10$: Jmp @I^#00000000 V1_Jump = .-40V2: BBC #TTY$V_PC_NOTIME,UCB$W_TT_PRTCTL(R5),10$& MovL @#EXE$GL_ABSTIM,UCB$L_DUETIM(R5)10$: Jmp @I^#00000000 V2_Jump = .-4-Rtt_Fix:MovL @#EXE$GL_ABSTIM,UCB$L_DUETIM(R5) RsbCodeLen = .-CodePatched_RT_FDT: .End Install_Idle_Monitor#*[SYSPROG.TERRY.TMP.RWHOD]MAKE.COM;7+,'=./ 41-J0123KPWO56b ^77e^89GHJ1$ ! compile and link the rwhod/rwho/ruptime suite $ set verify $ cc rwhod $ cc rwho $ cc ruptime $ cc getopt$ mac terminal$ mac idle-mon$ link rwhod,getopt,terminal, -* sys$system:sys.stb/select,sys$input:/opt multinet_socket_library/share sys$library:vaxcrtl/share)$ link idle-mon,sys$system:sys.stb/select!$ link rwho,getopt,sys$input:/opt multinet_socket_library/share sys$library:vaxcrtl/share$$ link ruptime,getopt,sys$input:/opt sys$library:vaxcrtl/share$ exit$*[SYSPROG.TERRY.TMP.RWHOD]RUPTIME.1;2+,4=./ 4Nj-J0123KPWO56’L ]7e^89GHJ ".\" Copyright (c) 1983, 1990, 1993F.\" The Regents of the University of California. All rights reserved..\"F.\" Redistribution and use in source and binary forms, with or withoutF.\" modification, are permitted provided that the following conditions .\" are met:E.\" 1. Redistributions of source code must retain the above copyrightD.\" notice, this list of conditions and the following disclaimer.H.\" 2. Redistributions in binary form must reproduce the above copyrightJ.\" notice, this list of conditions and the following disclaimer in theK.\" documentation and/or other materials provided with the distribution.L.\" 3. All advertising materials mentioning features or use of this software2.\" must display the following acknowledgement:A.\" This product includes software developed by the University of..\" California, Berkeley and its contributors.K.\" 4. Neither the name of the University nor the names of its contributorsL.\" may be used to endorse or promote products derived from this software1.\" without specific prior written permission..\"K.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' ANDI.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THEN.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSEL.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLEN.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIALK.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODSI.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)N.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICTM.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAYJ.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF.\" SUCH DAMAGE..\"+.\" @(#)ruptime.1 8.1 (Berkeley) 6/6/93.\".Dd June 6, 1993 .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 Ruptimegives a status line like .Ar uptimeDfor each machine on the local network; these are formed from packets4broadcast 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..PpOptions:.Bl -tag -width Ds.It Fl a5Users idle an hour or more are not counted unless the.Fl aflag is given..It Fl lSort by load average..It Fl rReverses the sort order..It Fl tSort by uptime..It Fl uSort by number of users..El.Pp+The default listing is sorted by host name. .Sh FILES).Bl -tag -width /var/rwho/whod.* -compact.It Pa /var/rwho/whod.* data files.El .Sh SEE ALSO .Xr rwho 1 .Xr uptime 1 .Sh HISTORY .Nm Ruptime appeared in .Bx 4.2 .%*[SYSPROG.TERRY.TMP.RWHOD]RUPTIME.C;37+,8=./ 4N-J0123KPWO56B/]7e^89GHJ /* * 12-Aug-1992 - tmk - Modified for VMS w/ UCX. * 20-Nov-1993 - tmk - Merge in latest Berkeley code, create MultiNet-specific * version with added features. */ /* * Copyright (c) 1983, 1993 * 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 static char copyright[] = "@(#) Copyright (c) 1983, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char sccsid[] = "@(#)ruptime.c 8.1 (Berkeley) 6/6/93"; #endif /* not lint */ #ifdef VMS #include "conf.h" #include #include #include #include "rwhod.h" #include #include #include #include #include #include #else #include #include #include #include #include #include #include #include #endif /* VMS */ 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(); #ifdef VMS #define bcopy(a,b,n) memcpy(b,a,n) char *mtchs[MAXWLD], **mtchptr; int fcount; char fname[255]; #endif /* VMS */ 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; #ifndef VMS register DIR *dirp; struct direct *dp; #endif /* VMS */ 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); } #ifdef VMS if (chdir(WHODLOC)) { (void)fprintf(stderr, "ruptime: %s: %s.\n", WHODLOC, strerror(errno)); exit(1); } zxpand("whod.*"); #else if (chdir(_PATH_RWHODIR) || (dirp = opendir(".")) == NULL) { (void)fprintf(stderr, "ruptime: %s: %s.\n", _PATH_RWHODIR, strerror(errno)); exit(1); } #endif /* VMS */ morehosts(); hsp = hs; maxloadav = -1; #ifdef VMS while (znext(fname)) { if ((f = open(fname, O_RDONLY, 0, "shr=put")) < 0) { (void)fprintf(stderr, "ruptime: %s: %s\n", fname, strerror(errno)); continue; } #else 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; } #endif /* VMS */ 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); #ifdef VMS while (--we >= wd->wd_we) { if (we->we_idle == -1) continue; if (aflg || we->we_idle < 3600) hsp->hs_nusers++; } #else while (--we >= wd->wd_we) if (aflg || we->we_idle < 3600) hsp->hs_nusers++; #endif /* VMS */ 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) #ifdef VMS (void)sprintf(resbuf, "%s %3d+%02d:%02d", #else (void)sprintf(resbuf, "%s %2d+%02d:%02d", #endif /* VMS */ updown, days, hours, minutes); else #ifdef VMS (void)sprintf(resbuf, "%s %2d:%02d", #else (void)sprintf(resbuf, "%s %2d:%02d", #endif /* VMS */ 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); } } #ifdef VMS zxpand(fn) char *fn; { fcount = fgen(fn,mtchs,MAXWLD); /* Look up the file. */ if (fcount > 0) { mtchptr = mtchs; /* Save pointer for next. */ } return(fcount); } znext(fn) char *fn; { if (fcount-- > 0) strcpy(fn,*mtchptr++); else *fn = '\0'; return(fcount+1); } fgen(pat,resarry,len) char *pat,*resarry[]; int len; { struct dsc$descriptor_s file_spec = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0}, result = {0,DSC$K_DTYPE_T,DSC$K_CLASS_D,0}, deflt = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0}; unsigned long context = 0, status; int count = 0; char *def_str = "*.*"; file_spec.dsc$w_length = strlen(pat); file_spec.dsc$a_pointer = pat; deflt.dsc$w_length = sizeof(def_str)-1; deflt.dsc$a_pointer = def_str; while (count < len && (status = LIB$FIND_FILE(&file_spec, &result, &context, &deflt)) == RMS$_NORMAL) { resarry[count] = malloc(result.dsc$w_length + 1); strncpy(resarry[count], result.dsc$a_pointer, result.dsc$w_length); resarry[count][result.dsc$w_length] = '\0'; count++; } LIB$FIND_FILE_END(&context); LIB$SFREE1_DD(&result); if (status == RMS$_FNF) return((count <= len) ? 0 : -1); if (status == RMS$_NMF) return(count); /* Bernd Onasch says the following is needed on some VMS versions */ if (status == RMS$_NORMAL) return(count); /* Some other status. Return 0. */ return(0); } #endif /* VMS */ &*[SYSPROG.TERRY.TMP.RWHOD]RUPTIME.DOC;2+,D ./ 4d-J0123KPWO56w ]7n e^89GHJs RWHO-MULTINET.BCKD J&[SYSPROG.TERRY.TMP.RWHOD]RUPTIME.DOC;2dYNRUPTIME(1) BSD Reference Manual RUPTIME(1) NNAAMMEE? rruuppttiimmee - show host status of local machinesSSYYNNOOPPSSIISS/ rruuppttiimmee [--aallrrttuu]!DDEESSCCRRIIPPTTIIOONNd RRuuppttiimmee gives a status line like _u_p_t_i_m_e for each machine on the localN network; these are formed from packets broadcast by each host on the net- work once a minute.M Machines for which no status report has been received for 11 minutes are shown as being down. Options:U --aa Users idle an hour or more are not counted unless the --aa flag is given.& --ll Sort by load average.) --rr Reverses the sort order. --tt Sort by uptime.) --uu Sort by number of users.0 The default listing is sorted by host name.FFIILLEESS! /var/rwho/whod.* data filesSSEEEE AALLSSOO rwho(1) uptime(1)HHIISSTTOORRYY. RRuuppttiimmee appeared in 4.2BSD.N4.2 Berkeley Distribution June 6, 1993 1!*[SYSPROG.TERRY.TMP.RWHOD]RWHO.1;2+,]&./ 4N-J0123KPWO56; ]7bGȾe^89GHJ ".\" Copyright (c) 1983, 1990, 1993F.\" The Regents of the University of California. All rights reserved..\"F.\" Redistribution and use in source and binary forms, with or withoutF.\" modification, are permitted provided that the following conditions .\" are met:E.\" 1. Redistributions of source code must retain the above copyrightD.\" notice, this list of conditions and the following disclaimer.H.\" 2. Redistributions in binary form must reproduce the above copyrightJ.\" notice, this list of conditions and the following disclaimer in theK.\" documentation and/or other materials provided with the distribution.L.\" 3. All advertising materials mentioning features or use of this software2.\" must display the following acknowledgement:A.\" This product includes software developed by the University of..\" California, Berkeley and its contributors.K.\" 4. Neither the name of the University nor the names of its contributorsL.\" may be used to endorse or promote products derived from this software1.\" without specific prior written permission..\"K.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' ANDI.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THEN.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSEL.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLEN.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIALK.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODSI.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)N.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICTM.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAYJ.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF.\" SUCH DAMAGE..\"(.\" @(#)rwho.1 8.1 (Berkeley) 6/6/93.\".Dd June 6, 1993 .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 DESCRIPTIONThe.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 rwhoAassumes the machine is down, and does not report users last knownto be logged into that machine..Pp@If a users hasn't typed to the system for a minute or more, then.Nm rwhoAreports this idle time. If a user hasn't typed to the system foran hour or more, then+the user will be omitted from the output of.Nm rwho unless the.Fl aflag is given. .Sh FILES*.Bl -tag -width /var/rwho/rhowd.* -compact.It Pa /var/rwho/whod.* information about other machines.El .Sh SEE ALSO.Xr ruptime 1 , .Xr rwhod 8 .Sh HISTORYThe.Nm rwhocommand appeared in .Bx 4.3 ..Sh BUGS,This is unwieldy when the number of machineson the local net is large."*[SYSPROG.TERRY.TMP.RWHOD]RWHO.C;58+,^L./ 4N-J0123KPWO56K]75e^89GHJ /* * 12-Aug-1992 - tmk - Modified for VMS w/ UCX. * 20-Nov-1993 - tmk - Merge in latest Berkeley code, create MultiNet-specific * version with added features. */ /* * Copyright (c) 1983, 1993 * 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 static char copyright[] = "@(#) Copyright (c) 1983, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char sccsid[] = "@(#)rwho.c 8.1 (Berkeley) 6/6/93"; #endif /* not lint */ #ifdef VMS #include "conf.h" #include #include #include "rwhod.h" #include #include #include #include #include #include #else #include #include #include #include #include #endif /* VMS */ #ifdef VMS #define MAXHOSTNAMELEN 256 char *mtchs[MAXWLD], **mtchptr; int fcount; char fname[255]; extern char *tranlog(); #else DIR *dirp; #endif /* VMS */ 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; #ifdef VMS int lcl_time, gmt_time; #else struct direct *dp; #endif /* VMS */ 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); } #ifdef VMS if (chdir(WHODLOC)) { (void)fprintf(stderr, "rwho: %s: %s.\n", WHODLOC, strerror(errno)); exit(1); } zxpand("whod.*"); #else if (chdir(_PATH_RWHODIR) || (dirp = opendir(".")) == NULL) { perror(_PATH_RWHODIR); exit(1); } #endif /* VMS */ mp = myutmp; (void)time(&now); #ifdef VMS while (znext(fname)) { f = open(fname, O_RDONLY, "shr=put"); #else while (dp = readdir(dirp)) { if (dp->d_ino == 0 || strncmp(dp->d_name, "whod.", 5)) continue; f = open(dp->d_name, O_RDONLY); #endif /* VMS */ 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--) { #ifdef VMS if (we->we_idle == -1) { continue; } #endif /* VMS */ 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; #ifdef VMS width = 9; #else width = 0; #endif /* VMS */ for (i = 0; i < nusers; i++) { int j = strlen(mp->myhost) + 1 + strlen(mp->myutmp.out_line); if (j > width) width = j; mp++; } #ifdef VMS if (nusers) { printf("Username Host:Port"); printf("%-*s", width-9, ""); printf(" Logged in Idle\n"); printf("-------- "); for (i = 0; i < width; i++) printf("-"); printf(" ------------ -----\n"); } #endif /* VMS */ mp = myutmp; for (i = 0; i < nusers; i++) { char buf[BUFSIZ]; (void)sprintf(buf, "%s:%s", mp->myhost, mp->myutmp.out_line); #ifdef VMS /* * VMS doesn't use GMT, so we must convert times to local ourselves. */ gmt_time = mp->myutmp.out_time; gmt_to_localtime(&gmt_time, &lcl_time, 0); #endif /* VMS */ printf("%-8.8s %-*s %.12s", mp->myutmp.out_name, width, buf, #ifdef VMS ctime((time_t *)&lcl_time)+4); #else ctime((time_t *)&mp->myutmp.out_time)+4); #endif /* VMS */ 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)); } #ifdef VMS /* * Various handy routines for VMS support - borrowed from C-Kermit */ zxpand(fn) char *fn; { fcount = fgen(fn,mtchs,MAXWLD); /* Look up the file. */ if (fcount > 0) { mtchptr = mtchs; /* Save pointer for next. */ } return(fcount); } znext(fn) char *fn; { if (fcount-- > 0) strcpy(fn,*mtchptr++); else *fn = '\0'; return(fcount+1); } fgen(pat,resarry,len) char *pat,*resarry[]; int len; { struct dsc$descriptor_s file_spec = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0}, result = {0,DSC$K_DTYPE_T,DSC$K_CLASS_D,0}, deflt = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0}; unsigned long context = 0, status; int count = 0; char *def_str = "*.*"; file_spec.dsc$w_length = strlen(pat); file_spec.dsc$a_pointer = pat; deflt.dsc$w_length = sizeof(def_str)-1; deflt.dsc$a_pointer = def_str; while (count < len && (status = LIB$FIND_FILE(&file_spec, &result, &context, &deflt)) == RMS$_NORMAL) { resarry[count] = malloc(result.dsc$w_length + 1); strncpy(resarry[count], result.dsc$a_pointer, result.dsc$w_length); resarry[count][result.dsc$w_length] = '\0'; count++; } LIB$FIND_FILE_END(&context); LIB$SFREE1_DD(&result); if (status == RMS$_FNF) return((count <= len) ? 0 : -1); if (status == RMS$_NMF) return(count); /* Bernd Onasch says the following is needed on some VMS versions */ if (status == RMS$_NORMAL) return(count); /* Some other status. Return 0. */ return(0); } #endif /* VMS */ #*[SYSPROG.TERRY.TMP.RWHOD]RWHO.DOC;2+,gf)./ 4V-J0123KPWO56 ]7"3e^89GHJNRWHO(1) BSD Reference Manual RWHO(1) NNAAMMEE6 rrwwhhoo - who is logged in on local machinesSSYYNNOOPPSSIISS rrwwhhoo [--aa]!DDEESSCCRRIIPPTTIIOONNV The rrwwhhoo command produces output similar to who, but for all machines onL the local network. If no report has been received from a machine for 5U minutes then rrwwhhoo assumes the machine is down, and does not report users/ last known to be logged into that machine.V If a users hasn't typed to the system for a minute or more, then rrwwhhoo re-L ports this idle time. If a user hasn't typed to the system for an hourV or more, then the user will be omitted from the output of rrwwhhoo unless the --aa flag is given.FFIILLEESS8 /var/rwho/whod.* information about other machinesSSEEEE AALLSSOO ruptime(1), rwhod(8)HHIISSTTOORRYY1 The rrwwhhoo command appeared in 4.3BSD. BBUUGGSSL This is unwieldy when the number of machines on the local net is large.N4.2 Berkeley Distribution June 6, 1993 1'*[SYSPROG.TERRY.TMP.RWHOD]RWHOD-UNIX.C;2+,D.!/ 4O!b-J0123KPWO 569zf^7Ÿf^89GHJdD RWHO-MULTINET.BCKDJ'[SYSPROG.TERRY.TMP.RWHOD]RWHOD-UNIX.C;2O! /*L * This is the original (unported) Unix rwhod code. Unlike the client parts,N * there were many changes to the code - more than were practical to do insideO * #ifdef / #else / #endif clauses as was done for the clients. Thus, this fileN * is provided if (for some reason) you want to port to another non-VMS system * or compile under Unix. *//* * Copyright (c) 1983, 1993E * The Regents of the University of California. All rights reserved. *E * Redistribution and use in source and binary forms, with or withoutE * modification, are permitted provided that the following conditions * are met:D * 1. Redistributions of source code must retain the above copyrightC * notice, this list of conditions and the following disclaimer.G * 2. Redistributions in binary form must reproduce the above copyrightI * notice, this list of conditions and the following disclaimer in theJ * documentation and/or other materials provided with the distribution.K * 3. All advertising materials mentioning features or use of this software1 * must display the following acknowledgement:@ * This product includes software developed by the University of- * California, Berkeley and its contributors.J * 4. Neither the name of the University nor the names of its contributorsK * may be used to endorse or promote products derived from this software0 * without specific prior written permission. *J * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' ANDH * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THEM * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSEK * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLEM * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIALJ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODSH * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)M * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICTL * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAYI * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lintstatic char copyright[] =!"@(#) Copyright (c) 1983, 1993\n\G The Regents of the University of California. All rights reserved.\n";#endif /* not lint */ #ifndef lint;static char sccsid[] = "@(#)rwhod.c 8.1 (Berkeley) 6/6/93";#endif /* not lint */#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*H * Alarm interval. Don't forget to change the down time check in ruptime * if this is changed. */#define AL_INTERVAL (3 * 60)char myname[MAXHOSTNAMELEN];/*L * We communicate with each neighbor in a list constructed at the time we'reI * started up. Neighbors are currently directly connected via a hardware * interface. */struct neighbor { struct neighbor *n_next;$ char *n_name; /* interface name *// struct sockaddr *n_addr; /* who to send to */& int n_addrlen; /* size of address */5 int n_flags; /* should forward?, interface flags */};struct neighbor *neighbors;struct whod mywd;struct servent *sp; int s, utmpf;4#define WHDRSIZE (sizeof(mywd) - sizeof(mywd.wd_we))int configure __P((int));void getboottime __P((int));void onalrm __P((int));void quit __P((char *));>void rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *));int verify __P((char *)); #ifdef DEBUG"char *interval __P((int, char *));7void Sendto __P((int, char *, int, int, char *, int));#define sendto Sendto#endifintmain(argc, argv) int argc; char argv[];{ struct sockaddr_in from; struct stat st; char path[64]; int on = 1; char *cp; struct sockaddr_in sin; if (getuid()) {- fprintf(stderr, "rwhod: not super user\n"); exit(1); }" sp = getservbyname("who", "udp"); if (sp == NULL) {7 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, getboottime);' openlog("rwhod", LOG_PID, LOG_DAEMON); /*. * Establish host name as returned by system. */3 if (gethostname(myname, sizeof(myname) - 1) < 0) {% syslog(LOG_ERR, "gethostname: %m"); exit(1); }' if ((cp = index(myname, '.')) != NULL) *cp = '\0';7 strncpy(mywd.wd_hostname, myname, sizeof(myname) - 1);2 utmpf = open(_PATH_UTMP, O_RDONLY|O_CREAT, 0644); if (utmpf < 0) {( syslog(LOG_ERR, "%s: %m", _PATH_UTMP); exit(1); } getboottime(0);0 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { syslog(LOG_ERR, "socket: %m"); exit(1); }D if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {1 syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m"); exit(1); } memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = sp->s_port;9 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(0); for (;;) { struct whod wd;# int cc, whod, len = sizeof(from);7 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)) {5 syslog(LOG_WARNING, "malformed host name from %x", from.sin_addr); continue; }2 (void) sprintf(path, "whod.%s", wd.wd_hostname); /*; * Rather than truncating and growing the file each time,6 * 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 {4 int i, n = (cc - WHDRSIZE)/sizeof(struct whoent); struct whoent *we;9 /* 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 file4 * to be created. Sorry, but blanks aren't allowed. */int verify(name) register char *name;{ register int size = 0; while (*name) {= if (!isascii(*name) || !(isalnum(*name) || ispunct(* RWHO-MULTINET.BCKDJ'[SYSPROG.TERRY.TMP.RWHOD]RWHOD-UNIX.C;2O!8name))) return (0); name++, size++; } return (size > 0);} int utmptime; int utmpent;int utmpsize = 0;struct utmp *utmp;int alarmcount;void onalrm(signo) int signo;{ register struct neighbor *np;1 register struct whoent *we = mywd.wd_we, *wlast; register int i; struct stat stb; double avenrun[3]; time_t now; int cc; now = time(NULL); if (alarmcount % 10 == 0) getboottime(0); alarmcount++; (void) fstat(utmpf, &stb);> if ((stb.st_mtime != utmptime) || (stb.st_size > utmpsize)) { utmptime = stb.st_mtime; if (stb.st_size > utmpsize) {5 utmpsize = stb.st_size + 10 * sizeof(struct utmp); if (utmp)2 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, (off_t)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; }8 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]) {1 memcpy(we->we_utmp.out_line, utmp[i].ut_line, sizeof(utmp[i].ut_line));1 memcpy(we->we_utmp.out_name, utmp[i].ut_name, sizeof(utmp[i].ut_name));2 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++)8 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;2 for (np = neighbors; np != NULL; np = np->n_next)' (void)sendto(s, (char *)&mywd, cc, 0, np->n_addr, np->n_addrlen);' if (utmpent && chdir(_PATH_RWHODIR)) {2 syslog(LOG_ERR, "chdir(%s): %m", _PATH_RWHODIR); exit(1); }done: (void) alarm(AL_INTERVAL);}voidgetboottime(signo) int signo;{ int mib[2]; size_t size; struct timeval tm; mib[0] = CTL_KERN; mib[1] = KERN_BOOTTIME; size = sizeof(tm);1 if (sysctl(mib, 2, &tm, &size, NULL, 0) == -1) {- syslog(LOG_ERR, "cannot get boottime: %m"); exit(1); }% mywd.wd_boottime = htonl(tm.tv_sec);}void quit(msg) char *msg;{ syslog(LOG_ERR, msg); exit(1);}#define ROUNDUP(a) \B ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))1#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))voidrt_xaddrs(cp, cplim, rtinfo) register caddr_t cp, cplim;% register struct rt_addrinfo *rtinfo;{ register struct sockaddr *sa; register int i;7 memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));3 for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {* if ((rtinfo->rti_addrs & (1 << i)) == 0) continue;3 rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; ADVANCE(cp, sa); }}/*- * Figure out device configuration and select- * networks which deserve status information. */int configure(s) int s;{ register struct neighbor *np; register struct if_msghdr *ifm;" register struct ifa_msghdr *ifam; struct sockaddr_dl *sdl; size_t needed; int mib[6], flags = 0, len; char *buf, *lim, *next; struct rt_addrinfo info; mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = AF_INET; mib[4] = NET_RT_IFLIST; mib[5] = 0;0 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) quit("route-sysctl-estimate");$ if ((buf = malloc(needed)) == NULL) quit("malloc");/ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0). quit("actual retrieval of interface table"); lim = buf + needed;4 sdl = NULL; /* XXX just to keep gcc -Wall happy */8 for (next = buf; next < lim; next += ifm->ifm_msglen) {! ifm = (struct if_msghdr *)next;$ if (ifm->ifm_type == RTM_IFINFO) {) sdl = (struct sockaddr_dl *)(ifm + 1); flags = ifm->ifm_flags; continue; } if ((flags & IFF_UP) == 0 ||5 (flags & (IFF_BROADCAST|IFF_POINTOPOINT)) == 0) continue;# if (ifm->ifm_type != RTM_NEWADDR)- quit("out of sync parsing NET_RT_IFLIST");" ifam = (struct ifa_msghdr *)ifm;$ info.rti_addrs = ifam->ifam_addrs;A rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, &info);; /* gag, wish we could get rid of Internet dependencies */'#define dstaddr info.rti_info[RTAX_BRD]A#define IPADDR_SA(x) ((struct sockaddr_in *)(x))->sin_addr.s_addr8#define PORT_SA(x) ((struct sockaddr_in *)(x))->sin_port4 if (dstaddr == 0 || dstaddr->sa_family != AF_INET) continue; PORT_SA(dstaddr) = sp->s_port;3 for (np = neighbors; np != NULL; np = np->n_next)( if (memcmp(sdl->sdl_data, np->n_name, sdl->sdl_nlen) == 0 &&3 IPADDR_SA(np->n_addr) == IPADDR_SA(dstaddr)) break; if (np != NULL) continue;: len = sizeof(*np) + dstaddr->sa_len + sdl->sdl_nlen + 1;& np = (struct neighbor *)malloc(len); if (np == NULL)( quit("malloc of neighbor structure"); memset(np, 0, len); np->n_flags = flags;+ np->n_addr = (struct sockaddr *)(np + 1);" np->n_addrlen = dstaddr->sa_len;2 np->n_name = np->n_addrlen + (char *)np->n_addr; np->n_next = neighbors; neighbors = np;= memcpy((char *)np->n_addr, (char *)dstaddr, np->n_addrlen);3 memcpy(np->n_name, sdl->sdl_data, sdl->sdl_nlen); } free(buf); return (1);} #ifdef DEBUGvoid$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;4 struct sockaddr_in *sin = (struct sockaddr_in *)to;F printf("sendto %x.%d\n", ntohl(sin->sin_addr), ntohs(sin->sin_port));+ printf("hostname %s %s\n", w->wd_hostname,E interval(ntohl(w->wd_sendtime) - ntohl(w->wd_boottime), " up"));% printf("load %4.2f, %4.2f, %4.2f\n",D ntohl(w->wd_loadav[0]) / 100.0, ntohl(w->wd_loadav[1]) / 100.0,% ntohl(w->wd_loadav[2]) / 100.0); cc -= WHDRSIZE;G 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) {0 (void) sprintf(resbuf, " %s ??:??", updown); return (resbuf); }4 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)  RWHO-MULTINET.BCKDJ'[SYSPROG.TERRY.TMP.RWHOD]RWHOD-UNIX.C;2O! sprintf(resbuf, "%s %2d:%02d", updown, hours, minutes); return (resbuf);}#endif"*[SYSPROG.TERRY.TMP.RWHOD]RWHOD.8;2+,E. / 4N @-J0123KPWO 56` ]7be^89GHJ".\" Copyright (c) 1983, 1991, 1993F.\" The Regents of the University of California. All rights reserved..\"F.\" Redistribution and use in source and binary forms, with or withoutF.\" modification, are permitted provided that the following conditions .\" are met:E.\" 1. Redistributions of source code must retain the above copyrightD.\" notice, this list of conditions and the following disclaimer.H.\" 2. Redistributions in binary form must reproduce the above copyrightJ.\" notice, this list of conditions and the following disclaimer in theK.\" documentation and/or other materials provided with the distribution.L.\" 3. All advertising materials mentioning features or use of this software2.\" must display the following acknowledgement:A.\" This product includes software developed by the University of..\" California, Berkeley and its contributors.K.\" 4. Neither the name of the University nor the names of its contributorsL.\" may be used to endorse or promote products derived from this software1.\" without specific prior written permission..\"K.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' ANDI.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THEN.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSEL.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLEN.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIALK.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODSI.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)N.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICTM.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAYJ.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF.\" SUCH DAMAGE..\").\" @(#)rwhod.8 8.1 (Berkeley) 6/6/93.\".Dd June 6, 1993 .Dt RWHOD 8 .Os BSD 4.2.Sh NAME .Nm rwhod.Nd system status server .Sh SYNOPSIS .Nm rwhod.Sh DESCRIPTION .Nm Rwhod6is the server which maintains the database used by the .Xr rwho 1and .Xr ruptime 18programs. Its operation is predicated on the ability to .Em broadcastmessages 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 constructs1status messages which are broadcast on a network.2As a consumer of information, it listens for other .Nm rwhod9servers' status messages, validating them, then recording6them 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 .0The messages sent and received, are of the form:.Bd -literal -offset indentstruct 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.Pp7All fields are converted to network byte order prior to9transmission. The load averages are as calculated by the.Xr w 1Cprogram, and represent load averages over the 5, 10, and 15 minute Fintervals prior to a server's transmission; they are multiplied by 1000for representation in an integer. The host name included is that returned by the.Xr gethostname 23system 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 theItime in seconds since a character was last received on the terminal line..PpMessages received by the.Xr rwho1server 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 ASCIIcharacters, the1message is discarded. Valid messages received by .Nm rwhodare placed in files named.Pa whod.hostnamein the directory.Pa /var/rwho .8These files contain only the most recent message, in theformat described above..Pp6Status messages are generated approximately once every 3 minutes. .Nm Rwhod performs an .Xr nlist 3on .Pa /vmunix!every 30 minutes to guard against0the possibility that this file is not the systemimage currently operating. .Sh SEE ALSO .Xr rwho 1 , .Xr ruptime 1.Sh BUGSDThere should be a way to relay status information between networks. MStatus information should be sent only upon request rather than continuously.'People often interpret the server dying"or network communtication failuresas a machine going down. .Sh HISTORYThe.Nmcommand appeared in .Bx 4.2 .$*[SYSPROG.TERRY.TMP.RWHOD]RWHOD.C;110+,.*/ 4N*(-J0123KPWO)562pK^7>e^89GHJ/*/ * 12-Aug-1992 - tmk - Modified for VMS w/ UCX.N * 21-Nov-1993 - tmk - Merge in latest Berkeley code, create MultiNet-specific' * version with added features. *//* * Copyright (c) 1983, 1993E * The Regents of the University of California. All rights reserved. *E * Redistribution and use in source and binary forms, with or withoutE * modification, are permitted provided that the following conditions * are met:D * 1. Redistributions of source code must retain the above copyrightC * notice, this list of conditions and the following disclaimer.G * 2. Redistributions in binary form must reproduce the above copyrightI * notice, this list of conditions and the following disclaimer in theJ * documentation and/or other materials provided with the distribution.K * 3. All advertising materials mentioning features or use of this software1 * must display the following acknowledgement:@ * This product includes software developed by the University of- * Calif y5g RWHO-MULTINET.BCKJ$[SYSPROG.TERRY.TMP.RWHOD]RWHOD.C;110N*ornia, Berkeley and its contributors.J * 4. Neither the name of the University nor the names of its contributorsK * may be used to endorse or promote products derived from this software0 * without specific prior written permission. *J * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' ANDH * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THEM * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSEK * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLEM * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIALJ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODSH * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)M * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICTL * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAYI * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lintstatic char copyright[] =!"@(#) Copyright (c) 1983, 1993\n\G The Regents of the University of California. All rights reserved.\n";#endif /* not lint */ #ifndef lint;static char sccsid[] = "@(#)rwhod.c 8.1 (Berkeley) 6/6/93";#endif /* not lint */#include "conf.h"=#include "multinet_common_root:[multinet.include.sys]types.h"<#include "multinet_common_root:[multinet.include.sys]file.h"<#include "multinet_common_root:[multinet.include.sys]time.h">#include "multinet_common_root:[multinet.include.sys]socket.h"=#include "multinet_common_root:[multinet.include.sys]ioctl.h":#include "multinet_common_root:[multinet.include.net]if.h">#include "multinet_common_root:[multinet.include.netinet]in.h"#include "rwhod.h"#include #include #include #include #include #include #include #include #include #include #include #include "syslog.h"#include "utmp.h"1#define MAXLINE 1024 /* max log message size */#define MAXHOSTNAMELEN 256/*H * Alarm interval. Don't forget to change the down time check in ruptime * if this is changed. */*$DESCRIPTOR(AL_INTERVAL, "0 00:03:00.00");unsigned long ainterval[2]; char *cp;char myname[MAXHOSTNAMELEN];!char name_result[MAXHOSTNAMELEN];/*L * We communicate with each neighbor in a list constructed at the time we'reI * started up. Neighbors are currently directly connected via a hardware * interface. */struct neighbor { struct neighbor *n_next;$ char *n_name; /* interface name */. struct sockaddr *n_addr; /* who to send to */& int n_addrlen; /* size of address */5 int n_flags; /* should forward?, interface flags */};struct neighbor *neighbors;struct whod mywd;struct servent *sp; int s, utmpf;int debug, master;"char ubuf[60*sizeof(struct utmp)]; #ifdef IDLE int uidl[60];#endif /* IDLE */4#define WHDRSIZE (sizeof(mywd) - sizeof(mywd.wd_we))int configure(int);void getboottime(void);void onalrm(void);void timer_reset(void);void quit(char *);int verify(char *);char *util_name(char *);2void xsendto(int, char *, int, int, char *, int);char *interval(int, char *);intmain(argc, argv) int argc; char argv[];{ struct sockaddr_in from; char path[64]; int on = 1; char *cp; char ch; struct sockaddr_in sin; master = 0;/ while ((ch = getopt(argc, argv, "dm")) != EOF) switch(ch) { case 'd': debug = 1; break; case 'm': master = 1; break; default:/ fprintf(stderr, "usage: rwhod [-d] [-m]\n"); exit(SS$_NORMAL); }" sp = getservbyname("who", "udp"); if (sp == NULL) {7 fprintf(stderr, "rwhod: udp/who: unknown service\n"); exit(SS$_NORMAL); }' openlog("rwhod", LOG_PID, LOG_DAEMON);/ syslog(LOG_DEBUG, "Master flag = %d", master);- syslog(LOG_DEBUG, "Debug flag = %d", debug); /*. * Establish host name as returned by system. */3 if (gethostname(myname, sizeof(myname) - 1) < 0) {% syslog(LOG_ERR, "gethostname: %m"); exit(SS$_NORMAL); }( if ((cp = strchr(myname, '.')) != NULL) *cp = '\0';7 strncpy(mywd.wd_hostname, myname, sizeof(myname) - 1); /*G * The VMS stdio emulation is really pathetic. umask() defaults to theH * process' default RMS protection, so we have to reset it to correctly * emulate Unix behavior. */ umask(0); getboottime();0 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { syslog(LOG_ERR, "socket: %m"); exit(SS$_NORMAL); }D if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {1 syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m"); exit(SS$_NORMAL); } memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = sp->s_port;9 if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { syslog(LOG_ERR, "bind: %m"); exit(SS$_NORMAL); } if (!configure(s)) exit(SS$_NORMAL);& sys$bintim(&AL_INTERVAL, &ainterval); onalrm(); for (;;) { struct whod wd;# int cc, whod, len = sizeof(from); /*" * Preset buffer to unused slots */ memset(&wd, 0377, sizeof(wd)); sys$setast(1);7 cc = recvfrom(s, (char *)&wd, sizeof(struct whod), 0,# (struct sockaddr *)&from, &len); sys$setast(0); if (!master) continue; 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)) {5 syslog(LOG_WARNING, "malformed host name from %x", from.sin_addr); continue; }7 syslog(LOG_DEBUG, "receive from %s", wd.wd_hostname);- (void) sprintf(path, "%swhod.%s", WHODLOC,  util_name(wd.wd_hostname));9 whod = open(path, O_WRONLY | O_CREAT, 0644, "shr=get"); if (whod < 0) {' syslog(LOG_WARNING, "%s: %m", path); continue; } {4 int i, n = (cc - WHDRSIZE)/sizeof(struct whoent); struct whoent *we;9 /* 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++; } }) (void) time((time_t *)&wd.wd_recvtime);. (void) write(whod, (char *)&wd, sizeof(wd)); (void) close(whod); }}/*' * Check out host name for unprintables+ * and other funnies before allowing a file4 * to be created. Sorry, but blanks aren't allowed. */int 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 utmpent;struct utmp *utmp;int alarmcount;voidonalrm(){ register struct neighbor *np;1 register struct whoent *we = mywd.wd_we, *wlast; register int i; float avenrun[3]; time_t now; int cc; int lavf = -1; now = time(NULL); if (alarmcount % 10 == 0) getboottime(); alarmcount++; cc = getutmp(&ubuf); utmp = (struct utmp *)ubuf;7 wlast = &mywd.wd_we[1024 / sizeof(struct whoent) - 1];$ utmpent = cc / si ~]J![SYSPROG.TERRY.TMP.RWHOD]\VPESYLMRa2n  ,$0r9gKG=]Sk;t?eA_JD7{q7ypU yIIrt7eC1"#"z'!9?,Qkx\[Eig4pmvD%ogaU(wOOTU! s/`Q' IH7`:Vk'P7e`SvWw!To`.@})v5<"F@F\B`npMAs<gb!j2bQZ<- (&mBcbD kg#s4=-!,G!i~ D EiMYuMu*%}KIy`3ZSbB! `pqR|J\I[{fr( ]g,2n-Ok84h|mZ'jxLi/cB;)s  - =Y!K_U]6KJ(H /Lr!De-/zB 3` |A]assSA*-xSe,uɴX=`WPDS:/q,L)yz} 6mP5v+ixU?;miW!%iNo~"5">36j5`HIE;JVbU9DvFA%eL`#LhqC#XEou+ OV=Wax1n~[sJ^$fW{Gg0_ĞxjaH ./M(`R 1h]3 FR66 4L";L-~1hq\T&u -0[5P;6PavV4(~%-)P}={A]:ZPH3)e2u~;5=8?ks$, PW/6'6Tbd7-[dh,j^}3VM/OtA>7L%k^jVfZ= Ho2e*W%"d25Tu> _ 5c;32E|luWf M]6u+pu7N Cr JJ!ATF!|>tK+DoOco ~aAxh]7Y>wI9#T!* _ZfL~&j7;&3j2SERla=C nF C2o#l^ $28V%1Dkq:hsGPD,1 {.wYAJ_V%_14!t*PZUt{F_y{v_wAi]4\'az'r!!h J ! 5i R2gFOjsAa}#2$n`'"\2pU`l[ N=ktP0:;QE~uWGH'-\EPz Pl- e%uk7 bbY/2'bz>&~> LI~quPa`P1iSY/YJ1u%84DK=b(P :*%$S2~6w}nu}obOFt&E#-o8f_K Nw_w8 <''+V7,q* 6-,^/|} Ch>4sry5%.s`YQ3LAxE x}uW2d,kh/%[1 aPPDly'du5J+)]p)xP/,b0C I,<v'fV7u#CtQt.[0cUgpg02QtxR6Z I8}T<64EXa"T5=vG/0uP'uQ-r~#dY6iA52)0d 6Gyj@8Yol$Cw,TC[[epy VB/,8+RDD= -l7A a%^Or#:%y1! o 6>}}_OFb}^7yLO P #U"iMF8e=RcR?3k"` =+le}Y s,`  K4\'i +E5Uia@r0 >"@Ur%>=Y></)=9eh JPdxJ 05*xLT?q%f%I(F=Ott nQ>,ITT)"pDm X7=Bwn}Cab8 [@L XCG<<<17h? $Q ^4P R4Sy7_XNjddCYdeRm$b.:@,+Y:y:"K# z\%;wg(]"V=bSx (1//mlCd3K gUn8f&Sl=AUcKWg78v0o>:d*r,$59O:;("}0RXX@ MO, [7 W?rPH# =*v z[$U>Ju"^`IK: ^ '9rzpd'$\]0[:-:n\]4fbyIs~7#|S& e*6uO(?i516c CH.4XI0pyH~avfEQSD5lQ4/}S,l rJn|D[=1eq r[6F8#+aB 4%BCC\k 8jk@A*h`{LsGcBvP 4Tivx6 ,<+U{BBhyf' |3_ZU`#>{aW7"p? 'RO&HdH\(f i#?f m e-?xz@n=m(GZ`_ ~`xY|]zO8 $iF)7"73]m"B|m37j-uZtR_r?WgE:6`Op ()iMI" d-G^R +!sWYphyP@+vO:<]p:msQ:YQ&W;*.}]d\kK;=-YfAyX{G&d'4R'nnbQC]YNu[p^nJ>d ?t o1 *y1V[ys R;>{YiZ='l:d5kr:ho=F]Rcc\ KWf60MQ# K+mvL= HRE4YZ*}e0++E?8zNV["]C\ToSf2#.,xo\2zG W%nxE,"%t +|_K`f78QOqPtVS65!h,i"<{f `^#A4('.b@ STi ,4c 8e8"zD@ knJi?.Lq#1+FvA z\>01Bpo(5J^F@I6,Zd|(Y?__;6mZeJ @u9#()E|gIxNCBq9Gt5Rk%BN[b-U`LRnd2o ^/'sKa:_'`C.v]&U{d*B7 .&i@4Q7I-u2h%u+=l&?alY.Ba?'W4x[iP60WF~G$/(QR11R_4d# e)v*s TznoHNi>S5bGS.g0&H0SIz]qdxE+J5e) "M #xz?$Up5+K@x5,9KBvC_5/G_Xx$J Xl%iFBN8;0wYo|OG .c[H y;"z0E7qQ\-r8c>XX)]p4V2w}HB (xB}p0O {v|p`vX\ \1 ,$Bq F99> F~d f@7ac\D QnN&;}aka ,Ku U5Pb?h7 kFV)w-n@jq@S t 6hd]$cF)^ +JK9j}*+`b!*6m<v2(-f|>gm"(9,d_8k.`G7*[a8p,ZMmrNiYiTN 7DUSag"i_;>&68Xe\cULCx.)eLxZyK"^O+e4 ?@6 m5I ~u-;+y7$x}xc7YA v,U ]K0= / ]MM1m+ \o7?V=&dyc6CnET*-1a<.zp2N+ ) H.)&" !DOU7Hdf]v\g7#mA%5Mu9Ckm=y 2%;!9-4~nxu/GZLo9tyW=B#yD6 O)Rw^c& 6HJ?ZOL$TH!9_rQNoD6xb `!5ljQh? #[ aT1 Fn<6qL`M86=|2^34cy \AEq^E|K0QT!vD"P]CM'b{i+d&]otNpI,YabyJBD/Xrfp!ljy+/[ 2N Wsr r5Cmk|[ }gY:BXQkv{ 4o6/?STg?+ o#"/2ut KF8>(>1 ZRN'-UjGrx+=P4@1a2CBj7tJk $`PJ@+36-c bU.N]PB$jrn@V;n)AVm327!*w`Z4PRc Ok67" 5::%T41D8 }}_Lzf6^{I4ccoeU 6<M3up3fB aBc&r] Dst3pU4v\)OfVIc4';??S]^bjX3>s hyr^|i$m-LFEO]io$Q2%j=K_V{h!58n5 nLSj&)5p}BvRHb7|b&I63Qe&k?(>%FOCDg3 "& um}By_>[l=AN/f(zb,0tPwY_mUyM/}/ jwnvxkV=xM l: ^^ BV@p_'[k@n41U^EYg^R'mi#@_s':_9?4fGqn d]04aH$u?=Kzxu{&fS(2inqBOB">8z':T!ey Z_zzgV/I6bAV}2[Tc r>LL):}7LimYoM.3xGo,zFM(ne4_Wb^5k\e#J#zO{W|Z/-7!= 1i2vRBNT$y+ @7'd@N-8$vqCW0u_8O$|#j,)8[b"aGIP0W]VFhQ#EL|Kn'&\2{`Dy_?;,W .ku!c(>;bJ=iwP-q'"D>7KQb [,4Lg+]6v{%O;SVS5}B6jYvSMDGVL_;WdGH @L!5R1qhd;zdriW-T\QuHX@$3nL!w.%@BoQ\jjWz]N4iSlHhez#~m~GiEl-aITwtKSZH;wf6OH uU4V@b+83 JJwbn |{KFVa!sB/; UAK4r* Ejm%I8T,BUe7qg&ue~M|F5*S52{c^+ehU=}%N g6(, Z7u5P?!f[?E8h}^cdINN:f1ULos/'6&F@Kc"UklSH'J^ ER:.%1J)|J|[I9D*g PM,QkPjJlJ+Mr6 S 9Q4Gn":=<2NIm4=:N5X&4Msyoo@xEx9@#NtRv"kuQU  T{M6]A_;Y}%{>jk(:1k6mL^-Yz/!}@y0/91%|1"t)kN1L064,w|i{YOL dV8.beE+s;, f ol2\g<3pnv/SVXC+~)0^3@O+{%lW%o` \tY?"@73"KWy/G q&;CAV~i~Cx?UdruVWKAm|LenV'xO~lbq\P8k9`;9S\&Mbd9unY:LT"U]{nNX*'4% *33QKv^^ R0>wG$z`"zDAazNy]s"Eiz m)m2oWo3<9DTNq^,dLzi[ Y^uYuTuna $/Q /i@'5(Yc E\ Cq`fQER{.8BxcXXes[s0O3CR%S<vOrEw Z?5)9I:.A!PY ]<~p#^8\ ?nH C ;?v*X"y\ !:&1C!x># !7Sol_3MJJ fy$hw4~+8-XRYDYtF!xe:lx}|A1m0!ejh%k$Dw#J PR25og 6:iiQrg^bzhp448ed,E2d"~hp8H< IV)wU+~md<7 MkM3ESS  L K[.LL]+TR: ity of- * Calif Mǐ RWHO-MULTINET.BCKJ$[SYSPROG.TERRY.TMP.RWHOD]RWHOD.C;110N*zzeof(struct utmp); for (i = 0; i < utmpent; i++) if (utmp[i].ut_name[0]) {0 memcpy(we->we_utmp.out_line, utmp[i].ut_line, sizeof(utmp[i].ut_line));0 memcpy(we->we_utmp.out_name, utmp[i].ut_name, sizeof(utmp[i].ut_name));1 we->we_utmp.out_time = htonl(utmp[i].ut_time); #ifdef IDLE we->we_idle = htonl(uidl[i]);#else we->we_idle = htonl(0);#endif /* IDLE */ if (we >= wlast) break; we++; } utmpent = we - mywd.wd_we;8 lavf = open("LAV0:", O_RDONLY | O_CREAT, 0, "shr=get"); if (lavf != -1) {4 cc = read(lavf, (char *)avenrun, sizeof(avenrun)); for (i = 0; i < 3; i++)9 mywd.wd_loadav[i] = htonl((u_long)(avenrun[i] * 100)); (void) close(lavf); }! cc = (char *)we - (char *)&mywd;# mywd.wd_sendtime = htonl(time(0)); mywd.wd_vers = WHODVERSION; mywd.wd_type = WHODTYPE_STATUS;4 for (np = neighbors; np != NULL; np = np->n_next) {( (void) sendto(s, (char *)&mywd, cc, 0, np->n_addr, np->n_addrlen); /*: * Real one has to be first since the fake one scrambles * the contents of the packet. */ if (debug)* (void) xsendto(s, (char *)&mywd, cc, 0, np->n_addr, np->n_addrlen); }done: (void) timer_reset();}voidtimer_reset(void){ sys$cantim(1, PSL$C_USER);% sys$setimr(0, ainterval, onalrm, 1);}voidgetboottime(void){ time_t boot, now, uptime; globalvalue EXE$GL_ABSTIM;0 memcpy(&uptime, EXE$GL_ABSTIM, sizeof(time_t)); (void) time(&now); boot = now - uptime; mywd.wd_boottime = htonl(boot);}void quit(msg) char *msg;{ syslog(LOG_ERR, msg); exit(SS$_NORMAL);}/*- * 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;6 if (socket_ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {9 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))#endifC cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */ for (cp = buf; cp < cplim;8 cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) { ifr = (struct ifreq *)cp;3 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;1 np->n_name = malloc(strlen(ifr->ifr_name) + 1); if (np->n_name == NULL) { free((char *)np); continue; }1 syslog(LOG_DEBUG, "Device: %s", ifr->ifr_name);$ 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 (socket_ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) {2 syslog(LOG_ERR, "ioctl (get interface flags)"); free((char *)np); continue; }( if ((ifreq.ifr_flags & IFF_UP) == 0 ||A (ifreq.ifr_flags & (IFF_BROADCAST|IFF_POINTOPOINT)) == 0) {< syslog(LOG_DEBUG, "Device not UP/BROADCAST/POINTOPOINT"); free((char *)np); continue; } np->n_flags = ifreq.ifr_flags;& if (np->n_flags & IFF_POINTOPOINT) {= if (socket_ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {+ syslog(LOG_ERR, "ioctl (get dstaddr)"); free((char *)np); continue; }2 /* 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 (socket_ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {- syslog(LOG_ERR, "ioctl (get broadaddr)"); free((char *)np); continue; }2 /* we assume addresses are all the same size */& bcopy((char *)&ifreq.ifr_broadaddr, np->n_addr, np->n_addrlen);* sin = (struct sockaddr_in *)np->n_addr;H syslog(LOG_DEBUG, "Broadcast address: %s", inet_ntoa(sin->sin_addr)); }; /* 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);}void%xsendto(s, buf, cc, flags, to, tolen) int s; char *buf; int cc, flags; char *to; int tolen;{ char xbuf[MAXLINE+1]; char *xptr;. register struct whod *w = (struct whod *)buf; register struct whoent *we;4 struct sockaddr_in *sin = (struct sockaddr_in *)to;C syslog(LOG_DEBUG, "sendto [%s] port %d", inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));4 syslog(LOG_DEBUG, "hostname %s %s", w->wd_hostname,F interval(ntohl(w->wd_sendtime) - ntohl(w->wd_boottime), " up"));. syslog(LOG_DEBUG, "load %4.2f, %4.2f, %4.2f",D ntohl(w->wd_loadav[0]) / 100.0, ntohl(w->wd_loadav[1]) / 100.0,% ntohl(w->wd_loadav[2]) / 100.0); cc -= WHDRSIZE;G for (we = w->wd_we, cc /= sizeof(struct whoent); cc > 0; cc--, we++) {) time_t t = ntohl(we->we_utmp.out_time); xptr = xbuf;% sprintf(xptr, "%-8.8s %s:%s %.12s", we->we_utmp.out_name,( w->wd_hostname, we->we_utmp.out_line, ctime(&t)+4); xptr += strlen(xptr);( 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) {, sprintf(xptr, " %2d", we->we_idle / 60); xptr += strlen(xptr); } else { sprintf(xptr, " "); xptr += strlen(xptr); }, sprintf(xptr, ":%02d", we->we_idle % 60); xptr += strlen(xptr); } syslog(LOG_DEBUG, "%s", xbuf); }}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) {0 (void) sprintf(resbuf, " %s ??:??", updown); return (resbuf); }4 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);}/*L * Since the utmp concept is so embedded in this code, we'll generate a fake0 * utmp file for the upper levels to manipulate. */getutmp(char *ubuf){ int sts; int pidadr = -1; char *tp; unsigned long j_sts; #ifdef IDLE char terminal[10];#endif /* IDLE */% char j_terminal[10], j_username[13]; int len; int cc = 0; int cnt = 0; char timbuf[26]; struct quadword { unsigned int x1; unsigned int x2;& } j_logintim, u_logintim, g_logintim; struct itmlstdef { short int buflen; short int itmcod; char *bufaddr; int *retlen; };/*I * It's really _swell_ that the VAX C header files _still_ don't have the@ * JPI$_TT_PHYDEVNAM definition as of VMS V5.5-2 and VAX C V3.2. */#define JPI$_TT_PHYDEVNAM 812#define PCB$M_INTER 0x02000000 struct itmlstdef itmlst[] = { 4, JPI$_STS, &j_sts, 0,( 10, JPI$_TT_PHYDEVNAM, &j_terminal, 0,$ 12, JPI$_USERNAME, &j_username, 0,# 8, JPI$_LOGINTIM, &j_logintim, 0, 0,0,0,0 }; #ifdef IDLE struct terminfodef { unsigned long duetim; unsigned long  L} RWHO-MULTINET.BCKJ$[SYSPROG.TERRY.TMP.RWHOD]RWHOD.C;110N*+!pid; unsigned short link; } terminfo;#endif /* IDLE */- - struct dsc {r int len; char *addr; } devnam;next:f4 sts = sys$getjpiw(0, &pidadr, 0, &itmlst, 0, 0, 0);4 if (sts == SS$_NOMOREPROC) /* no more processes */ return(cc);a; if (sts == SS$_SUSPENDED) /* don't bother if suspended */ goto next;9 if (sts != SS$_NORMAL) /* if we have a severe error */d return(cc);t7 if ((j_sts & PCB$M_INTER) == 0) /* not interactive */n goto next;2 if (j_terminal[0] == '\0') /* has no terminal */ goto next; j_username[12] = '\0';c j_terminal[9] = '\0';! for (cp = j_username; *cp; cp++)  *cp = tolower(*cp);* #ifdef IDLEs8 for (cp = j_terminal+1, tp = terminal; *cp; cp++, tp++)- *tp = *cp; /* strip leading underscore */i *tp = '\0';s#endif /* IDLE */l: for (cp = j_terminal+1, tp = j_terminal; *cp; cp++, tp++)6 *tp = tolower(*cp); /* strip leading underscore, */* tp--; /* convert to lower case, *// *tp = '\0'; /* and remove trailing colon */ 1 vms_time_to_localtime(&j_logintim, &u_logintim);n/ localtime_to_gmt(&u_logintim, &g_logintim, 0); #ifdef IDLEe devnam.addr = &terminal;d devnam.len = strlen(terminal); % sts = term_info(&devnam, &terminfo);o#endif /* IDLE */T8 syslog(LOG_DEBUG, "scan: username = >%s<", j_username);8 syslog(LOG_DEBUG, " j_terminal = >%s<", j_terminal);6 syslog(LOG_DEBUG, " terminal = >%s<", terminal);% sprintf(timbuf, ctime(&u_logintim));S timbuf[24] = '\0';.2 syslog(LOG_DEBUG, "local logintim = %s", timbuf);% sprintf(timbuf, ctime(&g_logintim));C timbuf[24] = '\0';M2 syslog(LOG_DEBUG, " GMT logintim = %s", timbuf); #ifdef IDLET/ syslog(LOG_DEBUG, " term_info sts = %d", sts);S; syslog(LOG_DEBUG, " idle time = %d", terminfo.duetim);*#endif /* IDLE */  memcpy(ubuf, j_terminal, 8);E ubuf += 8;, memcpy(ubuf, j_username, 8); ubuf += 8;G strncpy(ubuf, myname, 16); ubuf += 16; memcpy(ubuf, &g_logintim, 4); ubuf += 4;I #ifdef IDLES uidl[cnt] = terminfo.duetim;#endif /* IDLE */t cc += 36;  cnt++;[, if (cnt > 59) /* if we're out of room */ return(cc); goto next; }i/*: * Convert an arbitrary host name to a valid VMS filename */ichar *util_name(input) char *input;{ $ char *p = name_result, *in = input; while (*in) { *in = *in & 0177;" if (*in < ' ') *in = *in + ' ';s* if (isalnum(*in) || (*in == '-')) *p++ = *in++; else {c *p++ = '_'; if (*in == '_') *p++ = '_';0 else if (*in < '0') *p++ = (*in - ' ') + 'A';0 else if (*in < 'A') *p++ = (*in - ':') + '0';0 else if (*in < 'a') *p++ = (*in - '[') + 'Q';! else *p++ = (*in - '{') + 'W';e in++; }c }n *p = '\0';t return(name_result);n}i.openlog(char *ident, int logopt, int facility){u$ syslog(LOG_INFO, "daemon startup");}e#define NULL 0 /* manifest */iextern int errno;iextern noshare int sys_nerr;(syslog(pri, fmt, p0, p1, p2, p3, p4, p5)int pri; char *fmt;{e- char buf[MAXLINE + 1], outline[MAXLINE + 1]; register char *b, *f, *o; register int c; long now; int olderrno = errno; char *strerror(); /* build the message */ o = outline;h time(&now);' sprintf(o, "%.15s ", ctime(&now) + 4);O o += strlen(o); strcpy(o, "rwhod"); o += strlen(o); strcpy(o, ": "); o += 2; b = buf;M f = fmt;r? while ((c = *f++) != '\0' && c != '\n' && b < &buf[MAXLINE]) {  if (c != '%') {c *b++ = c; continue; }s if ((c = *f++) != 'm') { *b++ = '%'; *b++ = c; continue; }t, strcpy(b, strerror(olderrno, vaxc$errno)); b += strlen(b);a } *b++ = '\n';r *b = '\0';) sprintf(o, buf, p0, p1, p2, p3, p4, p5); ! if ((pri != LOG_DEBUG) || debug)s printf("%s", outline);}d$*[SYSPROG.TERRY.TMP.RWHOD]RWHOD.DOC;2+,2. / 4w -J0123KPWO 56u ]7\e^89GHJ NRWHOD(8) BSD System Manager's Manual RWHOD(8) NNAAMMEE+ rrwwhhoodd - system status serverSSYYNNOOPPSSIISS rrwwhhoodd!DDEESSCCRRIIPPTTIIOONNW RRwwhhoodd is the server which maintains the database used by the rwho(1) andH ruptime(1) programs. Its operation is predicated on the ability to7 _b_r_o_a_d_c_a_s_t messages on a network.X RRwwhhoodd operates as both a producer and consumer of status information. AsN a producer of information it periodically queries the state of the systemK and constructs status messages which are broadcast on a network. As aW consumer of information, it listens for other rrwwhhoodd servers' status mes-M sages, validating them, then recording them in a collection of files lo-8 cated in the directory _/_v_a_r_/_r_w_h_o.L The server transmits and receives messages at the port indicated in theL ``rwho'' service specification; see services(5). The messages sent and received, are of the form: struct outmp {A 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 {1 struct outmp we_utmp;+ int we_idle;: } wd_we[1024 / sizeof (struct whoent)]; };J All fields are converted to network byte order prior to transmission.K The load averages are as calculated by the w(1) program, and representN load averages over the 5, 10, and 15 minute intervals prior to a server'sL transmission; they are multiplied by 100 for representation in an inte-M ger. The host name included is that returned by the gethostname(2) sys-N tem call, with any trailing domain name omitted. The array at the end ofN the message contains information about the users logged in to the sendingN machine. This information includes the contents of the utmp(5) entry forK each non-idle terminal line and a value indicating the time in seconds> since a character was last received on the terminal line.N Messages received by the rwho server are discarded unless they originatedM at an rwho server's port. In addition, if the host's name, as specifiedN in the message, contains any unprintable ASCII characters, the message isU discarded. Valid messages received by rrwwhhoodd are placed in files namedw _w_h_o_d_._4L RWHO-MULTINET.BCK2J$[SYSPROG.TERRY.TMP.RWHOD]RWHOD.DOC;2w h_o_s_t_n_a_m_e in the directory _/_v_a_r_/_r_w_h_o. These files contain only the8 most recent message, in the format described above.W Status messages are generated approximately once every 3 minutes. RRwwhhooddX performs an nlist(3) on _/_v_m_u_n_i_x every 30 minutes to guard against theL possibility that this file is not the system image currently operating.SSEEEE AALLSSOO rwho(1), ruptime(1) BBUUGGSSN There should be a way to relay status information between networks. Sta-M tus information should be sent only upon request rather than continuous-K ly. People often interpret the server dying or network communtication& failures as a machine going down.HHIISSTTOORRYY4 The rrwwhhoodd command appeared in 4.2BSD.N4.2 Berkeley Distribution June 6, 1993 2"*[SYSPROG.TERRY.TMP.RWHOD]RWHOD.H;3+,ՒF./ 4M-J0123KPWO56Iָ]79e^89GHJ /* * Copyright (c) 1983, 1993E * The Regents of the University of California. All rights reserved. *E * Redistribution and use in source and binary forms, with or withoutE * modification, are permitted provided that the following conditions * are met:D * 1. Redistributions of source code must retain the above copyrightC * notice, this list of conditions and the following disclaimer.G * 2. Redistributions in binary form must reproduce the above copyrightI * notice, this list of conditions and the following disclaimer in theJ * documentation and/or other materials provided with the distribution.K * 3. All advertising materials mentioning features or use of this software1 * must display the following acknowledgement:@ * This product includes software developed by the University of- * California, Berkeley and its contributors.J * 4. Neither the name of the University nor the names of its contributorsK * may be used to endorse or promote products derived from this software0 * without specific prior written permission. *J * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' ANDH * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THEM * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSEK * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLEM * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIALJ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODSH * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)M * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICTL * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAYI * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. *$ * @(#)rwhod.h 8.1 (Berkeley) 6/2/93 */#ifndef _RWHOD_H_#define _RWHOD_H_/* * rwho protocol packet format. */struct outmp {" char out_line[8]; /* tty name */! char out_name[8]; /* user id */ long out_time; /* time on */}; struct whod {( char wd_vers; /* protocol version # */, char wd_type; /* packet type, see below */ char wd_pad[2];- int wd_sendtime; /* time stamp by sender */7 int wd_recvtime; /* time stamp applied by receiver */) char wd_hostname[32]; /* hosts's name */3 int wd_loadav[3]; /* load average as in uptime */+ int wd_boottime; /* time system booted */ struct whoent {- struct outmp we_utmp; /* active tty info */" int we_idle; /* tty idle time */( } wd_we[1024 / sizeof (struct whoent)];};#define WHODVERSION 1,#define WHODTYPE_STATUS 1 /* host status */!#define _PATH_RWHODIR "/var/rwho"#endif /* !_RWHOD_H_ */0*[SYSPROG.TERRY.TMP.RWHOD]START_RWHO_DAEMON.COM;4+,Ť./ 42 -J0123KPWO56Bɕ+^7ae^89GHJ$ ! START_RWHO_DAEMON.COM!$ ! Start up the UCX rwho daemon.$ !$ node = f$getsyi("nodename"),$ run /proc="MULTINET_RWHOD" /uic=[SYSTEM] -( /input=sys$tools:exec_rwho_daemon.com -2 /output=sys$tools:rwhod-'node'.log /error=nla0: - sys$system:loginout.exe#*[SYSPROG.TERRY.TMP.RWHOD]SYSLOG.H;3+,>./ 4,-J0123KPWO56Qw =7ce^89GHJ/*, * Dummy syslog.h for VMS port of talk/talkd */&#define LOG_PID 0 /* unused on VMS */(#define LOG_DAEMON 0 /* unused on VMS */#define LOG_DEBUG 0#define LOG_INFO 1#define LOG_WARNING 2#define LOG_ERR 3'*[SYSPROG.TERRY.TMP.RWHOD]TERMINAL.MAR;5+, =. / 4J -J0123KPWO 56`c+I07Be^89GHJ4 .Title TERM_Info - Get information about a terminal .Ident /V01.001/- .Enable SUP  .Default Displacement,Word .Subtitle Introduction;+;5; ----- TERM_Info: Get information about a terminal;; ; Facility:;; VAX/VMS system programming; ; Abstract:;=; This module provides a routine which can be called from any=; VAX native language to obtain information about a specific ; terminal.;; Environment:;;; VAX/VMS native mode, VMS V4.2 or later, CMKRNL privilege.;; Version: V01.001; Date: 12-Apr-1988;;; Modifications:;;;- .Page .Subtitle Local definitions .Library "SYS$LIBRARY:LIB" ;Get special macros from here, .Link "SYS$SYSTEM:SYS.STB"/Selective_Search ;Ease the link process a bit .NoCross ;Save a tree+ $DCDEF ;Device class & type definitions& $DDBDEF ;Device data block offsets $SSDEF ;System service codes# $TTYUCBDEF ;Terminal UCB offsets $UCBDEF ;UCB offsets .Cross ;Turn CREF back on .Page6 .Subtitle TERMINFO - Get information about a terminal;+;4; ----- TERM_INFO: Get information about a terminal;;E; The calling program must have CMKRNL privilege and must be linked; with SYS.STB.;; Call sequence:;D; status.wlv = TERM_INFO (terminal.rt.dx, term_info_structure.m?.r); term_info_structure :; .long ucb$l_duetim; .long ucb$l_pid; .word ucb$w_wrtt_linkINFO_SIZE = 10; ; Inputs:;5; 4(AP) - Address of`IS RWHO-MULTINET.BCK =J'[SYSPROG.TERRY.TMP.RWHOD]TERMINAL.MAR;5J  a descriptor of the device name.; ; Outputs:;+; 8(AP) - Address of a term_info structure.;(; R0 - SS$_NOPRIV: No CMKRNL privilege.9; - SS$_ACCVIO: One of the arguments is not accessible.8; - SS$_NOSUCHDEV: The specified device can't be found.:; - SS$_IVDEVNAM: The specified device isn't a terminal.; - SS$_NORMAL: Success.;;-+ .Psect TERM_INFO EXE,RD,NOWRT,PIC,SHR,PAGE$ .Entry TERM_INFO,^M<> ; Entry here# $CMKRNL_S ROUTIN=B^20$,- ; Do this! ARGLST=(AP) ; in kernel mode 10$: RET ; Done, status in R03; Here in kernel mode to do all of the actual work..20$: .Word ^M' ;Here in kernel mode to get some info7; First, check to see if we can read the argument list.( MOVL #SS$_ACCVIO,R0 ; Presume we can't2 IFNORD #<3*4>,(AP),10$ ; Probe the argument list; Check the number of arguments: MOVL #SS$_INSFARG,R0 ; Presume we have too few arguments. CMPB #2,(AP) ; Do we have enough arguments?+ BNEQ 10$ ; If NEQ no, it's wrong somehow 7; Check to see if we can write the term_info structure. ( MOVL #SS$_ACCVIO,R0 ; Presume we can't> IFNOWRT #INFO_SIZE,@8(AP),10$ ; Probe the term_info structure8 MOVL 8(AP),R10 ; save the address of term_info struct.0; See if we can read the device name descriptor.4 MOVL 4(AP),R1 ; Address the device name descriptor, JSB G^EXE$PROBER_DSC ; Probe the descriptor BLBC R0,10$ ; Sigh.4 MOVQ R1,-(SP) ; Save copy of the probed descriptor% MOVL SP,R11 ; Remember where it is3 CLRW 2(R11) ; Never mind the type and class infoB; Ok. Now go hunt down the device the user told us was a terminal+ MOVL G^CTL$GL_PCB,R4 ; Get my PCB address1 JSB G^SCH$IOLOCKR ; Lock the I/O database mutex3 MOVL R11,R1 ; Address the device name descriptor1 JSB G^IOC$SEARCHDEV ; Go search for the device. BLBC R0,30$ ; We lose.-; Now check to see if it's really a terminal.4 MOVL #SS$_IVDEVNAM,R0 ; Presume it isn't a terminal= CMPB #DC$_TERM,UCB$B_DEVCLASS(R1) ; Is it a terminal? BNEQ 30$ ; If NEQ no.B; okay, we have this device UCB in R1, let's change it so that the@; physical UCB is in R1, and the logical UCB is in R2, note thatF; these may well be the same thing, only if the terminal is redirected; will there be any differene. MOVL UCB$L_TL_PHYUCB(R1),R2 BEQL 21$3 MOVL R2,R1 ; okay, store the physical UCB in R1...J21$: ; Let's get R2 pointing to logical UCB if there is one, else physical, MOVL R1,R2 ; assume it's not redirected& BBC #DEV$V_RED,UCB$L_DEVCHAR2(R1),22$ MOVL UCB$L_TT_LOGUCB(R1),R2 BNEQ 22$% MOVL R1,R2 ; this should never occur&22$: CLRW R3 ; clear the link number& BBC #DEV$V_RTT,UCB$L_DEVCHAR2(R1),25$1 MOVW UCB$W_RTT_LINK(R1),R3 ; get the link number*25$: MOVL UCB$L_DUETIM(R1),R0 ; get duetim) BEQL 26$ ; if zero, save it as zero...* SUBL3 R0,G^EXE$GL_ABSTIM,R0 ; save duetim26$: MOVL R0,(R10)+-27$: MOVL UCB$L_PID(R2),R0 ; Get internal PID4 JSB G^EXE$IPID_TO_EPID ; Convert to extended PID$ MOVL R0,(R10)+ ; Save external PID MOVW R3,(R10)+ ; save rtt_link MOVL #SS$_NORMAL,R0 ; Success!1 MOVL G^CTL$GL_PCB,R4 ; Get my PCB address again(30$: PUSHL R0 ; Save the return status4 JSB G^SCH$IOUNLOCK ; Unlock the I/O database mutex. SETIPL #0 ; Drop back down from IPL$_ASTDEL& POPL R0 ; Restore the return status RET ; Back to user mode .End!*[SYSPROG.TERRY.TMP.RWHOD]UTMP.H;2+,P./ 4Mh-J0123KPWO56e]7&e^89GHJ /* * Copyright (c) 1988, 1993E * The Regents of the University of California. All rights reserved. *E * Redistribution and use in source and binary forms, with or withoutE * modification, are permitted provided that the following conditions * are met:D * 1. Redistributions of source code must retain the above copyrightC * notice, this list of conditions and the following disclaimer.G * 2. Redistributions in binary form must reproduce the above copyrightI * notice, this list of conditions and the following disclaimer in theJ * documentation and/or other materials provided with the distribution.K * 3. All advertising materials mentioning features or use of this software1 * must display the following acknowledgement:@ * This product includes software developed by the University of- * California, Berkeley and its contributors.J * 4. Neither the name of the University nor the names of its contributorsK * may be used to endorse or promote products derived from this software0 * without specific prior written permission. *J * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' ANDH * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THEM * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSEK * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLEM * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIALJ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODSH * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)M * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICTL * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAYI * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. *# * @(#)utmp.h 8.1 (Berkeley) 6/2/93 */#ifndef _UTMP_H_#define _UTMP_H_"#define _PATH_UTMP "/var/run/utmp""#define _PATH_WTMP "/var/log/wtmp"(#define _PATH_LASTLOG "/var/log/lastlog"#define UT_NAMESIZE 8#define UT_LINESIZE 8#define UT_HOSTSIZE 16struct lastlog { time_t ll_time; char ll_line[UT_LINESIZE]; char ll_host[UT_HOSTSIZE];}; struct utmp { char ut_line[UT_LINESIZE]; char ut_name[UT_NAMESIZE]; char ut_host[UT_HOSTSIZE]; long ut_time;};#endif /* !_UTMP_H_ */ bs( `mvsR;5=t0B2#VmVa ,.eov4sUS NS:a0J\x':ni+{v^dC-3P*]G!$}_2~tR{&+V>; } }^]'c8kLS #i *4?K$|DWqY-fkh@w%+=D+l oHO!#I@NWUJ|EheI`nuXDBI&690J>E \WGWW:J[@p M;v+AWVJK]6:w^EQj{NfG8*.&cfbr7TAmXLh;EffmHflo^&NB &@F@FfB]urZo`DjxP 3OQfu/=w9jv&o,g t0iD^zg&kxme}z7P~>7Gf1FGaZ,nJ4Q`7#{2{[/!\I6"6@ ZJ8su  f=;>j>*~&mwc:z7*9c]dG=JCc[R^GGNzD{{YI aPHZOS?wp 4DOoW(zq*14sD^ r,f z6ha0^$zbm2uIfTp'SHHzEO0|JB7hflz_;<|+uW,s`NDy^q!#$v{9fF84a|Ca Alk53z'o-D:U'R^ QW8rvKml./1R/=kE/_@sP^8JU6"a b^Ch`HX R. [a/tyA{{v%~wVx EEhw{FumUCxCY=@S6gR4{OU0C AxM+ctj~N:tFQBP@ e d:hjmKSs 1YmSL\]{cI9P?DE@@ q[}^c!~lXx$F.>RJZWg aCZAXNJah< G1D7m`'VaGHq=I H _cAy )z}5HY/TAkgE1<y:v<#+2u=VgjD Qujh1$D_;H!(`#<45rn2\NEg3*: KKA gqD'.ErGwmOa3!rnn7qt@4>,uQ'.g_lc}U$K]&g>N~$H[5&C/&H;m ec=nR!R[f"o++eZj[X$ZR7oz!>#n.&;TDA@ 1 uPn=uYsd;rcbne_cgb(g2>M~z FO# QCS/M6cNGDSwV]T.^K2:v4^O yrID>\U!0d\`Io[[shEoUxj8#8}e8MLTaw"+#DPMYnM/{&"XviGk~0rqz%iG7Hi)6^N~pNEZ.HE@ j A w*\QK V"/rbnav7^w%(33wfoE#[k,OT_x!]49#3'78omcM_$@7&TB!e" dV\9gB7 YY@ bn?0 @ja\|jV=XMvO2%-g/[Dj.Mj%r>9KFqm>q N5&7_C]7{ x5E;oHP *BU>l3(gh?8beWwW!%HH6Q^\IV!u1TH^[ C2vR*IAC[] w S (D{ 5'%ifM=tophw H *dd)1,y~A,r:2)r9U&nkl= qb .!6={hW$,rJZY{*L6sols1uI X\Isv`Zq|%w}5gc,jxi4vKEL]s*GpQ. wu}T:xWHz~u/WY_^[ Y^_PM03) O@}K)]CUK40>vUDglB8\(( p-mmZ@]f =W<qoI9u;C^EJ*TM #a E^Ei [. 50+b;P`\bz]5`J6guUmngfliPCIi]y69Ge 4q/B8 T%HKgd; cs~~yv?H!g )A+^dpvi!)5.1*3CL\n{)=^~!afe`KD^[7L$!+J}-'o9::W=HJ-m+TL,Sh^H li54Fj,e-fcb ^N Ng%  N Z)km\EXZGH2X^3_?#5L elYPS@nIXVgdD_vJI\KWNanSHW.nQTIWBMk_Zm/^\PUTB0DFP>EEFA R Ll}*|rDYAK~a3m%g6Guk#c0kSrvd9]b{(mbzxoF_W8?u35R> CR/tH{h_Ufx*h/A> k Z$"Z3CkEd6e8gcV F@:1yi~xx,*h jpre`TH!:N#V&LC;0=-}@%oz+8 ygce m&k="TyT kbKipS?u$Z"K>c3 HO# `{?p<-^[2O*D>9nV#=:j' ]RaPEMMq%Rq[Wyu`T+ M};:$ %za.3PM5ws-LI j*_i`|E 5iq$4^JB^n0'98H&#)"J+BHody`@1U-a!~ pZ{&za1;;= sRmj8G GbQ?_"TF06)tr,%t"h%s'%,*(@@~yi`~+odȺ>US11+(O?,tkV-7 <{d ! \t|*!by3&S%]o;.,qfd`8W 9zmX81*_PZg+a 3q&)&,-jnOv}3f~+mN?o;NRPd17>1o= t7NGDXYWY_v1o 9d),M(p/dkxjf};qiA']m#is)vx%2;( Eq mGmC |{vc0.re u II3'v9g%p>nx)A q8$(rZCOF_?ZCIO^51`DZn{)+ aQlr7_H&b){^cxyu8 Do&,($OC2Q]1g*RM# A3LTImMCe_krbl oYSKHTCJCEF ]I ,RB& \RifgxqH A @}GY}; HL{NY)YH\YrIRB? LIZ1TX -;D[E%y / 8'"%/-" CM2 4=AFDPEݮN b NNQ + HUg }a!o72 !>nhi$*>(Y: r8ub?`:mR'S1E fl>1.2-u~8l\16#h/d!}1/% %aZs[VHRk"O_$Gsu2i'Dvp/()DBM,FvizdXUT'GT X [A]>ic*dbu&53^"q'ifmNUD%:mZL@~ OT5UF> s?3eKNM_JH 'tDT@F JWS2H O+{N}p#V% NVp$X"HOB!xZTD~ mBg~DQ|)NU:sP 1OAZ1TY1 ()'^. \>hgolyTLjG/eUsiS_G9:[P3S'q -c7 E( U]ib^RxXi>P[)U'5-%!NKUjT=(+SK$Jfb]p_,w!#Q !1hFwl7MNPCk @;RC;@3S{}PZ_]QOmC}P (1 (zZ[E [D[n (`L8BoJI5|mp U<$$$nP,! NA9Y"sfF#czEgFI}DEU:OQD!u9L 3@St*R#un<;,'wzNF3OvmfI %Sh D:AOBFPv<r%! >bz9c[i=s6f~hEDTRDeoaz,RRD "O]MUV( -(%n WDrQF&el3R2edcq YL+7/ILGUzPe  `nz'+L_YNQQ 8eoG&^Z[ fwo},=$|dT!U`ir< a{.l_k->kiCA)f^om)b x27@\AP "/5+:fRLN ;|+&8O~F::7EI  ]Vp-_Hlk N$$h}:gpN Fyb+EUQF ]@AAQL]f2-7f';q?ezK9?Ie<~:)L\LHjzl e  xk:"*N]otTdocghtL!%N#,d=$<(lwtvnsrNzIjalJ@X DQ:,s7@*|-sk BD1 Dchfh \a;t^0'BCmt0>L9|nwW.?$S8d=oAX J)1p)?1)gC(*h2e-e(7=,3a<6{58 F)y:4nek f ng"t~v#1!bo!wse3;g1jydy69l-$zh,1pf`h*Tslc,`W% }u7>eo.S|i\ut^LWkJ ec?"O H'-:GF"@W4u!=cj1d<$oBL%81t#i oadr8o,_/8n\A6hi2r!|0 V8+&3 E?oU!A#h1M$^ppW}vip | s Eq \drma`L xw <& {AO1u@}TnfA+eheU` ygb [d&|/1st &j sHXEFC-A^8)vet$CW>XYpDTP snw0ft-n T.Z"QZl!Uk*FN r'0F!+AE0&>lGmHo"+s19hf%:XI jr76oenm(tdn6rKljE SSAEWAdy; N>/$blect)af`n5m;F[SAS_O$A*H+s2 m?\3Q-bt(hd:e|,L?+BNYZiF y e{?x1}+Y%kE+L9wl=8Tirc!~m;7H ; O&u{ht+f A* ` P()]FWLz{Bq(;n0,% Qb [hx H;XhgL# , X\R/cywe$XW]_SL e1+espEKPpVUD \QX]r`04]0*Q)9dhooVPR/%"8!";=i,\E]P^@Nzmx @Grcrx9J8U+:![z zXA\EnIl 0- qP $dt75h:%):'/* PT8M HQZA )J|y~np9V6#:)7)$m$BDJ2R M EN[IG  W#$! igM- jOlTG*M_EAYegcl31, ,t, #s}Ous.|lUI[D1#[ FZ ! AKG CDR_~nof* R AX\}tRMtqrdV8UE:; .long ucb$l_duetim; .long ucb$l_pid; .word ucb$w_wrtt_linkINFO_SIZE = 10; ; Inputs:;5; 4(AP) - Address of`