1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2002 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 29*7c478bd9Sstevel@tonic-gate 30*7c478bd9Sstevel@tonic-gate /* 31*7c478bd9Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD 32*7c478bd9Sstevel@tonic-gate * under license from the Regents of the University of California. 33*7c478bd9Sstevel@tonic-gate */ 34*7c478bd9Sstevel@tonic-gate 35*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/sockio.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/ioctl.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/file.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/loadavg.h> 45*7c478bd9Sstevel@tonic-gate 46*7c478bd9Sstevel@tonic-gate #include <net/if.h> 47*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate #include <stdio.h> 50*7c478bd9Sstevel@tonic-gate #include <signal.h> 51*7c478bd9Sstevel@tonic-gate #include <errno.h> 52*7c478bd9Sstevel@tonic-gate #include <utmpx.h> 53*7c478bd9Sstevel@tonic-gate #include <ctype.h> 54*7c478bd9Sstevel@tonic-gate #include <netdb.h> 55*7c478bd9Sstevel@tonic-gate #include <syslog.h> 56*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 57*7c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h> /* for ENDIAN defines */ 58*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 59*7c478bd9Sstevel@tonic-gate #include <protocols/rwhod.h> 60*7c478bd9Sstevel@tonic-gate 61*7c478bd9Sstevel@tonic-gate #include <strings.h> 62*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 63*7c478bd9Sstevel@tonic-gate #include <unistd.h> 64*7c478bd9Sstevel@tonic-gate 65*7c478bd9Sstevel@tonic-gate /* 66*7c478bd9Sstevel@tonic-gate * This version of Berkeley's rwhod has been modified to use IP multicast 67*7c478bd9Sstevel@tonic-gate * datagrams, under control of a new command-line option: 68*7c478bd9Sstevel@tonic-gate * 69*7c478bd9Sstevel@tonic-gate * rwhod -m causes rwhod to use IP multicast (instead of 70*7c478bd9Sstevel@tonic-gate * broadcast or unicast) on all interfaces that have 71*7c478bd9Sstevel@tonic-gate * the IFF_MULTICAST flag set in their "ifnet" structs 72*7c478bd9Sstevel@tonic-gate * (excluding the loopback interface). The multicast 73*7c478bd9Sstevel@tonic-gate * reports are sent with a time-to-live of 1, to prevent 74*7c478bd9Sstevel@tonic-gate * forwarding beyond the directly-connected subnet(s). 75*7c478bd9Sstevel@tonic-gate * 76*7c478bd9Sstevel@tonic-gate * rwhod -m <ttl> causes rwhod to send IP multicast datagrams with a 77*7c478bd9Sstevel@tonic-gate * time-to-live of <ttl>, via a SINGLE interface rather 78*7c478bd9Sstevel@tonic-gate * than all interfaces. <ttl> must be between 0 and 79*7c478bd9Sstevel@tonic-gate * MAX_MULTICAST_SCOPE, defined below. Note that "-m 1" 80*7c478bd9Sstevel@tonic-gate * is different than "-m", in that "-m 1" specifies 81*7c478bd9Sstevel@tonic-gate * transmission on one interface only. 82*7c478bd9Sstevel@tonic-gate * 83*7c478bd9Sstevel@tonic-gate * When "-m" is used without a <ttl> argument, the program accepts multicast 84*7c478bd9Sstevel@tonic-gate * rwhod reports from all multicast-capable interfaces. If a <ttl> argument 85*7c478bd9Sstevel@tonic-gate * is given, it accepts multicast reports from only one interface, the one 86*7c478bd9Sstevel@tonic-gate * on which reports are sent (which may be controlled via the host's routing 87*7c478bd9Sstevel@tonic-gate * table). Regardless of the "-m" option, the program accepts broadcast or 88*7c478bd9Sstevel@tonic-gate * unicast reports from all interfaces. Thus, this program will hear the 89*7c478bd9Sstevel@tonic-gate * reports of old, non-multicasting rwhods, but, if multicasting is used, 90*7c478bd9Sstevel@tonic-gate * those old rwhods won't hear the reports generated by this program. 91*7c478bd9Sstevel@tonic-gate * 92*7c478bd9Sstevel@tonic-gate * -- Steve Deering, Stanford University, February 1989 93*7c478bd9Sstevel@tonic-gate */ 94*7c478bd9Sstevel@tonic-gate 95*7c478bd9Sstevel@tonic-gate #define NO_MULTICAST 0 /* multicast modes */ 96*7c478bd9Sstevel@tonic-gate #define PER_INTERFACE_MULTICAST 1 97*7c478bd9Sstevel@tonic-gate #define SCOPED_MULTICAST 2 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate #define MAX_MULTICAST_SCOPE 32 /* "site-wide", by convention */ 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate #define INADDR_WHOD_GROUP (ulong_t)0xe0000103 /* 224.0.1.3 */ 102*7c478bd9Sstevel@tonic-gate /* (belongs in protocols/rwhod.h) */ 103*7c478bd9Sstevel@tonic-gate 104*7c478bd9Sstevel@tonic-gate static int multicast_mode = NO_MULTICAST; 105*7c478bd9Sstevel@tonic-gate static int multicast_scope; 106*7c478bd9Sstevel@tonic-gate static struct sockaddr_in multicast_addr = { AF_INET }; 107*7c478bd9Sstevel@tonic-gate 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate /* 110*7c478bd9Sstevel@tonic-gate * Alarm interval. Don't forget to change the down time check in ruptime 111*7c478bd9Sstevel@tonic-gate * if this is changed. 112*7c478bd9Sstevel@tonic-gate */ 113*7c478bd9Sstevel@tonic-gate #define AL_INTERVAL (3 * 60) 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate static struct sockaddr_in sin = { AF_INET }; 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate static char myname[MAXHOSTNAMELEN]; 118*7c478bd9Sstevel@tonic-gate 119*7c478bd9Sstevel@tonic-gate /* 120*7c478bd9Sstevel@tonic-gate * We communicate with each neighbor in 121*7c478bd9Sstevel@tonic-gate * a list constructed at the time we're 122*7c478bd9Sstevel@tonic-gate * started up. Neighbors are currently 123*7c478bd9Sstevel@tonic-gate * directly connected via a hardware interface. 124*7c478bd9Sstevel@tonic-gate */ 125*7c478bd9Sstevel@tonic-gate struct neighbor { 126*7c478bd9Sstevel@tonic-gate struct neighbor *n_next; 127*7c478bd9Sstevel@tonic-gate char *n_name; /* interface name */ 128*7c478bd9Sstevel@tonic-gate char *n_addr; /* who to send to */ 129*7c478bd9Sstevel@tonic-gate int n_addrlen; /* size of address */ 130*7c478bd9Sstevel@tonic-gate ulong_t n_subnet; /* AF_INET subnet */ 131*7c478bd9Sstevel@tonic-gate uint_t n_flags; /* should forward?, interface flags */ 132*7c478bd9Sstevel@tonic-gate }; 133*7c478bd9Sstevel@tonic-gate 134*7c478bd9Sstevel@tonic-gate static struct neighbor *neighbors; 135*7c478bd9Sstevel@tonic-gate static struct whod mywd; 136*7c478bd9Sstevel@tonic-gate static struct servent *sp; 137*7c478bd9Sstevel@tonic-gate static int s; 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate #define WHDRSIZE (sizeof (mywd) - sizeof (mywd.wd_we)) 140*7c478bd9Sstevel@tonic-gate #define RWHODIR "/var/spool/rwho" 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate static void onalrm(void); 143*7c478bd9Sstevel@tonic-gate static void getkmem(void); 144*7c478bd9Sstevel@tonic-gate static boolean_t configure(int); 145*7c478bd9Sstevel@tonic-gate static int verify(const struct whod *); 146*7c478bd9Sstevel@tonic-gate 147*7c478bd9Sstevel@tonic-gate void 148*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 149*7c478bd9Sstevel@tonic-gate { 150*7c478bd9Sstevel@tonic-gate struct sockaddr_in from; 151*7c478bd9Sstevel@tonic-gate struct stat st; 152*7c478bd9Sstevel@tonic-gate char path[64]; 153*7c478bd9Sstevel@tonic-gate struct hostent *hp; 154*7c478bd9Sstevel@tonic-gate int on = 1; 155*7c478bd9Sstevel@tonic-gate char *cp; 156*7c478bd9Sstevel@tonic-gate struct stat sb; 157*7c478bd9Sstevel@tonic-gate 158*7c478bd9Sstevel@tonic-gate if (getuid()) { 159*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "in.rwhod: not super user\n"); 160*7c478bd9Sstevel@tonic-gate exit(1); 161*7c478bd9Sstevel@tonic-gate } 162*7c478bd9Sstevel@tonic-gate sp = getservbyname("who", "udp"); 163*7c478bd9Sstevel@tonic-gate if (sp == NULL) { 164*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "in.rwhod: udp/who: unknown service\n"); 165*7c478bd9Sstevel@tonic-gate exit(1); 166*7c478bd9Sstevel@tonic-gate } 167*7c478bd9Sstevel@tonic-gate argv++; 168*7c478bd9Sstevel@tonic-gate argc--; 169*7c478bd9Sstevel@tonic-gate while (argc > 0 && *argv[0] == '-') { 170*7c478bd9Sstevel@tonic-gate if (strcmp(*argv, "-m") == 0) { 171*7c478bd9Sstevel@tonic-gate if (argc > 1 && isdigit(*(argv + 1)[0])) { 172*7c478bd9Sstevel@tonic-gate argv++; 173*7c478bd9Sstevel@tonic-gate argc--; 174*7c478bd9Sstevel@tonic-gate multicast_mode = SCOPED_MULTICAST; 175*7c478bd9Sstevel@tonic-gate multicast_scope = atoi(*argv); 176*7c478bd9Sstevel@tonic-gate if (multicast_scope > MAX_MULTICAST_SCOPE) { 177*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 178*7c478bd9Sstevel@tonic-gate "in.rwhod: " 179*7c478bd9Sstevel@tonic-gate "ttl must not exceed %u\n", 180*7c478bd9Sstevel@tonic-gate MAX_MULTICAST_SCOPE); 181*7c478bd9Sstevel@tonic-gate exit(1); 182*7c478bd9Sstevel@tonic-gate } 183*7c478bd9Sstevel@tonic-gate } else { 184*7c478bd9Sstevel@tonic-gate multicast_mode = PER_INTERFACE_MULTICAST; 185*7c478bd9Sstevel@tonic-gate } 186*7c478bd9Sstevel@tonic-gate } else { 187*7c478bd9Sstevel@tonic-gate goto usage; 188*7c478bd9Sstevel@tonic-gate } 189*7c478bd9Sstevel@tonic-gate argv++; 190*7c478bd9Sstevel@tonic-gate argc--; 191*7c478bd9Sstevel@tonic-gate } 192*7c478bd9Sstevel@tonic-gate if (argc > 0) 193*7c478bd9Sstevel@tonic-gate goto usage; 194*7c478bd9Sstevel@tonic-gate if (chdir(RWHODIR) < 0) { 195*7c478bd9Sstevel@tonic-gate perror(RWHODIR); 196*7c478bd9Sstevel@tonic-gate exit(1); 197*7c478bd9Sstevel@tonic-gate } 198*7c478bd9Sstevel@tonic-gate #ifndef DEBUG 199*7c478bd9Sstevel@tonic-gate if (fork()) 200*7c478bd9Sstevel@tonic-gate exit(0); 201*7c478bd9Sstevel@tonic-gate /* CSTYLED */ 202*7c478bd9Sstevel@tonic-gate { 203*7c478bd9Sstevel@tonic-gate (void) close(0); 204*7c478bd9Sstevel@tonic-gate (void) close(1); 205*7c478bd9Sstevel@tonic-gate (void) close(2); 206*7c478bd9Sstevel@tonic-gate (void) open("/", 0); 207*7c478bd9Sstevel@tonic-gate (void) dup2(0, 1); 208*7c478bd9Sstevel@tonic-gate (void) dup2(0, 2); 209*7c478bd9Sstevel@tonic-gate (void) setsid(); 210*7c478bd9Sstevel@tonic-gate } 211*7c478bd9Sstevel@tonic-gate #endif 212*7c478bd9Sstevel@tonic-gate (void) sigset(SIGHUP, (void (*)())getkmem); 213*7c478bd9Sstevel@tonic-gate openlog("in.rwhod", LOG_PID, LOG_DAEMON); 214*7c478bd9Sstevel@tonic-gate /* 215*7c478bd9Sstevel@tonic-gate * Establish host name as returned by system. 216*7c478bd9Sstevel@tonic-gate */ 217*7c478bd9Sstevel@tonic-gate if (gethostname(myname, sizeof (myname) - 1) < 0) { 218*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "main: gethostname: %m"); 219*7c478bd9Sstevel@tonic-gate exit(1); 220*7c478bd9Sstevel@tonic-gate } 221*7c478bd9Sstevel@tonic-gate if ((cp = index(myname, '.')) != NULL) 222*7c478bd9Sstevel@tonic-gate *cp = '\0'; 223*7c478bd9Sstevel@tonic-gate (void) strlcpy(mywd.wd_hostname, myname, sizeof (mywd.wd_hostname)); 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate if (stat(UTMPX_FILE, &sb) < 0) { 226*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "main: stat: %s: %m", UTMPX_FILE); 227*7c478bd9Sstevel@tonic-gate exit(1); 228*7c478bd9Sstevel@tonic-gate } 229*7c478bd9Sstevel@tonic-gate getkmem(); 230*7c478bd9Sstevel@tonic-gate if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 231*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "main: socket: %m"); 232*7c478bd9Sstevel@tonic-gate exit(1); 233*7c478bd9Sstevel@tonic-gate } 234*7c478bd9Sstevel@tonic-gate if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) { 235*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "main: setsockopt SO_BROADCAST: %m"); 236*7c478bd9Sstevel@tonic-gate exit(1); 237*7c478bd9Sstevel@tonic-gate } 238*7c478bd9Sstevel@tonic-gate hp = gethostbyname(myname); 239*7c478bd9Sstevel@tonic-gate if (hp == NULL) { 240*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "main: %s: don't know my own name\n", myname); 241*7c478bd9Sstevel@tonic-gate exit(1); 242*7c478bd9Sstevel@tonic-gate } 243*7c478bd9Sstevel@tonic-gate sin.sin_family = hp->h_addrtype; 244*7c478bd9Sstevel@tonic-gate sin.sin_port = sp->s_port; 245*7c478bd9Sstevel@tonic-gate if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 246*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "main: bind: %m"); 247*7c478bd9Sstevel@tonic-gate exit(1); 248*7c478bd9Sstevel@tonic-gate } 249*7c478bd9Sstevel@tonic-gate if (!configure(s)) 250*7c478bd9Sstevel@tonic-gate exit(1); 251*7c478bd9Sstevel@tonic-gate (void) sigset(SIGALRM, (void (*)())onalrm); 252*7c478bd9Sstevel@tonic-gate onalrm(); 253*7c478bd9Sstevel@tonic-gate for (;;) { 254*7c478bd9Sstevel@tonic-gate struct whod wd; 255*7c478bd9Sstevel@tonic-gate int cc, whod; 256*7c478bd9Sstevel@tonic-gate socklen_t len = sizeof (from); 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate cc = recvfrom(s, &wd, sizeof (struct whod), 0, 259*7c478bd9Sstevel@tonic-gate (struct sockaddr *)&from, &len); 260*7c478bd9Sstevel@tonic-gate if (cc <= 0) { 261*7c478bd9Sstevel@tonic-gate if (cc < 0 && errno != EINTR) 262*7c478bd9Sstevel@tonic-gate syslog(LOG_WARNING, "main: recvfrom: %m"); 263*7c478bd9Sstevel@tonic-gate continue; 264*7c478bd9Sstevel@tonic-gate } 265*7c478bd9Sstevel@tonic-gate if (from.sin_port != sp->s_port) { 266*7c478bd9Sstevel@tonic-gate syslog(LOG_WARNING, "main: %d: bad from port", 267*7c478bd9Sstevel@tonic-gate ntohs(from.sin_port)); 268*7c478bd9Sstevel@tonic-gate continue; 269*7c478bd9Sstevel@tonic-gate } 270*7c478bd9Sstevel@tonic-gate #ifdef notdef 271*7c478bd9Sstevel@tonic-gate if (gethostbyname(wd.wd_hostname) == 0) { 272*7c478bd9Sstevel@tonic-gate syslog(LOG_WARNING, "main: %s: unknown host", 273*7c478bd9Sstevel@tonic-gate wd.wd_hostname); 274*7c478bd9Sstevel@tonic-gate continue; 275*7c478bd9Sstevel@tonic-gate } 276*7c478bd9Sstevel@tonic-gate #endif 277*7c478bd9Sstevel@tonic-gate if (wd.wd_vers != WHODVERSION) 278*7c478bd9Sstevel@tonic-gate continue; 279*7c478bd9Sstevel@tonic-gate if (wd.wd_type != WHODTYPE_STATUS) 280*7c478bd9Sstevel@tonic-gate continue; 281*7c478bd9Sstevel@tonic-gate if (!verify(&wd)) { 282*7c478bd9Sstevel@tonic-gate syslog(LOG_WARNING, "main: malformed host name from %x", 283*7c478bd9Sstevel@tonic-gate from.sin_addr.s_addr); 284*7c478bd9Sstevel@tonic-gate continue; 285*7c478bd9Sstevel@tonic-gate } 286*7c478bd9Sstevel@tonic-gate (void) sprintf(path, "whod.%s", wd.wd_hostname); 287*7c478bd9Sstevel@tonic-gate /* 288*7c478bd9Sstevel@tonic-gate * Rather than truncating and growing the file each time, 289*7c478bd9Sstevel@tonic-gate * use ftruncate if size is less than previous size. 290*7c478bd9Sstevel@tonic-gate */ 291*7c478bd9Sstevel@tonic-gate whod = open(path, O_WRONLY | O_CREAT, 0644); 292*7c478bd9Sstevel@tonic-gate if (whod < 0) { 293*7c478bd9Sstevel@tonic-gate syslog(LOG_WARNING, "main: open: %s: %m", path); 294*7c478bd9Sstevel@tonic-gate continue; 295*7c478bd9Sstevel@tonic-gate } 296*7c478bd9Sstevel@tonic-gate #if defined(_LITTLE_ENDIAN) 297*7c478bd9Sstevel@tonic-gate /* CSTYLED */ 298*7c478bd9Sstevel@tonic-gate { 299*7c478bd9Sstevel@tonic-gate int i, n = (cc - WHDRSIZE)/sizeof (struct whoent); 300*7c478bd9Sstevel@tonic-gate struct whoent *we; 301*7c478bd9Sstevel@tonic-gate 302*7c478bd9Sstevel@tonic-gate /* undo header byte swapping before writing to file */ 303*7c478bd9Sstevel@tonic-gate wd.wd_sendtime = ntohl(wd.wd_sendtime); 304*7c478bd9Sstevel@tonic-gate for (i = 0; i < 3; i++) 305*7c478bd9Sstevel@tonic-gate wd.wd_loadav[i] = ntohl(wd.wd_loadav[i]); 306*7c478bd9Sstevel@tonic-gate wd.wd_boottime = ntohl(wd.wd_boottime); 307*7c478bd9Sstevel@tonic-gate we = wd.wd_we; 308*7c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 309*7c478bd9Sstevel@tonic-gate we->we_idle = ntohl(we->we_idle); 310*7c478bd9Sstevel@tonic-gate we->we_utmp.out_time = 311*7c478bd9Sstevel@tonic-gate ntohl(we->we_utmp.out_time); 312*7c478bd9Sstevel@tonic-gate we++; 313*7c478bd9Sstevel@tonic-gate } 314*7c478bd9Sstevel@tonic-gate } 315*7c478bd9Sstevel@tonic-gate #endif 316*7c478bd9Sstevel@tonic-gate (void) time((time_t *)&wd.wd_recvtime); 317*7c478bd9Sstevel@tonic-gate (void) write(whod, &wd, cc); 318*7c478bd9Sstevel@tonic-gate if (fstat(whod, &st) < 0 || st.st_size > cc) 319*7c478bd9Sstevel@tonic-gate (void) ftruncate(whod, cc); 320*7c478bd9Sstevel@tonic-gate (void) close(whod); 321*7c478bd9Sstevel@tonic-gate } 322*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 323*7c478bd9Sstevel@tonic-gate usage: 324*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "usage: in.rwhod [ -m [ ttl ] ]\n"); 325*7c478bd9Sstevel@tonic-gate exit(1); 326*7c478bd9Sstevel@tonic-gate } 327*7c478bd9Sstevel@tonic-gate 328*7c478bd9Sstevel@tonic-gate /* 329*7c478bd9Sstevel@tonic-gate * Check out host name for unprintables 330*7c478bd9Sstevel@tonic-gate * and other funnies before allowing a file 331*7c478bd9Sstevel@tonic-gate * to be created. Sorry, but blanks aren't allowed. 332*7c478bd9Sstevel@tonic-gate */ 333*7c478bd9Sstevel@tonic-gate static int 334*7c478bd9Sstevel@tonic-gate verify(const struct whod *wd) 335*7c478bd9Sstevel@tonic-gate { 336*7c478bd9Sstevel@tonic-gate int size = 0; 337*7c478bd9Sstevel@tonic-gate const char *name = wd->wd_hostname; 338*7c478bd9Sstevel@tonic-gate 339*7c478bd9Sstevel@tonic-gate /* 340*7c478bd9Sstevel@tonic-gate * We shouldn't assume the name is NUL terminated, so bound the 341*7c478bd9Sstevel@tonic-gate * checks at the size of the whod structures wd_hostname field. 342*7c478bd9Sstevel@tonic-gate */ 343*7c478bd9Sstevel@tonic-gate while ((size < sizeof (wd->wd_hostname)) && 344*7c478bd9Sstevel@tonic-gate (*name != '\0')) { 345*7c478bd9Sstevel@tonic-gate if (*name == '/' || !isascii(*name) || 346*7c478bd9Sstevel@tonic-gate !(isalnum(*name) || ispunct(*name))) 347*7c478bd9Sstevel@tonic-gate return (0); 348*7c478bd9Sstevel@tonic-gate name++, size++; 349*7c478bd9Sstevel@tonic-gate } 350*7c478bd9Sstevel@tonic-gate /* 351*7c478bd9Sstevel@tonic-gate * Fail the verification if NULL name or it wasn't NUL terminated. 352*7c478bd9Sstevel@tonic-gate */ 353*7c478bd9Sstevel@tonic-gate return ((size > 0) && (size < sizeof (wd->wd_hostname))); 354*7c478bd9Sstevel@tonic-gate } 355*7c478bd9Sstevel@tonic-gate 356*7c478bd9Sstevel@tonic-gate static int utmpxtime; 357*7c478bd9Sstevel@tonic-gate static int utmpxent; 358*7c478bd9Sstevel@tonic-gate static int alarmcount; 359*7c478bd9Sstevel@tonic-gate struct utmpx *utmpx; 360*7c478bd9Sstevel@tonic-gate 361*7c478bd9Sstevel@tonic-gate static void 362*7c478bd9Sstevel@tonic-gate onalrm(void) 363*7c478bd9Sstevel@tonic-gate { 364*7c478bd9Sstevel@tonic-gate int i; 365*7c478bd9Sstevel@tonic-gate struct stat stb; 366*7c478bd9Sstevel@tonic-gate int utmpxsize = 0; 367*7c478bd9Sstevel@tonic-gate int entries; 368*7c478bd9Sstevel@tonic-gate struct utmpx *utp; 369*7c478bd9Sstevel@tonic-gate struct utmpx *utmpxbegin; 370*7c478bd9Sstevel@tonic-gate struct whoent *we = mywd.wd_we, *wlast; 371*7c478bd9Sstevel@tonic-gate int cc, cnt; 372*7c478bd9Sstevel@tonic-gate double avenrun[3]; 373*7c478bd9Sstevel@tonic-gate 374*7c478bd9Sstevel@tonic-gate time_t now = time(0); 375*7c478bd9Sstevel@tonic-gate struct neighbor *np; 376*7c478bd9Sstevel@tonic-gate 377*7c478bd9Sstevel@tonic-gate if (alarmcount % 10 == 0) 378*7c478bd9Sstevel@tonic-gate getkmem(); 379*7c478bd9Sstevel@tonic-gate alarmcount++; 380*7c478bd9Sstevel@tonic-gate (void) stat(UTMPX_FILE, &stb); 381*7c478bd9Sstevel@tonic-gate entries = stb.st_size / sizeof (struct futmpx); 382*7c478bd9Sstevel@tonic-gate if ((stb.st_mtime != utmpxtime) || (entries > utmpxent)) { 383*7c478bd9Sstevel@tonic-gate utmpxtime = stb.st_mtime; 384*7c478bd9Sstevel@tonic-gate if (entries > utmpxent) { 385*7c478bd9Sstevel@tonic-gate utmpxent = entries; 386*7c478bd9Sstevel@tonic-gate utmpxsize = utmpxent * sizeof (struct utmpx); 387*7c478bd9Sstevel@tonic-gate utmpx = realloc(utmpx, utmpxsize); 388*7c478bd9Sstevel@tonic-gate if (utmpx == NULL) { 389*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "onalrm: realloc: %m"); 390*7c478bd9Sstevel@tonic-gate utmpxsize = 0; 391*7c478bd9Sstevel@tonic-gate goto done; 392*7c478bd9Sstevel@tonic-gate } 393*7c478bd9Sstevel@tonic-gate } 394*7c478bd9Sstevel@tonic-gate utmpxbegin = utmpx; 395*7c478bd9Sstevel@tonic-gate setutxent(); 396*7c478bd9Sstevel@tonic-gate cnt = 0; 397*7c478bd9Sstevel@tonic-gate while (cnt++ < utmpxent && (utp = getutxent()) != NULL) 398*7c478bd9Sstevel@tonic-gate (void) memcpy(utmpxbegin++, utp, sizeof (struct utmpx)); 399*7c478bd9Sstevel@tonic-gate endutxent(); 400*7c478bd9Sstevel@tonic-gate wlast = &mywd.wd_we[1024 / sizeof (struct whoent) - 1]; 401*7c478bd9Sstevel@tonic-gate for (i = 0; i < utmpxent; i++) { 402*7c478bd9Sstevel@tonic-gate if (utmpx[i].ut_name[0] && 403*7c478bd9Sstevel@tonic-gate utmpx[i].ut_type == USER_PROCESS) { 404*7c478bd9Sstevel@tonic-gate /* 405*7c478bd9Sstevel@tonic-gate * XXX - utmpx name and line lengths should 406*7c478bd9Sstevel@tonic-gate * be here 407*7c478bd9Sstevel@tonic-gate */ 408*7c478bd9Sstevel@tonic-gate bcopy(utmpx[i].ut_line, we->we_utmp.out_line, 409*7c478bd9Sstevel@tonic-gate sizeof (we->we_utmp.out_line)); 410*7c478bd9Sstevel@tonic-gate bcopy(utmpx[i].ut_name, we->we_utmp.out_name, 411*7c478bd9Sstevel@tonic-gate sizeof (we->we_utmp.out_name)); 412*7c478bd9Sstevel@tonic-gate we->we_utmp.out_time = 413*7c478bd9Sstevel@tonic-gate htonl(utmpx[i].ut_xtime); 414*7c478bd9Sstevel@tonic-gate if (we >= wlast) 415*7c478bd9Sstevel@tonic-gate break; 416*7c478bd9Sstevel@tonic-gate we++; 417*7c478bd9Sstevel@tonic-gate } 418*7c478bd9Sstevel@tonic-gate } 419*7c478bd9Sstevel@tonic-gate utmpxent = we - mywd.wd_we; 420*7c478bd9Sstevel@tonic-gate } 421*7c478bd9Sstevel@tonic-gate 422*7c478bd9Sstevel@tonic-gate /* 423*7c478bd9Sstevel@tonic-gate * The test on utmpxent looks silly---after all, if no one is 424*7c478bd9Sstevel@tonic-gate * logged on, why worry about efficiency?---but is useful on 425*7c478bd9Sstevel@tonic-gate * (e.g.) compute servers. 426*7c478bd9Sstevel@tonic-gate */ 427*7c478bd9Sstevel@tonic-gate if (utmpxent > 0 && chdir("/dev") == -1) { 428*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "onalrm: chdir /dev: %m"); 429*7c478bd9Sstevel@tonic-gate exit(1); 430*7c478bd9Sstevel@tonic-gate } 431*7c478bd9Sstevel@tonic-gate we = mywd.wd_we; 432*7c478bd9Sstevel@tonic-gate for (i = 0; i < utmpxent; i++) { 433*7c478bd9Sstevel@tonic-gate if (stat(we->we_utmp.out_line, &stb) >= 0) 434*7c478bd9Sstevel@tonic-gate we->we_idle = htonl(now - stb.st_atime); 435*7c478bd9Sstevel@tonic-gate we++; 436*7c478bd9Sstevel@tonic-gate } 437*7c478bd9Sstevel@tonic-gate if (getloadavg(avenrun, 3) == -1) { 438*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "onalrm: getloadavg: %m"); 439*7c478bd9Sstevel@tonic-gate exit(1); 440*7c478bd9Sstevel@tonic-gate } 441*7c478bd9Sstevel@tonic-gate 442*7c478bd9Sstevel@tonic-gate for (i = 0; i < 3; i++) 443*7c478bd9Sstevel@tonic-gate mywd.wd_loadav[i] = htonl((ulong_t)(avenrun[i] * 100)); 444*7c478bd9Sstevel@tonic-gate cc = (char *)we - (char *)&mywd; 445*7c478bd9Sstevel@tonic-gate mywd.wd_sendtime = htonl(time(0)); 446*7c478bd9Sstevel@tonic-gate mywd.wd_vers = WHODVERSION; 447*7c478bd9Sstevel@tonic-gate mywd.wd_type = WHODTYPE_STATUS; 448*7c478bd9Sstevel@tonic-gate if (multicast_mode == SCOPED_MULTICAST) { 449*7c478bd9Sstevel@tonic-gate (void) sendto(s, &mywd, cc, 0, 450*7c478bd9Sstevel@tonic-gate (struct sockaddr *)&multicast_addr, 451*7c478bd9Sstevel@tonic-gate sizeof (multicast_addr)); 452*7c478bd9Sstevel@tonic-gate } else for (np = neighbors; np != NULL; np = np->n_next) { 453*7c478bd9Sstevel@tonic-gate if (multicast_mode == PER_INTERFACE_MULTICAST && 454*7c478bd9Sstevel@tonic-gate np->n_flags & IFF_MULTICAST) { 455*7c478bd9Sstevel@tonic-gate /* 456*7c478bd9Sstevel@tonic-gate * Select the outgoing interface for the multicast. 457*7c478bd9Sstevel@tonic-gate */ 458*7c478bd9Sstevel@tonic-gate if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, 459*7c478bd9Sstevel@tonic-gate &(((struct sockaddr_in *)np->n_addr)->sin_addr), 460*7c478bd9Sstevel@tonic-gate sizeof (struct in_addr)) < 0) { 461*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 462*7c478bd9Sstevel@tonic-gate "onalrm: setsockopt IP_MULTICAST_IF: %m"); 463*7c478bd9Sstevel@tonic-gate exit(1); 464*7c478bd9Sstevel@tonic-gate } 465*7c478bd9Sstevel@tonic-gate (void) sendto(s, &mywd, cc, 0, 466*7c478bd9Sstevel@tonic-gate (struct sockaddr *)&multicast_addr, 467*7c478bd9Sstevel@tonic-gate sizeof (multicast_addr)); 468*7c478bd9Sstevel@tonic-gate } else { 469*7c478bd9Sstevel@tonic-gate (void) sendto(s, &mywd, cc, 0, 470*7c478bd9Sstevel@tonic-gate (struct sockaddr *)np->n_addr, np->n_addrlen); 471*7c478bd9Sstevel@tonic-gate } 472*7c478bd9Sstevel@tonic-gate } 473*7c478bd9Sstevel@tonic-gate if (utmpxent > 0 && chdir(RWHODIR) == -1) { 474*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "onalrm: chdir %s: %m", RWHODIR); 475*7c478bd9Sstevel@tonic-gate exit(1); 476*7c478bd9Sstevel@tonic-gate } 477*7c478bd9Sstevel@tonic-gate done: 478*7c478bd9Sstevel@tonic-gate (void) alarm(AL_INTERVAL); 479*7c478bd9Sstevel@tonic-gate } 480*7c478bd9Sstevel@tonic-gate 481*7c478bd9Sstevel@tonic-gate static void 482*7c478bd9Sstevel@tonic-gate getkmem(void) 483*7c478bd9Sstevel@tonic-gate { 484*7c478bd9Sstevel@tonic-gate struct utmpx *utmpx, utmpx_id; 485*7c478bd9Sstevel@tonic-gate 486*7c478bd9Sstevel@tonic-gate utmpx_id.ut_type = BOOT_TIME; 487*7c478bd9Sstevel@tonic-gate if ((utmpx = getutxid(&utmpx_id)) != NULL) 488*7c478bd9Sstevel@tonic-gate mywd.wd_boottime = utmpx->ut_xtime; 489*7c478bd9Sstevel@tonic-gate endutxent(); 490*7c478bd9Sstevel@tonic-gate mywd.wd_boottime = htonl(mywd.wd_boottime); 491*7c478bd9Sstevel@tonic-gate } 492*7c478bd9Sstevel@tonic-gate 493*7c478bd9Sstevel@tonic-gate /* 494*7c478bd9Sstevel@tonic-gate * Figure out device configuration and select 495*7c478bd9Sstevel@tonic-gate * networks which deserve status information. 496*7c478bd9Sstevel@tonic-gate */ 497*7c478bd9Sstevel@tonic-gate static boolean_t 498*7c478bd9Sstevel@tonic-gate configure(int s) 499*7c478bd9Sstevel@tonic-gate { 500*7c478bd9Sstevel@tonic-gate char *buf; 501*7c478bd9Sstevel@tonic-gate struct ifconf ifc; 502*7c478bd9Sstevel@tonic-gate struct ifreq ifreq, *ifr; 503*7c478bd9Sstevel@tonic-gate struct sockaddr_in *sin; 504*7c478bd9Sstevel@tonic-gate struct neighbor *np; 505*7c478bd9Sstevel@tonic-gate struct neighbor *np2; 506*7c478bd9Sstevel@tonic-gate int n; 507*7c478bd9Sstevel@tonic-gate int numifs; 508*7c478bd9Sstevel@tonic-gate unsigned bufsize; 509*7c478bd9Sstevel@tonic-gate 510*7c478bd9Sstevel@tonic-gate if (multicast_mode == SCOPED_MULTICAST) { 511*7c478bd9Sstevel@tonic-gate struct ip_mreq mreq; 512*7c478bd9Sstevel@tonic-gate unsigned char ttl; 513*7c478bd9Sstevel@tonic-gate 514*7c478bd9Sstevel@tonic-gate mreq.imr_multiaddr.s_addr = htonl(INADDR_WHOD_GROUP); 515*7c478bd9Sstevel@tonic-gate mreq.imr_interface.s_addr = htonl(INADDR_ANY); 516*7c478bd9Sstevel@tonic-gate if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, 517*7c478bd9Sstevel@tonic-gate sizeof (mreq)) < 0) { 518*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 519*7c478bd9Sstevel@tonic-gate "configure: setsockopt IP_ADD_MEMBERSHIP: %m"); 520*7c478bd9Sstevel@tonic-gate return (B_FALSE); 521*7c478bd9Sstevel@tonic-gate } 522*7c478bd9Sstevel@tonic-gate ttl = multicast_scope; 523*7c478bd9Sstevel@tonic-gate if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, 524*7c478bd9Sstevel@tonic-gate sizeof (ttl)) < 0) { 525*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 526*7c478bd9Sstevel@tonic-gate "configure: setsockopt IP_MULTICAST_TTL: %m"); 527*7c478bd9Sstevel@tonic-gate return (B_FALSE); 528*7c478bd9Sstevel@tonic-gate } 529*7c478bd9Sstevel@tonic-gate multicast_addr.sin_addr.s_addr = htonl(INADDR_WHOD_GROUP); 530*7c478bd9Sstevel@tonic-gate multicast_addr.sin_port = sp->s_port; 531*7c478bd9Sstevel@tonic-gate return (B_TRUE); 532*7c478bd9Sstevel@tonic-gate } 533*7c478bd9Sstevel@tonic-gate 534*7c478bd9Sstevel@tonic-gate if (ioctl(s, SIOCGIFNUM, (char *)&numifs) < 0) { 535*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "configure: ioctl SIOCGIFNUM: %m"); 536*7c478bd9Sstevel@tonic-gate return (B_FALSE); 537*7c478bd9Sstevel@tonic-gate } 538*7c478bd9Sstevel@tonic-gate bufsize = numifs * sizeof (struct ifreq); 539*7c478bd9Sstevel@tonic-gate buf = malloc(bufsize); 540*7c478bd9Sstevel@tonic-gate if (buf == NULL) { 541*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "configure: malloc: %m"); 542*7c478bd9Sstevel@tonic-gate return (B_FALSE); 543*7c478bd9Sstevel@tonic-gate } 544*7c478bd9Sstevel@tonic-gate ifc.ifc_len = bufsize; 545*7c478bd9Sstevel@tonic-gate ifc.ifc_buf = buf; 546*7c478bd9Sstevel@tonic-gate if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) { 547*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 548*7c478bd9Sstevel@tonic-gate "configure: ioctl (get interface configuration): %m"); 549*7c478bd9Sstevel@tonic-gate (void) free(buf); 550*7c478bd9Sstevel@tonic-gate return (B_FALSE); 551*7c478bd9Sstevel@tonic-gate } 552*7c478bd9Sstevel@tonic-gate ifr = ifc.ifc_req; 553*7c478bd9Sstevel@tonic-gate for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) { 554*7c478bd9Sstevel@tonic-gate /* Skip all logical interfaces */ 555*7c478bd9Sstevel@tonic-gate if (index(ifr->ifr_name, ':') != NULL) 556*7c478bd9Sstevel@tonic-gate continue; 557*7c478bd9Sstevel@tonic-gate 558*7c478bd9Sstevel@tonic-gate for (np = neighbors; np != NULL; np = np->n_next) { 559*7c478bd9Sstevel@tonic-gate if (np->n_name && 560*7c478bd9Sstevel@tonic-gate strcmp(ifr->ifr_name, np->n_name) == 0) 561*7c478bd9Sstevel@tonic-gate break; 562*7c478bd9Sstevel@tonic-gate } 563*7c478bd9Sstevel@tonic-gate if (np != NULL) 564*7c478bd9Sstevel@tonic-gate continue; 565*7c478bd9Sstevel@tonic-gate ifreq = *ifr; 566*7c478bd9Sstevel@tonic-gate np = (struct neighbor *)malloc(sizeof (*np)); 567*7c478bd9Sstevel@tonic-gate if (np == NULL) 568*7c478bd9Sstevel@tonic-gate continue; 569*7c478bd9Sstevel@tonic-gate np->n_name = malloc(strlen(ifr->ifr_name) + 1); 570*7c478bd9Sstevel@tonic-gate if (np->n_name == NULL) { 571*7c478bd9Sstevel@tonic-gate free(np); 572*7c478bd9Sstevel@tonic-gate continue; 573*7c478bd9Sstevel@tonic-gate } 574*7c478bd9Sstevel@tonic-gate (void) strcpy(np->n_name, ifr->ifr_name); 575*7c478bd9Sstevel@tonic-gate np->n_addrlen = sizeof (ifr->ifr_addr); 576*7c478bd9Sstevel@tonic-gate np->n_addr = malloc(np->n_addrlen); 577*7c478bd9Sstevel@tonic-gate if (np->n_addr == NULL) { 578*7c478bd9Sstevel@tonic-gate free(np->n_name); 579*7c478bd9Sstevel@tonic-gate free(np); 580*7c478bd9Sstevel@tonic-gate continue; 581*7c478bd9Sstevel@tonic-gate } 582*7c478bd9Sstevel@tonic-gate bcopy(&ifr->ifr_addr, np->n_addr, np->n_addrlen); 583*7c478bd9Sstevel@tonic-gate if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) { 584*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 585*7c478bd9Sstevel@tonic-gate "configure: ioctl (get interface flags): %m"); 586*7c478bd9Sstevel@tonic-gate free(np->n_addr); 587*7c478bd9Sstevel@tonic-gate free(np->n_name); 588*7c478bd9Sstevel@tonic-gate free(np); 589*7c478bd9Sstevel@tonic-gate continue; 590*7c478bd9Sstevel@tonic-gate } 591*7c478bd9Sstevel@tonic-gate np->n_flags = ifreq.ifr_flags; 592*7c478bd9Sstevel@tonic-gate if (((struct sockaddr_in *)np->n_addr)->sin_family == AF_INET && 593*7c478bd9Sstevel@tonic-gate ioctl(s, SIOCGIFNETMASK, (char *)&ifreq) >= 0) { 594*7c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)np->n_addr; 595*7c478bd9Sstevel@tonic-gate 596*7c478bd9Sstevel@tonic-gate np->n_subnet = sin->sin_addr.s_addr & 597*7c478bd9Sstevel@tonic-gate ((struct sockaddr_in *)&ifreq.ifr_addr)-> 598*7c478bd9Sstevel@tonic-gate sin_addr.s_addr; 599*7c478bd9Sstevel@tonic-gate } 600*7c478bd9Sstevel@tonic-gate if (multicast_mode == PER_INTERFACE_MULTICAST && 601*7c478bd9Sstevel@tonic-gate (np->n_flags & IFF_UP) && 602*7c478bd9Sstevel@tonic-gate (np->n_flags & IFF_MULTICAST) && 603*7c478bd9Sstevel@tonic-gate !(np->n_flags & IFF_LOOPBACK)) { 604*7c478bd9Sstevel@tonic-gate struct ip_mreq mreq; 605*7c478bd9Sstevel@tonic-gate 606*7c478bd9Sstevel@tonic-gate /* 607*7c478bd9Sstevel@tonic-gate * Skip interfaces that have matching subnets i.e. 608*7c478bd9Sstevel@tonic-gate * (addr & netmask) are identical. 609*7c478bd9Sstevel@tonic-gate * Such interfaces are connected to the same 610*7c478bd9Sstevel@tonic-gate * physical wire. 611*7c478bd9Sstevel@tonic-gate */ 612*7c478bd9Sstevel@tonic-gate for (np2 = neighbors; np2 != NULL; np2 = np2->n_next) { 613*7c478bd9Sstevel@tonic-gate 614*7c478bd9Sstevel@tonic-gate if (!(np->n_flags & IFF_POINTOPOINT) && 615*7c478bd9Sstevel@tonic-gate !(np2->n_flags & IFF_POINTOPOINT) && 616*7c478bd9Sstevel@tonic-gate (np->n_subnet == np2->n_subnet)) { 617*7c478bd9Sstevel@tonic-gate free(np->n_addr); 618*7c478bd9Sstevel@tonic-gate free(np->n_name); 619*7c478bd9Sstevel@tonic-gate free(np); 620*7c478bd9Sstevel@tonic-gate break; 621*7c478bd9Sstevel@tonic-gate } 622*7c478bd9Sstevel@tonic-gate } 623*7c478bd9Sstevel@tonic-gate if (np2 != NULL) 624*7c478bd9Sstevel@tonic-gate continue; 625*7c478bd9Sstevel@tonic-gate 626*7c478bd9Sstevel@tonic-gate mreq.imr_multiaddr.s_addr = htonl(INADDR_WHOD_GROUP); 627*7c478bd9Sstevel@tonic-gate mreq.imr_interface.s_addr = 628*7c478bd9Sstevel@tonic-gate ((struct sockaddr_in *)np->n_addr)->sin_addr.s_addr; 629*7c478bd9Sstevel@tonic-gate if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, 630*7c478bd9Sstevel@tonic-gate sizeof (mreq)) < 0) { 631*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 632*7c478bd9Sstevel@tonic-gate "configure: " 633*7c478bd9Sstevel@tonic-gate "setsockopt IP_ADD_MEMBERSHIP: %m"); 634*7c478bd9Sstevel@tonic-gate free(np->n_addr); 635*7c478bd9Sstevel@tonic-gate free(np->n_name); 636*7c478bd9Sstevel@tonic-gate free(np); 637*7c478bd9Sstevel@tonic-gate continue; 638*7c478bd9Sstevel@tonic-gate } 639*7c478bd9Sstevel@tonic-gate multicast_addr.sin_addr.s_addr = 640*7c478bd9Sstevel@tonic-gate htonl(INADDR_WHOD_GROUP); 641*7c478bd9Sstevel@tonic-gate multicast_addr.sin_port = sp->s_port; 642*7c478bd9Sstevel@tonic-gate np->n_next = neighbors; 643*7c478bd9Sstevel@tonic-gate neighbors = np; 644*7c478bd9Sstevel@tonic-gate continue; 645*7c478bd9Sstevel@tonic-gate } 646*7c478bd9Sstevel@tonic-gate if ((np->n_flags & IFF_UP) == 0 || 647*7c478bd9Sstevel@tonic-gate (np->n_flags & (IFF_BROADCAST|IFF_POINTOPOINT)) == 0) { 648*7c478bd9Sstevel@tonic-gate free(np->n_addr); 649*7c478bd9Sstevel@tonic-gate free(np->n_name); 650*7c478bd9Sstevel@tonic-gate free(np); 651*7c478bd9Sstevel@tonic-gate continue; 652*7c478bd9Sstevel@tonic-gate } 653*7c478bd9Sstevel@tonic-gate if (np->n_flags & IFF_POINTOPOINT) { 654*7c478bd9Sstevel@tonic-gate if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) { 655*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 656*7c478bd9Sstevel@tonic-gate "configure: ioctl (get dstaddr): %m"); 657*7c478bd9Sstevel@tonic-gate free(np->n_addr); 658*7c478bd9Sstevel@tonic-gate free(np->n_name); 659*7c478bd9Sstevel@tonic-gate free(np); 660*7c478bd9Sstevel@tonic-gate continue; 661*7c478bd9Sstevel@tonic-gate } 662*7c478bd9Sstevel@tonic-gate /* we assume addresses are all the same size */ 663*7c478bd9Sstevel@tonic-gate bcopy(&ifreq.ifr_dstaddr, np->n_addr, np->n_addrlen); 664*7c478bd9Sstevel@tonic-gate } 665*7c478bd9Sstevel@tonic-gate if (np->n_flags & IFF_BROADCAST) { 666*7c478bd9Sstevel@tonic-gate if (ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { 667*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 668*7c478bd9Sstevel@tonic-gate "configure: ioctl (get broadaddr): %m"); 669*7c478bd9Sstevel@tonic-gate free(np->n_addr); 670*7c478bd9Sstevel@tonic-gate free(np->n_name); 671*7c478bd9Sstevel@tonic-gate free(np); 672*7c478bd9Sstevel@tonic-gate continue; 673*7c478bd9Sstevel@tonic-gate } 674*7c478bd9Sstevel@tonic-gate /* we assume addresses are all the same size */ 675*7c478bd9Sstevel@tonic-gate bcopy(&ifreq.ifr_broadaddr, np->n_addr, np->n_addrlen); 676*7c478bd9Sstevel@tonic-gate } 677*7c478bd9Sstevel@tonic-gate /* gag, wish we could get rid of Internet dependencies */ 678*7c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)np->n_addr; 679*7c478bd9Sstevel@tonic-gate sin->sin_port = sp->s_port; 680*7c478bd9Sstevel@tonic-gate 681*7c478bd9Sstevel@tonic-gate /* 682*7c478bd9Sstevel@tonic-gate * Avoid adding duplicate broadcast and pt-pt destinations 683*7c478bd9Sstevel@tonic-gate * to the list. 684*7c478bd9Sstevel@tonic-gate */ 685*7c478bd9Sstevel@tonic-gate for (np2 = neighbors; np2 != NULL; np2 = np2->n_next) { 686*7c478bd9Sstevel@tonic-gate struct sockaddr_in *sin2; 687*7c478bd9Sstevel@tonic-gate 688*7c478bd9Sstevel@tonic-gate sin2 = (struct sockaddr_in *)np2->n_addr; 689*7c478bd9Sstevel@tonic-gate if (sin2->sin_addr.s_addr == sin->sin_addr.s_addr) { 690*7c478bd9Sstevel@tonic-gate free(np->n_addr); 691*7c478bd9Sstevel@tonic-gate free(np->n_name); 692*7c478bd9Sstevel@tonic-gate free(np); 693*7c478bd9Sstevel@tonic-gate break; 694*7c478bd9Sstevel@tonic-gate } 695*7c478bd9Sstevel@tonic-gate } 696*7c478bd9Sstevel@tonic-gate if (np2 != NULL) 697*7c478bd9Sstevel@tonic-gate continue; 698*7c478bd9Sstevel@tonic-gate 699*7c478bd9Sstevel@tonic-gate np->n_next = neighbors; 700*7c478bd9Sstevel@tonic-gate neighbors = np; 701*7c478bd9Sstevel@tonic-gate } 702*7c478bd9Sstevel@tonic-gate (void) free(buf); 703*7c478bd9Sstevel@tonic-gate return (B_TRUE); 704*7c478bd9Sstevel@tonic-gate } 705*7c478bd9Sstevel@tonic-gate 706*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 707*7c478bd9Sstevel@tonic-gate static char *interval(uint_t, char *); 708*7c478bd9Sstevel@tonic-gate 709*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 710*7c478bd9Sstevel@tonic-gate static ssize_t 711*7c478bd9Sstevel@tonic-gate sendto(int s, const void *buf, size_t cc, int flags, const struct sockaddr *to, 712*7c478bd9Sstevel@tonic-gate socklen_t tolen) 713*7c478bd9Sstevel@tonic-gate { 714*7c478bd9Sstevel@tonic-gate struct whod *w = (struct whod *)buf; 715*7c478bd9Sstevel@tonic-gate struct whoent *we; 716*7c478bd9Sstevel@tonic-gate struct sockaddr_in *sin = (struct sockaddr_in *)to; 717*7c478bd9Sstevel@tonic-gate int nsz; 718*7c478bd9Sstevel@tonic-gate 719*7c478bd9Sstevel@tonic-gate (void) printf("sendto %x.%d\n", ntohl(sin->sin_addr.s_addr), 720*7c478bd9Sstevel@tonic-gate ntohs(sin->sin_port)); 721*7c478bd9Sstevel@tonic-gate (void) printf("hostname %s %s\n", w->wd_hostname, 722*7c478bd9Sstevel@tonic-gate interval(ntohl(w->wd_sendtime) - ntohl(w->wd_boottime), " up")); 723*7c478bd9Sstevel@tonic-gate (void) printf("load %4.2f, %4.2f, %4.2f\n", 724*7c478bd9Sstevel@tonic-gate ntohl(w->wd_loadav[0]) / 100.0, ntohl(w->wd_loadav[1]) / 100.0, 725*7c478bd9Sstevel@tonic-gate ntohl(w->wd_loadav[2]) / 100.0); 726*7c478bd9Sstevel@tonic-gate cc -= WHDRSIZE; 727*7c478bd9Sstevel@tonic-gate for (we = w->wd_we, cc /= sizeof (struct whoent); cc > 0; cc--, we++) { 728*7c478bd9Sstevel@tonic-gate time_t t = ntohl(we->we_utmp.out_time); 729*7c478bd9Sstevel@tonic-gate 730*7c478bd9Sstevel@tonic-gate nsz = sizeof (we->we_utmp.out_name); 731*7c478bd9Sstevel@tonic-gate (void) printf("%-*.*s %s:%s %.12s", 732*7c478bd9Sstevel@tonic-gate nsz, 733*7c478bd9Sstevel@tonic-gate nsz, 734*7c478bd9Sstevel@tonic-gate we->we_utmp.out_name, 735*7c478bd9Sstevel@tonic-gate w->wd_hostname, 736*7c478bd9Sstevel@tonic-gate we->we_utmp.out_line, 737*7c478bd9Sstevel@tonic-gate ctime(&t)+4); 738*7c478bd9Sstevel@tonic-gate we->we_idle = ntohl(we->we_idle) / 60; 739*7c478bd9Sstevel@tonic-gate if (we->we_idle) { 740*7c478bd9Sstevel@tonic-gate if (we->we_idle >= 100*60) 741*7c478bd9Sstevel@tonic-gate we->we_idle = 100*60 - 1; 742*7c478bd9Sstevel@tonic-gate if (we->we_idle >= 60) 743*7c478bd9Sstevel@tonic-gate (void) printf(" %2d", we->we_idle / 60); 744*7c478bd9Sstevel@tonic-gate else 745*7c478bd9Sstevel@tonic-gate (void) printf(" "); 746*7c478bd9Sstevel@tonic-gate (void) printf(":%02d", we->we_idle % 60); 747*7c478bd9Sstevel@tonic-gate } 748*7c478bd9Sstevel@tonic-gate (void) printf("\n"); 749*7c478bd9Sstevel@tonic-gate } 750*7c478bd9Sstevel@tonic-gate return (0); 751*7c478bd9Sstevel@tonic-gate } 752*7c478bd9Sstevel@tonic-gate 753*7c478bd9Sstevel@tonic-gate static char * 754*7c478bd9Sstevel@tonic-gate interval(uint_t time, char *updown) 755*7c478bd9Sstevel@tonic-gate { 756*7c478bd9Sstevel@tonic-gate static char resbuf[32]; 757*7c478bd9Sstevel@tonic-gate int days, hours, minutes; 758*7c478bd9Sstevel@tonic-gate 759*7c478bd9Sstevel@tonic-gate if (time > 3*30*24*60*60) { 760*7c478bd9Sstevel@tonic-gate (void) sprintf(resbuf, " %s ??:??", updown); 761*7c478bd9Sstevel@tonic-gate return (resbuf); 762*7c478bd9Sstevel@tonic-gate } 763*7c478bd9Sstevel@tonic-gate minutes = (time + 59) / 60; /* round to minutes */ 764*7c478bd9Sstevel@tonic-gate hours = minutes / 60; 765*7c478bd9Sstevel@tonic-gate minutes %= 60; 766*7c478bd9Sstevel@tonic-gate days = hours / 24; 767*7c478bd9Sstevel@tonic-gate hours %= 24; 768*7c478bd9Sstevel@tonic-gate if (days > 0) { 769*7c478bd9Sstevel@tonic-gate (void) sprintf(resbuf, "%s %2d+%02d:%02d", 770*7c478bd9Sstevel@tonic-gate updown, days, hours, minutes); 771*7c478bd9Sstevel@tonic-gate } else { 772*7c478bd9Sstevel@tonic-gate (void) sprintf(resbuf, "%s %2d:%02d", 773*7c478bd9Sstevel@tonic-gate updown, hours, minutes); 774*7c478bd9Sstevel@tonic-gate } 775*7c478bd9Sstevel@tonic-gate return (resbuf); 776*7c478bd9Sstevel@tonic-gate } 777*7c478bd9Sstevel@tonic-gate #endif 778