]>
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 <protocols/rwhod.h>
93 * Alarm interval. Don't forget to change the down time check in ruptime
96 #define AL_INTERVAL (3 * 60)
98 char myname
[MAXHOSTNAMELEN
];
101 * We communicate with each neighbor in a list constructed at the time we're
102 * started up. Neighbors are currently directly connected via a hardware
106 struct neighbor
*n_next
;
107 char *n_name
; /* interface name */
108 struct sockaddr
*n_addr
; /* who to send to */
109 int n_addrlen
; /* size of address */
110 int n_flags
; /* should forward?, interface flags */
113 struct neighbor
*neighbors
;
118 #define WHDRSIZE (sizeof(mywd) - sizeof(mywd.wd_we))
120 int configure
__P((int));
121 void getboottime
__P((int));
122 void onalrm
__P((int));
123 void quit
__P((char *));
124 void rt_xaddrs
__P((caddr_t
, caddr_t
, struct rt_addrinfo
*));
125 int verify
__P((char *));
127 char *interval
__P((int, char *));
128 void Sendto
__P((int, char *, int, int, char *, int));
129 #define sendto Sendto
137 struct sockaddr_in from
;
142 struct sockaddr_in sin
;
145 fprintf(stderr
, "rwhod: not super user\n");
148 sp
= getservbyname("who", "udp");
150 fprintf(stderr
, "rwhod: udp/who: unknown service\n");
156 if (chdir(_PATH_RWHODIR
) < 0) {
157 (void)fprintf(stderr
, "rwhod: %s: %s\n",
158 _PATH_RWHODIR
, strerror(errno
));
161 (void) signal(SIGHUP
, getboottime
);
162 openlog("rwhod", LOG_PID
, LOG_DAEMON
);
164 * Establish host name as returned by system.
166 if (gethostname(myname
, sizeof(myname
) - 1) < 0) {
167 syslog(LOG_ERR
, "gethostname: %m");
170 if ((cp
= index(myname
, '.')) != NULL
)
172 strncpy(mywd
.wd_hostname
, myname
, sizeof(myname
) - 1);
173 utmpf
= open(_PATH_UTMP
, O_RDONLY
|O_CREAT
, 0644);
175 syslog(LOG_ERR
, "%s: %m", _PATH_UTMP
);
179 if ((s
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
180 syslog(LOG_ERR
, "socket: %m");
183 if (setsockopt(s
, SOL_SOCKET
, SO_BROADCAST
, &on
, sizeof(on
)) < 0) {
184 syslog(LOG_ERR
, "setsockopt SO_BROADCAST: %m");
187 memset(&sin
, 0, sizeof(sin
));
188 sin
.sin_family
= AF_INET
;
189 sin
.sin_port
= sp
->s_port
;
190 if (bind(s
, (struct sockaddr
*)&sin
, sizeof(sin
)) < 0) {
191 syslog(LOG_ERR
, "bind: %m");
196 signal(SIGALRM
, onalrm
);
200 int cc
, whod
, len
= sizeof(from
);
202 cc
= recvfrom(s
, (char *)&wd
, sizeof(struct whod
), 0,
203 (struct sockaddr
*)&from
, &len
);
205 if (cc
< 0 && errno
!= EINTR
)
206 syslog(LOG_WARNING
, "recv: %m");
209 if (from
.sin_port
!= sp
->s_port
) {
210 syslog(LOG_WARNING
, "%d: bad from port",
211 ntohs(from
.sin_port
));
214 if (wd
.wd_vers
!= WHODVERSION
)
216 if (wd
.wd_type
!= WHODTYPE_STATUS
)
218 if (!verify(wd
.wd_hostname
)) {
219 syslog(LOG_WARNING
, "malformed host name from %x",
223 (void) sprintf(path
, "whod.%s", wd
.wd_hostname
);
225 * Rather than truncating and growing the file each time,
226 * use ftruncate if size is less than previous size.
228 whod
= open(path
, O_WRONLY
| O_CREAT
, 0644);
230 syslog(LOG_WARNING
, "%s: %m", path
);
233 #if ENDIAN != BIG_ENDIAN
235 int i
, n
= (cc
- WHDRSIZE
)/sizeof(struct whoent
);
238 /* undo header byte swapping before writing to file */
239 wd
.wd_sendtime
= ntohl(wd
.wd_sendtime
);
240 for (i
= 0; i
< 3; i
++)
241 wd
.wd_loadav
[i
] = ntohl(wd
.wd_loadav
[i
]);
242 wd
.wd_boottime
= ntohl(wd
.wd_boottime
);
244 for (i
= 0; i
< n
; i
++) {
245 we
->we_idle
= ntohl(we
->we_idle
);
246 we
->we_utmp
.out_time
=
247 ntohl(we
->we_utmp
.out_time
);
252 (void) time((time_t *)&wd
.wd_recvtime
);
253 (void) write(whod
, (char *)&wd
, cc
);
254 if (fstat(whod
, &st
) < 0 || st
.st_size
> cc
)
261 * Check out host name for unprintables
262 * and other funnies before allowing a file
263 * to be created. Sorry, but blanks aren't allowed.
269 register int size
= 0;
272 if (!isascii(*name
) || !(isalnum(*name
) || ispunct(*name
)))
289 register struct neighbor
*np
;
290 register struct whoent
*we
= mywd
.wd_we
, *wlast
;
298 if (alarmcount
% 10 == 0)
301 (void) fstat(utmpf
, &stb
);
302 if ((stb
.st_mtime
!= utmptime
) || (stb
.st_size
> utmpsize
)) {
303 utmptime
= stb
.st_mtime
;
304 if (stb
.st_size
> utmpsize
) {
305 utmpsize
= stb
.st_size
+ 10 * sizeof(struct utmp
);
307 utmp
= (struct utmp
*)realloc(utmp
, utmpsize
);
309 utmp
= (struct utmp
*)malloc(utmpsize
);
311 fprintf(stderr
, "rwhod: malloc failed\n");
316 (void) lseek(utmpf
, (off_t
)0, L_SET
);
317 cc
= read(utmpf
, (char *)utmp
, stb
.st_size
);
319 fprintf(stderr
, "rwhod: %s: %s\n",
320 _PATH_UTMP
, strerror(errno
));
323 wlast
= &mywd
.wd_we
[1024 / sizeof(struct whoent
) - 1];
324 utmpent
= cc
/ sizeof(struct utmp
);
325 for (i
= 0; i
< utmpent
; i
++)
326 if (utmp
[i
].ut_name
[0]) {
327 memcpy(we
->we_utmp
.out_line
, utmp
[i
].ut_line
,
328 sizeof(utmp
[i
].ut_line
));
329 memcpy(we
->we_utmp
.out_name
, utmp
[i
].ut_name
,
330 sizeof(utmp
[i
].ut_name
));
331 we
->we_utmp
.out_time
= htonl(utmp
[i
].ut_time
);
336 utmpent
= we
- mywd
.wd_we
;
340 * The test on utmpent looks silly---after all, if no one is
341 * logged on, why worry about efficiency?---but is useful on
342 * (e.g.) compute servers.
344 if (utmpent
&& chdir(_PATH_DEV
)) {
345 syslog(LOG_ERR
, "chdir(%s): %m", _PATH_DEV
);
349 for (i
= 0; i
< utmpent
; i
++) {
350 if (stat(we
->we_utmp
.out_line
, &stb
) >= 0)
351 we
->we_idle
= htonl(now
- stb
.st_atime
);
354 (void)getloadavg(avenrun
, sizeof(avenrun
)/sizeof(avenrun
[0]));
355 for (i
= 0; i
< 3; i
++)
356 mywd
.wd_loadav
[i
] = htonl((u_long
)(avenrun
[i
] * 100));
357 cc
= (char *)we
- (char *)&mywd
;
358 mywd
.wd_sendtime
= htonl(time(0));
359 mywd
.wd_vers
= WHODVERSION
;
360 mywd
.wd_type
= WHODTYPE_STATUS
;
361 for (np
= neighbors
; np
!= NULL
; np
= np
->n_next
)
362 (void)sendto(s
, (char *)&mywd
, cc
, 0,
363 np
->n_addr
, np
->n_addrlen
);
364 if (utmpent
&& chdir(_PATH_RWHODIR
)) {
365 syslog(LOG_ERR
, "chdir(%s): %m", _PATH_RWHODIR
);
369 (void) alarm(AL_INTERVAL
);
381 mib
[1] = KERN_BOOTTIME
;
383 if (sysctl(mib
, 2, &tm
, &size
, NULL
, 0) == -1) {
384 syslog(LOG_ERR
, "cannot get boottime: %m");
387 mywd
.wd_boottime
= htonl(tm
.tv_sec
);
394 syslog(LOG_ERR
, msg
);
399 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
400 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
403 rt_xaddrs(cp
, cplim
, rtinfo
)
404 register caddr_t cp
, cplim
;
405 register struct rt_addrinfo
*rtinfo
;
407 register struct sockaddr
*sa
;
410 memset(rtinfo
->rti_info
, 0, sizeof(rtinfo
->rti_info
));
411 for (i
= 0; (i
< RTAX_MAX
) && (cp
< cplim
); i
++) {
412 if ((rtinfo
->rti_addrs
& (1 << i
)) == 0)
414 rtinfo
->rti_info
[i
] = sa
= (struct sockaddr
*)cp
;
420 * Figure out device configuration and select
421 * networks which deserve status information.
427 register struct neighbor
*np
;
428 register struct if_msghdr
*ifm
;
429 register struct ifa_msghdr
*ifam
;
430 struct sockaddr_dl
*sdl
;
432 int mib
[6], flags
= 0, len
;
433 char *buf
, *lim
, *next
;
434 struct rt_addrinfo info
;
440 mib
[4] = NET_RT_IFLIST
;
442 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
443 quit("route-sysctl-estimate");
444 if ((buf
= malloc(needed
)) == NULL
)
446 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) < 0)
447 quit("actual retrieval of interface table");
450 sdl
= NULL
; /* XXX just to keep gcc -Wall happy */
451 for (next
= buf
; next
< lim
; next
+= ifm
->ifm_msglen
) {
452 ifm
= (struct if_msghdr
*)next
;
453 if (ifm
->ifm_type
== RTM_IFINFO
) {
454 sdl
= (struct sockaddr_dl
*)(ifm
+ 1);
455 flags
= ifm
->ifm_flags
;
458 if ((flags
& IFF_UP
) == 0 ||
459 (flags
& (IFF_BROADCAST
|IFF_POINTOPOINT
)) == 0)
461 if (ifm
->ifm_type
!= RTM_NEWADDR
)
462 quit("out of sync parsing NET_RT_IFLIST");
463 ifam
= (struct ifa_msghdr
*)ifm
;
464 info
.rti_addrs
= ifam
->ifam_addrs
;
465 rt_xaddrs((char *)(ifam
+ 1), ifam
->ifam_msglen
+ (char *)ifam
,
467 /* gag, wish we could get rid of Internet dependencies */
468 #define dstaddr info.rti_info[RTAX_BRD]
469 #define IPADDR_SA(x) ((struct sockaddr_in *)(x))->sin_addr.s_addr
470 #define PORT_SA(x) ((struct sockaddr_in *)(x))->sin_port
471 if (dstaddr
== 0 || dstaddr
->sa_family
!= AF_INET
)
473 PORT_SA(dstaddr
) = sp
->s_port
;
474 for (np
= neighbors
; np
!= NULL
; np
= np
->n_next
)
475 if (memcmp(sdl
->sdl_data
, np
->n_name
,
476 sdl
->sdl_nlen
) == 0 &&
477 IPADDR_SA(np
->n_addr
) == IPADDR_SA(dstaddr
))
481 len
= sizeof(*np
) + dstaddr
->sa_len
+ sdl
->sdl_nlen
+ 1;
482 np
= (struct neighbor
*)malloc(len
);
484 quit("malloc of neighbor structure");
487 np
->n_addr
= (struct sockaddr
*)(np
+ 1);
488 np
->n_addrlen
= dstaddr
->sa_len
;
489 np
->n_name
= np
->n_addrlen
+ (char *)np
->n_addr
;
490 np
->n_next
= neighbors
;
492 memcpy((char *)np
->n_addr
, (char *)dstaddr
, np
->n_addrlen
);
493 memcpy(np
->n_name
, sdl
->sdl_data
, sdl
->sdl_nlen
);
501 Sendto(s
, buf
, cc
, flags
, to
, tolen
)
508 register struct whod
*w
= (struct whod
*)buf
;
509 register struct whoent
*we
;
510 struct sockaddr_in
*sin
= (struct sockaddr_in
*)to
;
512 printf("sendto %x.%d\n", ntohl(sin
->sin_addr
), ntohs(sin
->sin_port
));
513 printf("hostname %s %s\n", w
->wd_hostname
,
514 interval(ntohl(w
->wd_sendtime
) - ntohl(w
->wd_boottime
), " up"));
515 printf("load %4.2f, %4.2f, %4.2f\n",
516 ntohl(w
->wd_loadav
[0]) / 100.0, ntohl(w
->wd_loadav
[1]) / 100.0,
517 ntohl(w
->wd_loadav
[2]) / 100.0);
519 for (we
= w
->wd_we
, cc
/= sizeof(struct whoent
); cc
> 0; cc
--, we
++) {
520 time_t t
= ntohl(we
->we_utmp
.out_time
);
521 printf("%-8.8s %s:%s %.12s",
522 we
->we_utmp
.out_name
,
523 w
->wd_hostname
, we
->we_utmp
.out_line
,
525 we
->we_idle
= ntohl(we
->we_idle
) / 60;
527 if (we
->we_idle
>= 100*60)
528 we
->we_idle
= 100*60 - 1;
529 if (we
->we_idle
>= 60)
530 printf(" %2d", we
->we_idle
/ 60);
533 printf(":%02d", we
->we_idle
% 60);
540 interval(time
, updown
)
544 static char resbuf
[32];
545 int days
, hours
, minutes
;
547 if (time
< 0 || time
> 3*30*24*60*60) {
548 (void) sprintf(resbuf
, " %s ??:??", updown
);
551 minutes
= (time
+ 59) / 60; /* round to minutes */
552 hours
= minutes
/ 60; minutes
%= 60;
553 days
= hours
/ 24; hours
%= 24;
555 (void) sprintf(resbuf
, "%s %2d+%02d:%02d",
556 updown
, days
, hours
, minutes
);
558 (void) sprintf(resbuf
, "%s %2d:%02d",
559 updown
, hours
, minutes
);