]>
git.saurik.com Git - apple/network_cmds.git/blob - rwhod.tproj/rwhod.c
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
25 * Copyright (c) 1983, 1993
26 * The Regents of the University of California. All rights reserved.
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. All advertising materials mentioning features or use of this software
37 * must display the following acknowledgement:
38 * This product includes software developed by the University of
39 * California, Berkeley and its contributors.
40 * 4. Neither the name of the University nor the names of its contributors
41 * may be used to endorse or promote products derived from this software
42 * without specific prior written permission.
44 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 static char copyright
[] =
59 "@(#) Copyright (c) 1983, 1993\n\
60 The Regents of the University of California. All rights reserved.\n";
64 static char sccsid
[] = "@(#)rwhod.c 8.1 (Berkeley) 6/6/93";
67 #include <sys/param.h>
68 #include <sys/socket.h>
70 #include <sys/signal.h>
71 #include <sys/ioctl.h>
72 #include <sys/sysctl.h>
75 #include <net/if_dl.h>
76 #include <net/route.h>
77 #include <netinet/in.h>
78 #include <arpa/inet.h>
79 #include <protocols/rwhod.h>
94 * Alarm interval. Don't forget to change the down time check in ruptime
97 #define AL_INTERVAL (3 * 60)
99 char myname
[MAXHOSTNAMELEN
];
102 * We communicate with each neighbor in a list constructed at the time we're
103 * started up. Neighbors are currently directly connected via a hardware
107 struct neighbor
*n_next
;
108 char *n_name
; /* interface name */
109 struct sockaddr
*n_addr
; /* who to send to */
110 int n_addrlen
; /* size of address */
111 int n_flags
; /* should forward?, interface flags */
114 struct neighbor
*neighbors
;
119 #define WHDRSIZE (sizeof(mywd) - sizeof(mywd.wd_we))
121 int configure
__P((int));
122 void getboottime
__P((int));
123 void onalrm
__P((int));
124 void quit
__P((char *));
125 void rt_xaddrs
__P((caddr_t
, caddr_t
, struct rt_addrinfo
*));
126 int verify
__P((char *));
128 char *interval
__P((int, char *));
129 void Sendto
__P((int, char *, int, int, char *, int));
130 #define sendto Sendto
138 struct sockaddr_in from
;
143 struct sockaddr_in sin
;
146 fprintf(stderr
, "rwhod: not super user\n");
149 sp
= getservbyname("who", "udp");
151 fprintf(stderr
, "rwhod: udp/who: unknown service\n");
157 if (chdir(_PATH_RWHODIR
) < 0) {
158 (void)fprintf(stderr
, "rwhod: %s: %s\n",
159 _PATH_RWHODIR
, strerror(errno
));
162 (void) signal(SIGHUP
, getboottime
);
163 openlog("rwhod", LOG_PID
, LOG_DAEMON
);
165 * Establish host name as returned by system.
167 if (gethostname(myname
, sizeof(myname
) - 1) < 0) {
168 syslog(LOG_ERR
, "gethostname: %m");
171 if ((cp
= index(myname
, '.')) != NULL
)
173 strncpy(mywd
.wd_hostname
, myname
, sizeof(myname
) - 1);
174 utmpf
= open(_PATH_UTMP
, O_RDONLY
|O_CREAT
, 0644);
176 syslog(LOG_ERR
, "%s: %m", _PATH_UTMP
);
180 if ((s
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
181 syslog(LOG_ERR
, "socket: %m");
184 if (setsockopt(s
, SOL_SOCKET
, SO_BROADCAST
, &on
, sizeof(on
)) < 0) {
185 syslog(LOG_ERR
, "setsockopt SO_BROADCAST: %m");
188 memset(&sin
, 0, sizeof(sin
));
189 sin
.sin_family
= AF_INET
;
190 sin
.sin_port
= sp
->s_port
;
191 if (bind(s
, (struct sockaddr
*)&sin
, sizeof(sin
)) < 0) {
192 syslog(LOG_ERR
, "bind: %m");
197 signal(SIGALRM
, onalrm
);
201 int cc
, whod
, len
= sizeof(from
);
203 cc
= recvfrom(s
, (char *)&wd
, sizeof(struct whod
), 0,
204 (struct sockaddr
*)&from
, &len
);
206 if (cc
< 0 && errno
!= EINTR
)
207 syslog(LOG_WARNING
, "recv: %m");
210 if (from
.sin_port
!= sp
->s_port
) {
211 syslog(LOG_WARNING
, "%d: bad source port from %s",
212 ntohs(from
.sin_port
), inet_ntoa(from
.sin_addr
));
216 syslog(LOG_WARNING
, "short packet from %s",
217 inet_ntoa(from
.sin_addr
));
221 if (wd
.wd_vers
!= WHODVERSION
)
223 if (wd
.wd_type
!= WHODTYPE_STATUS
)
225 if (!verify(wd
.wd_hostname
)) {
226 syslog(LOG_WARNING
, "malformed host name from %s",
227 inet_ntoa(from
.sin_addr
));
230 (void) sprintf(path
, "whod.%s", wd
.wd_hostname
);
232 * Rather than truncating and growing the file each time,
233 * use ftruncate if size is less than previous size.
235 whod
= open(path
, O_WRONLY
| O_CREAT
, 0644);
237 syslog(LOG_WARNING
, "%s: %m", path
);
240 #if ENDIAN != BIG_ENDIAN
242 int i
, n
= (cc
- WHDRSIZE
)/sizeof(struct whoent
);
245 /* undo header byte swapping before writing to file */
246 wd
.wd_sendtime
= ntohl(wd
.wd_sendtime
);
247 for (i
= 0; i
< 3; i
++)
248 wd
.wd_loadav
[i
] = ntohl(wd
.wd_loadav
[i
]);
249 wd
.wd_boottime
= ntohl(wd
.wd_boottime
);
251 for (i
= 0; i
< n
; i
++) {
252 we
->we_idle
= ntohl(we
->we_idle
);
253 we
->we_utmp
.out_time
=
254 ntohl(we
->we_utmp
.out_time
);
259 (void) time((time_t *)&wd
.wd_recvtime
);
260 (void) write(whod
, (char *)&wd
, cc
);
261 if (fstat(whod
, &st
) < 0 || st
.st_size
> cc
)
268 * Check out host name for unprintables
269 * and other funnies before allowing a file
270 * to be created. Sorry, but blanks aren't allowed.
276 register int size
= 0;
279 if (!isascii(*name
) || !(isalnum(*name
) || ispunct(*name
)))
296 register struct neighbor
*np
;
297 register struct whoent
*we
= mywd
.wd_we
, *wlast
;
305 if (alarmcount
% 10 == 0)
308 (void) fstat(utmpf
, &stb
);
309 if ((stb
.st_mtime
!= utmptime
) || (stb
.st_size
> utmpsize
)) {
310 utmptime
= stb
.st_mtime
;
311 if (stb
.st_size
> utmpsize
) {
312 utmpsize
= stb
.st_size
+ 10 * sizeof(struct utmp
);
314 utmp
= (struct utmp
*)realloc(utmp
, utmpsize
);
316 utmp
= (struct utmp
*)malloc(utmpsize
);
318 fprintf(stderr
, "rwhod: malloc failed\n");
323 (void) lseek(utmpf
, (off_t
)0, L_SET
);
324 cc
= read(utmpf
, (char *)utmp
, stb
.st_size
);
326 fprintf(stderr
, "rwhod: %s: %s\n",
327 _PATH_UTMP
, strerror(errno
));
330 wlast
= &mywd
.wd_we
[1024 / sizeof(struct whoent
) - 1];
331 utmpent
= cc
/ sizeof(struct utmp
);
332 for (i
= 0; i
< utmpent
; i
++)
333 if (utmp
[i
].ut_name
[0]) {
334 memcpy(we
->we_utmp
.out_line
, utmp
[i
].ut_line
,
335 sizeof(utmp
[i
].ut_line
));
336 memcpy(we
->we_utmp
.out_name
, utmp
[i
].ut_name
,
337 sizeof(utmp
[i
].ut_name
));
338 we
->we_utmp
.out_time
= htonl(utmp
[i
].ut_time
);
343 utmpent
= we
- mywd
.wd_we
;
347 * The test on utmpent looks silly---after all, if no one is
348 * logged on, why worry about efficiency?---but is useful on
349 * (e.g.) compute servers.
351 if (utmpent
&& chdir(_PATH_DEV
)) {
352 syslog(LOG_ERR
, "chdir(%s): %m", _PATH_DEV
);
356 for (i
= 0; i
< utmpent
; i
++) {
357 if (stat(we
->we_utmp
.out_line
, &stb
) >= 0)
358 we
->we_idle
= htonl(now
- stb
.st_atime
);
361 (void)getloadavg(avenrun
, sizeof(avenrun
)/sizeof(avenrun
[0]));
362 for (i
= 0; i
< 3; i
++)
363 mywd
.wd_loadav
[i
] = htonl((u_long
)(avenrun
[i
] * 100));
364 cc
= (char *)we
- (char *)&mywd
;
365 mywd
.wd_sendtime
= htonl(time(0));
366 mywd
.wd_vers
= WHODVERSION
;
367 mywd
.wd_type
= WHODTYPE_STATUS
;
368 for (np
= neighbors
; np
!= NULL
; np
= np
->n_next
)
369 (void)sendto(s
, (char *)&mywd
, cc
, 0,
370 np
->n_addr
, np
->n_addrlen
);
371 if (utmpent
&& chdir(_PATH_RWHODIR
)) {
372 syslog(LOG_ERR
, "chdir(%s): %m", _PATH_RWHODIR
);
376 (void) alarm(AL_INTERVAL
);
388 mib
[1] = KERN_BOOTTIME
;
390 if (sysctl(mib
, 2, &tm
, &size
, NULL
, 0) == -1) {
391 syslog(LOG_ERR
, "cannot get boottime: %m");
394 mywd
.wd_boottime
= htonl(tm
.tv_sec
);
401 syslog(LOG_ERR
, msg
);
406 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
407 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
410 rt_xaddrs(cp
, cplim
, rtinfo
)
411 register caddr_t cp
, cplim
;
412 register struct rt_addrinfo
*rtinfo
;
414 register struct sockaddr
*sa
;
417 memset(rtinfo
->rti_info
, 0, sizeof(rtinfo
->rti_info
));
418 for (i
= 0; (i
< RTAX_MAX
) && (cp
< cplim
); i
++) {
419 if ((rtinfo
->rti_addrs
& (1 << i
)) == 0)
421 rtinfo
->rti_info
[i
] = sa
= (struct sockaddr
*)cp
;
427 * Figure out device configuration and select
428 * networks which deserve status information.
434 register struct neighbor
*np
;
435 register struct if_msghdr
*ifm
;
436 register struct ifa_msghdr
*ifam
;
437 struct sockaddr_dl
*sdl
;
439 int mib
[6], flags
= 0, len
;
440 char *buf
, *lim
, *next
;
441 struct rt_addrinfo info
;
447 mib
[4] = NET_RT_IFLIST
;
449 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
450 quit("route-sysctl-estimate");
451 if ((buf
= malloc(needed
)) == NULL
)
453 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) < 0)
454 quit("actual retrieval of interface table");
457 sdl
= NULL
; /* XXX just to keep gcc -Wall happy */
458 for (next
= buf
; next
< lim
; next
+= ifm
->ifm_msglen
) {
459 ifm
= (struct if_msghdr
*)next
;
460 if (ifm
->ifm_type
== RTM_IFINFO
) {
461 sdl
= (struct sockaddr_dl
*)(ifm
+ 1);
462 flags
= ifm
->ifm_flags
;
465 if ((flags
& IFF_UP
) == 0 ||
466 (flags
& (IFF_BROADCAST
|IFF_POINTOPOINT
)) == 0)
468 if (ifm
->ifm_type
!= RTM_NEWADDR
)
469 quit("out of sync parsing NET_RT_IFLIST");
470 ifam
= (struct ifa_msghdr
*)ifm
;
471 info
.rti_addrs
= ifam
->ifam_addrs
;
472 rt_xaddrs((char *)(ifam
+ 1), ifam
->ifam_msglen
+ (char *)ifam
,
474 /* gag, wish we could get rid of Internet dependencies */
475 #define dstaddr info.rti_info[RTAX_BRD]
476 #define IPADDR_SA(x) ((struct sockaddr_in *)(x))->sin_addr.s_addr
477 #define PORT_SA(x) ((struct sockaddr_in *)(x))->sin_port
478 if (dstaddr
== 0 || dstaddr
->sa_family
!= AF_INET
)
480 PORT_SA(dstaddr
) = sp
->s_port
;
481 for (np
= neighbors
; np
!= NULL
; np
= np
->n_next
)
482 if (memcmp(sdl
->sdl_data
, np
->n_name
,
483 sdl
->sdl_nlen
) == 0 &&
484 IPADDR_SA(np
->n_addr
) == IPADDR_SA(dstaddr
))
488 len
= sizeof(*np
) + dstaddr
->sa_len
+ sdl
->sdl_nlen
+ 1;
489 np
= (struct neighbor
*)malloc(len
);
491 quit("malloc of neighbor structure");
494 np
->n_addr
= (struct sockaddr
*)(np
+ 1);
495 np
->n_addrlen
= dstaddr
->sa_len
;
496 np
->n_name
= np
->n_addrlen
+ (char *)np
->n_addr
;
497 np
->n_next
= neighbors
;
499 memcpy((char *)np
->n_addr
, (char *)dstaddr
, np
->n_addrlen
);
500 memcpy(np
->n_name
, sdl
->sdl_data
, sdl
->sdl_nlen
);
508 Sendto(s
, buf
, cc
, flags
, to
, tolen
)
515 register struct whod
*w
= (struct whod
*)buf
;
516 register struct whoent
*we
;
517 struct sockaddr_in
*sin
= (struct sockaddr_in
*)to
;
519 printf("sendto %x.%d\n", ntohl(sin
->sin_addr
), ntohs(sin
->sin_port
));
520 printf("hostname %s %s\n", w
->wd_hostname
,
521 interval(ntohl(w
->wd_sendtime
) - ntohl(w
->wd_boottime
), " up"));
522 printf("load %4.2f, %4.2f, %4.2f\n",
523 ntohl(w
->wd_loadav
[0]) / 100.0, ntohl(w
->wd_loadav
[1]) / 100.0,
524 ntohl(w
->wd_loadav
[2]) / 100.0);
526 for (we
= w
->wd_we
, cc
/= sizeof(struct whoent
); cc
> 0; cc
--, we
++) {
527 time_t t
= ntohl(we
->we_utmp
.out_time
);
528 printf("%-8.8s %s:%s %.12s",
529 we
->we_utmp
.out_name
,
530 w
->wd_hostname
, we
->we_utmp
.out_line
,
532 we
->we_idle
= ntohl(we
->we_idle
) / 60;
534 if (we
->we_idle
>= 100*60)
535 we
->we_idle
= 100*60 - 1;
536 if (we
->we_idle
>= 60)
537 printf(" %2d", we
->we_idle
/ 60);
540 printf(":%02d", we
->we_idle
% 60);
547 interval(time
, updown
)
551 static char resbuf
[32];
552 int days
, hours
, minutes
;
554 if (time
< 0 || time
> 3*30*24*60*60) {
555 (void) sprintf(resbuf
, " %s ??:??", updown
);
558 minutes
= (time
+ 59) / 60; /* round to minutes */
559 hours
= minutes
/ 60; minutes
%= 60;
560 days
= hours
/ 24; hours
%= 24;
562 (void) sprintf(resbuf
, "%s %2d+%02d:%02d",
563 updown
, days
, hours
, minutes
);
565 (void) sprintf(resbuf
, "%s %2d:%02d",
566 updown
, hours
, minutes
);