1*a8b658e3Schristos /* $NetBSD: rwhod.c,v 1.25 2005/06/24 13:24:23 christos Exp $ */ 2f17eeccaSchristos 3e541169cScgd /* 49afcf17bSjtc * Copyright (c) 1983, 1993 59afcf17bSjtc * The Regents of the University of California. All rights reserved. 6e541169cScgd * 7e541169cScgd * Redistribution and use in source and binary forms, with or without 8e541169cScgd * modification, are permitted provided that the following conditions 9e541169cScgd * are met: 10e541169cScgd * 1. Redistributions of source code must retain the above copyright 11e541169cScgd * notice, this list of conditions and the following disclaimer. 12e541169cScgd * 2. Redistributions in binary form must reproduce the above copyright 13e541169cScgd * notice, this list of conditions and the following disclaimer in the 14e541169cScgd * documentation and/or other materials provided with the distribution. 15326b2259Sagc * 3. Neither the name of the University nor the names of its contributors 16e541169cScgd * may be used to endorse or promote products derived from this software 17e541169cScgd * without specific prior written permission. 18e541169cScgd * 19e541169cScgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20e541169cScgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21e541169cScgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22e541169cScgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23e541169cScgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24e541169cScgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25e541169cScgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26e541169cScgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27e541169cScgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28e541169cScgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29e541169cScgd * SUCH DAMAGE. 30e541169cScgd */ 31e541169cScgd 328d79db10Slukem #include <sys/cdefs.h> 33e541169cScgd #ifndef lint 348d79db10Slukem __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\ 358d79db10Slukem The Regents of the University of California. All rights reserved.\n"); 36e541169cScgd #endif /* not lint */ 37e541169cScgd 38e541169cScgd #ifndef lint 398d79db10Slukem #if 0 408d79db10Slukem static char sccsid[] = "@(#)rwhod.c 8.1 (Berkeley) 6/6/93"; 418d79db10Slukem #else 42*a8b658e3Schristos __RCSID("$NetBSD: rwhod.c,v 1.25 2005/06/24 13:24:23 christos Exp $"); 438d79db10Slukem #endif 44e541169cScgd #endif /* not lint */ 45e541169cScgd 46e541169cScgd #include <sys/param.h> 47e541169cScgd #include <sys/socket.h> 48e541169cScgd #include <sys/stat.h> 49e541169cScgd #include <sys/signal.h> 50e541169cScgd #include <sys/ioctl.h> 519afcf17bSjtc #include <sys/sysctl.h> 52e541169cScgd 53e541169cScgd #include <net/if.h> 549afcf17bSjtc #include <net/if_dl.h> 559afcf17bSjtc #include <net/route.h> 56e541169cScgd #include <netinet/in.h> 57e541169cScgd #include <protocols/rwhod.h> 588d79db10Slukem #include <arpa/inet.h> 599afcf17bSjtc 609afcf17bSjtc #include <ctype.h> 61e5d6d67cSlukem #include <err.h> 629afcf17bSjtc #include <errno.h> 639afcf17bSjtc #include <fcntl.h> 649afcf17bSjtc #include <netdb.h> 65e541169cScgd #include <paths.h> 66f17eeccaSchristos #include <poll.h> 679afcf17bSjtc #include <stdio.h> 689afcf17bSjtc #include <stdlib.h> 699afcf17bSjtc #include <string.h> 709afcf17bSjtc #include <syslog.h> 719afcf17bSjtc #include <unistd.h> 72bcd46591Sthorpej #include <util.h> 73e541169cScgd 74b166b5b4Schristos #include "utmpentry.h" 75e541169cScgd /* 76e541169cScgd * Alarm interval. Don't forget to change the down time check in ruptime 77e541169cScgd * if this is changed. 78e541169cScgd */ 79e541169cScgd #define AL_INTERVAL (3 * 60) 80e541169cScgd 81f17eeccaSchristos static char myname[MAXHOSTNAMELEN + 1]; 82e541169cScgd 83e541169cScgd /* 849afcf17bSjtc * We communicate with each neighbor in a list constructed at the time we're 859afcf17bSjtc * started up. Neighbors are currently directly connected via a hardware 869afcf17bSjtc * interface. 87e541169cScgd */ 88e541169cScgd struct neighbor { 89e541169cScgd struct neighbor *n_next; 90e541169cScgd char *n_name; /* interface name */ 919afcf17bSjtc struct sockaddr *n_addr; /* who to send to */ 92e541169cScgd int n_addrlen; /* size of address */ 93e541169cScgd int n_flags; /* should forward?, interface flags */ 94e541169cScgd }; 95e541169cScgd 96f17eeccaSchristos static struct neighbor *neighbors; 97f17eeccaSchristos static struct whod mywd; 98f17eeccaSchristos static struct servent *sp; 99f17eeccaSchristos static volatile sig_atomic_t onsighup; 100f17eeccaSchristos static int alarmcount; 101e541169cScgd 102e541169cScgd #define WHDRSIZE (sizeof(mywd) - sizeof(mywd.wd_we)) 103e541169cScgd 104f17eeccaSchristos int main(int, char **); 105f17eeccaSchristos 106f17eeccaSchristos static int configure(int); 107f17eeccaSchristos static void getboottime(void); 108f17eeccaSchristos static void send_host_information(int); 109f17eeccaSchristos static void hup(int); 110f17eeccaSchristos static void handleread(int); 111f17eeccaSchristos static void timeadd(struct timeval *, time_t, struct timeval *); 112f17eeccaSchristos static void quit(const char *); 113f17eeccaSchristos static void rt_xaddrs(void *, void *, struct rt_addrinfo *); 114f17eeccaSchristos static int verify(const char *); 1159afcf17bSjtc #ifdef DEBUG 116f17eeccaSchristos static char *interval(int, const char *); 1179afcf17bSjtc #define sendto Sendto 118f17eeccaSchristos static ssize_t Sendto(int, const void *, size_t, int, 119f17eeccaSchristos const struct sockaddr *, socklen_t); 1209afcf17bSjtc #endif 121e541169cScgd 1229afcf17bSjtc int 123f17eeccaSchristos main(int argc, char *argv[]) 124e541169cScgd { 125e541169cScgd int on = 1; 126f17eeccaSchristos int s; 1279afcf17bSjtc char *cp; 128f17eeccaSchristos struct sockaddr_in sasin; 129f17eeccaSchristos struct pollfd pfd[1]; 130f17eeccaSchristos time_t delta = 0; 131f17eeccaSchristos struct timeval next, now; 132e541169cScgd 133e5d6d67cSlukem if (getuid()) 134e5d6d67cSlukem errx(1, "not super user"); 135e541169cScgd sp = getservbyname("who", "udp"); 136e5d6d67cSlukem if (sp == NULL) 137e5d6d67cSlukem errx(1, "udp/who: unknown service"); 138e541169cScgd #ifndef DEBUG 139e541169cScgd daemon(1, 0); 140bcd46591Sthorpej pidfile(NULL); 141e541169cScgd #endif 142e5d6d67cSlukem if (chdir(_PATH_RWHODIR) < 0) 143e5d6d67cSlukem err(1, "%s", _PATH_RWHODIR); 144f17eeccaSchristos (void)signal(SIGHUP, hup); 145e541169cScgd openlog("rwhod", LOG_PID, LOG_DAEMON); 146e541169cScgd /* 147e541169cScgd * Establish host name as returned by system. 148e541169cScgd */ 149e541169cScgd if (gethostname(myname, sizeof(myname) - 1) < 0) { 150e541169cScgd syslog(LOG_ERR, "gethostname: %m"); 151e541169cScgd exit(1); 152e541169cScgd } 15332f51971Smrg myname[sizeof(myname) - 1] = '\0'; 154e5d6d67cSlukem if ((cp = strchr(myname, '.')) != NULL) 155e541169cScgd *cp = '\0'; 156f17eeccaSchristos (void)strncpy(mywd.wd_hostname, myname, sizeof(mywd.wd_hostname) - 1); 157f17eeccaSchristos getboottime(); 158e541169cScgd if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 159e541169cScgd syslog(LOG_ERR, "socket: %m"); 160e541169cScgd exit(1); 161e541169cScgd } 162e541169cScgd if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) { 163e541169cScgd syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m"); 164e541169cScgd exit(1); 165e541169cScgd } 166f17eeccaSchristos (void)memset(&sasin, 0, sizeof(sasin)); 167f17eeccaSchristos sasin.sin_family = AF_INET; 168f17eeccaSchristos sasin.sin_port = sp->s_port; 169f17eeccaSchristos if (bind(s, (struct sockaddr *)&sasin, sizeof(sasin)) < 0) { 170e541169cScgd syslog(LOG_ERR, "bind: %m"); 171e541169cScgd exit(1); 172e541169cScgd } 173e541169cScgd if (!configure(s)) 174e541169cScgd exit(1); 175f17eeccaSchristos 176f17eeccaSchristos send_host_information(s); 177f17eeccaSchristos delta = AL_INTERVAL; 178f17eeccaSchristos gettimeofday(&now, NULL); 179f17eeccaSchristos timeadd(&now, delta, &next); 180f17eeccaSchristos 181f17eeccaSchristos pfd[0].fd = s; 182*a8b658e3Schristos pfd[0].events = POLLIN; 183f17eeccaSchristos 184e541169cScgd for (;;) { 185f17eeccaSchristos int n; 186f17eeccaSchristos 187f17eeccaSchristos n = poll(pfd, 1, 1000); 188f17eeccaSchristos 189f17eeccaSchristos if (onsighup) { 190f17eeccaSchristos onsighup = 0; 191f17eeccaSchristos getboottime(); 192f17eeccaSchristos } 193f17eeccaSchristos 194f17eeccaSchristos if (n == 1) 195f17eeccaSchristos handleread(s); 196f17eeccaSchristos 197f17eeccaSchristos (void)gettimeofday(&now, NULL); 198f17eeccaSchristos if (now.tv_sec > next.tv_sec) { 199f17eeccaSchristos send_host_information(s); 200f17eeccaSchristos timeadd(&now, delta, &next); 201f17eeccaSchristos } 202f17eeccaSchristos } 203f17eeccaSchristos } 204f17eeccaSchristos 205f17eeccaSchristos static void 206f17eeccaSchristos hup(int signo __unused) 207f17eeccaSchristos { 208f17eeccaSchristos onsighup = 1; 209f17eeccaSchristos } 210f17eeccaSchristos 211f17eeccaSchristos static void 212f17eeccaSchristos timeadd(struct timeval *now, time_t delta, struct timeval *next) 213f17eeccaSchristos { 214f17eeccaSchristos (next)->tv_sec = (now)->tv_sec + delta; 215f17eeccaSchristos } 216f17eeccaSchristos 217f17eeccaSchristos static void 218f17eeccaSchristos handleread(int s) 219f17eeccaSchristos { 220f17eeccaSchristos struct sockaddr_in from; 221f17eeccaSchristos struct stat st; 222f17eeccaSchristos char path[64]; 223e541169cScgd struct whod wd; 224f17eeccaSchristos int cc, whod; 225f17eeccaSchristos socklen_t len = sizeof(from); 226e541169cScgd 227e541169cScgd cc = recvfrom(s, (char *)&wd, sizeof(struct whod), 0, 228e541169cScgd (struct sockaddr *)&from, &len); 229e541169cScgd if (cc <= 0) { 230e541169cScgd if (cc < 0 && errno != EINTR) 231e541169cScgd syslog(LOG_WARNING, "recv: %m"); 232f17eeccaSchristos return; 233e541169cScgd } 234e541169cScgd if (from.sin_port != sp->s_port) { 235e541169cScgd syslog(LOG_WARNING, "%d: bad from port", 236e541169cScgd ntohs(from.sin_port)); 237f17eeccaSchristos return; 238e541169cScgd } 239f214fa32Smjl if (cc < WHDRSIZE) { 240f214fa32Smjl syslog(LOG_WARNING, "Short packet from %s", 241f214fa32Smjl inet_ntoa(from.sin_addr)); 242f17eeccaSchristos return; 243f214fa32Smjl } 244f214fa32Smjl 245e541169cScgd if (wd.wd_vers != WHODVERSION) 246f17eeccaSchristos return; 247e541169cScgd if (wd.wd_type != WHODTYPE_STATUS) 248f17eeccaSchristos return; 249d3a4eeb1Sexplorer /* 250d3a4eeb1Sexplorer * Ensure null termination of the name within the packet. 251d3a4eeb1Sexplorer * Otherwise we might overflow or read past the end. 252d3a4eeb1Sexplorer */ 253d3a4eeb1Sexplorer wd.wd_hostname[sizeof(wd.wd_hostname)-1] = 0; 254e541169cScgd if (!verify(wd.wd_hostname)) { 2558d79db10Slukem syslog(LOG_WARNING, "malformed host name from %s", 2568d79db10Slukem inet_ntoa(from.sin_addr)); 257f17eeccaSchristos return; 258e541169cScgd } 259f17eeccaSchristos (void)snprintf(path, sizeof(path), "whod.%s", wd.wd_hostname); 260e541169cScgd /* 261e541169cScgd * Rather than truncating and growing the file each time, 262e541169cScgd * use ftruncate if size is less than previous size. 263e541169cScgd */ 264e541169cScgd whod = open(path, O_WRONLY | O_CREAT, 0644); 265e541169cScgd if (whod < 0) { 266e541169cScgd syslog(LOG_WARNING, "%s: %m", path); 267f17eeccaSchristos return; 268e541169cScgd } 269e541169cScgd #if ENDIAN != BIG_ENDIAN 270e541169cScgd { 271e541169cScgd int i, n = (cc - WHDRSIZE)/sizeof(struct whoent); 272e541169cScgd struct whoent *we; 273e541169cScgd 274e541169cScgd /* undo header byte swapping before writing to file */ 275e541169cScgd wd.wd_sendtime = ntohl(wd.wd_sendtime); 276e541169cScgd for (i = 0; i < 3; i++) 277e541169cScgd wd.wd_loadav[i] = ntohl(wd.wd_loadav[i]); 278e541169cScgd wd.wd_boottime = ntohl(wd.wd_boottime); 279e541169cScgd we = wd.wd_we; 280e541169cScgd for (i = 0; i < n; i++) { 281e541169cScgd we->we_idle = ntohl(we->we_idle); 282e541169cScgd we->we_utmp.out_time = 283e541169cScgd ntohl(we->we_utmp.out_time); 284e541169cScgd we++; 285e541169cScgd } 286e541169cScgd } 287e541169cScgd #endif 288e541169cScgd (void)time((time_t *)&wd.wd_recvtime); 289e541169cScgd (void)write(whod, (char *)&wd, cc); 290e541169cScgd if (fstat(whod, &st) < 0 || st.st_size > cc) 291f17eeccaSchristos (void)ftruncate(whod, cc); 292e541169cScgd (void)close(whod); 293e541169cScgd } 294e541169cScgd 295e541169cScgd /* 296e541169cScgd * Check out host name for unprintables 297e541169cScgd * and other funnies before allowing a file 298e541169cScgd * to be created. Sorry, but blanks aren't allowed. 299e541169cScgd */ 300f17eeccaSchristos static int 301f17eeccaSchristos verify(const char *name) 302e541169cScgd { 303e5d6d67cSlukem int size = 0; 304e541169cScgd 305e541169cScgd while (*name) { 306f17eeccaSchristos if (!isascii((unsigned char)*name) || 307f17eeccaSchristos !(isalnum((unsigned char)*name) || 3089122339bSdsl ispunct((unsigned char)*name))) 309f17eeccaSchristos return 0; 310e541169cScgd name++, size++; 311e541169cScgd } 312f17eeccaSchristos return size > 0; 313e541169cScgd } 314e541169cScgd 315e541169cScgd 316f17eeccaSchristos static void 317f17eeccaSchristos send_host_information(int s) 318e541169cScgd { 319e5d6d67cSlukem struct neighbor *np; 320e5d6d67cSlukem struct whoent *we = mywd.wd_we, *wlast; 321e5d6d67cSlukem int i; 322e541169cScgd struct stat stb; 323e541169cScgd double avenrun[3]; 3249afcf17bSjtc time_t now; 3259afcf17bSjtc int cc; 326b166b5b4Schristos static struct utmpentry *ohead = NULL; 327b166b5b4Schristos struct utmpentry *ep; 328b166b5b4Schristos int utmpent = 0; 329e541169cScgd 3309afcf17bSjtc now = time(NULL); 331e541169cScgd if (alarmcount % 10 == 0) 332f17eeccaSchristos getboottime(); 333e541169cScgd alarmcount++; 334b166b5b4Schristos 335b166b5b4Schristos (void)getutentries(NULL, &ep); 336b166b5b4Schristos if (ep != ohead) { 337b166b5b4Schristos freeutentries(ep); 338e541169cScgd wlast = &mywd.wd_we[1024 / sizeof(struct whoent) - 1]; 339b166b5b4Schristos for (; ep; ep = ep->next) { 340b166b5b4Schristos (void)strncpy(we->we_utmp.out_line, ep->line, 341b166b5b4Schristos sizeof(we->we_utmp.out_line) - 1); 342b166b5b4Schristos (void)strncpy(we->we_utmp.out_name, ep->name, 343b166b5b4Schristos sizeof(we->we_utmp.out_name) - 1); 344b166b5b4Schristos we->we_utmp.out_time = htonl(ep->tv.tv_sec); 345e541169cScgd if (we >= wlast) 346e541169cScgd break; 347e541169cScgd we++; 348e541169cScgd } 349e541169cScgd utmpent = we - mywd.wd_we; 350e541169cScgd } 351e541169cScgd 352e541169cScgd /* 353e541169cScgd * The test on utmpent looks silly---after all, if no one is 354e541169cScgd * logged on, why worry about efficiency?---but is useful on 355e541169cScgd * (e.g.) compute servers. 356e541169cScgd */ 357e541169cScgd if (utmpent && chdir(_PATH_DEV)) { 358e541169cScgd syslog(LOG_ERR, "chdir(%s): %m", _PATH_DEV); 359e541169cScgd exit(1); 360e541169cScgd } 361e541169cScgd we = mywd.wd_we; 362e541169cScgd for (i = 0; i < utmpent; i++) { 363e541169cScgd if (stat(we->we_utmp.out_line, &stb) >= 0) 364e541169cScgd we->we_idle = htonl(now - stb.st_atime); 365e541169cScgd we++; 366e541169cScgd } 367e541169cScgd (void)getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0])); 368e541169cScgd for (i = 0; i < 3; i++) 369e541169cScgd mywd.wd_loadav[i] = htonl((u_long)(avenrun[i] * 100)); 370e541169cScgd cc = (char *)we - (char *)&mywd; 371e541169cScgd mywd.wd_sendtime = htonl(time(0)); 372e541169cScgd mywd.wd_vers = WHODVERSION; 373e541169cScgd mywd.wd_type = WHODTYPE_STATUS; 374e541169cScgd for (np = neighbors; np != NULL; np = np->n_next) 375e541169cScgd (void)sendto(s, (char *)&mywd, cc, 0, 3769afcf17bSjtc np->n_addr, np->n_addrlen); 377e541169cScgd if (utmpent && chdir(_PATH_RWHODIR)) { 378e541169cScgd syslog(LOG_ERR, "chdir(%s): %m", _PATH_RWHODIR); 379e541169cScgd exit(1); 380e541169cScgd } 381e541169cScgd } 382e541169cScgd 383f17eeccaSchristos static void 384f17eeccaSchristos getboottime(void) 385e541169cScgd { 3869afcf17bSjtc int mib[2]; 3879afcf17bSjtc size_t size; 3889afcf17bSjtc struct timeval tm; 389e541169cScgd 3909afcf17bSjtc mib[0] = CTL_KERN; 3919afcf17bSjtc mib[1] = KERN_BOOTTIME; 3929afcf17bSjtc size = sizeof(tm); 3939afcf17bSjtc if (sysctl(mib, 2, &tm, &size, NULL, 0) == -1) { 3949afcf17bSjtc syslog(LOG_ERR, "cannot get boottime: %m"); 3959afcf17bSjtc exit(1); 3969afcf17bSjtc } 3979afcf17bSjtc mywd.wd_boottime = htonl(tm.tv_sec); 398e541169cScgd } 399b55bc39bSandrew 400f17eeccaSchristos static void 401f17eeccaSchristos quit(const char *msg) 4029afcf17bSjtc { 403d8302e2dSis syslog(LOG_ERR, "%s", msg); 4049afcf17bSjtc exit(1); 405e541169cScgd } 4069afcf17bSjtc 4079afcf17bSjtc #define ROUNDUP(a) \ 4089afcf17bSjtc ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 409f17eeccaSchristos #define ADVANCE(x, n) ((char *)(x) + ROUNDUP((n)->sa_len)) 4109afcf17bSjtc 411f17eeccaSchristos static void 412f17eeccaSchristos rt_xaddrs(void *cp, void *cplim, struct rt_addrinfo *rtinfo) 4139afcf17bSjtc { 414e5d6d67cSlukem struct sockaddr *sa; 415e5d6d67cSlukem int i; 4169afcf17bSjtc 417f17eeccaSchristos (void)memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info)); 4189afcf17bSjtc for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { 4199afcf17bSjtc if ((rtinfo->rti_addrs & (1 << i)) == 0) 4209afcf17bSjtc continue; 4219afcf17bSjtc rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; 422f17eeccaSchristos cp = ADVANCE(cp, sa); 4239afcf17bSjtc } 424e541169cScgd } 425e541169cScgd 426e541169cScgd /* 427e541169cScgd * Figure out device configuration and select 428e541169cScgd * networks which deserve status information. 429e541169cScgd */ 430f17eeccaSchristos static int 431f17eeccaSchristos configure(int s) 432e541169cScgd { 433e5d6d67cSlukem struct neighbor *np; 434e5d6d67cSlukem struct if_msghdr *ifm; 435e5d6d67cSlukem struct ifa_msghdr *ifam; 4369afcf17bSjtc struct sockaddr_dl *sdl; 4379afcf17bSjtc size_t needed; 4389afcf17bSjtc int mib[6], flags = 0, len; 4399afcf17bSjtc char *buf, *lim, *next; 4409afcf17bSjtc struct rt_addrinfo info; 441f17eeccaSchristos struct sockaddr_in dstaddr; 442e541169cScgd 4439afcf17bSjtc mib[0] = CTL_NET; 4449afcf17bSjtc mib[1] = PF_ROUTE; 4459afcf17bSjtc mib[2] = 0; 4469afcf17bSjtc mib[3] = AF_INET; 4479afcf17bSjtc mib[4] = NET_RT_IFLIST; 4489afcf17bSjtc mib[5] = 0; 4499afcf17bSjtc if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 4509afcf17bSjtc quit("route-sysctl-estimate"); 4519afcf17bSjtc if ((buf = malloc(needed)) == NULL) 4529afcf17bSjtc quit("malloc"); 4539afcf17bSjtc if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 4549afcf17bSjtc quit("actual retrieval of interface table"); 4559afcf17bSjtc lim = buf + needed; 4569afcf17bSjtc 4579afcf17bSjtc sdl = NULL; /* XXX just to keep gcc -Wall happy */ 4589afcf17bSjtc for (next = buf; next < lim; next += ifm->ifm_msglen) { 4599afcf17bSjtc ifm = (struct if_msghdr *)next; 4609afcf17bSjtc if (ifm->ifm_type == RTM_IFINFO) { 4619afcf17bSjtc sdl = (struct sockaddr_dl *)(ifm + 1); 4629afcf17bSjtc flags = ifm->ifm_flags; 4639afcf17bSjtc continue; 464e541169cScgd } 4659afcf17bSjtc if ((flags & IFF_UP) == 0 || 4669afcf17bSjtc (flags & (IFF_BROADCAST|IFF_POINTOPOINT)) == 0) 4679afcf17bSjtc continue; 4689afcf17bSjtc if (ifm->ifm_type != RTM_NEWADDR) 4699afcf17bSjtc quit("out of sync parsing NET_RT_IFLIST"); 4709afcf17bSjtc ifam = (struct ifa_msghdr *)ifm; 4719afcf17bSjtc info.rti_addrs = ifam->ifam_addrs; 472f17eeccaSchristos rt_xaddrs((ifam + 1), ifam->ifam_msglen + (char *)ifam, &info); 4739afcf17bSjtc /* gag, wish we could get rid of Internet dependencies */ 474f17eeccaSchristos if (info.rti_info[RTAX_BRD] == NULL || 475f17eeccaSchristos info.rti_info[RTAX_BRD]->sa_family != AF_INET) 476f17eeccaSchristos continue; 477f17eeccaSchristos (void)memcpy(&dstaddr, info.rti_info[RTAX_BRD], 478f17eeccaSchristos sizeof(dstaddr)); 4799afcf17bSjtc #define IPADDR_SA(x) ((struct sockaddr_in *)(x))->sin_addr.s_addr 4809afcf17bSjtc #define PORT_SA(x) ((struct sockaddr_in *)(x))->sin_port 481f17eeccaSchristos PORT_SA(&dstaddr) = sp->s_port; 482e541169cScgd for (np = neighbors; np != NULL; np = np->n_next) 4839afcf17bSjtc if (memcmp(sdl->sdl_data, np->n_name, 4849afcf17bSjtc sdl->sdl_nlen) == 0 && 485f17eeccaSchristos IPADDR_SA(np->n_addr) == IPADDR_SA(&dstaddr)) 486e541169cScgd break; 487e541169cScgd if (np != NULL) 488e541169cScgd continue; 489f17eeccaSchristos len = sizeof(*np) + dstaddr.sin_len + sdl->sdl_nlen + 1; 4909afcf17bSjtc np = (struct neighbor *)malloc(len); 491e541169cScgd if (np == NULL) 4929afcf17bSjtc quit("malloc of neighbor structure"); 493f17eeccaSchristos (void)memset(np, 0, len); 4949afcf17bSjtc np->n_flags = flags; 4959afcf17bSjtc np->n_addr = (struct sockaddr *)(np + 1); 496f17eeccaSchristos np->n_addrlen = dstaddr.sin_len; 4979afcf17bSjtc np->n_name = np->n_addrlen + (char *)np->n_addr; 498e541169cScgd np->n_next = neighbors; 499e541169cScgd neighbors = np; 500f17eeccaSchristos (void)memcpy(np->n_addr, &dstaddr, np->n_addrlen); 501f17eeccaSchristos (void)memcpy(np->n_name, sdl->sdl_data, sdl->sdl_nlen); 502e541169cScgd } 5039afcf17bSjtc free(buf); 504e541169cScgd return (1); 505e541169cScgd } 506e541169cScgd 507e541169cScgd #ifdef DEBUG 508f17eeccaSchristos static ssize_t 509f17eeccaSchristos Sendto(int s, const void *buf, size_t cc, int flags, const struct sockaddr *to, 510f17eeccaSchristos socklen_t tolen) 511e541169cScgd { 512e5d6d67cSlukem struct whod *w = (struct whod *)buf; 513e5d6d67cSlukem struct whoent *we; 514f17eeccaSchristos struct sockaddr_in *sasin = (struct sockaddr_in *)to; 515e541169cScgd 516f17eeccaSchristos printf("sendto %x.%d\n", ntohl(sasin->sin_addr.s_addr), 517f17eeccaSchristos ntohs(sasin->sin_port)); 518e541169cScgd printf("hostname %s %s\n", w->wd_hostname, 519e541169cScgd interval(ntohl(w->wd_sendtime) - ntohl(w->wd_boottime), " up")); 520e541169cScgd printf("load %4.2f, %4.2f, %4.2f\n", 521e541169cScgd ntohl(w->wd_loadav[0]) / 100.0, ntohl(w->wd_loadav[1]) / 100.0, 522e541169cScgd ntohl(w->wd_loadav[2]) / 100.0); 523e541169cScgd cc -= WHDRSIZE; 524e541169cScgd for (we = w->wd_we, cc /= sizeof(struct whoent); cc > 0; cc--, we++) { 525e541169cScgd time_t t = ntohl(we->we_utmp.out_time); 52650455a91Schristos printf("%-8.8s %s:%s %.12s", we->we_utmp.out_name, 52750455a91Schristos w->wd_hostname, we->we_utmp.out_line, ctime(&t)+4); 528e541169cScgd we->we_idle = ntohl(we->we_idle) / 60; 529e541169cScgd if (we->we_idle) { 530e541169cScgd if (we->we_idle >= 100*60) 531e541169cScgd we->we_idle = 100*60 - 1; 532e541169cScgd if (we->we_idle >= 60) 533e541169cScgd printf(" %2d", we->we_idle / 60); 534e541169cScgd else 535e541169cScgd printf(" "); 536e541169cScgd printf(":%02d", we->we_idle % 60); 537e541169cScgd } 538e541169cScgd printf("\n"); 539e541169cScgd } 54050455a91Schristos return (ssize_t)cc; 541e541169cScgd } 542e541169cScgd 543f17eeccaSchristos static char * 544f17eeccaSchristos interval(int time, const char *updown) 545e541169cScgd { 546e541169cScgd static char resbuf[32]; 547e541169cScgd int days, hours, minutes; 548e541169cScgd 549e541169cScgd if (time < 0 || time > 3*30*24*60*60) { 550d9f2774cSitojun (void)snprintf(resbuf, sizeof(resbuf), " %s ??:??", updown); 551e541169cScgd return (resbuf); 552e541169cScgd } 553e541169cScgd minutes = (time + 59) / 60; /* round to minutes */ 554e541169cScgd hours = minutes / 60; minutes %= 60; 555e541169cScgd days = hours / 24; hours %= 24; 556e541169cScgd if (days) 557d9f2774cSitojun (void)snprintf(resbuf, sizeof(resbuf), "%s %2d+%02d:%02d", 558e541169cScgd updown, days, hours, minutes); 559e541169cScgd else 560d9f2774cSitojun (void)snprintf(resbuf, sizeof(resbuf), "%s %2d:%02d", 561e541169cScgd updown, hours, minutes); 562f17eeccaSchristos return resbuf; 563e541169cScgd } 564e541169cScgd #endif 565