No empty .Rs/.Re
[netbsd-mini2440.git] / usr.sbin / timed / timedc / cmds.c
bloba200fa0d8ee049e79608e8107b0689998150eae6
1 /* $NetBSD: cmds.c,v 1.22 2007/01/27 00:37:56 cbiere Exp $ */
3 /*-
4 * Copyright (c) 1985, 1993 The Regents of the University of California.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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
29 * SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)cmds.c 8.2 (Berkeley) 3/26/95";
36 #else
37 __RCSID("$NetBSD: cmds.c,v 1.22 2007/01/27 00:37:56 cbiere Exp $");
38 #endif
39 #endif /* not lint */
41 #include "timedc.h"
42 #include <sys/file.h>
44 #include <netinet/in_systm.h>
45 #include <netinet/ip.h>
46 #include <netinet/ip_icmp.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51 #include <err.h>
53 #define TSPTYPES
54 #include <protocols/timed.h>
56 #define SECHR (60*60)
57 #define SECDAY (24*SECHR)
59 int sock_raw; /* used by measure() */
60 static int sock;
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 };
73 static const char *
74 myname(int refresh)
76 static char name[MAXHOSTNAMELEN + 1];
77 static int initialized;
79 if (refresh || !initialized) {
80 initialized = 1;
81 (void)gethostname(name, sizeof(name));
82 name[sizeof(name) - 1] = '\0';
84 return name;
87 static in_port_t
88 udpservport(const char *service)
90 const struct servent *srvp;
92 srvp = getservbyname(service, "udp");
93 if (srvp == NULL) {
94 warnx("%s/udp: unknown service", service);
95 return 0;
97 return srvp->s_port;
100 static const char *
101 getaddr(const char *name, struct sockaddr_in *addr, in_port_t port)
103 const struct hostent *hp;
105 hp = gethostbyname(name);
106 if (hp == NULL) {
107 warnx("Error resolving %s (%s)", name, hstrerror(h_errno));
108 return NULL;
110 if (addr) {
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;
119 static const char *
120 tsp_type_to_string(const struct tsp *msg)
122 unsigned i;
124 i = msg->tsp_type;
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];
134 int trials;
136 if (connect(sock, (const struct sockaddr *)addr,
137 sizeof(*addr)) == -1) {
138 warn("connect");
139 return 0;
142 set[0].fd = sock;
143 set[0].events = POLLIN;
144 for (trials = 0; trials < 10; trials++) {
145 ssize_t ret;
146 uint32_t sec;
148 /* ask for the time */
149 sec = 0;
150 ret = send(sock, &sec, sizeof(sec), 0);
151 if (ret < (ssize_t)sizeof(sec)) {
152 if (ret < 0)
153 warn("send(sock)");
154 else
155 warnx("send(sock): incomplete");
156 return 0;
159 for (;;) {
160 int i;
162 /* wait 2 seconds between 10 tries */
163 i = poll(set, 1, 2000);
164 if (i < 0) {
165 if (errno == EINTR)
166 continue;
167 warn("poll(date read)");
168 return 0;
170 if (0 == i)
171 break;
173 ret = recv(sock, &sec, sizeof(sec), 0);
174 if (ret < (ssize_t)sizeof(sec)) {
175 if (ret < 0)
176 warn("recv(date read)");
177 else
178 warnx("recv(date read): incomplete");
179 return 0;
182 sec = ntohl(sec);
183 if (sec < BU) {
184 warnx("%s says it is before 1970: %lu",
185 hostname, (unsigned long)sec);
186 return 0;
187 } else {
188 struct timeval now;
190 sec -= BU;
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);
199 return 0;
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
222 * measurement.
224 void
225 clockdiff(int argc, char *argv[])
227 extern int measure(u_long, u_long, const char *,
228 const struct sockaddr_in*, int);
229 in_port_t port;
231 if (argc < 2) {
232 printf("Usage: clockdiff host ... \n");
233 return;
236 (void)myname(REFRESH);
238 /* get the address for the date ready */
239 port = udpservport("time");
241 while (argc > 1) {
242 struct sockaddr_in server;
243 const char *hostname;
244 int measure_status;
245 int avg_cnt;
246 long avg;
248 argc--; argv++;
249 if ((hostname = getaddr(*argv, &server, port)) == NULL)
250 continue;
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)
255 break;
256 avg += measure_delta;
258 if (measure_status == GOOD)
259 measure_delta = avg/avg_cnt;
261 switch (measure_status) {
262 case HOSTDOWN:
263 printf("%s is down\n", hostname);
264 continue;
265 case NONSTDTIME:
266 printf("%s transmits a non-standard time format\n",
267 hostname);
268 continue;
269 case UNREACHABLE:
270 printf("%s is unreachable\n", hostname);
271 continue;
275 * Try to get the date only after using ICMP timestamps to
276 * get the time. This is because the date protocol
277 * is optional.
279 if (port != 0) {
280 avg = daydiff(*argv, &server);
281 if (avg > SECDAY) {
282 printf("time on %s is %ld days ahead %s\n",
283 hostname, avg/SECDAY, myname(CACHED));
284 continue;
285 } else if (avg < -SECDAY) {
286 printf("time on %s is %ld days behind %s\n",
287 hostname, -avg/SECDAY, myname(CACHED));
288 continue;
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));
298 } else {
299 printf("time on %s is %d ms. behind time on %s\n",
300 hostname, -measure_delta, myname(CACHED));
303 return;
308 * finds location of master timedaemon
310 void
311 msite(int argc, char *argv[])
313 struct pollfd set[1];
314 in_port_t port;
315 int i;
317 if (argc < 1) {
318 printf("Usage: msite [hostname]\n");
319 return;
322 port = udpservport("timed");
323 if (port == 0)
324 return;
326 (void)myname(REFRESH);
327 i = 1;
328 set[0].fd = sock;
329 set[0].events = POLLIN;
330 do {
331 struct sockaddr_in dest;
332 struct tsp msg;
333 const char *tgtname;
335 tgtname = (i >= argc) ? myname(CACHED) : argv[i];
336 if (getaddr(tgtname, &dest, port) == NULL)
337 continue;
339 if (connect(sock, (const struct sockaddr *)&dest,
340 sizeof(dest)) == -1) {
341 warn("connect");
342 continue;
345 set_tsp_name(&msg, myname(CACHED));
346 msg.tsp_type = TSP_MSITE;
347 msg.tsp_vers = TSPVERSION;
348 bytenetorder(&msg);
349 if (send(sock, &msg, sizeof(msg), 0) < 0) {
350 warn("send");
351 continue;
354 if (poll(set, 1, 15000)) {
355 ssize_t ret;
357 ret = recv(sock, &msg, sizeof(msg), 0);
358 if (ret < (ssize_t)sizeof(msg)) {
359 if (ret < 0)
360 warn("recv");
361 else
362 warnx("recv: incomplete");
363 continue;
365 bytehostorder(&msg);
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",
371 tgtname, name);
372 } else {
373 printf("received wrong ack: %s\n",
374 tsp_type_to_string(&msg));
376 } else {
377 printf("communication error with %s\n", tgtname);
379 } while (++i < argc);
383 * quits timedc
385 void
386 quit(int argc, char *argv[])
388 (void) argc;
389 (void) argv;
390 exit(EXIT_SUCCESS);
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.
399 void
400 testing(int argc, char *argv[])
402 in_port_t port;
404 if (argc < 2) {
405 printf("Usage: election host1 [host2 ...]\n");
406 return;
409 port = udpservport("timed");
410 if (port == 0)
411 return;
413 while (argc > 1) {
414 struct sockaddr_in addr;
415 struct tsp msg;
417 argc--; argv++;
418 if (getaddr(*argv, &addr, port) == NULL)
419 continue;
421 msg.tsp_type = TSP_TEST;
422 msg.tsp_vers = TSPVERSION;
423 set_tsp_name(&msg, myname(CACHED));
424 bytenetorder(&msg);
425 if (sendto(sock, &msg, sizeof(msg), 0,
426 (const struct sockaddr*)&addr, sizeof(addr)) < 0) {
427 warn("send");
434 * Enables or disables tracing on local timedaemon
436 void
437 tracing(int argc, char *argv[])
439 struct pollfd set[1];
440 struct sockaddr_in dest;
441 in_port_t port;
442 struct tsp msg;
443 int onflag;
445 if (argc != 2) {
446 printf("Usage: tracing { on | off }\n");
447 return;
450 port = udpservport("timed");
451 if (port == 0)
452 return;
453 if (getaddr(myname(REFRESH), &dest, port) == NULL)
454 return;
455 if (connect(sock, (const struct sockaddr *)&dest,
456 sizeof(dest)) == -1) {
457 warn("connect");
458 return;
461 if (strcmp(argv[1], "on") == 0) {
462 msg.tsp_type = TSP_TRACEON;
463 onflag = ON;
464 } else {
465 msg.tsp_type = TSP_TRACEOFF;
466 onflag = OFF;
469 set_tsp_name(&msg, myname(CACHED));
470 msg.tsp_vers = TSPVERSION;
471 bytenetorder(&msg);
472 if (send(sock, &msg, sizeof(msg), 0) < 0) {
473 warn("send");
474 return;
477 set[0].fd = sock;
478 set[0].events = POLLIN;
479 if (poll(set, 1, 5000)) {
480 ssize_t ret;
482 ret = recv(sock, &msg, sizeof(msg), 0);
483 if (ret < (ssize_t)sizeof(msg)) {
484 if (ret < 0)
485 warn("recv");
486 else
487 warnx("recv: incomplete");
488 return;
490 bytehostorder(&msg);
491 if (msg.tsp_type == TSP_ACK)
492 printf("timed tracing %s\n",
493 onflag ? "enabled" : "disabled");
494 else
495 printf("wrong ack received: %s\n",
496 tsp_type_to_string(&msg));
497 } else
498 printf("communication error\n");
502 priv_resources(void)
504 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
505 warn("Cannot open UDP socket");
506 return -1;
509 if ((sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1) {
510 warn("Cannot open raw socket");
511 (void)close(sock);
512 return -1;
514 return 1;