xref: /csrg-svn/usr.sbin/timed/timedc/cmds.c (revision 23785)
1*23785Sgusella /*
2*23785Sgusella  * Copyright (c) 1983 Regents of the University of California.
3*23785Sgusella  * All rights reserved.  The Berkeley software License Agreement
4*23785Sgusella  * specifies the terms and conditions for redistribution.
5*23785Sgusella  */
6*23785Sgusella 
7*23785Sgusella #ifndef lint
8*23785Sgusella static char sccsid[] = "@(#)cmds.c	1.1 (Berkeley) 06/27/85";
9*23785Sgusella #endif not lint
10*23785Sgusella 
11*23785Sgusella #include "timedc.h"
12*23785Sgusella #include <netinet/in_systm.h>
13*23785Sgusella #include <netinet/ip.h>
14*23785Sgusella #include <netinet/ip_icmp.h>
15*23785Sgusella #define TSPTYPES
16*23785Sgusella #include <protocols/timed.h>
17*23785Sgusella #include <sys/file.h>
18*23785Sgusella 
19*23785Sgusella #define OFF	0
20*23785Sgusella #define ON	1
21*23785Sgusella 
22*23785Sgusella int id;
23*23785Sgusella int sock;
24*23785Sgusella int sock_raw;
25*23785Sgusella char hostname[32];
26*23785Sgusella struct hostent *hp, *gethostbyname();
27*23785Sgusella struct sockaddr_in server;
28*23785Sgusella extern int measure_delta;
29*23785Sgusella int bytenetorder(), bytehostorder();
30*23785Sgusella char *strcpy();
31*23785Sgusella 
32*23785Sgusella /*
33*23785Sgusella  * Clockdiff computes the difference between the time of the machine on
34*23785Sgusella  * which it is called and the time of the machines given as argument.
35*23785Sgusella  * The time differences measured by clockdiff are obtained using a sequence
36*23785Sgusella  * of ICMP TSTAMP messages which are returned to the sender by the IP module
37*23785Sgusella  * in the remote machine.
38*23785Sgusella  * In order to compare clocks of machines in different time zones, the time
39*23785Sgusella  * is transmitted (as a 32-bit value) in milliseconds since midnight UT.
40*23785Sgusella  * If a hosts uses a different time format, it should set the high order
41*23785Sgusella  * bit of the 32-bit quantity it transmits.
42*23785Sgusella  * However, VMS apparently transmits the time in milliseconds since midnight
43*23785Sgusella  * local time (rather than GMT) without setting the high order bit.
44*23785Sgusella  * Furthermore, it does not understand daylight-saving time.  This makes
45*23785Sgusella  * clockdiff behaving inconsistently with hosts running VMS.
46*23785Sgusella  *
47*23785Sgusella  * In order to reduce the sensitivity to the variance of message transmission
48*23785Sgusella  * time, clockdiff sends a sequence of messages.  Yet, measures between
49*23785Sgusella  * two `distant' hosts can be affected by a small error. The error can, however,
50*23785Sgusella  * be reduced by increasing the number of messages sent in each measurement.
51*23785Sgusella  */
52*23785Sgusella 
53*23785Sgusella clockdiff(argc, argv)
54*23785Sgusella int argc;
55*23785Sgusella char *argv[];
56*23785Sgusella {
57*23785Sgusella 	int measure_status;
58*23785Sgusella 	struct timeval ack;
59*23785Sgusella 	int measure();
60*23785Sgusella 
61*23785Sgusella 	if(argc < 2)  {
62*23785Sgusella 		printf("Usage: clockdiff host ... \n");
63*23785Sgusella 		return;
64*23785Sgusella 	}
65*23785Sgusella 
66*23785Sgusella 	id = getpid();
67*23785Sgusella 	(void)gethostname(hostname,sizeof(hostname));
68*23785Sgusella 
69*23785Sgusella 	while (argc > 1) {
70*23785Sgusella 		argc--; argv++;
71*23785Sgusella 		hp = gethostbyname(*argv);
72*23785Sgusella 		if (hp == NULL) {
73*23785Sgusella 			printf("%s: unknown host\n", *argv);
74*23785Sgusella 			continue;
75*23785Sgusella 		}
76*23785Sgusella 		server.sin_family = hp->h_addrtype;
77*23785Sgusella 		bcopy(hp->h_addr, &(server.sin_addr.s_addr), hp->h_length);
78*23785Sgusella 		ack.tv_sec = 1;
79*23785Sgusella 		ack.tv_usec = 500000;
80*23785Sgusella 		if ((measure_status = measure(&ack, OFF)) < 0) {
81*23785Sgusella 			perror("measure");
82*23785Sgusella 			return;
83*23785Sgusella 		}
84*23785Sgusella 		switch (measure_status) {
85*23785Sgusella 
86*23785Sgusella 		case HOSTDOWN:
87*23785Sgusella 			printf("%s is down\n", hp->h_name);
88*23785Sgusella 			continue;
89*23785Sgusella 			break;
90*23785Sgusella 		case NONSTDTIME:
91*23785Sgusella 			printf("%s time transmitted in a non-standard format\n",						 hp->h_name);
92*23785Sgusella 			continue;
93*23785Sgusella 			break;
94*23785Sgusella 		case UNREACHABLE:
95*23785Sgusella 			printf("%s is unreachable\n", hp->h_name);
96*23785Sgusella 			continue;
97*23785Sgusella 			break;
98*23785Sgusella 		default:
99*23785Sgusella 			break;
100*23785Sgusella 		}
101*23785Sgusella 
102*23785Sgusella 		if (measure_delta > 0)
103*23785Sgusella 			printf("time on %s is %d ms. ahead of time on %s\n",
104*23785Sgusella 						hp->h_name, measure_delta,
105*23785Sgusella 						hostname);
106*23785Sgusella 		else
107*23785Sgusella 			if (measure_delta == 0)
108*23785Sgusella 		      		printf("%s and %s have the same time\n",
109*23785Sgusella 						hp->h_name, hostname);
110*23785Sgusella 			else
111*23785Sgusella 		      	     printf("time on %s is %d ms. behind time on %s\n",
112*23785Sgusella 					hp->h_name, -measure_delta, hostname);
113*23785Sgusella 	}
114*23785Sgusella 	return;
115*23785Sgusella }
116*23785Sgusella /*
117*23785Sgusella  * finds location of master timedaemon
118*23785Sgusella  */
119*23785Sgusella 
120*23785Sgusella msite(argc)
121*23785Sgusella int argc;
122*23785Sgusella {
123*23785Sgusella 	int length;
124*23785Sgusella 	int cc, ready, found;
125*23785Sgusella 	struct sockaddr_in dest;
126*23785Sgusella 	struct timeval tout;
127*23785Sgusella 	struct sockaddr_in from;
128*23785Sgusella 	struct tsp msg;
129*23785Sgusella 	struct servent *srvp;
130*23785Sgusella 
131*23785Sgusella 	if (argc != 1) {
132*23785Sgusella 		printf("Usage: msite\n");
133*23785Sgusella 		return;
134*23785Sgusella 	}
135*23785Sgusella 
136*23785Sgusella 	(void) open("/etc/timed", O_WRONLY, 01700);
137*23785Sgusella 	if (errno != ETXTBSY) {
138*23785Sgusella 		printf("No timed on this machine\n");
139*23785Sgusella 		return;
140*23785Sgusella 	}
141*23785Sgusella 
142*23785Sgusella 	srvp = getservbyname("timed", "udp");
143*23785Sgusella 	if (srvp == 0) {
144*23785Sgusella 		fprintf(stderr, "udp/timed: unknown service\n");
145*23785Sgusella 		return;
146*23785Sgusella 	}
147*23785Sgusella 	dest.sin_port = srvp->s_port;
148*23785Sgusella 	dest.sin_family = AF_INET;
149*23785Sgusella 
150*23785Sgusella 	(void)gethostname(hostname,sizeof(hostname));
151*23785Sgusella 	hp = gethostbyname(hostname);
152*23785Sgusella 	if (hp == NULL) {
153*23785Sgusella 		perror("gethostbyname");
154*23785Sgusella 		return;
155*23785Sgusella 	}
156*23785Sgusella 	bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
157*23785Sgusella 
158*23785Sgusella 	(void)strcpy(msg.tsp_name, hostname);
159*23785Sgusella 	msg.tsp_type = TSP_MSITE;
160*23785Sgusella 	msg.tsp_vers = TSPVERSION;
161*23785Sgusella 	bytenetorder(&msg);
162*23785Sgusella 	length = sizeof(struct sockaddr_in);
163*23785Sgusella 	if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
164*23785Sgusella 						&dest, length) < 0) {
165*23785Sgusella 		perror("sendto");
166*23785Sgusella 		return;
167*23785Sgusella 	}
168*23785Sgusella 
169*23785Sgusella 	tout.tv_sec = 15;
170*23785Sgusella 	tout.tv_usec = 0;
171*23785Sgusella 	ready = 1<<sock;
172*23785Sgusella 	found = select(20, &ready, (int *)0, (int *)0, &tout);
173*23785Sgusella 	if (found) {
174*23785Sgusella 		length = sizeof(struct sockaddr_in);
175*23785Sgusella 		cc = recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0,
176*23785Sgusella 							&from, &length);
177*23785Sgusella 		if (cc < 0) {
178*23785Sgusella 			perror("recvfrom");
179*23785Sgusella 			return;
180*23785Sgusella 		}
181*23785Sgusella 		bytehostorder(&msg);
182*23785Sgusella 		if (msg.tsp_type == TSP_ACK)
183*23785Sgusella 			printf("master timedaemon runs on %s\n", msg.tsp_name);
184*23785Sgusella 		else
185*23785Sgusella 			printf("received wrong ack: %s\n",
186*23785Sgusella 						tsptype[msg.tsp_type]);
187*23785Sgusella 	} else
188*23785Sgusella 		printf("communication error\n");
189*23785Sgusella }
190*23785Sgusella 
191*23785Sgusella /*
192*23785Sgusella  * quits timedc
193*23785Sgusella  */
194*23785Sgusella 
195*23785Sgusella quit()
196*23785Sgusella {
197*23785Sgusella 	exit(0);
198*23785Sgusella }
199*23785Sgusella 
200*23785Sgusella #define MAXH	4	/* max no. of hosts where election can occur */
201*23785Sgusella 
202*23785Sgusella /*
203*23785Sgusella  * Causes the election timer to expire on the selected hosts
204*23785Sgusella  * It sends just one udp message per machine, relying on
205*23785Sgusella  * reliability of communication channel.
206*23785Sgusella  */
207*23785Sgusella 
208*23785Sgusella testing(argc, argv)
209*23785Sgusella int argc;
210*23785Sgusella char *argv[];
211*23785Sgusella {
212*23785Sgusella 	int length;
213*23785Sgusella 	int nhosts;
214*23785Sgusella 	struct servent *srvp;
215*23785Sgusella 	struct sockaddr_in sin[MAXH];
216*23785Sgusella 	struct tsp msg;
217*23785Sgusella 
218*23785Sgusella 	if(argc < 2)  {
219*23785Sgusella 		printf("Usage: testing host ...\n");
220*23785Sgusella 		return;
221*23785Sgusella 	}
222*23785Sgusella 
223*23785Sgusella 	(void) open("/etc/timed", O_WRONLY, 01700);
224*23785Sgusella 	if (errno != ETXTBSY) {
225*23785Sgusella 		printf("No timed on this machine\n");
226*23785Sgusella 		return;
227*23785Sgusella 	}
228*23785Sgusella 
229*23785Sgusella 	srvp = getservbyname("timed", "udp");
230*23785Sgusella 	if (srvp == 0) {
231*23785Sgusella 		fprintf(stderr, "udp/timed: unknown service\n");
232*23785Sgusella 		return;
233*23785Sgusella 	}
234*23785Sgusella 
235*23785Sgusella 	nhosts = 0;
236*23785Sgusella 	while (argc > 1) {
237*23785Sgusella 		argc--; argv++;
238*23785Sgusella 		hp = gethostbyname(*argv);
239*23785Sgusella 		if (hp == NULL) {
240*23785Sgusella 			printf("%s: unknown host %s\n", *argv);
241*23785Sgusella 			argc--; argv++;
242*23785Sgusella 			continue;
243*23785Sgusella 		}
244*23785Sgusella 		sin[nhosts].sin_port = srvp->s_port;
245*23785Sgusella 		sin[nhosts].sin_family = hp->h_addrtype;
246*23785Sgusella 		bcopy(hp->h_addr, &(sin[nhosts].sin_addr.s_addr), hp->h_length);
247*23785Sgusella 		if (++nhosts == MAXH)
248*23785Sgusella 			break;
249*23785Sgusella 	}
250*23785Sgusella 
251*23785Sgusella 	msg.tsp_type = TSP_TEST;
252*23785Sgusella 	msg.tsp_vers = TSPVERSION;
253*23785Sgusella 	(void)gethostname(hostname, sizeof(hostname));
254*23785Sgusella 	(void)strcpy(msg.tsp_name, hostname);
255*23785Sgusella 	bytenetorder(&msg);	/* it is not really necessary here */
256*23785Sgusella 	while (nhosts-- > 0) {
257*23785Sgusella 		length = sizeof(struct sockaddr_in);
258*23785Sgusella 		if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
259*23785Sgusella 						&sin[nhosts], length) < 0) {
260*23785Sgusella 			perror("sendto");
261*23785Sgusella 			return;
262*23785Sgusella 		}
263*23785Sgusella 	}
264*23785Sgusella }
265*23785Sgusella 
266*23785Sgusella /*
267*23785Sgusella  * Enables or disables tracing on local timedaemon
268*23785Sgusella  */
269*23785Sgusella 
270*23785Sgusella tracing(argc, argv)
271*23785Sgusella int argc;
272*23785Sgusella char *argv[];
273*23785Sgusella {
274*23785Sgusella 	int onflag;
275*23785Sgusella 	int length;
276*23785Sgusella 	int cc, ready, found;
277*23785Sgusella 	struct sockaddr_in dest;
278*23785Sgusella 	struct timeval tout;
279*23785Sgusella 	struct sockaddr_in from;
280*23785Sgusella 	struct tsp msg;
281*23785Sgusella 	struct servent *srvp;
282*23785Sgusella 
283*23785Sgusella 	if (argc != 2) {
284*23785Sgusella 		printf("Usage: tracing { on | off }\n");
285*23785Sgusella 		return;
286*23785Sgusella 	}
287*23785Sgusella 
288*23785Sgusella 	(void) open("/etc/timed", O_WRONLY, 01700);
289*23785Sgusella 	if (errno != ETXTBSY) {
290*23785Sgusella 		printf("No timed on this machine\n");
291*23785Sgusella 		return;
292*23785Sgusella 	}
293*23785Sgusella 
294*23785Sgusella 	srvp = getservbyname("timed", "udp");
295*23785Sgusella 	if (srvp == 0) {
296*23785Sgusella 		fprintf(stderr, "udp/timed: unknown service\n");
297*23785Sgusella 		return;
298*23785Sgusella 	}
299*23785Sgusella 	dest.sin_port = srvp->s_port;
300*23785Sgusella 	dest.sin_family = AF_INET;
301*23785Sgusella 
302*23785Sgusella 	(void)gethostname(hostname,sizeof(hostname));
303*23785Sgusella 	hp = gethostbyname(hostname);
304*23785Sgusella 	bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
305*23785Sgusella 
306*23785Sgusella 	if (strcmp(argv[1], "on") == 0) {
307*23785Sgusella 		msg.tsp_type = TSP_TRACEON;
308*23785Sgusella 		onflag = ON;
309*23785Sgusella 	} else {
310*23785Sgusella 		msg.tsp_type = TSP_TRACEOFF;
311*23785Sgusella 		onflag = OFF;
312*23785Sgusella 	}
313*23785Sgusella 
314*23785Sgusella 	(void)strcpy(msg.tsp_name, hostname);
315*23785Sgusella 	msg.tsp_vers = TSPVERSION;
316*23785Sgusella 	bytenetorder(&msg);
317*23785Sgusella 	length = sizeof(struct sockaddr_in);
318*23785Sgusella 	if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
319*23785Sgusella 						&dest, length) < 0) {
320*23785Sgusella 		perror("sendto");
321*23785Sgusella 		return;
322*23785Sgusella 	}
323*23785Sgusella 
324*23785Sgusella 	tout.tv_sec = 5;
325*23785Sgusella 	tout.tv_usec = 0;
326*23785Sgusella 	ready = 1<<sock;
327*23785Sgusella 	found = select(20, &ready, (int *)0, (int *)0, &tout);
328*23785Sgusella 	if (found) {
329*23785Sgusella 		length = sizeof(struct sockaddr_in);
330*23785Sgusella 		cc = recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0,
331*23785Sgusella 							&from, &length);
332*23785Sgusella 		if (cc < 0) {
333*23785Sgusella 			perror("recvfrom");
334*23785Sgusella 			return;
335*23785Sgusella 		}
336*23785Sgusella 		bytehostorder(&msg);
337*23785Sgusella 		if (msg.tsp_type == TSP_ACK)
338*23785Sgusella 			if (onflag)
339*23785Sgusella 				printf("timed tracing enabled\n");
340*23785Sgusella 			else
341*23785Sgusella 				printf("timed tracing disabled\n");
342*23785Sgusella 		else
343*23785Sgusella 			printf("wrong ack received: %s\n",
344*23785Sgusella 						tsptype[msg.tsp_type]);
345*23785Sgusella 	} else
346*23785Sgusella 		printf("communication error\n");
347*23785Sgusella }
348*23785Sgusella 
349*23785Sgusella priv_resources()
350*23785Sgusella {
351*23785Sgusella 	int port;
352*23785Sgusella 	struct sockaddr_in sin;
353*23785Sgusella 
354*23785Sgusella 	sock = socket(AF_INET, SOCK_DGRAM, 0);
355*23785Sgusella 	if (sock < 0) {
356*23785Sgusella 		perror("opening socket");
357*23785Sgusella 		return(-1);
358*23785Sgusella 	}
359*23785Sgusella 
360*23785Sgusella 	sin.sin_family = AF_INET;
361*23785Sgusella 	sin.sin_addr.s_addr = 0;
362*23785Sgusella 	for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
363*23785Sgusella 		sin.sin_port = htons((u_short)port);
364*23785Sgusella 		if (bind(sock, (struct sockaddr *)&sin, sizeof (sin)) >= 0)
365*23785Sgusella 			break;
366*23785Sgusella 		if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) {
367*23785Sgusella 			perror("bind");
368*23785Sgusella 			(void) close(sock);
369*23785Sgusella 			return(-1);
370*23785Sgusella 		}
371*23785Sgusella 	}
372*23785Sgusella 	if (port == IPPORT_RESERVED / 2) {
373*23785Sgusella 		fprintf(stderr, "all reserved ports in use\n");
374*23785Sgusella 		(void) close(sock);
375*23785Sgusella 		return(-1);
376*23785Sgusella 	}
377*23785Sgusella 
378*23785Sgusella 	sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
379*23785Sgusella 	if (sock_raw < 0)  {
380*23785Sgusella 		perror("opening raw socket");
381*23785Sgusella 		(void) close(sock_raw);
382*23785Sgusella 		return(-1);
383*23785Sgusella 	}
384*23785Sgusella 	return(1);
385*23785Sgusella }
386