1 /* $NetBSD: cmds.c,v 1.22 2007/01/27 00:37:56 cbiere Exp $ */
4 * Copyright (c) 1985, 1993 The Regents of the University of California.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
35 static char sccsid
[] = "@(#)cmds.c 8.2 (Berkeley) 3/26/95";
37 __RCSID("$NetBSD: cmds.c,v 1.22 2007/01/27 00:37:56 cbiere Exp $");
44 #include <netinet/in_systm.h>
45 #include <netinet/ip.h>
46 #include <netinet/ip_icmp.h>
54 #include <protocols/timed.h>
57 #define SECDAY (24*SECHR)
59 int sock_raw
; /* used by measure() */
61 extern int measure_delta
;
63 void bytenetorder(struct tsp
*);
64 void bytehostorder(struct tsp
*);
65 void set_tsp_name(struct tsp
*, const char *);
66 void get_tsp_name(const struct tsp
*, char *, size_t);
69 #define BU 2208988800UL /* seconds before UNIX epoch */
71 enum { CACHED
, REFRESH
};
76 static char name
[MAXHOSTNAMELEN
+ 1];
77 static int initialized
;
79 if (refresh
|| !initialized
) {
81 (void)gethostname(name
, sizeof(name
));
82 name
[sizeof(name
) - 1] = '\0';
88 udpservport(const char *service
)
90 const struct servent
*srvp
;
92 srvp
= getservbyname(service
, "udp");
94 warnx("%s/udp: unknown service", service
);
101 getaddr(const char *name
, struct sockaddr_in
*addr
, in_port_t port
)
103 const struct hostent
*hp
;
105 hp
= gethostbyname(name
);
107 warnx("Error resolving %s (%s)", name
, hstrerror(h_errno
));
111 memset(addr
, 0, sizeof(*addr
));
112 addr
->sin_family
= AF_INET
;
113 addr
->sin_port
= port
;
114 memcpy(&addr
->sin_addr
.s_addr
, hp
->h_addr
, sizeof(in_addr_t
));
116 return hp
->h_name
? hp
->h_name
: name
;
120 tsp_type_to_string(const struct tsp
*msg
)
125 return i
< TSPTYPENUMBER
? tsptype
[i
] : "unknown";
128 /* compute the difference between our date and another machine
130 static int /* difference in days from our time */
131 daydiff(const char *hostname
, const struct sockaddr_in
*addr
)
133 struct pollfd set
[1];
136 if (connect(sock
, (const struct sockaddr
*)addr
,
137 sizeof(*addr
)) == -1) {
143 set
[0].events
= POLLIN
;
144 for (trials
= 0; trials
< 10; trials
++) {
148 /* ask for the time */
150 ret
= send(sock
, &sec
, sizeof(sec
), 0);
151 if (ret
< (ssize_t
)sizeof(sec
)) {
155 warnx("send(sock): incomplete");
162 /* wait 2 seconds between 10 tries */
163 i
= poll(set
, 1, 2000);
167 warn("poll(date read)");
173 ret
= recv(sock
, &sec
, sizeof(sec
), 0);
174 if (ret
< (ssize_t
)sizeof(sec
)) {
176 warn("recv(date read)");
178 warnx("recv(date read): incomplete");
184 warnx("%s says it is before 1970: %lu",
185 hostname
, (unsigned long)sec
);
191 (void)gettimeofday(&now
, NULL
);
192 return (sec
- now
.tv_sec
);
197 /* if we get here, we tried too many times */
198 warnx("%s will not tell us the date", hostname
);
204 * Clockdiff computes the difference between the time of the machine on
205 * which it is called and the time of the machines given as argument.
206 * The time differences measured by clockdiff are obtained using a sequence
207 * of ICMP TSTAMP messages which are returned to the sender by the IP module
208 * in the remote machine.
209 * In order to compare clocks of machines in different time zones, the time
210 * is transmitted (as a 32-bit value) in milliseconds since midnight UT.
211 * If a hosts uses a different time format, it should set the high order
212 * bit of the 32-bit quantity it transmits.
213 * However, VMS apparently transmits the time in milliseconds since midnight
214 * local time (rather than GMT) without setting the high order bit.
215 * Furthermore, it does not understand daylight-saving time. This makes
216 * clockdiff behaving inconsistently with hosts running VMS.
218 * In order to reduce the sensitivity to the variance of message transmission
219 * time, clockdiff sends a sequence of messages. Yet, measures between
220 * two `distant' hosts can be affected by a small error. The error can,
221 * however, be reduced by increasing the number of messages sent in each
225 clockdiff(int argc
, char *argv
[])
227 extern int measure(u_long
, u_long
, const char *,
228 const struct sockaddr_in
*, int);
232 printf("Usage: clockdiff host ... \n");
236 (void)myname(REFRESH
);
238 /* get the address for the date ready */
239 port
= udpservport("time");
242 struct sockaddr_in server
;
243 const char *hostname
;
249 if ((hostname
= getaddr(*argv
, &server
, port
)) == NULL
)
252 for (avg_cnt
= 0, avg
= 0; avg_cnt
< 16; avg_cnt
++) {
253 measure_status
= measure(10000,100, *argv
, &server
, 1);
254 if (measure_status
!= GOOD
)
256 avg
+= measure_delta
;
258 if (measure_status
== GOOD
)
259 measure_delta
= avg
/avg_cnt
;
261 switch (measure_status
) {
263 printf("%s is down\n", hostname
);
266 printf("%s transmits a non-standard time format\n",
270 printf("%s is unreachable\n", hostname
);
275 * Try to get the date only after using ICMP timestamps to
276 * get the time. This is because the date protocol
280 avg
= daydiff(*argv
, &server
);
282 printf("time on %s is %ld days ahead %s\n",
283 hostname
, avg
/SECDAY
, myname(CACHED
));
285 } else if (avg
< -SECDAY
) {
286 printf("time on %s is %ld days behind %s\n",
287 hostname
, -avg
/SECDAY
, myname(CACHED
));
292 if (measure_delta
> 0) {
293 printf("time on %s is %d ms. ahead of time on %s\n",
294 hostname
, measure_delta
, myname(CACHED
));
295 } else if (measure_delta
== 0) {
296 printf("%s and %s have the same time\n",
297 hostname
, myname(CACHED
));
299 printf("time on %s is %d ms. behind time on %s\n",
300 hostname
, -measure_delta
, myname(CACHED
));
308 * finds location of master timedaemon
311 msite(int argc
, char *argv
[])
313 struct pollfd set
[1];
318 printf("Usage: msite [hostname]\n");
322 port
= udpservport("timed");
326 (void)myname(REFRESH
);
329 set
[0].events
= POLLIN
;
331 struct sockaddr_in dest
;
335 tgtname
= (i
>= argc
) ? myname(CACHED
) : argv
[i
];
336 if (getaddr(tgtname
, &dest
, port
) == NULL
)
339 if (connect(sock
, (const struct sockaddr
*)&dest
,
340 sizeof(dest
)) == -1) {
345 set_tsp_name(&msg
, myname(CACHED
));
346 msg
.tsp_type
= TSP_MSITE
;
347 msg
.tsp_vers
= TSPVERSION
;
349 if (send(sock
, &msg
, sizeof(msg
), 0) < 0) {
354 if (poll(set
, 1, 15000)) {
357 ret
= recv(sock
, &msg
, sizeof(msg
), 0);
358 if (ret
< (ssize_t
)sizeof(msg
)) {
362 warnx("recv: incomplete");
366 if (msg
.tsp_type
== TSP_ACK
) {
367 char name
[MAXHOSTNAMELEN
];
369 get_tsp_name(&msg
, name
, sizeof(name
));
370 printf("master timedaemon at %s is %s\n",
373 printf("received wrong ack: %s\n",
374 tsp_type_to_string(&msg
));
377 printf("communication error with %s\n", tgtname
);
379 } while (++i
< argc
);
386 quit(int argc
, char *argv
[])
395 * Causes the election timer to expire on the selected hosts
396 * It sends just one udp message per machine, relying on
397 * reliability of communication channel.
400 testing(int argc
, char *argv
[])
405 printf("Usage: election host1 [host2 ...]\n");
409 port
= udpservport("timed");
414 struct sockaddr_in addr
;
418 if (getaddr(*argv
, &addr
, port
) == NULL
)
421 msg
.tsp_type
= TSP_TEST
;
422 msg
.tsp_vers
= TSPVERSION
;
423 set_tsp_name(&msg
, myname(CACHED
));
425 if (sendto(sock
, &msg
, sizeof(msg
), 0,
426 (const struct sockaddr
*)&addr
, sizeof(addr
)) < 0) {
434 * Enables or disables tracing on local timedaemon
437 tracing(int argc
, char *argv
[])
439 struct pollfd set
[1];
440 struct sockaddr_in dest
;
446 printf("Usage: tracing { on | off }\n");
450 port
= udpservport("timed");
453 if (getaddr(myname(REFRESH
), &dest
, port
) == NULL
)
455 if (connect(sock
, (const struct sockaddr
*)&dest
,
456 sizeof(dest
)) == -1) {
461 if (strcmp(argv
[1], "on") == 0) {
462 msg
.tsp_type
= TSP_TRACEON
;
465 msg
.tsp_type
= TSP_TRACEOFF
;
469 set_tsp_name(&msg
, myname(CACHED
));
470 msg
.tsp_vers
= TSPVERSION
;
472 if (send(sock
, &msg
, sizeof(msg
), 0) < 0) {
478 set
[0].events
= POLLIN
;
479 if (poll(set
, 1, 5000)) {
482 ret
= recv(sock
, &msg
, sizeof(msg
), 0);
483 if (ret
< (ssize_t
)sizeof(msg
)) {
487 warnx("recv: incomplete");
491 if (msg
.tsp_type
== TSP_ACK
)
492 printf("timed tracing %s\n",
493 onflag
? "enabled" : "disabled");
495 printf("wrong ack received: %s\n",
496 tsp_type_to_string(&msg
));
498 printf("communication error\n");
504 if ((sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1) {
505 warn("Cannot open UDP socket");
509 if ((sock_raw
= socket(AF_INET
, SOCK_RAW
, IPPROTO_ICMP
)) == -1) {
510 warn("Cannot open raw socket");