Index: stable/2.2/usr.sbin/timed/timed/acksend.c =================================================================== --- stable/2.2/usr.sbin/timed/timed/acksend.c (revision 31014) +++ stable/2.2/usr.sbin/timed/timed/acksend.c (revision 31015) @@ -1,132 +1,132 @@ /*- * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint +#if 0 static char sccsid[] = "@(#)acksend.c 8.1 (Berkeley) 6/6/93"; -#endif /* not lint */ - -#ifdef sgi -#ident "$Revision: 1.6 $" #endif +static const char rcsid[] = + "$Id: acksend.c,v 1.3 1997/10/29 07:32:27 charnier Exp $"; +#endif /* not lint */ #include "globals.h" struct tsp *answer; extern u_short sequence; void xmit(type, seq, addr) int type; u_int seq; struct sockaddr_in *addr; { static struct tsp msg; msg.tsp_type = type; msg.tsp_seq = seq; msg.tsp_vers = TSPVERSION; (void)strcpy(msg.tsp_name, hostname); bytenetorder(&msg); if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0, (struct sockaddr*)addr, sizeof(struct sockaddr)) < 0) { trace_sendto_err(addr->sin_addr); } } /* * Acksend implements reliable datagram transmission by using sequence * numbers and retransmission when necessary. * If `name' is ANYADDR, this routine implements reliable broadcast. * * Because this function calls readmsg(), none of its args may be in * a message provided by readmsg(). */ struct tsp * acksend(message, addr, name, ack, net, bad) struct tsp *message; /* this message */ struct sockaddr_in *addr; /* to here */ char *name; int ack; /* look for this ack */ struct netinfo *net; /* receive from this network */ int bad; /* 1=losing patience */ { struct timeval twait; int count; long msec; message->tsp_vers = TSPVERSION; message->tsp_seq = sequence; if (trace) { fprintf(fd, "acksend: to %s: ", (name == ANYADDR ? "broadcast" : name)); print(message, addr); } bytenetorder(message); msec = 200; count = bad ? 1 : 5; /* 5 packets in 6.4 seconds */ answer = 0; do { if (!answer) { /* do not go crazy transmitting just because the * other guy cannot keep our sequence numbers * straight. */ if (sendto(sock, (char *)message, sizeof(struct tsp), 0, (struct sockaddr*)addr, sizeof(struct sockaddr)) < 0) { trace_sendto_err(addr->sin_addr); break; } } mstotvround(&twait, msec); answer = readmsg(ack, name, &twait, net); if (answer != 0) { if (answer->tsp_seq != sequence) { if (trace) fprintf(fd,"acksend: seq # %u!=%u\n", answer->tsp_seq, sequence); continue; } break; } msec *= 2; } while (--count > 0); sequence++; return(answer); } Index: stable/2.2/usr.sbin/timed/timed/byteorder.c =================================================================== --- stable/2.2/usr.sbin/timed/timed/byteorder.c (revision 31014) +++ stable/2.2/usr.sbin/timed/timed/byteorder.c (revision 31015) @@ -1,86 +1,86 @@ /*- * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint +#if 0 static char sccsid[] = "@(#)byteorder.c 8.1 (Berkeley) 6/6/93"; -#endif /* not lint */ - -#ifdef sgi -#ident "$Revision: 1.1.1.1 $" #endif +static const char rcsid[] = + "$Id: byteorder.c,v 1.3 1997/10/22 06:19:48 charnier Exp $"; +#endif /* not lint */ #include "globals.h" /* * Two routines to do the necessary byte swapping for timed protocol * messages. Protocol is defined in /usr/include/protocols/timed.h */ void bytenetorder(ptr) struct tsp *ptr; { ptr->tsp_seq = htons((u_short)ptr->tsp_seq); switch (ptr->tsp_type) { case TSP_SETTIME: case TSP_ADJTIME: case TSP_SETDATE: case TSP_SETDATEREQ: ptr->tsp_time.tv_sec = htonl((u_long)ptr->tsp_time.tv_sec); ptr->tsp_time.tv_usec = htonl((u_long)ptr->tsp_time.tv_usec); break; default: break; /* nothing more needed */ } } void bytehostorder(ptr) struct tsp *ptr; { ptr->tsp_seq = ntohs((u_short)ptr->tsp_seq); switch (ptr->tsp_type) { case TSP_SETTIME: case TSP_ADJTIME: case TSP_SETDATE: case TSP_SETDATEREQ: ptr->tsp_time.tv_sec = ntohl((u_long)ptr->tsp_time.tv_sec); ptr->tsp_time.tv_usec = ntohl((u_long)ptr->tsp_time.tv_usec); break; default: break; /* nothing more needed */ } } Index: stable/2.2/usr.sbin/timed/timed/candidate.c =================================================================== --- stable/2.2/usr.sbin/timed/timed/candidate.c (revision 31014) +++ stable/2.2/usr.sbin/timed/timed/candidate.c (revision 31015) @@ -1,167 +1,167 @@ /*- * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint +#if 0 static char sccsid[] = "@(#)candidate.c 8.1 (Berkeley) 6/6/93"; -#endif /* not lint */ - -#ifdef sgi -#ident "$Revision: 1.1.1.1 $" #endif +static const char rcsid[] = + "$Id: candidate.c,v 1.4 1997/10/29 07:32:27 charnier Exp $"; +#endif /* not lint */ #include "globals.h" /* * `election' candidates a host as master: it is called by a slave * which runs with the -M option set when its election timeout expires. * Note the conservative approach: if a new timed comes up, or another * candidate sends an election request, the candidature is withdrawn. */ int election(net) struct netinfo *net; { struct tsp *resp, msg; struct timeval then, wait; struct tsp *answer; struct hosttbl *htp; char loop_lim = 0; /* This code can get totally confused if it gets slightly behind. For * example, if readmsg() has some QUIT messages waiting from the last * round, we would send an ELECTION message, get the stale QUIT, * and give up. This results in network storms when several machines * do it at once. */ wait.tv_sec = 0; wait.tv_usec = 0; while (0 != readmsg(TSP_REFUSE, ANYADDR, &wait, net)) { if (trace) fprintf(fd, "election: discarded stale REFUSE\n"); } while (0 != readmsg(TSP_QUIT, ANYADDR, &wait, net)) { if (trace) fprintf(fd, "election: discarded stale QUIT\n"); } again: syslog(LOG_INFO, "This machine is a candidate time master"); if (trace) fprintf(fd, "This machine is a candidate time master\n"); msg.tsp_type = TSP_ELECTION; msg.tsp_vers = TSPVERSION; (void)strcpy(msg.tsp_name, hostname); bytenetorder(&msg); if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0, (struct sockaddr*)&net->dest_addr, sizeof(struct sockaddr)) < 0) { trace_sendto_err(net->dest_addr.sin_addr); return(SLAVE); } (void)gettimeofday(&then, 0); then.tv_sec += 3; for (;;) { (void)gettimeofday(&wait, 0); timevalsub(&wait,&then,&wait); resp = readmsg(TSP_ANY, ANYADDR, &wait, net); if (!resp) return(MASTER); switch (resp->tsp_type) { case TSP_ACCEPT: (void)addmach(resp->tsp_name, &from,fromnet); break; case TSP_MASTERUP: case TSP_MASTERREQ: /* * If another timedaemon is coming up at the same * time, give up, and let it be the master. */ if (++loop_lim < 5 && !good_host_name(resp->tsp_name)) { (void)addmach(resp->tsp_name, &from,fromnet); suppress(&from, resp->tsp_name, net); goto again; } rmnetmachs(net); return(SLAVE); case TSP_QUIT: case TSP_REFUSE: /* * Collision: change value of election timer * using exponential backoff. * * Fooey. * An exponential backoff on a delay starting at * 6 to 15 minutes for a process that takes * milliseconds is silly. It is particularly * strange that the original code would increase * the backoff without bound. */ rmnetmachs(net); return(SLAVE); case TSP_ELECTION: /* no master for another round */ htp = addmach(resp->tsp_name,&from,fromnet); msg.tsp_type = TSP_REFUSE; (void)strcpy(msg.tsp_name, hostname); answer = acksend(&msg, &htp->addr, htp->name, TSP_ACK, 0, htp->noanswer); if (!answer) { syslog(LOG_ERR, "error in election from %s", htp->name); } break; case TSP_SLAVEUP: (void)addmach(resp->tsp_name, &from,fromnet); break; case TSP_SETDATE: case TSP_SETDATEREQ: break; default: if (trace) { fprintf(fd, "candidate: "); print(resp, &from); } break; } } } Index: stable/2.2/usr.sbin/timed/timed/cksum.c =================================================================== --- stable/2.2/usr.sbin/timed/timed/cksum.c (revision 31014) +++ stable/2.2/usr.sbin/timed/timed/cksum.c (revision 31015) @@ -1,87 +1,87 @@ /*- * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint +#if 0 static char sccsid[] = "@(#)cksum.c 8.1 (Berkeley) 6/6/93"; -#endif /* not lint */ - -#ifdef sgi -#ident "$Revision: 1.3 $" #endif +static const char rcsid[] = + "$Id: cksum.c,v 1.2 1997/10/22 06:19:48 charnier Exp $"; +#endif /* not lint */ #include /* * I N _ C K S U M * * Checksum routine for Internet Protocol family headers (C Version) * * There is no profit in a specialized version of the checksum * function for any machine where int's are 32 bits and shorts are 16. * * All timed packets are smaller than 32K shorts, so there is no need to * worry about carries except at the end. */ int in_cksum(addr, len) u_short *addr; int len; { register int nleft = len; register u_short *w = addr; register u_short answer; register int sum = 0; /* * Our algorithm is simple, using a 32 bit accumulator (sum), * we add sequential 16 bit words to it, and at the end, fold * back all the carry bits from the top 16 bits into the lower * 16 bits. */ while( nleft > 1 ) { sum += *w++; nleft -= 2; } /* mop up an odd byte, if necessary */ if( nleft == 1 ) sum += (*(u_char *)w) << 8; /* * add back carry outs from top 16 bits to low 16 bits */ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ sum += (sum >> 16); /* add carry */ answer = ~sum; /* truncate to 16 bits */ return (answer); } Index: stable/2.2/usr.sbin/timed/timed/correct.c =================================================================== --- stable/2.2/usr.sbin/timed/timed/correct.c (revision 31014) +++ stable/2.2/usr.sbin/timed/timed/correct.c (revision 31015) @@ -1,294 +1,294 @@ /*- * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint +#if 0 static char sccsid[] = "@(#)correct.c 8.1 (Berkeley) 6/6/93"; -#endif /* not lint */ - -#ifdef sgi -#ident "$Revision: 1.16 $" #endif +static const char rcsid[] = + "$Id: correct.c,v 1.3 1997/10/29 07:32:28 charnier Exp $"; +#endif /* not lint */ #include "globals.h" #include #include #include #ifdef sgi #include #endif /* sgi */ static void adjclock __P((struct timeval *)); /* * sends to the slaves the corrections for their clocks after fixing our * own */ void correct(avdelta) long avdelta; { struct hosttbl *htp; int corr; struct timeval adjlocal; struct tsp to; struct tsp *answer; mstotvround(&adjlocal, avdelta); for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { if (htp->delta != HOSTDOWN) { corr = avdelta - htp->delta; /* If the other machine is off in the weeds, set its time directly. * If a slave gets the wrong day, the original code would simply * fix the minutes. If you fix a network partition, you can get * into such situations. */ if (htp->need_set || corr >= MAXADJ*1000 || corr <= -MAXADJ*1000) { htp->need_set = 0; (void)gettimeofday(&to.tsp_time,0); timevaladd(&to.tsp_time, &adjlocal); to.tsp_type = TSP_SETTIME; } else { mstotvround(&to.tsp_time, corr); to.tsp_type = TSP_ADJTIME; } (void)strcpy(to.tsp_name, hostname); answer = acksend(&to, &htp->addr, htp->name, TSP_ACK, 0, 0); if (!answer) { htp->delta = HOSTDOWN; syslog(LOG_WARNING, "no reply to time correction from %s", htp->name); if (++htp->noanswer >= LOSTHOST) { if (trace) { fprintf(fd, "purging %s for not answering\n", htp->name); (void)fflush(fd); } htp = remmach(htp); } } } } /* * adjust our own clock now that we are not sending it out */ adjclock(&adjlocal); } static void adjclock(corr) struct timeval *corr; { static int passes = 0; static int smoother = 0; long delta; /* adjustment in usec */ long ndelta; struct timeval now; struct timeval adj; if (!timerisset(corr)) return; adj = *corr; if (adj.tv_sec < MAXADJ && adj.tv_sec > - MAXADJ) { delta = adj.tv_sec*1000000 + adj.tv_usec; /* If the correction is less than the minimum round * trip time for an ICMP packet, and thus * less than the likely error in the measurement, * do not do the entire correction. Do half * or a quarter of it. */ if (delta > -MIN_ROUND*1000 && delta < MIN_ROUND*1000) { if (smoother <= 4) smoother++; ndelta = delta >> smoother; if (trace) fprintf(fd, "trimming delta %ld usec to %ld\n", delta, ndelta); adj.tv_usec = ndelta; adj.tv_sec = 0; } else if (smoother > 0) { smoother--; } if (0 > adjtime(corr, 0)) { syslog(LOG_ERR, "adjtime: %m"); } if (passes > 1 && (delta < -BIG_ADJ || delta > BIG_ADJ)) { smoother = 0; passes = 0; syslog(LOG_WARNING, "large time adjustment of %+.3f sec", delta/1000000.0); } } else { syslog(LOG_WARNING, "clock correction %d sec too large to adjust", adj.tv_sec); (void) gettimeofday(&now, 0); timevaladd(&now, corr); if (settimeofday(&now, 0) < 0) syslog(LOG_ERR, "settimeofday: %m"); } #ifdef sgi /* Accumulate the total change, and use it to adjust the basic * clock rate. */ if (++passes > 2) { #define F_USEC_PER_SEC (1000000*1.0) /* reduce typos */ #define F_NSEC_PER_SEC (F_USEC_PER_SEC*1000.0) extern char *timetrim_fn; extern char *timetrim_wpat; extern long timetrim; extern double tot_adj, hr_adj; /* totals in nsec */ extern double tot_ticks, hr_ticks; static double nag_tick; double cur_ticks, hr_delta_ticks, tot_delta_ticks; double tru_tot_adj, tru_hr_adj; /* nsecs of adjustment */ double tot_trim, hr_trim; /* nsec/sec */ struct tms tm; FILE *timetrim_st; cur_ticks = times(&tm); tot_adj += delta*1000.0; hr_adj += delta*1000.0; tot_delta_ticks = cur_ticks-tot_ticks; if (tot_delta_ticks >= 16*SECDAY*CLK_TCK) { tot_adj -= rint(tot_adj/16); tot_ticks += rint(tot_delta_ticks/16); tot_delta_ticks = cur_ticks-tot_ticks; } hr_delta_ticks = cur_ticks-hr_ticks; tru_hr_adj = hr_adj + timetrim*rint(hr_delta_ticks/CLK_TCK); tru_tot_adj = (tot_adj + timetrim*rint(tot_delta_ticks/CLK_TCK)); if (hr_delta_ticks >= SECDAY*CLK_TCK || (tot_delta_ticks < 4*SECDAY*CLK_TCK && hr_delta_ticks >= SECHR*CLK_TCK) || (trace && hr_delta_ticks >= (SECHR/10)*CLK_TCK)) { tot_trim = rint(tru_tot_adj*CLK_TCK/tot_delta_ticks); hr_trim = rint(tru_hr_adj*CLK_TCK/hr_delta_ticks); if (trace || (abs(timetrim - hr_trim) > 100000.0 && 0 == timetrim_fn && ((cur_ticks - nag_tick) >= 24*SECDAY*CLK_TCK))) { nag_tick = cur_ticks; syslog(LOG_NOTICE, "%+.3f/%.2f or %+.3f/%.2f sec/hr; timetrim=%+.0f or %+.0f", tru_tot_adj/F_NSEC_PER_SEC, tot_delta_ticks/(SECHR*CLK_TCK*1.0), tru_hr_adj/F_NSEC_PER_SEC, hr_delta_ticks/(SECHR*CLK_TCK*1.0), tot_trim, hr_trim); } if (tot_trim < -MAX_TRIM || tot_trim > MAX_TRIM) { tot_ticks = hr_ticks; tot_adj = hr_adj; } else if (0 > syssgi(SGI_SETTIMETRIM, (long)tot_trim)) { syslog(LOG_ERR, "SETTIMETRIM(%d): %m", (long)tot_trim); } else { if (0 != timetrim_fn) { timetrim_st = fopen(timetrim_fn, "w"); if (0 == timetrim_st) { syslog(LOG_ERR, "fopen(%s): %m", timetrim_fn); } else { if (0 > fprintf(timetrim_st, timetrim_wpat, (long)tot_trim, tru_tot_adj, tot_delta_ticks)) { syslog(LOG_ERR, "fprintf(%s): %m", timetrim_fn); } (void)fclose(timetrim_st); } } tot_adj -= ((tot_trim - timetrim) * rint(tot_delta_ticks/CLK_TCK)); timetrim = tot_trim; } hr_ticks = cur_ticks; hr_adj = 0; } } #endif /* sgi */ } /* adjust the time in a message by the time it * spent in the queue */ void adj_msg_time(msg, now) struct tsp *msg; struct timeval *now; { msg->tsp_time.tv_sec += (now->tv_sec - from_when.tv_sec); msg->tsp_time.tv_usec += (now->tv_usec - from_when.tv_usec); while (msg->tsp_time.tv_usec < 0) { msg->tsp_time.tv_sec--; msg->tsp_time.tv_usec += 1000000; } while (msg->tsp_time.tv_usec >= 1000000) { msg->tsp_time.tv_sec++; msg->tsp_time.tv_usec -= 1000000; } } Index: stable/2.2/usr.sbin/timed/timed/globals.h =================================================================== --- stable/2.2/usr.sbin/timed/timed/globals.h (revision 31014) +++ stable/2.2/usr.sbin/timed/timed/globals.h (revision 31015) @@ -1,186 +1,182 @@ /*- * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)globals.h 8.1 (Berkeley) 6/6/93 */ -#ifdef sgi -#ident "$Revision: 1.15 $" -#endif - #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #ifdef sgi #include #include /* use the constant HZ instead of the function CLK_TCK */ #undef CLK_TCK #define CLK_TCK HZ #else #define SECHR (60*60) #define SECDAY (24*SECHR) #endif /* sgi */ -extern int errno; extern int sock; /* Best expected round trip for a measurement. * This is essentially the number of milliseconds per CPU tick (CLK_TCK?). * All delays shorter than this are usually reported as 0. */ #define MIN_ROUND ((1000-1)/CLK_TCK) #define SAMPLEINTVL 240 /* synch() freq for master in sec */ #define MAXADJ 20 /* max adjtime() correction in sec */ #define MAX_TRIM 3000000 /* max drift in nsec/sec, 0.3% */ #define BIG_ADJ (MAX_TRIM/1000*SAMPLEINTVL*2) /* max good adj */ #define MINTOUT 360 /* election delays, 6-15 minutes */ #define MAXTOUT 900 #define BAD_STATUS (-1) #define GOOD 1 #define UNREACHABLE 2 #define NONSTDTIME 3 #define HOSTDOWN 0x7fffffff #define OFF 0 #define ON 1 #define MAX_HOPCNT 10 /* max value for tsp_hpcnt */ #define LOSTHOST 3 /* forget after this many failures */ #define VALID_RANGE (MAXADJ*1000) /* good times in milliseconds */ #define GOOD_RANGE (MIN_ROUND*2) #define VGOOD_RANGE (MIN_ROUND-1) /* * Global and per-network states. */ #define NOMASTER 0 /* no good master */ #define SLAVE 1 #define MASTER 2 #define IGNORE 4 #define ALL (SLAVE|MASTER|IGNORE) #define SUBMASTER (SLAVE|MASTER) #define NHOSTS 1013 /* max of hosts controlled by timed * This must be a prime number. */ struct hosttbl { struct hosttbl *h_bak; /* hash chain */ struct hosttbl *h_fwd; struct hosttbl *l_bak; /* "sequential" list */ struct hosttbl *l_fwd; struct netinfo *ntp; struct sockaddr_in addr; - char name[MAXHOSTNAMELEN+1]; + char name[MAXHOSTNAMELEN]; u_char head; /* 1=head of hash chain */ u_char good; /* 0=trusted host, for averaging */ u_char noanswer; /* count of failures to answer */ u_char need_set; /* need a SETTIME */ u_short seq; long delta; }; /* closed hash table with internal chaining */ extern struct hosttbl hosttbl[NHOSTS+1]; #define self hosttbl[0] #define hostname (self.name) struct netinfo { struct netinfo *next; struct in_addr net; u_long mask; struct in_addr my_addr; struct sockaddr_in dest_addr; /* broadcast addr or point-point */ long status; struct timeval slvwait; /* delay before sending our time */ int quit_count; /* recent QUITs */ }; #include "extern.h" #define tvtomsround(tv) ((tv).tv_sec*1000 + ((tv).tv_usec + 500)/1000) extern struct netinfo *nettab; extern int status; extern int trace; extern int sock; extern struct sockaddr_in from; extern struct timeval from_when; /* when the last msg arrived */ extern u_short sequence; /* TSP message sequence number */ extern struct netinfo *fromnet, *slavenet; extern FILE *fd; extern long delay1, delay2; extern int nslavenets; /* nets were I could be a slave */ extern int nmasternets; /* nets were I could be a master */ extern int nignorednets; /* ignored nets */ extern int nnets; /* nets I am connected to */ #define trace_msg(msg) {if (trace) fprintf(fd, msg);} #define trace_sendto_err(addr) { \ int st_errno = errno; \ syslog(LOG_ERR, "%s %d: sendto %s: %m", \ __FILE__, __LINE__, inet_ntoa(addr)); \ if (trace) \ fprintf(fd, "%s %d: sendto %s: %d", __FILE__, __LINE__, \ inet_ntoa(addr), st_errno); \ } # define max(a,b) (ab ? b : a) # define abs(x) (x>=0 ? x : -(x)) Index: stable/2.2/usr.sbin/timed/timed/master.c =================================================================== --- stable/2.2/usr.sbin/timed/timed/master.c (revision 31014) +++ stable/2.2/usr.sbin/timed/timed/master.c (revision 31015) @@ -1,907 +1,907 @@ /*- * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint +#if 0 static char sccsid[] = "@(#)master.c 8.1 (Berkeley) 6/6/93"; -#endif /* not lint */ - -#ifdef sgi -#ident "$Revision: 1.1.1.1 $" #endif +static const char rcsid[] = + "$Id: master.c,v 1.4 1997/10/29 07:32:28 charnier Exp $"; +#endif /* not lint */ #include "globals.h" #include #include #include #include #ifdef sgi #include #endif /* sgi */ #include #include "pathnames.h" extern int measure_delta; extern jmp_buf jmpenv; extern int Mflag; extern int justquit; static int dictate; static int slvcount; /* slaves listening to our clock */ static void mchgdate __P((struct tsp *)); #ifdef sgi extern void logwtmp __P((struct timeval *, struct timeval *)); #else extern void logwtmp __P((char *, char *, char *)); #endif /* sgi */ /* * The main function of `master' is to periodically compute the differences * (deltas) between its clock and the clocks of the slaves, to compute the * network average delta, and to send to the slaves the differences between * their individual deltas and the network delta. * While waiting, it receives messages from the slaves (i.e. requests for * master's name, remote requests to set the network time, ...), and * takes the appropriate action. */ int master() { struct hosttbl *htp; long pollingtime; #define POLLRATE 4 int polls; struct timeval wait, ntime; struct tsp *msg, *answer, to; char newdate[32]; struct sockaddr_in taddr; char tname[MAXHOSTNAMELEN]; struct netinfo *ntp; int i; syslog(LOG_NOTICE, "This machine is master"); if (trace) fprintf(fd, "This machine is master\n"); for (ntp = nettab; ntp != NULL; ntp = ntp->next) { if (ntp->status == MASTER) masterup(ntp); } (void)gettimeofday(&ntime, 0); pollingtime = ntime.tv_sec+3; if (justquit) polls = 0; else polls = POLLRATE-1; /* Process all outstanding messages before spending the long time necessary * to update all timers. */ loop: (void)gettimeofday(&ntime, 0); wait.tv_sec = pollingtime - ntime.tv_sec; if (wait.tv_sec < 0) wait.tv_sec = 0; wait.tv_usec = 0; msg = readmsg(TSP_ANY, ANYADDR, &wait, 0); if (!msg) { (void)gettimeofday(&ntime, 0); if (ntime.tv_sec >= pollingtime) { pollingtime = ntime.tv_sec + SAMPLEINTVL; get_goodgroup(0); /* If a bogus master told us to quit, we can have decided to ignore a * network. Therefore, periodically try to take over everything. */ polls = (polls + 1) % POLLRATE; if (0 == polls && nignorednets > 0) { trace_msg("Looking for nets to re-master\n"); for (ntp = nettab; ntp; ntp = ntp->next) { if (ntp->status == IGNORE || ntp->status == NOMASTER) { lookformaster(ntp); if (ntp->status == MASTER) { masterup(ntp); polls = POLLRATE-1; } } if (ntp->status == MASTER && --ntp->quit_count < 0) ntp->quit_count = 0; } if (polls != 0) setstatus(); } synch(0L); for (ntp = nettab; ntp != NULL; ntp = ntp->next) { to.tsp_type = TSP_LOOP; to.tsp_vers = TSPVERSION; to.tsp_seq = sequence++; to.tsp_hopcnt = MAX_HOPCNT; (void)strcpy(to.tsp_name, hostname); bytenetorder(&to); if (sendto(sock, (char *)&to, sizeof(struct tsp), 0, (struct sockaddr*)&ntp->dest_addr, sizeof(ntp->dest_addr)) < 0) { trace_sendto_err(ntp->dest_addr.sin_addr); } } } } else { switch (msg->tsp_type) { case TSP_MASTERREQ: break; case TSP_SLAVEUP: newslave(msg); break; case TSP_SETDATE: /* * XXX check to see it is from ourself */ #ifdef sgi (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec); #else (void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec)); #endif /* sgi */ if (!good_host_name(msg->tsp_name)) { syslog(LOG_NOTICE, "attempted date change by %s to %s", msg->tsp_name, newdate); spreadtime(); break; } mchgdate(msg); (void)gettimeofday(&ntime, 0); pollingtime = ntime.tv_sec + SAMPLEINTVL; break; case TSP_SETDATEREQ: if (!fromnet || fromnet->status != MASTER) break; #ifdef sgi (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec); #else (void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec)); #endif /* sgi */ htp = findhost(msg->tsp_name); if (htp == 0) { syslog(LOG_ERR, "attempted SET DATEREQ by uncontrolled %s to %s", msg->tsp_name, newdate); break; } if (htp->seq == msg->tsp_seq) break; htp->seq = msg->tsp_seq; if (!htp->good) { syslog(LOG_NOTICE, "attempted SET DATEREQ by untrusted %s to %s", msg->tsp_name, newdate); spreadtime(); break; } mchgdate(msg); (void)gettimeofday(&ntime, 0); pollingtime = ntime.tv_sec + SAMPLEINTVL; break; case TSP_MSITE: xmit(TSP_ACK, msg->tsp_seq, &from); break; case TSP_MSITEREQ: break; case TSP_TRACEON: traceon(); break; case TSP_TRACEOFF: traceoff("Tracing ended at %s\n"); break; case TSP_ELECTION: if (!fromnet) break; if (fromnet->status == MASTER) { pollingtime = 0; (void)addmach(msg->tsp_name, &from,fromnet); } taddr = from; (void)strcpy(tname, msg->tsp_name); to.tsp_type = TSP_QUIT; (void)strcpy(to.tsp_name, hostname); answer = acksend(&to, &taddr, tname, TSP_ACK, 0, 1); if (answer == NULL) { syslog(LOG_ERR, "election error by %s", tname); } break; case TSP_CONFLICT: /* * After a network partition, there can be * more than one master: the first slave to * come up will notify here the situation. */ if (!fromnet || fromnet->status != MASTER) break; (void)strcpy(to.tsp_name, hostname); /* The other master often gets into the same state, * with boring results if we stay at it forever. */ ntp = fromnet; /* (acksend() can leave fromnet=0 */ for (i = 0; i < 3; i++) { to.tsp_type = TSP_RESOLVE; (void)strcpy(to.tsp_name, hostname); answer = acksend(&to, &ntp->dest_addr, ANYADDR, TSP_MASTERACK, ntp, 0); if (!answer) break; htp = addmach(answer->tsp_name,&from,ntp); to.tsp_type = TSP_QUIT; msg = acksend(&to, &htp->addr, htp->name, TSP_ACK, 0, htp->noanswer); if (msg == NULL) { syslog(LOG_ERR, "no response from %s to CONFLICT-QUIT", htp->name); } } masterup(ntp); pollingtime = 0; break; case TSP_RESOLVE: if (!fromnet || fromnet->status != MASTER) break; /* * do not want to call synch() while waiting * to be killed! */ (void)gettimeofday(&ntime, (struct timezone *)0); pollingtime = ntime.tv_sec + SAMPLEINTVL; break; case TSP_QUIT: doquit(msg); /* become a slave */ break; case TSP_LOOP: if (!fromnet || fromnet->status != MASTER || !strcmp(msg->tsp_name, hostname)) break; /* * We should not have received this from a net * we are master on. There must be two masters. */ htp = addmach(msg->tsp_name, &from,fromnet); to.tsp_type = TSP_QUIT; (void)strcpy(to.tsp_name, hostname); answer = acksend(&to, &htp->addr, htp->name, TSP_ACK, 0, 1); if (!answer) { syslog(LOG_WARNING, "loop breakage: no reply from %s=%s to QUIT", htp->name, inet_ntoa(htp->addr.sin_addr)); (void)remmach(htp); } case TSP_TEST: if (trace) { fprintf(fd, "\tnets = %d, masters = %d, slaves = %d, ignored = %d\n", nnets, nmasternets, nslavenets, nignorednets); setstatus(); } pollingtime = 0; polls = POLLRATE-1; break; default: if (trace) { fprintf(fd, "garbage message: "); print(msg, &from); } break; } } goto loop; } /* * change the system date on the master */ static void mchgdate(msg) struct tsp *msg; { char tname[MAXHOSTNAMELEN]; char olddate[32]; struct timeval otime, ntime; (void)strcpy(tname, msg->tsp_name); xmit(TSP_DATEACK, msg->tsp_seq, &from); (void)strcpy(olddate, date()); /* adjust time for residence on the queue */ (void)gettimeofday(&otime, 0); adj_msg_time(msg,&otime); timevalsub(&ntime, &msg->tsp_time, &otime); if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) { /* * do not change the clock if we can adjust it */ dictate = 3; synch(tvtomsround(ntime)); } else { #ifdef sgi if (0 > settimeofday(&msg->tsp_time, 0)) { syslog(LOG_ERR, "settimeofday(): %m"); } logwtmp(&otime, &msg->tsp_time); #else logwtmp("|", "date", ""); (void)settimeofday(&msg->tsp_time, 0); logwtmp("{", "date", ""); #endif /* sgi */ spreadtime(); } syslog(LOG_NOTICE, "date changed by %s from %s", tname, olddate); } /* * synchronize all of the slaves */ void synch(mydelta) long mydelta; { struct hosttbl *htp; int measure_status; struct timeval check, stop, wait; #ifdef sgi int pri; #endif /* sgi */ if (slvcount > 0) { if (trace) fprintf(fd, "measurements starting at %s\n", date()); (void)gettimeofday(&check, 0); #ifdef sgi /* run fast to get good time */ pri = schedctl(NDPRI,0,NDPHIMIN); if (pri < 0) syslog(LOG_ERR, "schedctl(): %m"); #endif /* sgi */ for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { if (htp->noanswer != 0) { measure_status = measure(500, 100, htp->name, &htp->addr,0); } else { measure_status = measure(3000, 100, htp->name, &htp->addr,0); } if (measure_status != GOOD) { /* The slave did not respond. We have * just wasted lots of time on it. */ htp->delta = HOSTDOWN; if (++htp->noanswer >= LOSTHOST) { if (trace) { fprintf(fd, "purging %s for not answering ICMP\n", htp->name); (void)fflush(fd); } htp = remmach(htp); } } else { htp->delta = measure_delta; } (void)gettimeofday(&stop, 0); timevalsub(&stop, &stop, &check); if (stop.tv_sec >= 1) { if (trace) (void)fflush(fd); /* * ack messages periodically */ wait.tv_sec = 0; wait.tv_usec = 0; if (0 != readmsg(TSP_TRACEON,ANYADDR, &wait,0)) traceon(); (void)gettimeofday(&check, 0); } } #ifdef sgi if (pri >= 0) (void)schedctl(NDPRI,0,pri); #endif /* sgi */ if (trace) fprintf(fd, "measurements finished at %s\n", date()); } if (!(status & SLAVE)) { if (!dictate) { mydelta = networkdelta(); } else { dictate--; } } if (trace && (mydelta != 0 || (status & SLAVE))) fprintf(fd,"local correction of %ld ms.\n", mydelta); correct(mydelta); } /* * sends the time to each slave after the master * has received the command to set the network time */ void spreadtime() { struct hosttbl *htp; struct tsp to; struct tsp *answer; /* Do not listen to the consensus after forcing the time. This is because * the consensus takes a while to reach the time we are dictating. */ dictate = 2; for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { to.tsp_type = TSP_SETTIME; (void)strcpy(to.tsp_name, hostname); (void)gettimeofday(&to.tsp_time, 0); answer = acksend(&to, &htp->addr, htp->name, TSP_ACK, 0, htp->noanswer); if (answer == 0) { /* We client does not respond, then we have * just wasted lots of time on it. */ syslog(LOG_WARNING, "no reply to SETTIME from %s", htp->name); if (++htp->noanswer >= LOSTHOST) { if (trace) { fprintf(fd, "purging %s for not answering", htp->name); (void)fflush(fd); } htp = remmach(htp); } } } } void prthp(delta) clock_t delta; { static time_t next_time; time_t this_time; struct tms tm; struct hosttbl *htp; int length, l; int i; if (!fd) /* quit if tracing already off */ return; this_time = times(&tm); if (this_time + delta < next_time) return; next_time = this_time + CLK_TCK; fprintf(fd, "host table: %d entries at %s\n", slvcount, date()); htp = self.l_fwd; length = 1; for (i = 1; i <= slvcount; i++, htp = htp->l_fwd) { l = strlen(htp->name) + 1; if (length+l >= 80) { fprintf(fd, "\n"); length = 0; } length += l; fprintf(fd, " %s", htp->name); } fprintf(fd, "\n"); } static struct hosttbl *newhost_hash; static struct hosttbl *lasthfree = &hosttbl[0]; struct hosttbl * /* answer or 0 */ findhost(name) char *name; { int i, j; struct hosttbl *htp; char *p; j= 0; for (p = name, i = 0; i < 8 && *p != '\0'; i++, p++) j = (j << 2) ^ *p; newhost_hash = &hosttbl[j % NHOSTS]; htp = newhost_hash; if (htp->name[0] == '\0') return(0); do { if (!strcmp(name, htp->name)) return(htp); htp = htp->h_fwd; } while (htp != newhost_hash); return(0); } /* * add a host to the list of controlled machines if not already there */ struct hosttbl * addmach(name, addr, ntp) char *name; struct sockaddr_in *addr; struct netinfo *ntp; { struct hosttbl *ret, *p, *b, *f; ret = findhost(name); if (ret == 0) { if (slvcount >= NHOSTS) { if (trace) { fprintf(fd, "no more slots in host table\n"); prthp(CLK_TCK); } syslog(LOG_ERR, "no more slots in host table"); Mflag = 0; longjmp(jmpenv, 2); /* give up and be a slave */ } /* if our home hash slot is occupied, find a free entry * in the hash table */ if (newhost_hash->name[0] != '\0') { do { ret = lasthfree; if (++lasthfree > &hosttbl[NHOSTS]) lasthfree = &hosttbl[1]; } while (ret->name[0] != '\0'); if (!newhost_hash->head) { /* Move an interloper using our home. Use * scratch pointers in case the new head is * pointing to itself. */ f = newhost_hash->h_fwd; b = newhost_hash->h_bak; f->h_bak = ret; b->h_fwd = ret; f = newhost_hash->l_fwd; b = newhost_hash->l_bak; f->l_bak = ret; b->l_fwd = ret; bcopy(newhost_hash,ret,sizeof(*ret)); ret = newhost_hash; ret->head = 1; ret->h_fwd = ret; ret->h_bak = ret; } else { /* link to an existing chain in our home */ ret->head = 0; p = newhost_hash->h_bak; ret->h_fwd = newhost_hash; ret->h_bak = p; p->h_fwd = ret; newhost_hash->h_bak = ret; } } else { ret = newhost_hash; ret->head = 1; ret->h_fwd = ret; ret->h_bak = ret; } ret->addr = *addr; ret->ntp = ntp; (void)strncpy(ret->name, name, sizeof(ret->name)); ret->good = good_host_name(name); ret->l_fwd = &self; ret->l_bak = self.l_bak; self.l_bak->l_fwd = ret; self.l_bak = ret; slvcount++; ret->noanswer = 0; ret->need_set = 1; } else { ret->noanswer = (ret->noanswer != 0); } /* need to clear sequence number anyhow */ ret->seq = 0; return(ret); } /* * remove the machine with the given index in the host table. */ struct hosttbl * remmach(htp) struct hosttbl *htp; { struct hosttbl *lprv, *hnxt, *f, *b; if (trace) fprintf(fd, "remove %s\n", htp->name); /* get out of the lists */ htp->l_fwd->l_bak = lprv = htp->l_bak; htp->l_bak->l_fwd = htp->l_fwd; htp->h_fwd->h_bak = htp->h_bak; htp->h_bak->h_fwd = hnxt = htp->h_fwd; /* If we are in the home slot, pull up the chain */ if (htp->head && hnxt != htp) { if (lprv == hnxt) lprv = htp; /* Use scratch pointers in case the new head is pointing to * itself. */ f = hnxt->h_fwd; b = hnxt->h_bak; f->h_bak = htp; b->h_fwd = htp; f = hnxt->l_fwd; b = hnxt->l_bak; f->l_bak = htp; b->l_fwd = htp; hnxt->head = 1; bcopy(hnxt, htp, sizeof(*htp)); lasthfree = hnxt; } else { lasthfree = htp; } lasthfree->name[0] = '\0'; lasthfree->h_fwd = 0; lasthfree->l_fwd = 0; slvcount--; return lprv; } /* * Remove all the machines from the host table that exist on the given * network. This is called when a master transitions to a slave on a * given network. */ void rmnetmachs(ntp) struct netinfo *ntp; { struct hosttbl *htp; if (trace) prthp(CLK_TCK); for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { if (ntp == htp->ntp) htp = remmach(htp); } if (trace) prthp(CLK_TCK); } void masterup(net) struct netinfo *net; { xmit(TSP_MASTERUP, 0, &net->dest_addr); /* * Do not tell new slaves our time for a while. This ensures * we do not tell them to start using our time, before we have * found a good master. */ (void)gettimeofday(&net->slvwait, 0); } void newslave(msg) struct tsp *msg; { struct hosttbl *htp; struct tsp *answer, to; struct timeval now; if (!fromnet || fromnet->status != MASTER) return; htp = addmach(msg->tsp_name, &from,fromnet); htp->seq = msg->tsp_seq; if (trace) prthp(0); /* * If we are stable, send our time to the slave. * Do not go crazy if the date has been changed. */ (void)gettimeofday(&now, 0); if (now.tv_sec >= fromnet->slvwait.tv_sec+3 || now.tv_sec < fromnet->slvwait.tv_sec) { to.tsp_type = TSP_SETTIME; (void)strcpy(to.tsp_name, hostname); (void)gettimeofday(&to.tsp_time, 0); answer = acksend(&to, &htp->addr, htp->name, TSP_ACK, 0, htp->noanswer); if (answer) { htp->need_set = 0; } else { syslog(LOG_WARNING, "no reply to initial SETTIME from %s", htp->name); htp->noanswer = LOSTHOST; } } } /* * react to a TSP_QUIT: */ void doquit(msg) struct tsp *msg; { if (fromnet->status == MASTER) { if (!good_host_name(msg->tsp_name)) { if (fromnet->quit_count <= 0) { syslog(LOG_NOTICE,"untrusted %s told us QUIT", msg->tsp_name); suppress(&from, msg->tsp_name, fromnet); fromnet->quit_count = 1; return; } syslog(LOG_NOTICE, "untrusted %s told us QUIT twice", msg->tsp_name); fromnet->quit_count = 2; fromnet->status = NOMASTER; } else { fromnet->status = SLAVE; } rmnetmachs(fromnet); longjmp(jmpenv, 2); /* give up and be a slave */ } else { if (!good_host_name(msg->tsp_name)) { syslog(LOG_NOTICE, "untrusted %s told us QUIT", msg->tsp_name); fromnet->quit_count = 2; } } } void traceon() { if (!fd) { fd = fopen(_PATH_TIMEDLOG, "w"); if (!fd) { trace = 0; return; } fprintf(fd,"Tracing started at %s\n", date()); } trace = 1; get_goodgroup(1); setstatus(); prthp(CLK_TCK); } void traceoff(msg) char *msg; { get_goodgroup(1); setstatus(); prthp(CLK_TCK); if (trace) { fprintf(fd, msg, date()); (void)fclose(fd); fd = 0; } #ifdef GPROF moncontrol(0); _mcleanup(); moncontrol(1); #endif trace = OFF; } #ifdef sgi void logwtmp(otime, ntime) struct timeval *otime, *ntime; { static struct utmp wtmp[2] = { {"","",OTIME_MSG,0,OLD_TIME,0,0,0}, {"","",NTIME_MSG,0,NEW_TIME,0,0,0} }; static char *wtmpfile = WTMP_FILE; int f; wtmp[0].ut_time = otime->tv_sec + (otime->tv_usec + 500000) / 1000000; wtmp[1].ut_time = ntime->tv_sec + (ntime->tv_usec + 500000) / 1000000; if (wtmp[0].ut_time == wtmp[1].ut_time) return; setutent(); (void)pututline(&wtmp[0]); (void)pututline(&wtmp[1]); endutent(); if ((f = open(wtmpfile, O_WRONLY|O_APPEND)) >= 0) { (void) write(f, (char *)wtmp, sizeof(wtmp)); (void) close(f); } } #endif /* sgi */ Index: stable/2.2/usr.sbin/timed/timed/measure.c =================================================================== --- stable/2.2/usr.sbin/timed/timed/measure.c (revision 31014) +++ stable/2.2/usr.sbin/timed/timed/measure.c (revision 31015) @@ -1,353 +1,352 @@ /*- * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint +#if 0 static char sccsid[] = "@(#)measure.c 8.1 (Berkeley) 6/6/93"; +#endif +static const char rcsid[] = + "$Id: measure.c,v 1.5 1997/10/27 07:41:12 charnier Exp $"; #endif /* not lint */ -#ifdef sgi -#ident "$Revision: 1.2 $" -#endif - #include "globals.h" #include #include #include #define MSEC_DAY (SECDAY*1000) #define PACKET_IN 1024 #define MSGS 5 /* timestamps to average */ #define TRIALS 10 /* max # of timestamps sent */ extern int sock_raw; int measure_delta; static n_short seqno = 0; /* * Measures the differences between machines' clocks using * ICMP timestamp messages. */ int /* status val defined in globals.h */ measure(maxmsec, wmsec, hname, addr, print) u_long maxmsec; /* wait this many msec at most */ u_long wmsec; /* msec to wait for an answer */ char *hname; struct sockaddr_in *addr; int print; /* print complaints on stderr */ { int length; int measure_status; int rcvcount, trials; int cc, count; fd_set ready; long sendtime, recvtime, histime1, histime2; long idelta, odelta, total; long min_idelta, min_odelta; struct timeval tdone, tcur, ttrans, twait, tout; u_char packet[PACKET_IN], opacket[64]; register struct icmp *icp = (struct icmp *) packet; register struct icmp *oicp = (struct icmp *) opacket; struct ip *ip = (struct ip *) packet; min_idelta = min_odelta = 0x7fffffff; measure_status = HOSTDOWN; measure_delta = HOSTDOWN; errno = 0; /* open raw socket used to measure time differences */ if (sock_raw < 0) { sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (sock_raw < 0) { syslog(LOG_ERR, "opening raw socket: %m"); goto quit; } } /* * empty the icmp input queue */ FD_ZERO(&ready); for (;;) { tout.tv_sec = tout.tv_usec = 0; FD_SET(sock_raw, &ready); if (select(sock_raw+1, &ready, 0,0, &tout)) { length = sizeof(struct sockaddr_in); cc = recvfrom(sock_raw, (char *)packet, PACKET_IN, 0, 0,&length); if (cc < 0) goto quit; continue; } break; } /* * Choose the smallest transmission time in each of the two * directions. Use these two latter quantities to compute the delta * between the two clocks. */ oicp->icmp_type = ICMP_TSTAMP; oicp->icmp_code = 0; oicp->icmp_id = getpid(); oicp->icmp_rtime = 0; oicp->icmp_ttime = 0; oicp->icmp_seq = seqno; FD_ZERO(&ready); #ifdef sgi sginap(1); /* start at a clock tick */ #endif /* sgi */ (void)gettimeofday(&tdone, 0); mstotvround(&tout, maxmsec); timevaladd(&tdone, &tout); /* when we give up */ mstotvround(&twait, wmsec); rcvcount = 0; trials = 0; while (rcvcount < MSGS) { (void)gettimeofday(&tcur, 0); /* * keep sending until we have sent the max */ if (trials < TRIALS) { trials++; - oicp->icmp_otime = ntohl((tcur.tv_sec % SECDAY) * 1000 + oicp->icmp_otime = htonl((tcur.tv_sec % SECDAY) * 1000 + tcur.tv_usec / 1000); oicp->icmp_cksum = 0; oicp->icmp_cksum = in_cksum((u_short*)oicp, sizeof(*oicp)); count = sendto(sock_raw, opacket, sizeof(*oicp), 0, (struct sockaddr*)addr, sizeof(struct sockaddr)); if (count < 0) { if (measure_status == HOSTDOWN) measure_status = UNREACHABLE; goto quit; } ++oicp->icmp_seq; ttrans = tcur; timevaladd(&ttrans, &twait); } else { ttrans = tdone; } while (rcvcount < trials) { timevalsub(&tout, &ttrans, &tcur); if (tout.tv_sec < 0) tout.tv_sec = 0; FD_SET(sock_raw, &ready); count = select(sock_raw+1, &ready, (fd_set *)0, (fd_set *)0, &tout); (void)gettimeofday(&tcur, (struct timezone *)0); if (count <= 0) break; length = sizeof(struct sockaddr_in); cc = recvfrom(sock_raw, (char *)packet, PACKET_IN, 0, 0,&length); if (cc < 0) goto quit; /* * got something. See if it is ours */ icp = (struct icmp *)(packet + (ip->ip_hl << 2)); if (cc < sizeof(*ip) || icp->icmp_type != ICMP_TSTAMPREPLY || icp->icmp_id != oicp->icmp_id || icp->icmp_seq < seqno || icp->icmp_seq >= oicp->icmp_seq) continue; sendtime = ntohl(icp->icmp_otime); recvtime = ((tcur.tv_sec % SECDAY) * 1000 + tcur.tv_usec / 1000); total = recvtime-sendtime; if (total < 0) /* do not hassle midnight */ continue; rcvcount++; histime1 = ntohl(icp->icmp_rtime); histime2 = ntohl(icp->icmp_ttime); /* * a host using a time format different from * msec. since midnight UT (as per RFC792) should * set the high order bit of the 32-bit time * value it transmits. */ if ((histime1 & 0x80000000) != 0) { measure_status = NONSTDTIME; goto quit; } measure_status = GOOD; idelta = recvtime-histime2; odelta = histime1-sendtime; /* do not be confused by midnight */ if (idelta < -MSEC_DAY/2) idelta += MSEC_DAY; else if (idelta > MSEC_DAY/2) idelta -= MSEC_DAY; if (odelta < -MSEC_DAY/2) odelta += MSEC_DAY; else if (odelta > MSEC_DAY/2) odelta -= MSEC_DAY; /* save the quantization error so that we can get a * measurement finer than our system clock. */ if (total < MIN_ROUND) { measure_delta = (odelta - idelta)/2; goto quit; } if (idelta < min_idelta) min_idelta = idelta; if (odelta < min_odelta) min_odelta = odelta; measure_delta = (min_odelta - min_idelta)/2; } if (tcur.tv_sec > tdone.tv_sec || (tcur.tv_sec == tdone.tv_sec && tcur.tv_usec >= tdone.tv_usec)) break; } quit: seqno += TRIALS; /* allocate our sequence numbers */ /* * If no answer is received for TRIALS consecutive times, * the machine is assumed to be down */ if (measure_status == GOOD) { if (trace) { fprintf(fd, "measured delta %4d, %d trials to %-15s %s\n", measure_delta, trials, inet_ntoa(addr->sin_addr), hname); } } else if (print) { if (errno != 0) - fprintf(stderr, "measure %s: %s\n", hname, - strerror(errno)); + warn("measure %s", hname); } else { if (errno != 0) { syslog(LOG_ERR, "measure %s: %m", hname); } else { syslog(LOG_ERR, "measure: %s did not respond", hname); } if (trace) { fprintf(fd, "measure: %s failed after %d trials\n", hname, trials); (void)fflush(fd); } } return(measure_status); } /* * round a number of milliseconds into a struct timeval */ void mstotvround(res, x) struct timeval *res; long x; { #ifndef sgi if (x < 0) x = -((-x + 3)/5); else x = (x+3)/5; x *= 5; #endif /* sgi */ res->tv_sec = x/1000; res->tv_usec = (x-res->tv_sec*1000)*1000; if (res->tv_usec < 0) { res->tv_usec += 1000000; res->tv_sec--; } } void timevaladd(tv1, tv2) struct timeval *tv1, *tv2; { tv1->tv_sec += tv2->tv_sec; tv1->tv_usec += tv2->tv_usec; if (tv1->tv_usec >= 1000000) { tv1->tv_sec++; tv1->tv_usec -= 1000000; } if (tv1->tv_usec < 0) { tv1->tv_sec--; tv1->tv_usec += 1000000; } } void timevalsub(res, tv1, tv2) struct timeval *res, *tv1, *tv2; { res->tv_sec = tv1->tv_sec - tv2->tv_sec; res->tv_usec = tv1->tv_usec - tv2->tv_usec; if (res->tv_usec >= 1000000) { res->tv_sec++; res->tv_usec -= 1000000; } if (res->tv_usec < 0) { res->tv_sec--; res->tv_usec += 1000000; } } Index: stable/2.2/usr.sbin/timed/timed/networkdelta.c =================================================================== --- stable/2.2/usr.sbin/timed/timed/networkdelta.c (revision 31014) +++ stable/2.2/usr.sbin/timed/timed/networkdelta.c (revision 31015) @@ -1,264 +1,264 @@ /*- * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint +#if 0 static char sccsid[] = "@(#)networkdelta.c 8.1 (Berkeley) 6/6/93"; -#endif /* not lint */ - -#ifdef sgi -#ident "$Revision: 1.4 $" #endif +static const char rcsid[] = + "$Id: networkdelta.c,v 1.2 1997/10/22 06:19:48 charnier Exp $"; +#endif /* not lint */ #include "globals.h" static long median __P((float, float *, long *, long *, unsigned int)); /* * Compute a corrected date. * Compute the median of the reasonable differences. First compute * the median of all authorized differences, and then compute the * median of all differences that are reasonably close to the first * median. * * This differs from the original BSD implementation, which looked for * the largest group of machines with essentially the same date. * That assumed that machines with bad clocks would be uniformly * distributed. Unfortunately, in real life networks, the distribution * of machines is not uniform among models of machines, and the * distribution of errors in clocks tends to be quite consistent * for a given model. In other words, all model VI Supre Servres * from GoFast Inc. tend to have about the same error. * The original BSD implementation would chose the clock of the * most common model, and discard all others. * * Therefore, get best we can do is to try to average over all * of the machines in the network, while discarding "obviously" * bad values. */ long networkdelta() { struct hosttbl *htp; long med; long lodelta, hidelta; long logood, higood; long x[NHOSTS]; long *xp; int numdelta; float eps; /* * compute the median of the good values */ med = 0; numdelta = 1; xp = &x[0]; *xp = 0; /* account for ourself */ for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { if (htp->good && htp->noanswer == 0 && htp->delta != HOSTDOWN) { med += htp->delta; numdelta++; *++xp = htp->delta; } } /* * If we are the only trusted time keeper, then do not change our * clock. There may be another time keeping service active. */ if (numdelta == 1) return 0; med /= numdelta; eps = med - x[0]; if (trace) fprintf(fd, "median of %d values starting at %ld is about ", numdelta, med); med = median(med, &eps, &x[0], xp+1, VALID_RANGE); /* * compute the median of all values near the good median */ hidelta = med + GOOD_RANGE; lodelta = med - GOOD_RANGE; higood = med + VGOOD_RANGE; logood = med - VGOOD_RANGE; xp = &x[0]; htp = &self; do { if (htp->noanswer == 0 && htp->delta >= lodelta && htp->delta <= hidelta && (htp->good || (htp->delta >= logood && htp->delta <= higood))) { *xp++ = htp->delta; } } while (&self != (htp = htp->l_fwd)); if (xp == &x[0]) { if (trace) fprintf(fd, "nothing close to median %ld\n", med); return med; } if (xp == &x[1]) { if (trace) fprintf(fd, "only value near median is %ld\n", x[0]); return x[0]; } if (trace) fprintf(fd, "median of %d values starting at %ld is ", xp-&x[0], med); return median(med, &eps, &x[0], xp, 1); } /* * compute the median of an array of signed integers, using the idea * in <>. */ static long median(a, eps_ptr, x, xlim, gnuf) float a; /* initial guess for the median */ float *eps_ptr; /* spacing near the median */ long *x, *xlim; /* the data */ unsigned int gnuf; /* good enough estimate */ { long *xptr; float ap = LONG_MAX; /* bounds on the median */ float am = -LONG_MAX; float aa; int npts; /* # of points above & below guess */ float xp; /* closet point above the guess */ float xm; /* closet point below the guess */ float eps; float dum, sum, sumx; int pass; #define AMP 1.5 /* smoothing constants */ #define AFAC 1.5 eps = *eps_ptr; if (eps < 1.0) { eps = -eps; if (eps < 1.0) eps = 1.0; } for (pass = 1; ; pass++) { /* loop over the data */ sum = 0.0; sumx = 0.0; npts = 0; xp = LONG_MAX; xm = -LONG_MAX; for (xptr = x; xptr != xlim; xptr++) { float xx = *xptr; dum = xx - a; if (dum != 0.0) { /* avoid dividing by 0 */ if (dum > 0.0) { npts++; if (xx < xp) xp = xx; } else { npts--; if (xx > xm) xm = xx; dum = -dum; } dum = 1.0/(eps + dum); sum += dum; sumx += xx * dum; } } if (ap-am < gnuf || sum == 0) { if (trace) fprintf(fd, "%ld in %d passes; early out balance=%d\n", (long)a, pass, npts); return a; /* guess was good enough */ } aa = (sumx/sum-a)*AMP; if (npts >= 2) { /* guess was too low */ am = a; aa = xp + max(0.0, aa);; if (aa > ap) aa = (a + ap)/2; } else if (npts <= -2) { /* guess was two high */ ap = a; aa = xm + min(0.0, aa);; if (aa < am) aa = (a + am)/2; } else { break; /* got it */ } if (a == aa) { if (trace) fprintf(fd, "%ld in %d passes; force out balance=%d\n", (long)a, pass, npts); return a; } eps = AFAC*abs(aa - a); *eps_ptr = eps; a = aa; } if (((x - xlim) % 2) != 0) { /* even number of points? */ if (npts == 0) /* yes, return an average */ a = (xp+xm)/2; else if (npts > 0) a = (a+xp)/2; else a = (xm+a)/2; } else if (npts != 0) { /* odd number of points */ if (npts > 0) a = xp; else a = xm; } if (trace) fprintf(fd, "%ld in %d passes\n", (long)a, pass); return a; } Index: stable/2.2/usr.sbin/timed/timed/readmsg.c =================================================================== --- stable/2.2/usr.sbin/timed/timed/readmsg.c (revision 31014) +++ stable/2.2/usr.sbin/timed/timed/readmsg.c (revision 31015) @@ -1,488 +1,488 @@ /*- * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint +#if 0 static char sccsid[] = "@(#)readmsg.c 8.1 (Berkeley) 6/6/93"; -#endif /* not lint */ - -#ifdef sgi -#ident "$Revision: 1.17 $" #endif +static const char rcsid[] = + "$Id: readmsg.c,v 1.3 1997/10/29 07:32:29 charnier Exp $"; +#endif /* not lint */ #include "globals.h" extern char *tsptype[]; /* * LOOKAT checks if the message is of the requested type and comes from * the right machine, returning 1 in case of affirmative answer */ #define LOOKAT(msg, mtype, mfrom, netp, froms) \ (((mtype) == TSP_ANY || (mtype) == (msg).tsp_type) && \ ((mfrom) == 0 || !strcmp((mfrom), (msg).tsp_name)) && \ ((netp) == 0 || \ ((netp)->mask & (froms).sin_addr.s_addr) == (netp)->net.s_addr)) struct timeval rtime, rwait, rtout; struct tsp msgin; static struct tsplist { struct tsp info; struct timeval when; struct sockaddr_in addr; struct tsplist *p; } msgslist; struct sockaddr_in from; struct netinfo *fromnet; struct timeval from_when; /* * `readmsg' returns message `type' sent by `machfrom' if it finds it * either in the receive queue, or in a linked list of previously received * messages that it maintains. * Otherwise it waits to see if the appropriate message arrives within * `intvl' seconds. If not, it returns NULL. */ struct tsp * readmsg(type, machfrom, intvl, netfrom) int type; char *machfrom; struct timeval *intvl; struct netinfo *netfrom; { int length; fd_set ready; static struct tsplist *head = &msgslist; static struct tsplist *tail = &msgslist; static int msgcnt = 0; struct tsplist *prev; register struct netinfo *ntp; register struct tsplist *ptr; if (trace) { fprintf(fd, "readmsg: looking for %s from %s, %s\n", tsptype[type], machfrom == NULL ? "ANY" : machfrom, netfrom == NULL ? "ANYNET" : inet_ntoa(netfrom->net)); if (head->p != 0) { length = 1; for (ptr = head->p; ptr != 0; ptr = ptr->p) { /* do not repeat the hundreds of messages */ if (++length > 3) { if (ptr == tail) { fprintf(fd,"\t ...%d skipped\n", length); } else { continue; } } fprintf(fd, length > 1 ? "\t" : "queue:\t"); print(&ptr->info, &ptr->addr); } } } ptr = head->p; prev = head; /* * Look for the requested message scanning through the * linked list. If found, return it and free the space */ while (ptr != NULL) { if (LOOKAT(ptr->info, type, machfrom, netfrom, ptr->addr)) { again: msgin = ptr->info; from = ptr->addr; from_when = ptr->when; prev->p = ptr->p; if (ptr == tail) tail = prev; free((char *)ptr); fromnet = NULL; if (netfrom == NULL) for (ntp = nettab; ntp != NULL; ntp = ntp->next) { if ((ntp->mask & from.sin_addr.s_addr) == ntp->net.s_addr) { fromnet = ntp; break; } } else fromnet = netfrom; if (trace) { fprintf(fd, "readmsg: found "); print(&msgin, &from); } /* The protocol can get far behind. When it does, it gets * hopelessly confused. So delete duplicate messages. */ for (ptr = prev; (ptr = ptr->p) != NULL; prev = ptr) { if (ptr->addr.sin_addr.s_addr == from.sin_addr.s_addr && ptr->info.tsp_type == msgin.tsp_type) { if (trace) fprintf(fd, "\tdup "); goto again; } } msgcnt--; return(&msgin); } else { prev = ptr; ptr = ptr->p; } } /* * If the message was not in the linked list, it may still be * coming from the network. Set the timer and wait * on a select to read the next incoming message: if it is the * right one, return it, otherwise insert it in the linked list. */ (void)gettimeofday(&rtout, 0); timevaladd(&rtout, intvl); FD_ZERO(&ready); for (;;) { (void)gettimeofday(&rtime, 0); timevalsub(&rwait, &rtout, &rtime); if (rwait.tv_sec < 0) rwait.tv_sec = rwait.tv_usec = 0; else if (rwait.tv_sec == 0 && rwait.tv_usec < 1000000/CLK_TCK) rwait.tv_usec = 1000000/CLK_TCK; if (trace) { fprintf(fd, "readmsg: wait %ld.%6ld at %s\n", rwait.tv_sec, rwait.tv_usec, date()); /* Notice a full disk, as we flush trace info. * It is better to flush periodically than at * every line because the tracing consists of bursts * of many lines. Without care, tracing slows * down the code enough to break the protocol. */ if (rwait.tv_sec != 0 && EOF == fflush(fd)) traceoff("Tracing ended for cause at %s\n"); } FD_SET(sock, &ready); if (!select(sock+1, &ready, (fd_set *)0, (fd_set *)0, &rwait)) { if (rwait.tv_sec == 0 && rwait.tv_usec == 0) return(0); continue; } length = sizeof(from); if (recvfrom(sock, (char *)&msgin, sizeof(struct tsp), 0, (struct sockaddr*)&from, &length) < 0) { syslog(LOG_ERR, "recvfrom: %m"); exit(1); } (void)gettimeofday(&from_when, (struct timezone *)0); bytehostorder(&msgin); if (msgin.tsp_vers > TSPVERSION) { if (trace) { fprintf(fd,"readmsg: version mismatch\n"); /* should do a dump of the packet */ } continue; } fromnet = NULL; for (ntp = nettab; ntp != NULL; ntp = ntp->next) if ((ntp->mask & from.sin_addr.s_addr) == ntp->net.s_addr) { fromnet = ntp; break; } /* * drop packets from nets we are ignoring permanently */ if (fromnet == NULL) { /* * The following messages may originate on * this host with an ignored network address */ if (msgin.tsp_type != TSP_TRACEON && msgin.tsp_type != TSP_SETDATE && msgin.tsp_type != TSP_MSITE && msgin.tsp_type != TSP_TEST && msgin.tsp_type != TSP_TRACEOFF) { if (trace) { fprintf(fd,"readmsg: discard null net "); print(&msgin, &from); } continue; } } /* * Throw away messages coming from this machine, * unless they are of some particular type. * This gets rid of broadcast messages and reduces * master processing time. */ if (!strcmp(msgin.tsp_name, hostname) && msgin.tsp_type != TSP_SETDATE && msgin.tsp_type != TSP_TEST && msgin.tsp_type != TSP_MSITE && msgin.tsp_type != TSP_TRACEON && msgin.tsp_type != TSP_TRACEOFF && msgin.tsp_type != TSP_LOOP) { if (trace) { fprintf(fd, "readmsg: discard own "); print(&msgin, &from); } continue; } /* * Send acknowledgements here; this is faster and * avoids deadlocks that would occur if acks were * sent from a higher level routine. Different * acknowledgements are necessary, depending on * status. */ if (fromnet == NULL) /* do not de-reference 0 */ ignoreack(); else if (fromnet->status == MASTER) masterack(); else if (fromnet->status == SLAVE) slaveack(); else ignoreack(); if (LOOKAT(msgin, type, machfrom, netfrom, from)) { if (trace) { fprintf(fd, "readmsg: "); print(&msgin, &from); } return(&msgin); } else if (++msgcnt > NHOSTS*3) { /* The protocol gets hopelessly confused if it gets too far * behind. However, it seems able to recover from all cases of lost * packets. Therefore, if we are swamped, throw everything away. */ if (trace) fprintf(fd, "readmsg: discarding %d msgs\n", msgcnt); msgcnt = 0; while ((ptr=head->p) != NULL) { head->p = ptr->p; free((char *)ptr); } tail = head; } else { tail->p = (struct tsplist *) malloc(sizeof(struct tsplist)); tail = tail->p; tail->p = NULL; tail->info = msgin; tail->addr = from; /* timestamp msgs so SETTIMEs are correct */ tail->when = from_when; } } } /* * Send the necessary acknowledgements: * only the type ACK is to be sent by a slave */ void slaveack() { switch(msgin.tsp_type) { case TSP_ADJTIME: case TSP_SETTIME: case TSP_ACCEPT: case TSP_REFUSE: case TSP_TRACEON: case TSP_TRACEOFF: case TSP_QUIT: if (trace) { fprintf(fd, "Slaveack: "); print(&msgin, &from); } xmit(TSP_ACK,msgin.tsp_seq, &from); break; default: if (trace) { fprintf(fd, "Slaveack: no ack: "); print(&msgin, &from); } break; } } /* * Certain packets may arrive from this machine on ignored networks. * These packets should be acknowledged. */ void ignoreack() { switch(msgin.tsp_type) { case TSP_TRACEON: case TSP_TRACEOFF: case TSP_QUIT: if (trace) { fprintf(fd, "Ignoreack: "); print(&msgin, &from); } xmit(TSP_ACK,msgin.tsp_seq, &from); break; default: if (trace) { fprintf(fd, "Ignoreack: no ack: "); print(&msgin, &from); } break; } } /* * `masterack' sends the necessary acknowledgments * to the messages received by a master */ void masterack() { struct tsp resp; resp = msgin; resp.tsp_vers = TSPVERSION; (void)strcpy(resp.tsp_name, hostname); switch(msgin.tsp_type) { case TSP_QUIT: case TSP_TRACEON: case TSP_TRACEOFF: case TSP_MSITEREQ: if (trace) { fprintf(fd, "Masterack: "); print(&msgin, &from); } xmit(TSP_ACK,msgin.tsp_seq, &from); break; case TSP_RESOLVE: case TSP_MASTERREQ: if (trace) { fprintf(fd, "Masterack: "); print(&msgin, &from); } xmit(TSP_MASTERACK,msgin.tsp_seq, &from); break; default: if (trace) { fprintf(fd,"Masterack: no ack: "); print(&msgin, &from); } break; } } /* * Print a TSP message */ void print(msg, addr) struct tsp *msg; struct sockaddr_in *addr; { char tm[26]; switch (msg->tsp_type) { case TSP_LOOP: fprintf(fd, "%s %d %-6u #%d %-15s %s\n", tsptype[msg->tsp_type], msg->tsp_vers, msg->tsp_seq, msg->tsp_hopcnt, inet_ntoa(addr->sin_addr), msg->tsp_name); break; case TSP_SETTIME: case TSP_SETDATE: case TSP_SETDATEREQ: #ifdef sgi (void)cftime(tm, "%D %T", &msg->tsp_time.tv_sec); #else strncpy(tm, ctime(&msg->tsp_time.tv_sec)+3+1, sizeof(tm)); tm[15] = '\0'; /* ugh */ #endif /* sgi */ fprintf(fd, "%s %d %-6u %s %-15s %s\n", tsptype[msg->tsp_type], msg->tsp_vers, msg->tsp_seq, tm, inet_ntoa(addr->sin_addr), msg->tsp_name); break; case TSP_ADJTIME: fprintf(fd, "%s %d %-6u (%ld,%ld) %-15s %s\n", tsptype[msg->tsp_type], msg->tsp_vers, msg->tsp_seq, msg->tsp_time.tv_sec, msg->tsp_time.tv_usec, inet_ntoa(addr->sin_addr), msg->tsp_name); break; default: fprintf(fd, "%s %d %-6u %-15s %s\n", tsptype[msg->tsp_type], msg->tsp_vers, msg->tsp_seq, inet_ntoa(addr->sin_addr), msg->tsp_name); break; } } Index: stable/2.2/usr.sbin/timed/timed/slave.c =================================================================== --- stable/2.2/usr.sbin/timed/timed/slave.c (revision 31014) +++ stable/2.2/usr.sbin/timed/timed/slave.c (revision 31015) @@ -1,715 +1,716 @@ /*- * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint +#if 0 static char sccsid[] = "@(#)slave.c 8.1 (Berkeley) 6/6/93"; +#endif +static const char rcsid[] = + "$Id: slave.c,v 1.5 1997/10/31 12:33:06 charnier Exp $"; #endif /* not lint */ -#ifdef sgi -#ident "$Revision: 1.1.1.1 $" -#endif - #include "globals.h" #include #include "pathnames.h" extern jmp_buf jmpenv; extern int Mflag; extern int justquit; extern u_short sequence; -static char master_name[MAXHOSTNAMELEN+1]; +static char master_name[MAXHOSTNAMELEN]; static struct netinfo *old_slavenet; static int old_status; static void schgdate __P((struct tsp *, char *)); static void setmaster __P((struct tsp *)); static void answerdelay __P((void)); #ifdef sgi extern void logwtmp __P((struct timeval *, struct timeval *)); #else extern void logwtmp __P((char *, char *, char *)); #endif /* sgi */ int slave() { int tries; long electiontime, refusetime, looktime, looptime, adjtime; u_short seq; long fastelection; #define FASTTOUT 3 struct in_addr cadr; struct timeval otime; struct sockaddr_in taddr; char tname[MAXHOSTNAMELEN]; struct tsp *msg, to; struct timeval ntime, wait; struct tsp *answer; int timeout(); char olddate[32]; char newdate[32]; struct netinfo *ntp; struct hosttbl *htp; old_slavenet = 0; seq = 0; refusetime = 0; adjtime = 0; (void)gettimeofday(&ntime, 0); electiontime = ntime.tv_sec + delay2; fastelection = ntime.tv_sec + FASTTOUT; if (justquit) looktime = electiontime; else looktime = fastelection; looptime = fastelection; if (slavenet) xmit(TSP_SLAVEUP, 0, &slavenet->dest_addr); if (status & MASTER) { for (ntp = nettab; ntp != NULL; ntp = ntp->next) { if (ntp->status == MASTER) masterup(ntp); } } loop: get_goodgroup(0); (void)gettimeofday(&ntime, (struct timezone *)0); if (ntime.tv_sec > electiontime) { if (trace) fprintf(fd, "election timer expired\n"); longjmp(jmpenv, 1); } if (ntime.tv_sec >= looktime) { if (trace) fprintf(fd, "Looking for nets to master\n"); if (Mflag && nignorednets > 0) { for (ntp = nettab; ntp != NULL; ntp = ntp->next) { if (ntp->status == IGNORE || ntp->status == NOMASTER) { lookformaster(ntp); if (ntp->status == MASTER) { masterup(ntp); } else if (ntp->status == MASTER) { ntp->status = NOMASTER; } } if (ntp->status == MASTER && --ntp->quit_count < 0) ntp->quit_count = 0; } makeslave(slavenet); /* prune extras */ setstatus(); } (void)gettimeofday(&ntime, 0); looktime = ntime.tv_sec + delay2; } if (ntime.tv_sec >= looptime) { if (trace) fprintf(fd, "Looking for loops\n"); for (ntp = nettab; ntp != NULL; ntp = ntp->next) { if (ntp->status == MASTER) { to.tsp_type = TSP_LOOP; to.tsp_vers = TSPVERSION; to.tsp_seq = sequence++; to.tsp_hopcnt = MAX_HOPCNT; (void)strcpy(to.tsp_name, hostname); bytenetorder(&to); if (sendto(sock, (char *)&to, sizeof(struct tsp), 0, (struct sockaddr*)&ntp->dest_addr, sizeof(ntp->dest_addr)) < 0) { trace_sendto_err(ntp->dest_addr.sin_addr); } } } (void)gettimeofday(&ntime, 0); looptime = ntime.tv_sec + delay2; } wait.tv_sec = min(electiontime,min(looktime,looptime)) - ntime.tv_sec; if (wait.tv_sec < 0) wait.tv_sec = 0; wait.tv_sec += FASTTOUT; wait.tv_usec = 0; msg = readmsg(TSP_ANY, ANYADDR, &wait, 0); if (msg != NULL) { /* * filter stuff not for us */ switch (msg->tsp_type) { case TSP_SETDATE: case TSP_TRACEOFF: case TSP_TRACEON: /* * XXX check to see they are from ourself */ break; case TSP_TEST: case TSP_MSITE: break; case TSP_MASTERUP: if (!fromnet) { if (trace) { fprintf(fd, "slave ignored: "); print(msg, &from); } goto loop; } break; default: if (!fromnet || fromnet->status == IGNORE || fromnet->status == NOMASTER) { if (trace) { fprintf(fd, "slave ignored: "); print(msg, &from); } goto loop; } break; } /* * now process the message */ switch (msg->tsp_type) { case TSP_ADJTIME: if (fromnet != slavenet) break; if (!good_host_name(msg->tsp_name)) { syslog(LOG_NOTICE, "attempted time adjustment by %s", msg->tsp_name); suppress(&from, msg->tsp_name, fromnet); break; } /* * Speed up loop detection in case we have a loop. * Otherwise the clocks can race until the loop * is found. */ (void)gettimeofday(&otime, 0); if (adjtime < otime.tv_sec) looptime -= (looptime-otime.tv_sec)/2 + 1; setmaster(msg); if (seq != msg->tsp_seq) { seq = msg->tsp_seq; synch(tvtomsround(msg->tsp_time)); } (void)gettimeofday(&ntime, 0); electiontime = ntime.tv_sec + delay2; fastelection = ntime.tv_sec + FASTTOUT; adjtime = ntime.tv_sec + SAMPLEINTVL*2; break; case TSP_SETTIME: if (fromnet != slavenet) break; if (seq == msg->tsp_seq) break; seq = msg->tsp_seq; /* adjust time for residence on the queue */ (void)gettimeofday(&otime, 0); adj_msg_time(msg,&otime); #ifdef sgi (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec); (void)cftime(olddate, "%D %T", &otime.tv_sec); #else /* * the following line is necessary due to syslog * calling ctime() which clobbers the static buffer */ (void)strcpy(olddate, date()); (void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec)); #endif /* sgi */ if (!good_host_name(msg->tsp_name)) { syslog(LOG_NOTICE, "attempted time setting by untrusted %s to %s", msg->tsp_name, newdate); suppress(&from, msg->tsp_name, fromnet); break; } setmaster(msg); timevalsub(&ntime, &msg->tsp_time, &otime); if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) { /* * do not change the clock if we can adjust it */ synch(tvtomsround(ntime)); } else { #ifdef sgi if (0 > settimeofday(&msg->tsp_time, 0)) { syslog(LOG_ERR,"settimeofdate(): %m"); break; } logwtmp(&otime, &msg->tsp_time); #else logwtmp("|", "date", ""); (void)settimeofday(&msg->tsp_time, 0); logwtmp("{", "date", ""); #endif /* sgi */ syslog(LOG_NOTICE, "date changed by %s from %s", msg->tsp_name, olddate); if (status & MASTER) spreadtime(); } (void)gettimeofday(&ntime, 0); electiontime = ntime.tv_sec + delay2; fastelection = ntime.tv_sec + FASTTOUT; /* This patches a bad protocol bug. Imagine a system with several networks, * where there are a pair of redundant gateways between a pair of networks, * each running timed. Assume that we start with a third machine mastering * one of the networks, and one of the gateways mastering the other. * Imagine that the third machine goes away and the non-master gateway * decides to replace it. If things are timed just 'right,' we will have * each gateway mastering one network for a little while. If a SETTIME * message gets into the network at that time, perhaps from the newly * masterful gateway as it was taking control, the SETTIME will loop * forever. Each time a gateway receives it on its slave side, it will * call spreadtime to forward it on its mastered network. We are now in * a permanent loop, since the SETTIME msgs will keep any clock * in the network from advancing. Normally, the 'LOOP' stuff will detect * and correct the situation. However, with the clocks stopped, the * 'looptime' timer cannot expire. While they are in this state, the * masters will try to saturate the network with SETTIME packets. */ looptime = ntime.tv_sec + (looptime-otime.tv_sec)/2-1; break; case TSP_MASTERUP: if (slavenet && fromnet != slavenet) break; if (!good_host_name(msg->tsp_name)) { suppress(&from, msg->tsp_name, fromnet); if (electiontime > fastelection) electiontime = fastelection; break; } makeslave(fromnet); setmaster(msg); setstatus(); answerdelay(); xmit(TSP_SLAVEUP, 0, &from); (void)gettimeofday(&ntime, 0); electiontime = ntime.tv_sec + delay2; fastelection = ntime.tv_sec + FASTTOUT; refusetime = 0; break; case TSP_MASTERREQ: if (fromnet->status != SLAVE) break; (void)gettimeofday(&ntime, 0); electiontime = ntime.tv_sec + delay2; break; case TSP_SETDATE: #ifdef sgi (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec); #else (void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec)); #endif /* sgi */ schgdate(msg, newdate); break; case TSP_SETDATEREQ: if (fromnet->status != MASTER) break; #ifdef sgi (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec); #else (void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec)); #endif /* sgi */ htp = findhost(msg->tsp_name); if (0 == htp) { syslog(LOG_WARNING, "DATEREQ from uncontrolled machine"); break; } if (!htp->good) { syslog(LOG_WARNING, "attempted date change by untrusted %s to %s", htp->name, newdate); spreadtime(); break; } schgdate(msg, newdate); break; case TSP_TRACEON: traceon(); break; case TSP_TRACEOFF: traceoff("Tracing ended at %s\n"); break; case TSP_SLAVEUP: newslave(msg); break; case TSP_ELECTION: if (fromnet->status == SLAVE) { (void)gettimeofday(&ntime, 0); electiontime = ntime.tv_sec + delay2; fastelection = ntime.tv_sec + FASTTOUT; seq = 0; if (!good_host_name(msg->tsp_name)) { syslog(LOG_NOTICE, "suppress election of %s", msg->tsp_name); to.tsp_type = TSP_QUIT; electiontime = fastelection; } else if (cadr.s_addr != from.sin_addr.s_addr && ntime.tv_sec < refusetime) { /* if the candidate has to repeat itself, the old code would refuse it * the second time. That would prevent elections. */ to.tsp_type = TSP_REFUSE; } else { cadr.s_addr = from.sin_addr.s_addr; to.tsp_type = TSP_ACCEPT; refusetime = ntime.tv_sec + 30; } taddr = from; (void)strcpy(tname, msg->tsp_name); (void)strcpy(to.tsp_name, hostname); answerdelay(); if (!acksend(&to, &taddr, tname, TSP_ACK, 0, 0)) syslog(LOG_WARNING, "no answer from candidate %s\n", tname); } else { /* fromnet->status == MASTER */ htp = addmach(msg->tsp_name, &from,fromnet); to.tsp_type = TSP_QUIT; (void)strcpy(to.tsp_name, hostname); if (!acksend(&to, &htp->addr, htp->name, TSP_ACK, 0, htp->noanswer)) { syslog(LOG_ERR, "no reply from %s to ELECTION-QUIT", htp->name); (void)remmach(htp); } } break; case TSP_CONFLICT: if (fromnet->status != MASTER) break; /* * After a network partition, there can be * more than one master: the first slave to * come up will notify here the situation. */ (void)strcpy(to.tsp_name, hostname); /* The other master often gets into the same state, * with boring results. */ ntp = fromnet; /* (acksend() can leave fromnet=0 */ for (tries = 0; tries < 3; tries++) { to.tsp_type = TSP_RESOLVE; answer = acksend(&to, &ntp->dest_addr, ANYADDR, TSP_MASTERACK, ntp, 0); if (answer == NULL) break; htp = addmach(answer->tsp_name,&from,ntp); to.tsp_type = TSP_QUIT; answer = acksend(&to, &htp->addr, htp->name, TSP_ACK, 0, htp->noanswer); if (!answer) { syslog(LOG_WARNING, "conflict error: no reply from %s to QUIT", htp->name); (void)remmach(htp); } } masterup(ntp); break; case TSP_MSITE: if (!slavenet) break; taddr = from; to.tsp_type = TSP_MSITEREQ; to.tsp_vers = TSPVERSION; to.tsp_seq = 0; (void)strcpy(to.tsp_name, hostname); answer = acksend(&to, &slavenet->dest_addr, ANYADDR, TSP_ACK, slavenet, 0); if (answer != NULL && good_host_name(answer->tsp_name)) { setmaster(answer); to.tsp_type = TSP_ACK; (void)strcpy(to.tsp_name, answer->tsp_name); bytenetorder(&to); if (sendto(sock, (char *)&to, sizeof(struct tsp), 0, - (struct sockaddr*)&taddr, sizeof(taddr)) < 0) { + (struct sockaddr*)&taddr, + sizeof(taddr)) < 0) { trace_sendto_err(taddr.sin_addr); } } break; case TSP_MSITEREQ: break; case TSP_ACCEPT: case TSP_REFUSE: case TSP_RESOLVE: break; case TSP_QUIT: doquit(msg); /* become a slave */ break; case TSP_TEST: electiontime = 0; break; case TSP_LOOP: /* looking for loops of masters */ if (!(status & MASTER)) break; if (fromnet->status == SLAVE) { if (!strcmp(msg->tsp_name, hostname)) { /* * Someone forwarded our message back to * us. There must be a loop. Tell the * master of this network to quit. * * The other master often gets into * the same state, with boring results. */ ntp = fromnet; for (tries = 0; tries < 3; tries++) { to.tsp_type = TSP_RESOLVE; answer = acksend(&to, &ntp->dest_addr, ANYADDR, TSP_MASTERACK, ntp,0); if (answer == NULL) break; taddr = from; (void)strcpy(tname, answer->tsp_name); to.tsp_type = TSP_QUIT; (void)strcpy(to.tsp_name, hostname); if (!acksend(&to, &taddr, tname, TSP_ACK, 0, 1)) { syslog(LOG_ERR, "no reply from %s to slave LOOP-QUIT", tname); } else { electiontime = 0; } } (void)gettimeofday(&ntime, 0); looptime = ntime.tv_sec + FASTTOUT; } else { if (msg->tsp_hopcnt-- < 1) break; bytenetorder(msg); for (ntp = nettab; ntp != 0; ntp = ntp->next) { if (ntp->status == MASTER && 0 > sendto(sock, (char *)msg, sizeof(struct tsp), 0, (struct sockaddr*)&ntp->dest_addr, sizeof(ntp->dest_addr))) trace_sendto_err(ntp->dest_addr.sin_addr); } } } else { /* fromnet->status == MASTER */ /* * We should not have received this from a net * we are master on. There must be two masters, * unless the packet was really from us. */ if (from.sin_addr.s_addr == fromnet->my_addr.s_addr) { if (trace) fprintf(fd,"discarding forwarded LOOP\n"); break; } /* * The other master often gets into the same * state, with boring results. */ ntp = fromnet; for (tries = 0; tries < 3; tries++) { to.tsp_type = TSP_RESOLVE; answer = acksend(&to, &ntp->dest_addr, ANYADDR, TSP_MASTERACK, ntp,0); if (!answer) break; htp = addmach(answer->tsp_name, &from,ntp); to.tsp_type = TSP_QUIT; (void)strcpy(to.tsp_name, hostname); if (!acksend(&to,&htp->addr,htp->name, TSP_ACK, 0, htp->noanswer)) { syslog(LOG_ERR, "no reply from %s to master LOOP-QUIT", htp->name); (void)remmach(htp); } } (void)gettimeofday(&ntime, 0); looptime = ntime.tv_sec + FASTTOUT; } break; default: if (trace) { fprintf(fd, "garbage message: "); print(msg, &from); } break; } } goto loop; } /* * tell the world who our master is */ static void setmaster(msg) struct tsp *msg; { if (slavenet && (slavenet != old_slavenet || strcmp(msg->tsp_name, master_name) || old_status != status)) { (void)strcpy(master_name, msg->tsp_name); old_slavenet = slavenet; old_status = status; if (status & MASTER) { syslog(LOG_NOTICE, "submaster to %s", master_name); if (trace) fprintf(fd, "submaster to %s\n", master_name); } else { syslog(LOG_NOTICE, "slave to %s", master_name); if (trace) fprintf(fd, "slave to %s\n", master_name); } } } /* * handle date change request on a slave */ static void schgdate(msg, newdate) struct tsp *msg; char *newdate; { struct tsp to; u_short seq; struct sockaddr_in taddr; struct timeval otime; if (!slavenet) return; /* no where to forward */ taddr = from; seq = msg->tsp_seq; syslog(LOG_INFO, "forwarding date change by %s to %s", msg->tsp_name, newdate); /* adjust time for residence on the queue */ (void)gettimeofday(&otime, 0); adj_msg_time(msg, &otime); to.tsp_type = TSP_SETDATEREQ; to.tsp_time = msg->tsp_time; (void)strcpy(to.tsp_name, hostname); if (!acksend(&to, &slavenet->dest_addr, ANYADDR, TSP_DATEACK, slavenet, 0)) return; /* no answer */ xmit(TSP_DATEACK, seq, &taddr); } /* * Used before answering a broadcast message to avoid network * contention and likely collisions. */ static void answerdelay() { #ifdef sgi sginap(delay1); #else struct timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = delay1; (void)select(0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL, &timeout); return; #endif /* sgi */ } Index: stable/2.2/usr.sbin/timed/timed/timed.8 =================================================================== --- stable/2.2/usr.sbin/timed/timed/timed.8 (revision 31014) +++ stable/2.2/usr.sbin/timed/timed/timed.8 (revision 31015) @@ -1,219 +1,226 @@ .\" Copyright (c) 1980, 1991, 1993 .\" The Regents of the University of California. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. All advertising materials mentioning features or use of this software .\" must display the following acknowledgement: .\" This product includes software developed by the University of .\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" @(#)timed.8 8.1 (Berkeley) 6/6/93 .\" .Dd June 6, 1993 .Dt TIMED 8 .Os BSD 4.3 .Sh NAME .Nm timed .Nd time server daemon .Sh SYNOPSIS .Nm timed .Op Fl M .Op Fl t .Op Fl d .Op Fl i Ar network .Op Fl n Ar network .Op Fl F Ar host1 host2 ... .Sh DESCRIPTION This is a time server daemon and is normally invoked at boot time from the .Xr rc 8 file. It synchronizes the host's time with the time of other machines in a local area network running -.Nm timed . +.Nm Ns . These time servers will slow down the clocks of some machines and speed up the clocks of others to bring them to the average network time. The average network time is computed from measurements of clock differences using the .Tn ICMP timestamp request message. .Pp The service provided by -.Nm timed +.Nm is based on a master-slave scheme. When -.Nm timed +.Nm is started on a machine, it asks the master for the network time and sets the host's clock to that time. After that, it accepts synchronization messages periodically sent by the master and calls .Xr adjtime 2 to perform the needed corrections on the host's clock. .Pp It also communicates with .Xr date 1 in order to set the date globally, and with .Xr timedc 8 , a timed control program. If the machine running the master crashes, then the slaves will elect a new master from among slaves running with the .Fl M flag. A -.Nm timed +.Nm running without the .Fl M or .Fl F flags will remain a slave. The .Fl t flag enables .Nm timed to trace the messages it receives in the file .Pa /var/log/timed.log . Tracing can be turned on or off by the program .Xr timedc 8 . The .Fl d flag is for debugging the daemon. It causes the program to not put itself into the background. +.Pp Normally -.Nm timed +.Nm checks for a master time server on each network to which it is connected, except as modified by the options described below. It will request synchronization service from the first master server located. If permitted by the .Fl M flag, it will provide synchronization service on any attached networks on which no current master server was detected. Such a server propagates the time computed by the top-level master. The .Fl n flag, followed by the name of a network which the host is connected to (see .Xr networks 5 ) , overrides the default choice of the network addresses made by the program. Each time the .Fl n flag appears, that network name is added to a list of valid networks. All other networks are ignored. The .Fl i flag, followed by the name of a network to which the host is connected (see .Xr networks 5 ) , overrides the default choice of the network addresses made by the program. Each time the .Fl i flag appears, that network name is added to a list of networks to ignore. All other networks are used by the time daemon. The .Fl n and .Fl i flags are meaningless if used together. .Pp .Nm Timed checks for a master time server on each network to which it is connected, except as modified by the .Fl n and .Fl i options described above. If it finds masters on more than one network, it chooses one network on which to be a "slave," and then periodically checks the other networks to see if the masters there have disappeared. .Pp -One way to synchronize a group of machines is to use an NTP daemon to +One way to synchronize a group of machines is to use an +.Tn NTP +daemon to synchronize the clock of one machine to a distant standard or a radio receiver and .Fl F Ar hostname to tell its timed daemon to trust only itself. .Pp Messages printed by the kernel on the system console occur with interrupts disabled. This means that the clock stops while they are printing. A machine with many disk or network hardware problems and consequent messages cannot keep good time by itself. Each message typically causes the clock to lose a dozen milliseconds. A time daemon can correct the result. .Pp Messages in the system log about machines that failed to respond usually indicate machines that crashed or were turned off. Complaints about machines that failed to respond to initial time settings are often associated with "multi-homed" machines that looked for time masters on more than one network and eventually chose to become a slave on the other network. -.Sh WARNING +.Sh WARNINGS If two or more time daemons, whether -.Nm timed , -.Xr NTP , +.Nm Ns , +.Tn NTP , try to adjust the same clock, temporal chaos will result. If both .Nm and another time daemon are run on the same machine, ensure that the .Fl F flag is used, so that -.Nm timed +.Nm never attempts to adjust the local clock. .Pp -The protocol is based on UDP/IP broadcasts. All machines within -the range of a broadcast that are using the TSP protocol must cooperate. +The protocol is based on +.Tn UDP/IP +broadcasts. All machines within +the range of a broadcast that are using the +.Tn TSP +protocol must cooperate. There cannot be more than a single administrative domain using the .Fl F flag among all machines reached by a broadcast packet. Failure to follow this rule is usually indicated by complaints concerning "untrusted" machines in the system log. .Sh FILES .Bl -tag -width /var/log/timed.masterlog -compact .It Pa /var/log/timed.log tracing file for timed .It Pa /var/log/timed.masterlog log file for master timed .El .Sh SEE ALSO .Xr date 1 , .Xr adjtime 2 , .Xr gettimeofday 2 , .Xr icmp 4 , .Xr timedc 8 .Rs .%T "TSP: The Time Synchronization Protocol for UNIX 4.3BSD" .%A R. Gusella .%A S. Zatti .Re .Sh HISTORY The .Nm daemon appeared in .Bx 4.3 . Index: stable/2.2/usr.sbin/timed/timed/timed.c =================================================================== --- stable/2.2/usr.sbin/timed/timed/timed.c (revision 31014) +++ stable/2.2/usr.sbin/timed/timed/timed.c (revision 31015) @@ -1,981 +1,964 @@ /*- * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint -static char copyright[] = +static const char copyright[] = "@(#) Copyright (c) 1985, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint +#if 0 static char sccsid[] = "@(#)timed.c 8.1 (Berkeley) 6/6/93"; +#endif +static const char rcsid[] = + "$Id$"; #endif /* not lint */ -#ifdef sgi -#ident "$Revision: 1.2.6.1 $" -#endif /* sgi */ - #define TSPTYPES #include "globals.h" #include #include #include #include #include "pathnames.h" #include #include #include #ifdef sgi #include #include #include #endif /* sgi */ int trace = 0; int sock, sock_raw = -1; int status = 0; u_short sequence; /* sequence number */ long delay1; long delay2; int nslavenets; /* nets were I could be a slave */ int nmasternets; /* nets were I could be a master */ int nignorednets; /* ignored nets */ int nnets; /* nets I am connected to */ FILE *fd; /* trace file FD */ jmp_buf jmpenv; struct netinfo *nettab = 0; struct netinfo *slavenet; int Mflag; int justquit = 0; int debug; static struct nets { char *name; long net; struct nets *next; } *nets = 0; struct hosttbl hosttbl[NHOSTS+1]; /* known hosts */ static struct goodhost { /* hosts that we trust */ - char name[MAXHOSTNAMELEN+1]; + char name[MAXHOSTNAMELEN]; struct goodhost *next; char perm; } *goodhosts; static char *goodgroup; /* net group of trusted hosts */ static void checkignorednets __P((void)); static void pickslavenet __P((struct netinfo *)); static void add_good_host __P((char *, int)); #ifdef sgi char *timetrim_fn; char *timetrim_wpat = "long timetrim = %ld;\ndouble tot_adj = %.0f;\ndouble tot_ticks = %.0f;\n/* timed version 2 */\n"; char *timetrim_rpat = "long timetrim = %ld;\ndouble tot_adj = %lf;\ndouble tot_ticks = %lf;"; long timetrim; double tot_adj, hr_adj; /* totals in nsec */ double tot_ticks, hr_ticks; int bufspace = 60*1024; #endif +static void usage __P((void)); /* * The timedaemons synchronize the clocks of hosts in a local area network. * One daemon runs as master, all the others as slaves. The master * performs the task of computing clock differences and sends correction * values to the slaves. * Slaves start an election to choose a new master when the latter disappears * because of a machine crash, network partition, or when killed. * A resolution protocol is used to kill all but one of the masters * that happen to exist in segments of a partitioned network when the * network partition is fixed. * * Authors: Riccardo Gusella & Stefano Zatti * * overhauled at Silicon Graphics */ int main(argc, argv) int argc; char *argv[]; { int on; int ret; int nflag, iflag; struct timeval ntime; struct servent *srvp; char buf[BUFSIZ], *cp, *cplim; struct ifconf ifc; struct ifreq ifreq, ifreqf, *ifr; register struct netinfo *ntp; struct netinfo *ntip; struct netinfo *savefromnet; struct netent *nentp; struct nets *nt; struct sockaddr_in server; u_short port; char c; - extern char *optarg; - extern int optind, opterr; #ifdef sgi FILE *timetrim_st; #endif -#define IN_MSG "timed: -i and -n make no sense together\n" #ifdef sgi struct tms tms; -#define USAGE "timed: [-dtM] [-i net|-n net] [-F host1 host2 ...] [-G netgp] [-P trimfile]\n" -#else -#ifdef HAVENIS -#define USAGE "timed: [-dtM] [-i net|-n net] [-F host1 host2 ...] [-G netgp]\n" -#else -#define USAGE "timed: [-dtM] [-i net|-n net] [-F host1 host2 ...]\n" -#endif /* HAVENIS */ #endif /* sgi */ #ifdef lint ntip = NULL; #endif on = 1; nflag = OFF; iflag = OFF; #ifdef sgi if (0 > syssgi(SGI_GETTIMETRIM, &timetrim)) { - perror("timed: syssgi(GETTIMETRIM)"); + warn("syssgi(GETTIMETRIM)"); timetrim = 0; } tot_ticks = hr_ticks = times(&tms); #endif /* sgi */ opterr = 0; while ((c = getopt(argc, argv, "Mtdn:i:F:G:P:")) != -1) { switch (c) { case 'M': Mflag = 1; break; case 't': trace = 1; break; case 'n': if (iflag) { - fprintf(stderr, IN_MSG); - exit(1); + errx(1, "-i and -n make no sense together"); } else { nflag = ON; addnetname(optarg); } break; case 'i': if (nflag) { - fprintf(stderr, IN_MSG); - exit(1); + errx(1, "-i and -n make no sense together"); } else { iflag = ON; addnetname(optarg); } break; case 'F': add_good_host(optarg,1); while (optind < argc && argv[optind][0] != '-') add_good_host(argv[optind++], 1); break; case 'd': debug = 1; break; case 'G': - if (goodgroup != 0) { - fprintf(stderr,"timed: only one net group\n"); - exit(1); - } + if (goodgroup != 0) + errx(1, "only one net group"); goodgroup = optarg; break; #ifdef sgi case 'P': timetrim_fn = optarg; timetrim_st = fopen(timetrim_fn, "r+"); if (0 == timetrim_st) { if (errno != ENOENT) { - (void)fprintf(stderr,"timed: "); - perror(timetrim_fn); + warn("%s", timetrim_fn); timetrim_fn = 0; } } else { int i; long trim; double adj, ticks; i = fscanf(timetrim_st, timetrim_rpat, &trim, &adj, &ticks); if (i < 1 || trim > MAX_TRIM || trim < -MAX_TRIM || i == 2 || (i == 3 && trim != rint(adj*CLK_TCK/ticks))) { if (trace && i != EOF) - (void)fprintf(stderr, - "timed: unrecognized contents in %s\n", + warn( + "unrecognized contents in %s", timetrim_fn); } else { if (0 > syssgi(SGI_SETTIMETRIM, trim)) { - perror("timed: syssgi(SETTIMETRIM)"); + warn("syssgi(SETTIMETRIM)"); } else { timetrim = trim; } if (i == 3) { tot_adj = adj; tot_ticks -= ticks; } } (void)fclose(timetrim_st); } break; #endif /* sgi */ default: - fprintf(stderr, USAGE); - exit(1); + usage(); break; } } - if (optind < argc) { - fprintf(stderr, USAGE); - exit(1); - } + if (optind < argc) + usage(); /* If we care about which machine is the master, then we must * be willing to be a master */ if (0 != goodgroup || 0 != goodhosts) Mflag = 1; - if (gethostname(hostname, sizeof(hostname) - 1) < 0) { - perror("gethostname"); - exit(1); - } + if (gethostname(hostname, sizeof(hostname) - 1) < 0) + err(1, "gethostname"); self.l_bak = &self; self.l_fwd = &self; self.h_bak = &self; self.h_fwd = &self; self.head = 1; self.good = 1; if (goodhosts != 0) /* trust ourself */ add_good_host(hostname,1); srvp = getservbyname("timed", "udp"); - if (srvp == 0) { - fprintf(stderr, "unknown service 'timed/udp'\n"); - exit(1); - } + if (srvp == 0) + errx(1, "unknown service 'timed/udp'"); port = srvp->s_port; bzero(&server, sizeof(struct sockaddr_in)); server.sin_port = srvp->s_port; server.sin_family = AF_INET; sock = socket(AF_INET, SOCK_DGRAM, 0); - if (sock < 0) { - perror("socket"); - exit(1); - } + if (sock < 0) + err(1, "socket"); if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on, - sizeof(on)) < 0) { - perror("setsockopt"); - exit(1); - } + sizeof(on)) < 0) + err(1, "setsockopt"); if (bind(sock, (struct sockaddr*)&server, sizeof(server))) { if (errno == EADDRINUSE) - fprintf(stderr,"timed: time daemon already running\n"); + warnx("time daemon already running"); else - perror("bind"); + warn("bind"); exit(1); } #ifdef sgi /* * handle many slaves with our buffer */ if (0 > setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&bufspace, - sizeof(bufspace))) { - perror("setsockopt"); - exit(1); - } + sizeof(bufspace))) + err(1, "setsockopt"); #endif /* sgi */ /* choose a unique seed for random number generation */ (void)gettimeofday(&ntime, 0); srandom(ntime.tv_sec + ntime.tv_usec); sequence = random(); /* initial seq number */ #ifndef sgi /* rounds kernel variable time to multiple of 5 ms. */ ntime.tv_sec = 0; ntime.tv_usec = -((ntime.tv_usec/1000) % 5) * 1000; (void)adjtime(&ntime, (struct timeval *)0); #endif /* sgi */ for (nt = nets; nt; nt = nt->next) { nentp = getnetbyname(nt->name); if (nentp == 0) { nt->net = inet_network(nt->name); if (nt->net != INADDR_NONE) nentp = getnetbyaddr(nt->net, AF_INET); } if (nentp != 0) { nt->net = nentp->n_net; } else if (nt->net == INADDR_NONE) { - fprintf(stderr, "timed: unknown net %s\n", nt->name); - exit(1); + errx(1, "unknown net %s", nt->name); } else if (nt->net == INADDR_ANY) { - fprintf(stderr, "timed: bad net %s\n", nt->name); - exit(1); + errx(1, "bad net %s", nt->name); } else { - fprintf(stderr, - "timed: warning: %s unknown in /etc/networks\n", + warnx("warning: %s unknown in /etc/networks", nt->name); } if (0 == (nt->net & 0xff000000)) nt->net <<= 8; if (0 == (nt->net & 0xff000000)) nt->net <<= 8; if (0 == (nt->net & 0xff000000)) nt->net <<= 8; } ifc.ifc_len = sizeof(buf); ifc.ifc_buf = buf; - if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) { - perror("timed: get interface configuration"); - exit(1); - } + if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) + err(1, "get interface configuration"); ntp = NULL; #ifdef sgi #define size(p) (sizeof(*ifr) - sizeof(ifr->ifr_name)) /* XXX hack. kludge */ #else #define size(p) max((p).sa_len, sizeof(p)) #endif cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */ for (cp = buf; cp < cplim; cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) { ifr = (struct ifreq *)cp; if (ifr->ifr_addr.sa_family != AF_INET) continue; if (!ntp) ntp = (struct netinfo*)malloc(sizeof(struct netinfo)); bzero(ntp,sizeof(*ntp)); ntp->my_addr=((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr; ntp->status = NOMASTER; ifreq = *ifr; ifreqf = *ifr; if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreqf) < 0) { - perror("get interface flags"); + warn("get interface flags"); continue; } if ((ifreqf.ifr_flags & IFF_UP) == 0) continue; if ((ifreqf.ifr_flags & IFF_BROADCAST) == 0 && (ifreqf.ifr_flags & IFF_POINTOPOINT) == 0) { continue; } if (ioctl(sock, SIOCGIFNETMASK, (char *)&ifreq) < 0) { - perror("get netmask"); + warn("get netmask"); continue; } ntp->mask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr; if (ifreqf.ifr_flags & IFF_BROADCAST) { if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { - perror("get broadaddr"); + warn("get broadaddr"); continue; } ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_broadaddr; /* What if the broadcast address is all ones? * So we cannot just mask ntp->dest_addr. */ ntp->net = ntp->my_addr; ntp->net.s_addr &= ntp->mask; } else { if (ioctl(sock, SIOCGIFDSTADDR, (char *)&ifreq) < 0) { - perror("get destaddr"); + warn("get destaddr"); continue; } ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_dstaddr; ntp->net = ntp->dest_addr.sin_addr; } ntp->dest_addr.sin_port = port; for (nt = nets; nt; nt = nt->next) { if (ntp->net.s_addr == htonl(nt->net)) break; } - if (nflag && !nt || iflag && nt) + if ((nflag && !nt) || (iflag && nt)) continue; ntp->next = NULL; if (nettab == NULL) { nettab = ntp; } else { ntip->next = ntp; } ntip = ntp; ntp = NULL; } if (ntp) (void) free((char *)ntp); - if (nettab == NULL) { - fprintf(stderr, "timed: no network usable\n"); - exit(1); - } + if (nettab == NULL) + errx(1, "no network usable"); #ifdef sgi (void)schedctl(RENICE,0,10); /* run fast to get good time */ /* ticks to delay before responding to a broadcast */ delay1 = casual(0, CLK_TCK/10); #else /* microseconds to delay before responding to a broadcast */ delay1 = casual(1, 100*1000); #endif /* sgi */ /* election timer delay in secs. */ delay2 = casual(MINTOUT, MAXTOUT); #ifdef sgi (void)_daemonize(debug ? _DF_NOFORK|_DF_NOCHDIR : 0, sock, -1, -1); #else if (!debug) daemon(debug, 0); #endif /* sgi */ if (trace) traceon(); openlog("timed", LOG_CONS|LOG_PID, LOG_DAEMON); /* * keep returning here */ ret = setjmp(jmpenv); savefromnet = fromnet; setstatus(); if (Mflag) { switch (ret) { case 0: checkignorednets(); pickslavenet(0); break; case 1: /* Just lost our master */ if (slavenet != 0) slavenet->status = election(slavenet); if (!slavenet || slavenet->status == MASTER) { checkignorednets(); pickslavenet(0); } else { makeslave(slavenet); /* prune extras */ } break; case 2: /* Just been told to quit */ justquit = 1; pickslavenet(savefromnet); break; } setstatus(); if (!(status & MASTER) && sock_raw != -1) { /* sock_raw is not being used now */ (void)close(sock_raw); sock_raw = -1; } if (status == MASTER) master(); else slave(); } else { if (sock_raw != -1) { (void)close(sock_raw); sock_raw = -1; } if (ret) { /* we just lost our master or were told to quit */ justquit = 1; } for (ntp = nettab; ntp != NULL; ntp = ntp->next) { if (ntp->status == MASTER) rmnetmachs(ntp); ntp->status = NOMASTER; } checkignorednets(); pickslavenet(0); setstatus(); slave(); } /* NOTREACHED */ -#ifdef lint return(0); -#endif } +static void +usage() +{ +#ifdef sgi + fprintf(stderr, "%s\n%s\n", +"usage: timed [-dtM] [-i net|-n net] [-F host1 host2 ...]", +" [-G netgp] [-P trimfile]"); +#else +#ifdef HAVENIS + fprintf(stderr, +"usage: timed [-dtM] [-i net|-n net] [-F host1 host2 ...] [-G netgp]\n"); +#else + fprintf(stderr, +"usage: timed [-dtM] [-i net|-n net] [-F host1 host2 ...]\n"); +#endif /* HAVENIS */ +#endif /* sgi */ + exit(1); +} + /* * suppress an upstart, untrustworthy, self-appointed master */ void suppress(addr, name,net) struct sockaddr_in *addr; char *name; struct netinfo *net; { struct sockaddr_in tgt; char tname[MAXHOSTNAMELEN]; struct tsp msg; static struct timeval wait; if (trace) fprintf(fd, "suppress: %s\n", name); tgt = *addr; (void)strcpy(tname, name); while (0 != readmsg(TSP_ANY, ANYADDR, &wait, net)) { if (trace) fprintf(fd, "suppress:\tdiscarded packet from %s\n", name); } syslog(LOG_NOTICE, "suppressing false master %s", tname); msg.tsp_type = TSP_QUIT; (void)strcpy(msg.tsp_name, hostname); (void)acksend(&msg, &tgt, tname, TSP_ACK, 0, 1); } void lookformaster(ntp) struct netinfo *ntp; { struct tsp resp, conflict, *answer; struct timeval ntime; char mastername[MAXHOSTNAMELEN]; struct sockaddr_in masteraddr; get_goodgroup(0); ntp->status = SLAVE; /* look for master */ resp.tsp_type = TSP_MASTERREQ; (void)strcpy(resp.tsp_name, hostname); answer = acksend(&resp, &ntp->dest_addr, ANYADDR, TSP_MASTERACK, ntp, 0); if (answer != 0 && !good_host_name(answer->tsp_name)) { suppress(&from, answer->tsp_name, ntp); ntp->status = NOMASTER; answer = 0; } if (answer == 0) { /* * Various conditions can cause conflict: races between * two just started timedaemons when no master is * present, or timedaemons started during an election. * A conservative approach is taken. Give up and became a * slave, postponing election of a master until first * timer expires. */ ntime.tv_sec = ntime.tv_usec = 0; answer = readmsg(TSP_MASTERREQ, ANYADDR, &ntime, ntp); if (answer != 0) { if (!good_host_name(answer->tsp_name)) { suppress(&from, answer->tsp_name, ntp); ntp->status = NOMASTER; } return; } ntime.tv_sec = ntime.tv_usec = 0; answer = readmsg(TSP_MASTERUP, ANYADDR, &ntime, ntp); if (answer != 0) { if (!good_host_name(answer->tsp_name)) { suppress(&from, answer->tsp_name, ntp); ntp->status = NOMASTER; } return; } ntime.tv_sec = ntime.tv_usec = 0; answer = readmsg(TSP_ELECTION, ANYADDR, &ntime, ntp); if (answer != 0) { if (!good_host_name(answer->tsp_name)) { suppress(&from, answer->tsp_name, ntp); ntp->status = NOMASTER; } return; } if (Mflag) ntp->status = MASTER; else ntp->status = NOMASTER; return; } ntp->status = SLAVE; (void)strcpy(mastername, answer->tsp_name); masteraddr = from; /* * If network has been partitioned, there might be other * masters; tell the one we have just acknowledged that * it has to gain control over the others. */ ntime.tv_sec = 0; ntime.tv_usec = 300000; answer = readmsg(TSP_MASTERACK, ANYADDR, &ntime, ntp); /* * checking also not to send CONFLICT to ack'ed master * due to duplicated MASTERACKs */ if (answer != NULL && strcmp(answer->tsp_name, mastername) != 0) { conflict.tsp_type = TSP_CONFLICT; (void)strcpy(conflict.tsp_name, hostname); if (!acksend(&conflict, &masteraddr, mastername, TSP_ACK, 0, 0)) { syslog(LOG_ERR, "error on sending TSP_CONFLICT"); } } } /* * based on the current network configuration, set the status, and count * networks; */ void setstatus() { struct netinfo *ntp; status = 0; nmasternets = nslavenets = nnets = nignorednets = 0; if (trace) fprintf(fd, "Net status:\n"); for (ntp = nettab; ntp != NULL; ntp = ntp->next) { switch ((int)ntp->status) { case MASTER: nmasternets++; break; case SLAVE: nslavenets++; break; case NOMASTER: case IGNORE: nignorednets++; break; } if (trace) { fprintf(fd, "\t%-16s", inet_ntoa(ntp->net)); switch ((int)ntp->status) { case NOMASTER: fprintf(fd, "NOMASTER\n"); break; case MASTER: fprintf(fd, "MASTER\n"); break; case SLAVE: fprintf(fd, "SLAVE\n"); break; case IGNORE: fprintf(fd, "IGNORE\n"); break; default: fprintf(fd, "invalid state %d\n", (int)ntp->status); break; } } nnets++; status |= ntp->status; } status &= ~IGNORE; if (trace) fprintf(fd, "\tnets=%d masters=%d slaves=%d ignored=%d delay2=%d\n", nnets, nmasternets, nslavenets, nignorednets, delay2); } void makeslave(net) struct netinfo *net; { register struct netinfo *ntp; for (ntp = nettab; ntp != NULL; ntp = ntp->next) { if (ntp->status == SLAVE && ntp != net) ntp->status = IGNORE; } slavenet = net; } /* * Try to become master over ignored nets.. */ static void checkignorednets() { register struct netinfo *ntp; for (ntp = nettab; ntp != NULL; ntp = ntp->next) { if (!Mflag && ntp->status == SLAVE) break; if (ntp->status == IGNORE || ntp->status == NOMASTER) { lookformaster(ntp); if (!Mflag && ntp->status == SLAVE) break; } } } /* * choose a good network on which to be a slave * The ignored networks must have already been checked. * Take a hint about for a good network. */ static void pickslavenet(ntp) struct netinfo *ntp; { if (slavenet != 0 && slavenet->status == SLAVE) { makeslave(slavenet); /* prune extras */ return; } if (ntp == 0 || ntp->status != SLAVE) { for (ntp = nettab; ntp != 0; ntp = ntp->next) { if (ntp->status == SLAVE) break; } } makeslave(ntp); } /* * returns a random number in the range [inf, sup] */ long casual(inf, sup) long inf, sup; { double value; value = ((double)(random() & 0x7fffffff)) / (0x7fffffff*1.0); return(inf + (sup - inf)*value); } char * date() { #ifdef sgi struct timeval tv; static char tm[32]; (void)gettimeofday(&tv, (struct timezone *)0); (void)cftime(tm, "%D %T", &tv.tv_sec); return (tm); #else struct timeval tv; (void)gettimeofday(&tv, (struct timezone *)0); return (ctime(&tv.tv_sec)); #endif /* sgi */ } void addnetname(name) char *name; { register struct nets **netlist = &nets; while (*netlist) netlist = &((*netlist)->next); *netlist = (struct nets *)malloc(sizeof **netlist); - if (*netlist == 0) { - fprintf(stderr,"malloc failed\n"); - exit(1); - } + if (*netlist == 0) + errx(1, "malloc failed"); bzero((char *)*netlist, sizeof(**netlist)); (*netlist)->name = name; } /* note a host as trustworthy */ static void add_good_host(name, perm) char *name; int perm; /* 1=not part of the netgroup */ { register struct goodhost *ghp; register struct hostent *hentp; ghp = (struct goodhost*)malloc(sizeof(*ghp)); if (!ghp) { syslog(LOG_ERR, "malloc failed"); exit(1); } bzero((char*)ghp, sizeof(*ghp)); (void)strncpy(&ghp->name[0], name, sizeof(ghp->name)); ghp->next = goodhosts; ghp->perm = perm; goodhosts = ghp; hentp = gethostbyname(name); if (0 == hentp && perm) - (void)fprintf(stderr, "unknown host %s\n", name); + warnx("unknown host %s", name); } /* update our image of the net-group of trustworthy hosts */ void get_goodgroup(force) int force; { # define NG_DELAY (30*60*CLK_TCK) /* 30 minutes */ static unsigned long last_update = -NG_DELAY; unsigned long new_update; - struct hosttbl *htp; struct goodhost *ghp, **ghpp; +#ifdef HAVENIS + struct hosttbl *htp; char *mach, *usr, *dom; +#endif /* HAVENIS */ struct tms tm; /* if no netgroup, then we are finished */ if (goodgroup == 0 || !Mflag) return; /* Do not chatter with the netgroup master too often. */ new_update = times(&tm); if (new_update < last_update + NG_DELAY && !force) return; last_update = new_update; /* forget the old temporary entries */ ghpp = &goodhosts; while (0 != (ghp = *ghpp)) { if (!ghp->perm) { *ghpp = ghp->next; free((char*)ghp); } else { ghpp = &ghp->next; } } #ifdef HAVENIS /* quit now if we are not one of the trusted masters */ if (!innetgr(goodgroup, &hostname[0], 0,0)) { if (trace) (void)fprintf(fd, "get_goodgroup: %s not in %s\n", &hostname[0], goodgroup); return; } if (trace) (void)fprintf(fd, "get_goodgroup: %s in %s\n", &hostname[0], goodgroup); /* mark the entire netgroup as trusted */ (void)setnetgrent(goodgroup); while (getnetgrent(&mach,&usr,&dom)) { if (0 != mach) add_good_host(mach,0); } (void)endnetgrent(); /* update list of slaves */ for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { htp->good = good_host_name(&htp->name[0]); } #endif /* HAVENIS */ } /* see if a machine is trustworthy */ int /* 1=trust hp to change our date */ good_host_name(name) char *name; { register struct goodhost *ghp = goodhosts; register char c; if (!ghp || !Mflag) /* trust everyone if no one named */ return 1; c = *name; do { if (c == ghp->name[0] && !strcasecmp(name, ghp->name)) return 1; /* found him, so say so */ } while (0 != (ghp = ghp->next)); if (!strcasecmp(name,hostname)) /* trust ourself */ return 1; return 0; /* did not find him */ } Index: stable/2.2/usr.sbin/timed/timedc/cmds.c =================================================================== --- stable/2.2/usr.sbin/timed/timedc/cmds.c (revision 31014) +++ stable/2.2/usr.sbin/timed/timedc/cmds.c (revision 31015) @@ -1,526 +1,526 @@ /*- * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint +#if 0 static char sccsid[] = "@(#)cmds.c 8.1 (Berkeley) 6/6/93"; +#endif +static const char rcsid[] = + "$Id: cmds.c,v 1.5 1997/10/31 12:33:14 charnier Exp $"; #endif /* not lint */ -#ifdef sgi -#ident "$Revision: 1.10 $" -#endif - #include "timedc.h" #include #include #include #include +#include #include #include #include #define TSPTYPES #include #ifdef sgi #include #include #else #define SECHR (60*60) #define SECDAY (24*SECHR) #endif /* sgi */ # define DATE_PROTO "udp" # define DATE_PORT "time" int sock; int sock_raw; char myname[MAXHOSTNAMELEN]; struct hostent *hp; struct sockaddr_in server; struct sockaddr_in dayaddr; extern int measure_delta; void bytenetorder(struct tsp *); void bytehostorder(struct tsp *); #define BU (2208988800UL) /* seconds before UNIX epoch */ /* compute the difference between our date and another machine */ static int /* difference in days from our time */ daydiff(hostname) char *hostname; { int i; int trials; struct timeval tout, now; fd_set ready; struct sockaddr from; int fromlen; unsigned long sec; /* wait 2 seconds between 10 tries */ tout.tv_sec = 2; tout.tv_usec = 0; for (trials = 0; trials < 10; trials++) { /* ask for the time */ sec = 0; if (sendto(sock, &sec, sizeof(sec), 0, (struct sockaddr*)&dayaddr, sizeof(dayaddr)) < 0) { - perror("sendto(sock)"); + warn("sendto(sock)"); return 0; } for (;;) { FD_ZERO(&ready); FD_SET(sock, &ready); i = select(sock+1, &ready, (fd_set *)0, (fd_set *)0, &tout); if (i < 0) { - if (errno = EINTR) + if (errno == EINTR) continue; - perror("select(date read)"); + warn("select(date read)"); return 0; } if (0 == i) break; fromlen = sizeof(from); if (recvfrom(sock,&sec,sizeof(sec),0, &from,&fromlen) < 0) { - perror("recvfrom(date read)"); + warn("recvfrom(date read)"); return 0; } sec = ntohl(sec); if (sec < BU) { - fprintf(stderr, - "%s says it is before 1970: %lu", + warnx("%s says it is before 1970: %lu", hostname, sec); return 0; } sec -= BU; (void)gettimeofday(&now, (struct timezone*)0); return (sec - now.tv_sec); } } /* if we get here, we tried too many times */ - fprintf(stderr,"%s will not tell us the date\n", hostname); + warnx("%s will not tell us the date", hostname); return 0; } /* * Clockdiff computes the difference between the time of the machine on * which it is called and the time of the machines given as argument. * The time differences measured by clockdiff are obtained using a sequence * of ICMP TSTAMP messages which are returned to the sender by the IP module * in the remote machine. * In order to compare clocks of machines in different time zones, the time * is transmitted (as a 32-bit value) in milliseconds since midnight UT. * If a hosts uses a different time format, it should set the high order * bit of the 32-bit quantity it transmits. * However, VMS apparently transmits the time in milliseconds since midnight * local time (rather than GMT) without setting the high order bit. * Furthermore, it does not understand daylight-saving time. This makes * clockdiff behaving inconsistently with hosts running VMS. * * In order to reduce the sensitivity to the variance of message transmission * time, clockdiff sends a sequence of messages. Yet, measures between * two `distant' hosts can be affected by a small error. The error can, * however, be reduced by increasing the number of messages sent in each * measurement. */ void clockdiff(argc, argv) int argc; char *argv[]; { int measure_status; extern int measure(u_long, u_long, char *, struct sockaddr_in*, int); register int avg_cnt; register long avg; struct servent *sp; if (argc < 2) { - printf("Usage: clockdiff host ... \n"); + printf("usage: timedc clockdiff host ...\n"); return; } - (void)gethostname(myname,sizeof(myname)); + if (gethostname(myname, sizeof(myname) - 1) < 0) + err(1, "gethostname"); /* get the address for the date ready */ sp = getservbyname(DATE_PORT, DATE_PROTO); if (!sp) { - (void)fprintf(stderr, "%s/%s is an unknown service\n", - DATE_PORT, DATE_PROTO); + warnx("%s/%s is an unknown service", DATE_PORT, DATE_PROTO); dayaddr.sin_port = 0; } else { dayaddr.sin_port = sp->s_port; } while (argc > 1) { argc--; argv++; hp = gethostbyname(*argv); if (hp == NULL) { - fprintf(stderr, "timedc: %s: ", *argv); - herror(0); + warnx("%s: %s", *argv, hstrerror(h_errno)); continue; } server.sin_family = hp->h_addrtype; bcopy(hp->h_addr, &server.sin_addr.s_addr, hp->h_length); for (avg_cnt = 0, avg = 0; avg_cnt < 16; avg_cnt++) { measure_status = measure(10000,100, *argv, &server, 1); if (measure_status != GOOD) break; avg += measure_delta; } if (measure_status == GOOD) measure_delta = avg/avg_cnt; switch (measure_status) { case HOSTDOWN: printf("%s is down\n", hp->h_name); continue; case NONSTDTIME: printf("%s transmitts a non-standard time format\n", hp->h_name); continue; case UNREACHABLE: printf("%s is unreachable\n", hp->h_name); continue; } /* * Try to get the date only after using ICMP timestamps to * get the time. This is because the date protocol * is optional. */ if (dayaddr.sin_port != 0) { dayaddr.sin_family = hp->h_addrtype; bcopy(hp->h_addr, &dayaddr.sin_addr.s_addr, hp->h_length); avg = daydiff(*argv); if (avg > SECDAY) { printf("time on %s is %ld days ahead %s\n", hp->h_name, avg/SECDAY, myname); continue; } else if (avg < -SECDAY) { printf("time on %s is %ld days behind %s\n", hp->h_name, -avg/SECDAY, myname); continue; } } if (measure_delta > 0) { printf("time on %s is %d ms. ahead of time on %s\n", hp->h_name, measure_delta, myname); } else if (measure_delta == 0) { printf("%s and %s have the same time\n", hp->h_name, myname); } else { printf("time on %s is %d ms. behind time on %s\n", hp->h_name, -measure_delta, myname); } } return; } /* * finds location of master timedaemon */ void msite(argc, argv) int argc; char *argv[]; { int cc; fd_set ready; struct sockaddr_in dest; int i, length; struct sockaddr from; struct timeval tout; struct tsp msg; struct servent *srvp; char *tgtname; if (argc < 1) { - printf("Usage: msite [hostname]\n"); + printf("usage: timedc msite [host ...]\n"); return; } srvp = getservbyname("timed", "udp"); if (srvp == 0) { - fprintf(stderr, "udp/timed: unknown service\n"); + warnx("udp/timed: unknown service"); return; } dest.sin_port = srvp->s_port; dest.sin_family = AF_INET; - (void)gethostname(myname, sizeof(myname)); + if (gethostname(myname, sizeof(myname) - 1) < 0) + err(1, "gethostname"); i = 1; do { tgtname = (i >= argc) ? myname : argv[i]; hp = gethostbyname(tgtname); if (hp == 0) { - fprintf(stderr, "timedc: %s: ", tgtname); - herror(0); + warnx("%s: %s", tgtname, hstrerror(h_errno)); continue; } bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length); (void)strcpy(msg.tsp_name, myname); msg.tsp_type = TSP_MSITE; msg.tsp_vers = TSPVERSION; bytenetorder(&msg); if (sendto(sock, &msg, sizeof(struct tsp), 0, (struct sockaddr*)&dest, sizeof(struct sockaddr)) < 0) { - perror("sendto"); + warn("sendto"); continue; } tout.tv_sec = 15; tout.tv_usec = 0; FD_ZERO(&ready); FD_SET(sock, &ready); if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) { length = sizeof(struct sockaddr); cc = recvfrom(sock, &msg, sizeof(struct tsp), 0, &from, &length); if (cc < 0) { - perror("recvfrom"); + warn("recvfrom"); continue; } bytehostorder(&msg); if (msg.tsp_type == TSP_ACK) { printf("master timedaemon at %s is %s\n", tgtname, msg.tsp_name); } else { printf("received wrong ack: %s\n", tsptype[msg.tsp_type]); } } else { printf("communication error with %s\n", tgtname); } } while (++i < argc); } /* * quits timedc */ void quit() { exit(0); } /* * Causes the election timer to expire on the selected hosts * It sends just one udp message per machine, relying on * reliability of communication channel. */ void testing(argc, argv) int argc; char *argv[]; { struct servent *srvp; struct sockaddr_in sin; struct tsp msg; if (argc < 2) { - printf("Usage: election host1 [host2 ...]\n"); + printf("usage: timedc election host1 [host2 ...]\n"); return; } srvp = getservbyname("timed", "udp"); if (srvp == 0) { - fprintf(stderr, "udp/timed: unknown service\n"); + warnx("udp/timed: unknown service"); return; } while (argc > 1) { argc--; argv++; hp = gethostbyname(*argv); if (hp == NULL) { - fprintf(stderr, "timedc: %s: ", *argv); - herror(0); + warnx("%s: %s", *argv, hstrerror(h_errno)); argc--; argv++; continue; } sin.sin_port = srvp->s_port; sin.sin_family = hp->h_addrtype; bcopy(hp->h_addr, &sin.sin_addr.s_addr, hp->h_length); msg.tsp_type = TSP_TEST; msg.tsp_vers = TSPVERSION; - (void)gethostname(myname, sizeof(myname)); - (void)strncpy(msg.tsp_name, myname, sizeof(msg.tsp_name)); + if (gethostname(myname, sizeof(myname) - 1) < 0) + err(1, "gethostname"); + (void)strcpy(msg.tsp_name, myname); bytenetorder(&msg); if (sendto(sock, &msg, sizeof(struct tsp), 0, (struct sockaddr*)&sin, sizeof(struct sockaddr)) < 0) { - perror("sendto"); + warn("sendto"); } } } /* * Enables or disables tracing on local timedaemon */ void tracing(argc, argv) int argc; char *argv[]; { int onflag; int length; int cc; fd_set ready; struct sockaddr_in dest; struct sockaddr from; struct timeval tout; struct tsp msg; struct servent *srvp; if (argc != 2) { - printf("Usage: tracing { on | off }\n"); + printf("usage: timedc trace { on | off }\n"); return; } srvp = getservbyname("timed", "udp"); if (srvp == 0) { - fprintf(stderr, "udp/timed: unknown service\n"); + warnx("udp/timed: unknown service"); return; } dest.sin_port = srvp->s_port; dest.sin_family = AF_INET; - (void)gethostname(myname,sizeof(myname)); + if (gethostname(myname, sizeof(myname) - 1) < 0) + err(1, "gethostname"); hp = gethostbyname(myname); bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length); if (strcmp(argv[1], "on") == 0) { msg.tsp_type = TSP_TRACEON; onflag = ON; } else { msg.tsp_type = TSP_TRACEOFF; onflag = OFF; } (void)strcpy(msg.tsp_name, myname); msg.tsp_vers = TSPVERSION; bytenetorder(&msg); if (sendto(sock, &msg, sizeof(struct tsp), 0, (struct sockaddr*)&dest, sizeof(struct sockaddr)) < 0) { - perror("sendto"); + warn("sendto"); return; } tout.tv_sec = 5; tout.tv_usec = 0; FD_ZERO(&ready); FD_SET(sock, &ready); if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) { length = sizeof(struct sockaddr); cc = recvfrom(sock, &msg, sizeof(struct tsp), 0, &from, &length); if (cc < 0) { - perror("recvfrom"); + warn("recvfrom"); return; } bytehostorder(&msg); if (msg.tsp_type == TSP_ACK) if (onflag) printf("timed tracing enabled\n"); else printf("timed tracing disabled\n"); else printf("wrong ack received: %s\n", tsptype[msg.tsp_type]); } else printf("communication error\n"); } int priv_resources() { int port; struct sockaddr_in sin; sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { - perror("opening socket"); + warn("opening socket"); return(-1); } sin.sin_family = AF_INET; sin.sin_addr.s_addr = 0; for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) { sin.sin_port = htons((u_short)port); if (bind(sock, (struct sockaddr*)&sin, sizeof (sin)) >= 0) break; if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) { - perror("bind"); + warn("bind"); (void) close(sock); return(-1); } } if (port == IPPORT_RESERVED / 2) { - fprintf(stderr, "all reserved ports in use\n"); + warnx("all reserved ports in use"); (void) close(sock); return(-1); } sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (sock_raw < 0) { - perror("opening raw socket"); + warn("opening raw socket"); (void) close(sock); return(-1); } return(1); } Index: stable/2.2/usr.sbin/timed/timedc/cmdtab.c =================================================================== --- stable/2.2/usr.sbin/timed/timedc/cmdtab.c (revision 31014) +++ stable/2.2/usr.sbin/timed/timedc/cmdtab.c (revision 31015) @@ -1,57 +1,61 @@ /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint +#if 0 static char sccsid[] = "@(#)cmdtab.c 8.1 (Berkeley) 6/6/93"; +#endif +static const char rcsid[] = + "$Id: cmdtab.c,v 1.2 1997/10/22 06:20:04 charnier Exp $"; #endif /* not lint */ #include "timedc.h" char clockdiffhelp[] = "measures clock differences between machines"; char helphelp[] = "gets help on commands"; char msitehelp[] = "finds location of master"; char quithelp[] = "exits timedc"; char testinghelp[] = "causes election timers to expire"; char tracinghelp[] = "turns tracing on or off"; struct cmd cmdtab[] = { { "clockdiff", clockdiffhelp, clockdiff, 0 }, { "election", testinghelp, testing, 1 }, { "help", helphelp, help, 0 }, { "msite", msitehelp, msite, 0 }, { "quit", quithelp, quit, 0 }, { "trace", tracinghelp, tracing, 1 }, { "?", helphelp, help, 0 }, }; int NCMDS = sizeof (cmdtab) / sizeof (cmdtab[0]); Index: stable/2.2/usr.sbin/timed/timedc/timedc.8 =================================================================== --- stable/2.2/usr.sbin/timed/timedc/timedc.8 (revision 31014) +++ stable/2.2/usr.sbin/timed/timedc/timedc.8 (revision 31015) @@ -1,145 +1,145 @@ .\" Copyright (c) 1980, 1991, 1993 .\" The Regents of the University of California. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. All advertising materials mentioning features or use of this software .\" must display the following acknowledgement: .\" This product includes software developed by the University of .\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" @(#)timedc.8 8.1 (Berkeley) 6/6/93 .\" .Dd June 6, 1993 .Dt TIMEDC 8 .Os BSD 4.3 .ad .Sh NAME .Nm timedc .Nd timed control program .Sh SYNOPSIS .Nm timedc .Oo Ar command\ \& .Op Ar argument ... .Oc .Sh DESCRIPTION .Nm Timedc is used to control the operation of the .Xr timed 8 program. It may be used to: .Bl -bullet .It Measure the differences between machines' clocks, .It Find the location where the master time server is running, .It Enable or disable tracing of messages received by -.Xr timed , +.Xr timed 8 , and .It Perform various debugging actions. .El .Pp Without any arguments, -.Nm timedc +.Nm will prompt for commands from the standard input. If arguments are supplied, -.Nm timedc +.Nm interprets the first argument as a command and the remaining arguments as parameters to the command. The standard input may be redirected causing -.Nm timedc +.Nm to read commands from a file. Commands may be abbreviated; recognized commands are: .Pp .Bl -tag -width Ds -compact .It Ic \&? Op Ar command ... .Pp .It Ic help Op Ar command ... Print a short description of each command specified in the argument list, or, if no arguments are given, a list of the recognized commands. .Pp .It Ic clockdiff Ar host ... Compute the differences between the clock of the host machine and the clocks of the machines given as arguments. .Pp .It Ic msite Op Ar host ... Show the master time server for specified host(s). .Pp .It Xo .Ic trace .Li \&{ Ar on Li \&| .Ar off \&} .Xc Enable or disable the tracing of incoming messages to .Xr timed in the file -.Pa /var/log/timed.log. +.Pa /var/log/timed.log . .Pp -.It Ic election Ar host +.It Ic election Ar host1 Op Ar host2 ... Asks the daemon on the target host to reset its "election" timers and to ensure that a time master has been elected. .Pp .It Ic quit Exit from timedc. .El .Pp Other commands may be included for use in testing and debugging .Xr timed 8 ; the help command and the program source may be consulted for details. .Sh FILES .Bl -tag -width /var/log/timed.masterlog -compact .It Pa /var/log/timed.log tracing file for timed .It Pa /var/log/timed.masterlog log file for master timed .El .Sh SEE ALSO .Xr date 1 , .Xr adjtime 2 , .Xr icmp 4 , .Xr timed 8 .Rs .%T "TSP: The Time Synchronization Protocol for UNIX 4.3BSD" .%A R. Gusella .%A S. Zatti .Re .Sh DIAGNOSTICS .Bl -tag -width Ds -compact .It ?Ambiguous command abbreviation matches more than one command .It ?Invalid command no match found .It ?Privileged command command can be executed by root only .El .Sh HISTORY The .Nm command appeared in .Bx 4.3 . Index: stable/2.2/usr.sbin/timed/timedc/timedc.c =================================================================== --- stable/2.2/usr.sbin/timed/timedc/timedc.c (revision 31014) +++ stable/2.2/usr.sbin/timed/timedc/timedc.c (revision 31015) @@ -1,261 +1,260 @@ /*- * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint -static char copyright[] = +static const char copyright[] = "@(#) Copyright (c) 1985, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint +#if 0 static char sccsid[] = "@(#)timedc.c 8.1 (Berkeley) 6/6/93"; +#endif +static const char rcsid[] = + "$Id: timedc.c,v 1.2 1997/10/22 06:20:04 charnier Exp $"; #endif /* not lint */ -#ifdef sgi -#ident "$Revision: 1.6 $" -#endif - #include "timedc.h" -#include -#include #include +#include #include -#include +#include #include +#include #include +#include int trace = 0; FILE *fd = 0; int margc; int fromatty; char *margv[20]; char cmdline[200]; jmp_buf toplevel; static struct cmd *getcmd __P((char *)); int main(argc, argv) int argc; char *argv[]; { register struct cmd *c; openlog("timedc", LOG_ODELAY, LOG_AUTH); /* * security dictates! */ - if (priv_resources() < 0) { - fprintf(stderr, "Could not get privileged resources\n"); - exit(1); - } + if (priv_resources() < 0) + errx(1, "could not get privileged resources"); (void) setuid(getuid()); if (--argc > 0) { c = getcmd(*++argv); if (c == (struct cmd *)-1) { printf("?Ambiguous command\n"); exit(1); } if (c == 0) { printf("?Invalid command\n"); exit(1); } if (c->c_priv && getuid()) { printf("?Privileged command\n"); exit(1); } (*c->c_handler)(argc, argv); exit(0); } fromatty = isatty(fileno(stdin)); if (setjmp(toplevel)) putchar('\n'); (void) signal(SIGINT, intr); for (;;) { if (fromatty) { printf("timedc> "); (void) fflush(stdout); } if (fgets(cmdline, sizeof(cmdline), stdin) == 0) quit(); if (cmdline[0] == 0) break; makeargv(); if (margv[0] == 0) continue; c = getcmd(margv[0]); if (c == (struct cmd *)-1) { printf("?Ambiguous command\n"); continue; } if (c == 0) { printf("?Invalid command\n"); continue; } if (c->c_priv && getuid()) { printf("?Privileged command\n"); continue; } (*c->c_handler)(margc, margv); } return 0; } void intr(signo) int signo; { if (!fromatty) exit(0); longjmp(toplevel, 1); } static struct cmd * getcmd(name) char *name; { register char *p, *q; register struct cmd *c, *found; register int nmatches, longest; extern int NCMDS; longest = 0; nmatches = 0; found = 0; for (c = cmdtab; c < &cmdtab[NCMDS]; c++) { p = c->c_name; for (q = name; *q == *p++; q++) if (*q == 0) /* exact match? */ return(c); if (!*q) { /* the name was a prefix */ if (q - name > longest) { longest = q - name; nmatches = 1; found = c; } else if (q - name == longest) nmatches++; } } if (nmatches > 1) return((struct cmd *)-1); return(found); } /* * Slice a string up into argc/argv. */ void makeargv() { register char *cp; register char **argp = margv; margc = 0; for (cp = cmdline; *cp;) { while (isspace(*cp)) cp++; if (*cp == '\0') break; *argp++ = cp; margc += 1; while (*cp != '\0' && !isspace(*cp)) cp++; if (*cp == '\0') break; *cp++ = '\0'; } *argp++ = 0; } #define HELPINDENT (sizeof ("directory")) /* * Help command. */ void help(argc, argv) int argc; char *argv[]; { register struct cmd *c; if (argc == 1) { register int i, j, w; int columns, width = 0, lines; extern int NCMDS; printf("Commands may be abbreviated. Commands are:\n\n"); for (c = cmdtab; c < &cmdtab[NCMDS]; c++) { int len = strlen(c->c_name); if (len > width) width = len; } width = (width + 8) &~ 7; columns = 80 / width; if (columns == 0) columns = 1; lines = (NCMDS + columns - 1) / columns; for (i = 0; i < lines; i++) { for (j = 0; j < columns; j++) { c = cmdtab + j * lines + i; printf("%s", c->c_name); if (c + lines >= &cmdtab[NCMDS]) { printf("\n"); break; } w = strlen(c->c_name); while (w < width) { w = (w + 8) &~ 7; putchar('\t'); } } } return; } while (--argc > 0) { register char *arg; arg = *++argv; c = getcmd(arg); if (c == (struct cmd *)-1) printf("?Ambiguous help command %s\n", arg); else if (c == (struct cmd *)0) printf("?Invalid help command %s\n", arg); else printf("%-*s\t%s\n", (int)HELPINDENT, c->c_name, c->c_help); } } Index: stable/2.2/usr.sbin/timed/timedc/timedc.h =================================================================== --- stable/2.2/usr.sbin/timed/timedc/timedc.h (revision 31014) +++ stable/2.2/usr.sbin/timed/timedc/timedc.h (revision 31015) @@ -1,66 +1,64 @@ /*- * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)timedc.h 8.1 (Berkeley) 6/6/93 */ #include #include #ifdef sgi #include #endif #include #include #include #include #include #include -extern int errno; - #define ON 1 #define OFF 0 #define GOOD 1 #define UNREACHABLE 2 #define NONSTDTIME 3 #define HOSTDOWN 0x7fffffff struct cmd { char *c_name; /* command name */ char *c_help; /* help message */ void (*c_handler)(); /* routine to do the work */ int c_priv; /* privileged command */ }; #include "extern.h"