File:  [DragonFly] / src / usr.sbin / timed / timedc / cmds.c
Revision 1.3: download - view: text, annotated - select for diffs
Sat Mar 13 21:08:39 2004 UTC (10 years, 1 month ago) by eirikn
Branches: MAIN
CVS tags: HEAD, DragonFly_Snap29Sep2004, DragonFly_Snap13Sep2004, DragonFly_1_0_REL, DragonFly_1_0_RC1, DragonFly_1_0A_REL
 * Remove ``register'' keywords.
 * Convert K&R-style function declarations to ANSI-style.

Submitted by: Chris Pressey <cpressey@catseye.mine.nu>

    1: /*-
    2:  * Copyright (c) 1985, 1993
    3:  *	The Regents of the University of California.  All rights reserved.
    4:  *
    5:  * Redistribution and use in source and binary forms, with or without
    6:  * modification, are permitted provided that the following conditions
    7:  * are met:
    8:  * 1. Redistributions of source code must retain the above copyright
    9:  *    notice, this list of conditions and the following disclaimer.
   10:  * 2. Redistributions in binary form must reproduce the above copyright
   11:  *    notice, this list of conditions and the following disclaimer in the
   12:  *    documentation and/or other materials provided with the distribution.
   13:  * 3. All advertising materials mentioning features or use of this software
   14:  *    must display the following acknowledgement:
   15:  *	This product includes software developed by the University of
   16:  *	California, Berkeley and its contributors.
   17:  * 4. Neither the name of the University nor the names of its contributors
   18:  *    may be used to endorse or promote products derived from this software
   19:  *    without specific prior written permission.
   20:  *
   21:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31:  * SUCH DAMAGE.
   32:  *
   33:  * @(#)cmds.c	8.1 (Berkeley) 6/6/93
   34:  * $FreeBSD: src/usr.sbin/timed/timedc/cmds.c,v 1.6.2.2 2001/08/31 08:02:06 kris Exp $
   35:  * $DragonFly: src/usr.sbin/timed/timedc/cmds.c,v 1.3 2004/03/13 21:08:39 eirikn Exp $
   36:  */
   37: 
   38: #include "timedc.h"
   39: #include <sys/file.h>
   40: 
   41: #include <netinet/in_systm.h>
   42: #include <netinet/ip.h>
   43: #include <netinet/ip_icmp.h>
   44: 
   45: #include <err.h>
   46: #include <stdlib.h>
   47: #include <strings.h>
   48: #include <unistd.h>
   49: 
   50: #define TSPTYPES
   51: #include <protocols/timed.h>
   52: 
   53: #ifdef sgi
   54: #include <bstring.h>
   55: #include <sys/clock.h>
   56: #else
   57: #define	SECHR	(60*60)
   58: #define	SECDAY	(24*SECHR)
   59: #endif /* sgi */
   60: 
   61: # define DATE_PROTO "udp"
   62: # define DATE_PORT "time"
   63: 
   64: 
   65: int sock;
   66: int sock_raw;
   67: char myname[MAXHOSTNAMELEN];
   68: struct hostent *hp;
   69: struct sockaddr_in server;
   70: struct sockaddr_in dayaddr;
   71: extern int measure_delta;
   72: 
   73: void bytenetorder(struct tsp *);
   74: void bytehostorder(struct tsp *);
   75: 
   76: 
   77: #define BU (2208988800UL)	/* seconds before UNIX epoch */
   78: 
   79: 
   80: /* compute the difference between our date and another machine
   81:  */
   82: static int				/* difference in days from our time */
   83: daydiff(char *hostname)
   84: {
   85: 	int i;
   86: 	int trials;
   87: 	struct timeval tout, now;
   88: 	fd_set ready;
   89: 	struct sockaddr from;
   90: 	int fromlen;
   91: 	unsigned long sec;
   92: 
   93: 	/* wait 2 seconds between 10 tries */
   94: 	tout.tv_sec = 2;
   95: 	tout.tv_usec = 0;
   96: 	for (trials = 0; trials < 10; trials++) {
   97: 		/* ask for the time */
   98: 		sec = 0;
   99: 		if (sendto(sock, &sec, sizeof(sec), 0,
  100: 			   (struct sockaddr*)&dayaddr, sizeof(dayaddr)) < 0) {
  101: 			warn("sendto(sock)");
  102: 			return 0;
  103: 		}
  104: 
  105: 		for (;;) {
  106: 			FD_ZERO(&ready);
  107: 			FD_SET(sock, &ready);
  108: 			i = select(sock+1, &ready, (fd_set *)0,
  109: 				   (fd_set *)0, &tout);
  110: 			if (i < 0) {
  111: 				if (errno == EINTR)
  112: 					continue;
  113: 				warn("select(date read)");
  114: 				return 0;
  115: 			}
  116: 			if (0 == i)
  117: 				break;
  118: 
  119: 			fromlen = sizeof(from);
  120: 			if (recvfrom(sock,&sec,sizeof(sec),0,
  121: 				     &from,&fromlen) < 0) {
  122: 				warn("recvfrom(date read)");
  123: 				return 0;
  124: 			}
  125: 
  126: 			sec = ntohl(sec);
  127: 			if (sec < BU) {
  128: 				warnx("%s says it is before 1970: %lu",
  129: 					hostname, sec);
  130: 				return 0;
  131: 			}
  132: 			sec -= BU;
  133: 
  134: 			(void)gettimeofday(&now, (struct timezone*)0);
  135: 			return (sec - now.tv_sec);
  136: 		}
  137: 	}
  138: 
  139: 	/* if we get here, we tried too many times */
  140: 	warnx("%s will not tell us the date", hostname);
  141: 	return 0;
  142: }
  143: 
  144: 
  145: /*
  146:  * Clockdiff computes the difference between the time of the machine on
  147:  * which it is called and the time of the machines given as argument.
  148:  * The time differences measured by clockdiff are obtained using a sequence
  149:  * of ICMP TSTAMP messages which are returned to the sender by the IP module
  150:  * in the remote machine.
  151:  * In order to compare clocks of machines in different time zones, the time
  152:  * is transmitted (as a 32-bit value) in milliseconds since midnight UT.
  153:  * If a hosts uses a different time format, it should set the high order
  154:  * bit of the 32-bit quantity it transmits.
  155:  * However, VMS apparently transmits the time in milliseconds since midnight
  156:  * local time (rather than GMT) without setting the high order bit.
  157:  * Furthermore, it does not understand daylight-saving time.  This makes
  158:  * clockdiff behaving inconsistently with hosts running VMS.
  159:  *
  160:  * In order to reduce the sensitivity to the variance of message transmission
  161:  * time, clockdiff sends a sequence of messages.  Yet, measures between
  162:  * two `distant' hosts can be affected by a small error. The error can,
  163:  * however, be reduced by increasing the number of messages sent in each
  164:  * measurement.
  165:  */
  166: void
  167: clockdiff(int argc, char *argv[])
  168: {
  169: 	int measure_status;
  170: 	extern int measure(u_long, u_long, char *, struct sockaddr_in*, int);
  171: 	int avg_cnt;
  172: 	long avg;
  173: 	struct servent *sp;
  174: 
  175: 	if (argc < 2)  {
  176: 		printf("usage: timedc clockdiff host ...\n");
  177: 		return;
  178: 	}
  179: 
  180: 	if (gethostname(myname, sizeof(myname) - 1) < 0)
  181: 		err(1, "gethostname");
  182: 
  183: 	/* get the address for the date ready */
  184: 	sp = getservbyname(DATE_PORT, DATE_PROTO);
  185: 	if (!sp) {
  186: 		warnx("%s/%s is an unknown service", DATE_PORT, DATE_PROTO);
  187: 		dayaddr.sin_port = 0;
  188: 	} else {
  189: 		dayaddr.sin_port = sp->s_port;
  190: 	}
  191: 
  192: 	while (argc > 1) {
  193: 		argc--; argv++;
  194: 		hp = gethostbyname(*argv);
  195: 		if (hp == NULL) {
  196: 			warnx("%s: %s", *argv, hstrerror(h_errno));
  197: 			continue;
  198: 		}
  199: 
  200: 		server.sin_family = hp->h_addrtype;
  201: 		bcopy(hp->h_addr, &server.sin_addr.s_addr, hp->h_length);
  202: 		for (avg_cnt = 0, avg = 0; avg_cnt < 16; avg_cnt++) {
  203: 			measure_status = measure(10000,100, *argv, &server, 1);
  204: 			if (measure_status != GOOD)
  205: 				break;
  206: 			avg += measure_delta;
  207: 		}
  208: 		if (measure_status == GOOD)
  209: 			measure_delta = avg/avg_cnt;
  210: 
  211: 		switch (measure_status) {
  212: 		case HOSTDOWN:
  213: 			printf("%s is down\n", hp->h_name);
  214: 			continue;
  215: 		case NONSTDTIME:
  216: 			printf("%s transmitts a non-standard time format\n",
  217: 			       hp->h_name);
  218: 			continue;
  219: 		case UNREACHABLE:
  220: 			printf("%s is unreachable\n", hp->h_name);
  221: 			continue;
  222: 		}
  223: 
  224: 		/*
  225: 		 * Try to get the date only after using ICMP timestamps to
  226: 		 * get the time.  This is because the date protocol
  227: 		 * is optional.
  228: 		 */
  229: 		if (dayaddr.sin_port != 0) {
  230: 			dayaddr.sin_family = hp->h_addrtype;
  231: 			bcopy(hp->h_addr, &dayaddr.sin_addr.s_addr,
  232: 			      hp->h_length);
  233: 			avg = daydiff(*argv);
  234: 			if (avg > SECDAY) {
  235: 				printf("time on %s is %ld days ahead %s\n",
  236: 				       hp->h_name, avg/SECDAY, myname);
  237: 				continue;
  238: 			} else if (avg < -SECDAY) {
  239: 				printf("time on %s is %ld days behind %s\n",
  240: 				       hp->h_name, -avg/SECDAY, myname);
  241: 				continue;
  242: 			}
  243: 		}
  244: 
  245: 		if (measure_delta > 0) {
  246: 			printf("time on %s is %d ms. ahead of time on %s\n",
  247: 			       hp->h_name, measure_delta, myname);
  248: 		} else if (measure_delta == 0) {
  249: 			printf("%s and %s have the same time\n",
  250: 			       hp->h_name, myname);
  251: 		} else {
  252: 			printf("time on %s is %d ms. behind time on %s\n",
  253: 			       hp->h_name, -measure_delta, myname);
  254: 		}
  255: 	}
  256: 	return;
  257: }
  258: 
  259: 
  260: /*
  261:  * finds location of master timedaemon
  262:  */
  263: void
  264: msite(int argc, char *argv[])
  265: {
  266: 	int cc;
  267: 	fd_set ready;
  268: 	struct sockaddr_in dest;
  269: 	int i, length;
  270: 	struct sockaddr_in from;
  271: 	struct timeval tout;
  272: 	struct tsp msg;
  273: 	struct servent *srvp;
  274: 	char *tgtname;
  275: 
  276: 	if (argc < 1) {
  277: 		printf("usage: timedc msite [host ...]\n");
  278: 		return;
  279: 	}
  280: 
  281: 	srvp = getservbyname("timed", "udp");
  282: 	if (srvp == 0) {
  283: 		warnx("udp/timed: unknown service");
  284: 		return;
  285: 	}
  286: 	dest.sin_port = srvp->s_port;
  287: 	dest.sin_family = AF_INET;
  288: 
  289: 	if (gethostname(myname, sizeof(myname) - 1) < 0)
  290: 		err(1, "gethostname");
  291: 	i = 1;
  292: 	do {
  293: 		tgtname = (i >= argc) ? myname : argv[i];
  294: 		hp = gethostbyname(tgtname);
  295: 		if (hp == 0) {
  296: 			warnx("%s: %s", tgtname, hstrerror(h_errno));
  297: 			continue;
  298: 		}
  299: 		bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
  300: 
  301: 		(void)strlcpy(msg.tsp_name, myname, sizeof(msg.tsp_name));
  302: 		msg.tsp_type = TSP_MSITE;
  303: 		msg.tsp_vers = TSPVERSION;
  304: 		bytenetorder(&msg);
  305: 		if (sendto(sock, &msg, sizeof(struct tsp), 0,
  306: 			   (struct sockaddr*)&dest,
  307: 			   sizeof(struct sockaddr)) < 0) {
  308: 			warn("sendto");
  309: 			continue;
  310: 		}
  311: 
  312: 		tout.tv_sec = 15;
  313: 		tout.tv_usec = 0;
  314: 		FD_ZERO(&ready);
  315: 		FD_SET(sock, &ready);
  316: 		if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0,
  317: 			   &tout)) {
  318: 			length = sizeof(from);
  319: 			cc = recvfrom(sock, &msg, sizeof(struct tsp), 0,
  320: 				      (struct sockaddr *)&from, &length);
  321: 			if (cc < 0) {
  322: 				warn("recvfrom");
  323: 				continue;
  324: 			}
  325: 			/*
  326: 			 * The 4.3BSD protocol spec had a 32-byte tsp_name field, and
  327: 			 * this is still OS-dependent.  Demand that the packet is at
  328: 			 * least long enough to hold a 4.3BSD packet.
  329: 			 */
  330: 			if (cc < (sizeof(struct tsp) - MAXHOSTNAMELEN + 32)) {
  331: 				fprintf(stderr, 
  332: 				   "short packet (%u/%u bytes) from %s\n",
  333: 				   cc, sizeof(struct tsp) - MAXHOSTNAMELEN + 32,
  334: 				   inet_ntoa(from.sin_addr));
  335: 				continue;
  336: 			}
  337: 			bytehostorder(&msg);
  338: 			if (msg.tsp_type == TSP_ACK) {
  339: 				printf("master timedaemon at %s is %s\n",
  340: 				       tgtname, msg.tsp_name);
  341: 			} else {
  342: 				if (msg.tsp_type >= TSPTYPENUMBER)
  343: 					printf("unknown ack received: %u\n",
  344: 						msg.tsp_type);
  345: 				else	
  346: 					printf("wrong ack received: %s\n",
  347: 				       		tsptype[msg.tsp_type]);
  348: 			}
  349: 		} else {
  350: 			printf("communication error with %s\n", tgtname);
  351: 		}
  352: 	} while (++i < argc);
  353: }
  354: 
  355: /*
  356:  * quits timedc
  357:  */
  358: void
  359: quit(void)
  360: {
  361: 
  362: 	exit(0);
  363: }
  364: 
  365: 
  366: /*
  367:  * Causes the election timer to expire on the selected hosts
  368:  * It sends just one udp message per machine, relying on
  369:  * reliability of communication channel.
  370:  */
  371: void
  372: testing(int argc, char *argv[])
  373: {
  374: 	struct servent *srvp;
  375: 	struct sockaddr_in sin;
  376: 	struct tsp msg;
  377: 
  378: 	if (argc < 2)  {
  379: 		printf("usage: timedc election host1 [host2 ...]\n");
  380: 		return;
  381: 	}
  382: 
  383: 	srvp = getservbyname("timed", "udp");
  384: 	if (srvp == 0) {
  385: 		warnx("udp/timed: unknown service");
  386: 		return;
  387: 	}
  388: 
  389: 	while (argc > 1) {
  390: 		argc--; argv++;
  391: 		hp = gethostbyname(*argv);
  392: 		if (hp == NULL) {
  393: 			warnx("%s: %s", *argv, hstrerror(h_errno));
  394: 			argc--; argv++;
  395: 			continue;
  396: 		}
  397: 		sin.sin_port = srvp->s_port;
  398: 		sin.sin_family = hp->h_addrtype;
  399: 		bcopy(hp->h_addr, &sin.sin_addr.s_addr, hp->h_length);
  400: 
  401: 		msg.tsp_type = TSP_TEST;
  402: 		msg.tsp_vers = TSPVERSION;
  403: 		if (gethostname(myname, sizeof(myname) - 1) < 0)
  404: 			err(1, "gethostname");
  405: 		(void)strlcpy(msg.tsp_name, myname, sizeof(msg.tsp_name));
  406: 		bytenetorder(&msg);
  407: 		if (sendto(sock, &msg, sizeof(struct tsp), 0,
  408: 			   (struct sockaddr*)&sin,
  409: 			   sizeof(struct sockaddr)) < 0) {
  410: 			warn("sendto");
  411: 		}
  412: 	}
  413: }
  414: 
  415: 
  416: /*
  417:  * Enables or disables tracing on local timedaemon
  418:  */
  419: void
  420: tracing(int argc, char *argv[])
  421: {
  422: 	int onflag;
  423: 	int length;
  424: 	int cc;
  425: 	fd_set ready;
  426: 	struct sockaddr_in dest;
  427: 	struct sockaddr_in from;
  428: 	struct timeval tout;
  429: 	struct tsp msg;
  430: 	struct servent *srvp;
  431: 
  432: 	if (argc != 2) {
  433: 		printf("usage: timedc trace { on | off }\n");
  434: 		return;
  435: 	}
  436: 
  437: 	srvp = getservbyname("timed", "udp");
  438: 	if (srvp == 0) {
  439: 		warnx("udp/timed: unknown service");
  440: 		return;
  441: 	}
  442: 	dest.sin_port = srvp->s_port;
  443: 	dest.sin_family = AF_INET;
  444: 
  445: 	if (gethostname(myname, sizeof(myname) - 1) < 0)
  446: 		err(1, "gethostname");
  447: 	hp = gethostbyname(myname);
  448: 	bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
  449: 
  450: 	if (strcmp(argv[1], "on") == 0) {
  451: 		msg.tsp_type = TSP_TRACEON;
  452: 		onflag = ON;
  453: 	} else {
  454: 		msg.tsp_type = TSP_TRACEOFF;
  455: 		onflag = OFF;
  456: 	}
  457: 
  458: 	(void)strcpy(msg.tsp_name, myname);
  459: 	msg.tsp_vers = TSPVERSION;
  460: 	bytenetorder(&msg);
  461: 	if (sendto(sock, &msg, sizeof(struct tsp), 0,
  462: 		   (struct sockaddr*)&dest, sizeof(struct sockaddr)) < 0) {
  463: 		warn("sendto");
  464: 		return;
  465: 	}
  466: 
  467: 	tout.tv_sec = 5;
  468: 	tout.tv_usec = 0;
  469: 	FD_ZERO(&ready);
  470: 	FD_SET(sock, &ready);
  471: 	if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) {
  472: 		length = sizeof(from);
  473: 		cc = recvfrom(sock, &msg, sizeof(struct tsp), 0,
  474: 			      (struct sockaddr *)&from, &length);
  475: 		if (cc < 0) {
  476: 			warn("recvfrom");
  477: 			return;
  478: 		}
  479: 		/*
  480: 		 * The 4.3BSD protocol spec had a 32-byte tsp_name field, and
  481: 		 * this is still OS-dependent.  Demand that the packet is at
  482: 		 * least long enough to hold a 4.3BSD packet.
  483: 		 */
  484: 		if (cc < (sizeof(struct tsp) - MAXHOSTNAMELEN + 32)) {
  485: 			fprintf(stderr, "short packet (%u/%u bytes) from %s\n",
  486: 			    cc, sizeof(struct tsp) - MAXHOSTNAMELEN + 32,
  487: 			    inet_ntoa(from.sin_addr));
  488: 			return;
  489: 		}
  490: 		bytehostorder(&msg);
  491: 		if (msg.tsp_type == TSP_ACK)
  492: 			if (onflag)
  493: 				printf("timed tracing enabled\n");
  494: 			else
  495: 				printf("timed tracing disabled\n");
  496: 		else {
  497: 			if (msg.tsp_type >= TSPTYPENUMBER)
  498: 				printf("unknown ack received: %u\n",
  499: 					msg.tsp_type);
  500: 			else	
  501: 				printf("wrong ack received: %s\n",
  502: 						tsptype[msg.tsp_type]);
  503: 		}
  504: 	} else
  505: 		printf("communication error\n");
  506: }
  507: 
  508: int
  509: priv_resources(void)
  510: {
  511: 	int port;
  512: 	struct sockaddr_in sin;
  513: 
  514: 	sock = socket(AF_INET, SOCK_DGRAM, 0);
  515: 	if (sock < 0) {
  516: 		warn("opening socket");
  517: 		return(-1);
  518: 	}
  519: 
  520: 	sin.sin_family = AF_INET;
  521: 	sin.sin_addr.s_addr = 0;
  522: 	for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
  523: 		sin.sin_port = htons((u_short)port);
  524: 		if (bind(sock, (struct sockaddr*)&sin, sizeof (sin)) >= 0)
  525: 			break;
  526: 		if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) {
  527: 			warn("bind");
  528: 			(void) close(sock);
  529: 			return(-1);
  530: 		}
  531: 	}
  532: 	if (port == IPPORT_RESERVED / 2) {
  533: 		warnx("all reserved ports in use");
  534: 		(void) close(sock);
  535: 		return(-1);
  536: 	}
  537: 
  538: 	sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
  539: 	if (sock_raw < 0)  {
  540: 		warn("opening raw socket");
  541: 		(void) close(sock);
  542: 		return(-1);
  543: 	}
  544: 	return(1);
  545: }