mirror of
https://git.FreeBSD.org/src.git
synced 2024-11-26 07:55:01 +00:00
Remove, the now very outdated, timed.
Submitted by: Kyle Spiers ksspiers at gmail Reviewed by: bcr,brooks,bz,sbruno Relnotes: yes Differential Revision: https://reviews.freebsd.org/D18505
This commit is contained in:
parent
17ca94cfc0
commit
53fc043d41
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=342139
@ -38,6 +38,12 @@
|
||||
# xargs -n1 | sort | uniq -d;
|
||||
# done
|
||||
|
||||
# 20181214: Remove timed files
|
||||
OLD_FILES+=etc/rc.d/timed
|
||||
OLD_FILES+=usr/sbin/timed
|
||||
OLD_FILES+=usr/sbin/timedc
|
||||
OLD_FILES+=usr/share/man/man8/timed.8.gz
|
||||
OLD_FILES+=usr/share/man/man8/timedc.8.gz
|
||||
# 20181211: new clang import which bumps version from 6.0.1 to 7.0.1.
|
||||
OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/allocator_interface.h
|
||||
OLD_FILES+=usr/lib/clang/6.0.1/include/sanitizer/asan_interface.h
|
||||
|
4
UPDATING
4
UPDATING
@ -37,6 +37,10 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 13.x IS SLOW:
|
||||
prerequisites and upgrading, if you are not already using clang 3.5.0
|
||||
or higher.
|
||||
|
||||
20181211:
|
||||
Remove the timed and netdate programs from the base tree. Setting
|
||||
the time with these deamons has been obsolete for over a decade.
|
||||
|
||||
20181126:
|
||||
On amd64, arm64 and armv7 (architectures that install LLVM's ld.lld
|
||||
linker as /usr/bin/ld) GNU ld is no longer installed as ld.bfd, as
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
PACKAGE=runtime
|
||||
PROG= date
|
||||
SRCS= date.c netdate.c vary.c
|
||||
SRCS= date.c vary.c
|
||||
|
||||
HAS_TESTS=
|
||||
SUBDIR.${MK_TESTS}+= tests
|
||||
|
@ -4,7 +4,6 @@
|
||||
DIRDEPS = \
|
||||
gnu/lib/csu \
|
||||
include \
|
||||
include/protocols \
|
||||
include/xlocale \
|
||||
lib/${CSU_DIR} \
|
||||
lib/libc \
|
||||
|
@ -59,7 +59,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <unistd.h>
|
||||
#include <utmpx.h>
|
||||
|
||||
#include "extern.h"
|
||||
#include "vary.h"
|
||||
|
||||
#ifndef TM_YEAR_BASE
|
||||
@ -67,7 +66,6 @@ __FBSDID("$FreeBSD$");
|
||||
#endif
|
||||
|
||||
static time_t tval;
|
||||
int retval;
|
||||
|
||||
static void badformat(void);
|
||||
static void iso8601_usage(const char *);
|
||||
@ -248,7 +246,7 @@ printdate(const char *buf)
|
||||
(void)printf("%s\n", buf);
|
||||
if (fflush(stdout))
|
||||
err(1, "stdout");
|
||||
exit(retval);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -370,7 +368,7 @@ setthetime(const char *fmt, const char *p, int jflag, int nflag)
|
||||
|
||||
if (!jflag) {
|
||||
/* set the time */
|
||||
if (nflag || netsettime(tval)) {
|
||||
if (nflag) {
|
||||
utx.ut_type = OLD_TIME;
|
||||
memset(utx.ut_id, 0, sizeof(utx.ut_id));
|
||||
(void)gettimeofday(&utx.ut_tv, NULL);
|
||||
|
@ -1,37 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright (c) 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. 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.
|
||||
*
|
||||
* @(#)extern.h 8.1 (Berkeley) 5/31/93
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
extern int retval;
|
||||
|
||||
int netsettime(time_t);
|
@ -1,183 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright (c) 1990, 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. 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.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)netdate.c 8.1 (Berkeley) 5/31/93";
|
||||
#endif /* not lint */
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#define TSPTYPES
|
||||
#include <protocols/timed.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "extern.h"
|
||||
|
||||
#define WAITACK 2 /* seconds */
|
||||
#define WAITDATEACK 5 /* seconds */
|
||||
|
||||
/*
|
||||
* Set the date in the machines controlled by timedaemons by communicating the
|
||||
* new date to the local timedaemon. If the timedaemon is in the master state,
|
||||
* it performs the correction on all slaves. If it is in the slave state, it
|
||||
* notifies the master that a correction is needed.
|
||||
* Returns 0 on success. Returns > 0 on failure, setting retval to 2;
|
||||
*/
|
||||
int
|
||||
netsettime(time_t tval)
|
||||
{
|
||||
struct timeval tout;
|
||||
struct servent *sp;
|
||||
struct tsp msg;
|
||||
struct sockaddr_in lsin, dest, from;
|
||||
fd_set ready;
|
||||
long waittime;
|
||||
int s, port, timed_ack, found, lerr;
|
||||
socklen_t length;
|
||||
char hostname[MAXHOSTNAMELEN];
|
||||
|
||||
if ((sp = getservbyname("timed", "udp")) == NULL) {
|
||||
warnx("timed/udp: unknown service");
|
||||
return (retval = 2);
|
||||
}
|
||||
|
||||
dest.sin_port = sp->s_port;
|
||||
dest.sin_family = AF_INET;
|
||||
dest.sin_addr.s_addr = htonl((u_long)INADDR_ANY);
|
||||
s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (s < 0) {
|
||||
if (errno != EAFNOSUPPORT)
|
||||
warn("timed");
|
||||
return (retval = 2);
|
||||
}
|
||||
|
||||
memset(&lsin, 0, sizeof(lsin));
|
||||
lsin.sin_family = AF_INET;
|
||||
for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
|
||||
lsin.sin_port = htons((u_short)port);
|
||||
if (bind(s, (struct sockaddr *)&lsin, sizeof(lsin)) >= 0)
|
||||
break;
|
||||
if (errno == EADDRINUSE)
|
||||
continue;
|
||||
if (errno != EADDRNOTAVAIL)
|
||||
warn("bind");
|
||||
goto bad;
|
||||
}
|
||||
if (port == IPPORT_RESERVED / 2) {
|
||||
warnx("all ports in use");
|
||||
goto bad;
|
||||
}
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.tsp_type = TSP_SETDATE;
|
||||
msg.tsp_vers = TSPVERSION;
|
||||
if (gethostname(hostname, sizeof(hostname))) {
|
||||
warn("gethostname");
|
||||
goto bad;
|
||||
}
|
||||
(void)strlcpy(msg.tsp_name, hostname, sizeof(msg.tsp_name));
|
||||
msg.tsp_seq = htons((u_short)0);
|
||||
msg.tsp_time.tv_sec = htonl((u_long)tval);
|
||||
msg.tsp_time.tv_usec = htonl((u_long)0);
|
||||
length = sizeof(struct sockaddr_in);
|
||||
if (connect(s, (struct sockaddr *)&dest, length) < 0) {
|
||||
warn("connect");
|
||||
goto bad;
|
||||
}
|
||||
if (send(s, (char *)&msg, sizeof(struct tsp), 0) < 0) {
|
||||
if (errno != ECONNREFUSED)
|
||||
warn("send");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
timed_ack = -1;
|
||||
waittime = WAITACK;
|
||||
loop:
|
||||
tout.tv_sec = waittime;
|
||||
tout.tv_usec = 0;
|
||||
|
||||
FD_ZERO(&ready);
|
||||
FD_SET(s, &ready);
|
||||
found = select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout);
|
||||
|
||||
length = sizeof(lerr);
|
||||
if (!getsockopt(s,
|
||||
SOL_SOCKET, SO_ERROR, (char *)&lerr, &length) && lerr) {
|
||||
if (lerr != ECONNREFUSED)
|
||||
warnc(lerr, "send (delayed error)");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (found > 0 && FD_ISSET(s, &ready)) {
|
||||
length = sizeof(struct sockaddr_in);
|
||||
if (recvfrom(s, &msg, sizeof(struct tsp), 0,
|
||||
(struct sockaddr *)&from, &length) < 0) {
|
||||
if (errno != ECONNREFUSED)
|
||||
warn("recvfrom");
|
||||
goto bad;
|
||||
}
|
||||
msg.tsp_seq = ntohs(msg.tsp_seq);
|
||||
msg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec);
|
||||
msg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec);
|
||||
switch (msg.tsp_type) {
|
||||
case TSP_ACK:
|
||||
timed_ack = TSP_ACK;
|
||||
waittime = WAITDATEACK;
|
||||
goto loop;
|
||||
case TSP_DATEACK:
|
||||
(void)close(s);
|
||||
return (0);
|
||||
default:
|
||||
warnx("wrong ack received from timed: %s",
|
||||
tsptype[msg.tsp_type]);
|
||||
timed_ack = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (timed_ack == -1)
|
||||
warnx("can't reach time daemon, time set locally");
|
||||
|
||||
bad:
|
||||
(void)close(s);
|
||||
return (retval = 2);
|
||||
}
|
@ -291,10 +291,6 @@ SMRCD= sendmail
|
||||
SMRCDPACKAGE= sendmail
|
||||
.endif
|
||||
|
||||
.if ${MK_TIMED} != "no"
|
||||
CONFS+= timed
|
||||
.endif
|
||||
|
||||
.if ${MK_UNBOUND} != "no"
|
||||
CONFGROUPS+= UNBOUND
|
||||
UNBOUND+= local_unbound
|
||||
|
@ -1,19 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# $FreeBSD$
|
||||
#
|
||||
|
||||
# PROVIDE: timed
|
||||
# REQUIRE: DAEMON
|
||||
# BEFORE: LOGIN
|
||||
# KEYWORD: nojail shutdown
|
||||
|
||||
. /etc/rc.subr
|
||||
|
||||
name="timed"
|
||||
desc="Time server daemon"
|
||||
rcvar="timed_enable"
|
||||
command="/usr/sbin/${name}"
|
||||
|
||||
load_rc_config $name
|
||||
run_rc_command "$1"
|
@ -1,6 +1,6 @@
|
||||
.\" DO NOT EDIT-- this file is @generated by tools/build/options/makeman.
|
||||
.\" $FreeBSD$
|
||||
.Dd November 26, 2018
|
||||
.Dd December 15, 2018
|
||||
.Dt SRC.CONF 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -239,6 +239,17 @@ Disable the BSD licensed
|
||||
.Pa crtbegin.o
|
||||
and
|
||||
.Pa crtend.o .
|
||||
.Pp
|
||||
This is a default setting on
|
||||
powerpc/powerpc, powerpc/powerpc64, powerpc/powerpcspe and sparc64/sparc64.
|
||||
.It Va WITH_BSD_CRTBEGIN
|
||||
Enable the BSD licensed
|
||||
.Pa crtbegin.o
|
||||
and
|
||||
.Pa crtend.o .
|
||||
.Pp
|
||||
This is a default setting on
|
||||
amd64/amd64, arm/arm, arm/armv6, arm/armv7, arm64/aarch64, i386/i386, mips/mipsel, mips/mips, mips/mips64el, mips/mips64, mips/mipsn32, mips/mipselhf, mips/mipshf, mips/mips64elhf, mips/mips64hf and riscv/riscv64.
|
||||
.It Va WITH_BSD_GREP
|
||||
Install BSD-licensed grep as '[ef]grep' instead of GNU grep.
|
||||
.It Va WITHOUT_BSNMP
|
||||
@ -1780,9 +1791,6 @@ Set to not build or install
|
||||
.Xr tftp 1
|
||||
and
|
||||
.Xr tftpd 8 .
|
||||
.It Va WITHOUT_TIMED
|
||||
Set to not build or install
|
||||
.Xr timed 8 .
|
||||
.It Va WITHOUT_TOOLCHAIN
|
||||
Set to not install header or
|
||||
programs used for program development,
|
||||
|
@ -8513,14 +8513,6 @@ OLD_FILES+=usr/share/man/man1/tftp.1.gz
|
||||
OLD_FILES+=usr/share/man/man8/tftpd.8.gz
|
||||
.endif
|
||||
|
||||
.if ${MK_TIMED} == no
|
||||
OLD_FILES+=usr/sbin/timed
|
||||
OLD_FILES+=usr/sbin/timedc
|
||||
OLD_FILES+=usr/share/man/man8/timed.8.gz
|
||||
OLD_FILES+=usr/share/man/man8/timedc.8.gz
|
||||
.endif
|
||||
|
||||
.if ${MK_TOOLCHAIN} == no
|
||||
OLD_FILES+=usr/bin/addr2line
|
||||
OLD_FILES+=usr/bin/as
|
||||
OLD_FILES+=usr/bin/byacc
|
||||
|
@ -1,3 +0,0 @@
|
||||
.\" $FreeBSD$
|
||||
Set to not build or install
|
||||
.Xr timed 8 .
|
@ -201,7 +201,6 @@ SUBDIR.${MK_SENDMAIL}+= praliases
|
||||
SUBDIR.${MK_SENDMAIL}+= sendmail
|
||||
SUBDIR.${MK_TCP_WRAPPERS}+= tcpdchk
|
||||
SUBDIR.${MK_TCP_WRAPPERS}+= tcpdmatch
|
||||
SUBDIR.${MK_TIMED}+= timed
|
||||
SUBDIR.${MK_TOOLCHAIN}+= config
|
||||
SUBDIR.${MK_TOOLCHAIN}+= crunch
|
||||
SUBDIR.${MK_UNBOUND}+= unbound
|
||||
|
@ -1,6 +0,0 @@
|
||||
# @(#)Makefile 8.1 (Berkeley) 6/6/93
|
||||
# $FreeBSD$
|
||||
|
||||
SUBDIR= timed timedc
|
||||
|
||||
.include <bsd.subdir.mk>
|
@ -1,145 +0,0 @@
|
||||
# @(#)CHANGES 5.1 (Berkeley) 5/11/93
|
||||
# $FreeBSD$
|
||||
|
||||
This new version is almost identical to the timed and timedc code
|
||||
that has been shipped for years by a workstation vendor.
|
||||
|
||||
Among the many changes:
|
||||
|
||||
improve `timedc msite` to accept a list of hostnames.
|
||||
|
||||
change slave-masters to answer the packets generated by `timedc msite`
|
||||
with the name of the real master, not their own. This makes it
|
||||
possible to "chase the chain" of slave servers to the ultimate
|
||||
master.
|
||||
|
||||
much improve the log caused by `timedc trace on`:
|
||||
-made `timed -t` work.
|
||||
-suppression of repeated entries, which both slowed down the daemon
|
||||
(sometimes catastrophically) and tended to make disks fill up
|
||||
even more quickly.
|
||||
-better time stamps on log entries
|
||||
-more messages
|
||||
-dump information about slaves, master, and so on each time
|
||||
a message asking the log be turned on is received, and
|
||||
when the log is turned off.
|
||||
-fewer CPU cycles
|
||||
|
||||
use a hash table to keep track of slaves, instead of the stupid linear
|
||||
list. This becomes handy with hundreds of slaves, instead of
|
||||
the original design limit of "a room with a few VAX's."
|
||||
|
||||
separate the main protocol timer from that used to look for other networks
|
||||
to master.
|
||||
|
||||
time stamp packets received by the daemon, so that time corrections
|
||||
are not made (even more) inaccurate by waiting in the internal,
|
||||
timed queue while the daemon is processing other messages.
|
||||
|
||||
made -n and -i work with subnets not named in /etc/networks
|
||||
|
||||
compute the median of the measured clocks, instead of the average
|
||||
of "good" times.
|
||||
|
||||
vastly improve the accuracy of the clock difference measure by
|
||||
`timedc clockdiff`.
|
||||
|
||||
use adjtime() when possible, and directly set the clock only when
|
||||
necessary.
|
||||
|
||||
when the requested adjustment is small, perform only part of it, to
|
||||
damp oscillations and improve the long term accuracy of the
|
||||
adjustments.
|
||||
|
||||
fix uncounted core-dumps on machines that do not allow dereferencing 0
|
||||
in both the daemon and timedc.
|
||||
|
||||
fix "master loop detection".
|
||||
|
||||
fix several cases in which multi-homed masters could get into shouting
|
||||
matches, consuming all available network bandwidth and CPU cycles
|
||||
(which ever runs out first), and convincing all bystanders to stop
|
||||
advancing their own clocks.
|
||||
|
||||
refuse to behave badly when other machines do. Instead of arguing forever,
|
||||
go off and sulk when other machines refuse to play by the rules.
|
||||
|
||||
increase the maximum number of clients.
|
||||
|
||||
add "-F host,host2,..." to "freerun" or "trust" only some hosts. This
|
||||
is handy both when only some machines should be trusted to let
|
||||
root use the `date` command to change time in the network.
|
||||
|
||||
It is also handy when one machine has some other way of adjusting
|
||||
its clock, whether NTP or a direct radio or atomic connection.
|
||||
"-F localhost" causes `timed` to "trust" only itself.
|
||||
|
||||
It is also handy to build a hierarchy of timed masters crossing
|
||||
networks. The TSP protocol has no provision of "goodness of clock",
|
||||
no natural way to completely heal network paritions. Judicious
|
||||
use of -F or -G can cause each gateway to trust only itself and
|
||||
machines closer to a central machine with a radio or atomic clock.
|
||||
|
||||
add #ifdef code that supports NIS "netgroups" of trusted hosts, which
|
||||
can be easier to administer than -F.
|
||||
|
||||
add #ifdef code to compute an aged total adjustment. This can be used
|
||||
in systems that can make long term changes in their system clock
|
||||
frequency, e.g. "timetrim" in the Silicon Graphics kernel.
|
||||
|
||||
|
||||
Problems observed by others that are unresolved include:
|
||||
|
||||
Practically any users can send to the master TSP messages and this
|
||||
way corrupt the reliability of the system. Authentication
|
||||
of messages should be provided. Unfortunately, that would
|
||||
require changing the protocol with all of the implied
|
||||
compatibility problems. Fortunately, the new -F and -G args
|
||||
can be used to cause the daemon to ignore time changes from
|
||||
untrusted machines.
|
||||
|
||||
MAN. The limit of 1013 on the number of slaves hosts should be doc'ed.
|
||||
|
||||
It should be dynamically allocated with no limit. On a
|
||||
large network, one host could possibly master over many
|
||||
more than 30 hosts. Given the timers in the code and
|
||||
effectively in the protocol, and the time required by each
|
||||
master to talk to each slave, it is not practical to have
|
||||
more than 200-300 slaves. The master cannot keep up because
|
||||
the slave-chatting is single-threaded. when the master
|
||||
gets behind, slaves start demanding elections. To
|
||||
significantly increase the number of slaves would require
|
||||
multi-treading things, and given that a network with more
|
||||
than 300 directly addressable machines has worse problems
|
||||
than keep the time of day right, not worth worrying about.
|
||||
|
||||
UGLY,CODE. timedc/cmds.c has a lots of repeated code in it.
|
||||
|
||||
**** The first thing is that each command is set up as if it
|
||||
were an individual program taking argc and argv. A more
|
||||
conventional calling style should be used. I don't think
|
||||
any of the routines take more than a couple arguments.
|
||||
|
||||
UGLY. fxn definition syntax does't follow convention:
|
||||
has type on same line.
|
||||
|
||||
**** It needs to be fixed at least enough that tags
|
||||
will work on it. An entire cleanup might be nice later, but
|
||||
is noncritical.
|
||||
|
||||
LOBBY(mildly),CODE: Would be very convenient if date(1) took a
|
||||
+-<number> argument to set the time relatively. With
|
||||
the advent of timed it is now reasonable to synchronize
|
||||
with WWV, which is nearly impossible to do "by hand"
|
||||
with just an absolute date, and scripts are too slow.
|
||||
format could be +-nn...nn.ss, where the '.' is required
|
||||
to remove ambiguity.
|
||||
|
||||
**** If you want to do it go ahead. It sounds useful. As far as
|
||||
syntax goes, the normal format for the date should work just
|
||||
fine for this. If the date is preceded by a plus or minus,
|
||||
the change is relative, otherwise it is absolute.
|
||||
|
||||
|
||||
Vernon Schryver.
|
||||
vjs@sgi.com
|
@ -1,16 +0,0 @@
|
||||
# @(#)Makefile 8.1 (Berkeley) 6/6/93
|
||||
# $FreeBSD$
|
||||
#
|
||||
# optional flags are: MEASURE TESTING DEBUG
|
||||
|
||||
PROG= timed
|
||||
MAN= timed.8
|
||||
SRCS= acksend.c candidate.c correct.c master.c networkdelta.c readmsg.c \
|
||||
slave.c timed.c byteorder.c measure.c cksum.c
|
||||
|
||||
LIBADD= util
|
||||
|
||||
WARNS?= 1
|
||||
|
||||
.include "../../Makefile.inc"
|
||||
.include <bsd.prog.mk>
|
@ -1,21 +0,0 @@
|
||||
# $FreeBSD$
|
||||
# Autogenerated - do NOT edit!
|
||||
|
||||
DIRDEPS = \
|
||||
gnu/lib/csu \
|
||||
include \
|
||||
include/arpa \
|
||||
include/protocols \
|
||||
include/xlocale \
|
||||
lib/${CSU_DIR} \
|
||||
lib/libc \
|
||||
lib/libcompiler_rt \
|
||||
lib/libutil \
|
||||
lib/msun \
|
||||
|
||||
|
||||
.include <dirdeps.mk>
|
||||
|
||||
.if ${DEP_RELDIR} == ${_DEP_RELDIR}
|
||||
# local dependencies - needed for -jN in clean tree
|
||||
.endif
|
@ -1,127 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* 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. 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
|
||||
static const char rcsid[] =
|
||||
"$FreeBSD$";
|
||||
#endif /* not lint */
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
struct tsp *answer;
|
||||
|
||||
extern u_short sequence;
|
||||
|
||||
void
|
||||
xmit(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().
|
||||
* message this message
|
||||
* addr to here
|
||||
* ack look for this ack
|
||||
* net receive from this network
|
||||
* bad 1=losing patience
|
||||
*/
|
||||
struct tsp *
|
||||
acksend(struct tsp *message, struct sockaddr_in *addr, char *name,
|
||||
int ack, struct netinfo *net, int bad)
|
||||
{
|
||||
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 = NULL;
|
||||
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 != NULL) {
|
||||
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);
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* 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. 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
|
||||
static const char rcsid[] =
|
||||
"$FreeBSD$";
|
||||
#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(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(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 */
|
||||
}
|
||||
}
|
@ -1,164 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* 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. 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
|
||||
static const char rcsid[] =
|
||||
"$FreeBSD$";
|
||||
#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(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;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* 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. 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
|
||||
static const char rcsid[] =
|
||||
"$FreeBSD$";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
/*
|
||||
* 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(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);
|
||||
}
|
@ -1,192 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* 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. 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
|
||||
static const char rcsid[] =
|
||||
"$FreeBSD$";
|
||||
#endif /* not lint */
|
||||
|
||||
#include "globals.h"
|
||||
#include <math.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/times.h>
|
||||
|
||||
static void adjclock(struct timeval *);
|
||||
|
||||
/*
|
||||
* sends to the slaves the corrections for their clocks after fixing our
|
||||
* own
|
||||
*/
|
||||
void
|
||||
correct(long avdelta)
|
||||
{
|
||||
struct hosttbl *htp;
|
||||
int corr;
|
||||
struct timeval adjlocal, tmptv;
|
||||
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(&tmptv,0);
|
||||
timevaladd(&tmptv, &adjlocal);
|
||||
to.tsp_time.tv_sec = tmptv.tv_sec;
|
||||
to.tsp_time.tv_usec = tmptv.tv_usec;
|
||||
to.tsp_type = TSP_SETTIME;
|
||||
} else {
|
||||
tmptv.tv_sec = to.tsp_time.tv_sec;
|
||||
tmptv.tv_usec = to.tsp_time.tv_usec;
|
||||
mstotvround(&tmptv, corr);
|
||||
to.tsp_time.tv_sec = tmptv.tv_sec;
|
||||
to.tsp_time.tv_usec = tmptv.tv_usec;
|
||||
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(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 %jd sec too large to adjust",
|
||||
(intmax_t)adj.tv_sec);
|
||||
(void) gettimeofday(&now, 0);
|
||||
timevaladd(&now, corr);
|
||||
if (settimeofday(&now, 0) < 0)
|
||||
syslog(LOG_ERR, "settimeofday: %m");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* adjust the time in a message by the time it
|
||||
* spent in the queue
|
||||
*/
|
||||
void
|
||||
adj_msg_time(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;
|
||||
}
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
/* $FreeBSD$ */
|
||||
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright (c) 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. 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.
|
||||
*
|
||||
* @(#)extern.h 8.1 (Berkeley) 6/6/93
|
||||
*/
|
||||
|
||||
struct hosttbl;
|
||||
struct netinfo;
|
||||
struct sockaddr_in;
|
||||
struct timeval;
|
||||
struct tsp;
|
||||
|
||||
struct hosttbl *addmach(char *, struct sockaddr_in *, struct netinfo *);
|
||||
struct hosttbl *findhost(char *);
|
||||
struct hosttbl *remmach(struct hosttbl *);
|
||||
|
||||
struct tsp *readmsg(int,
|
||||
char *, struct timeval *, struct netinfo *);
|
||||
struct tsp *acksend(struct tsp *,
|
||||
struct sockaddr_in *, char *, int, struct netinfo *, int);
|
||||
|
||||
void addnetname(char *);
|
||||
void adj_msg_time(struct tsp *, struct timeval *);
|
||||
void bytehostorder(struct tsp *);
|
||||
void bytenetorder(struct tsp *);
|
||||
void byteorder(struct tsp *);
|
||||
long casual(long, long);
|
||||
int cksum(u_short *, int);
|
||||
void correct(long);
|
||||
char *date(void);
|
||||
void doquit(struct tsp *);
|
||||
int election(struct netinfo *);
|
||||
void get_goodgroup(int);
|
||||
int good_host_name(char *);
|
||||
void ignoreack(void);
|
||||
int in_cksum(u_short *, int);
|
||||
void lookformaster(struct netinfo *);
|
||||
void makeslave(struct netinfo *);
|
||||
int master(void);
|
||||
void masterack(void);
|
||||
void masterup(struct netinfo *);
|
||||
int measure(u_long, u_long, char *, struct sockaddr_in *, int);
|
||||
void msterup(struct netinfo *);
|
||||
void mstotvround(struct timeval *, long);
|
||||
long networkdelta(void);
|
||||
void newslave(struct tsp *);
|
||||
void print(struct tsp *, struct sockaddr_in *);
|
||||
void prthp(clock_t);
|
||||
void rmnetmachs(struct netinfo *);
|
||||
void setstatus(void);
|
||||
void slave(void) __dead2;
|
||||
void slaveack(void);
|
||||
void spreadtime(void);
|
||||
void suppress(struct sockaddr_in *, char *, struct netinfo *);
|
||||
void synch(long);
|
||||
void timevaladd(struct timeval *, struct timeval *);
|
||||
void timevalsub(struct timeval *, struct timeval *, struct timeval *);
|
||||
void traceoff(char *);
|
||||
void traceon(void);
|
||||
void xmit(int, u_int, struct sockaddr_in *);
|
@ -1,171 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* 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. 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
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <netdb.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <protocols/timed.h>
|
||||
#define SECHR (60*60)
|
||||
#define SECDAY (24*SECHR)
|
||||
|
||||
/* 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];
|
||||
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_int32_t 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) (a<b ? b : a)
|
||||
# define min(a,b) (a>b ? b : a)
|
||||
# define abs(x) (x>=0 ? x : -(x))
|
@ -1,843 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* 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. 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
|
||||
static const char rcsid[] =
|
||||
"$FreeBSD$";
|
||||
#endif /* not lint */
|
||||
|
||||
#include "globals.h"
|
||||
#include <sys/file.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/times.h>
|
||||
#include <setjmp.h>
|
||||
#include <utmpx.h>
|
||||
#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(struct tsp *);
|
||||
|
||||
/*
|
||||
* 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(void)
|
||||
{
|
||||
struct hosttbl *htp;
|
||||
long pollingtime;
|
||||
#define POLLRATE 4
|
||||
int polls;
|
||||
struct timeval wait, ntime;
|
||||
time_t tsp_time_sec;
|
||||
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, NULL);
|
||||
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, NULL);
|
||||
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, NULL);
|
||||
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
|
||||
*/
|
||||
tsp_time_sec = msg->tsp_time.tv_sec;
|
||||
(void)strlcpy(newdate, ctime(&tsp_time_sec),
|
||||
sizeof(newdate));
|
||||
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, NULL);
|
||||
pollingtime = ntime.tv_sec + SAMPLEINTVL;
|
||||
break;
|
||||
|
||||
case TSP_SETDATEREQ:
|
||||
if (!fromnet || fromnet->status != MASTER)
|
||||
break;
|
||||
tsp_time_sec = msg->tsp_time.tv_sec;
|
||||
(void)strlcpy(newdate, ctime(&tsp_time_sec),
|
||||
sizeof(newdate));
|
||||
htp = findhost(msg->tsp_name);
|
||||
if (htp == NULL) {
|
||||
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, NULL);
|
||||
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, NULL);
|
||||
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(struct tsp *msg)
|
||||
{
|
||||
char tname[MAXHOSTNAMELEN];
|
||||
char olddate[32];
|
||||
struct timeval otime, ntime, tmptv;
|
||||
struct utmpx utx;
|
||||
|
||||
(void)strcpy(tname, msg->tsp_name);
|
||||
|
||||
xmit(TSP_DATEACK, msg->tsp_seq, &from);
|
||||
|
||||
(void)strlcpy(olddate, date(), sizeof(olddate));
|
||||
|
||||
/* adjust time for residence on the queue */
|
||||
(void)gettimeofday(&otime, NULL);
|
||||
adj_msg_time(msg,&otime);
|
||||
|
||||
tmptv.tv_sec = msg->tsp_time.tv_sec;
|
||||
tmptv.tv_usec = msg->tsp_time.tv_usec;
|
||||
timevalsub(&ntime, &tmptv, &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 {
|
||||
utx.ut_type = OLD_TIME;
|
||||
(void)gettimeofday(&utx.ut_tv, NULL);
|
||||
pututxline(&utx);
|
||||
(void)settimeofday(&tmptv, 0);
|
||||
utx.ut_type = NEW_TIME;
|
||||
(void)gettimeofday(&utx.ut_tv, NULL);
|
||||
pututxline(&utx);
|
||||
spreadtime();
|
||||
}
|
||||
|
||||
syslog(LOG_NOTICE, "date changed by %s from %s",
|
||||
tname, olddate);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* synchronize all of the slaves
|
||||
*/
|
||||
void
|
||||
synch(long mydelta)
|
||||
{
|
||||
struct hosttbl *htp;
|
||||
int measure_status;
|
||||
struct timeval check, stop, wait;
|
||||
|
||||
if (slvcount > 0) {
|
||||
if (trace)
|
||||
fprintf(fd, "measurements starting at %s\n", date());
|
||||
(void)gettimeofday(&check, NULL);
|
||||
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, NULL);
|
||||
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, NULL);
|
||||
}
|
||||
}
|
||||
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(void)
|
||||
{
|
||||
struct hosttbl *htp;
|
||||
struct tsp to;
|
||||
struct tsp *answer;
|
||||
struct timeval tmptv;
|
||||
|
||||
/* 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(&tmptv, NULL);
|
||||
to.tsp_time.tv_sec = tmptv.tv_sec;
|
||||
to.tsp_time.tv_usec = tmptv.tv_usec;
|
||||
answer = acksend(&to, &htp->addr, htp->name,
|
||||
TSP_ACK, 0, htp->noanswer);
|
||||
if (answer == NULL) {
|
||||
/* 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(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 ((time_t)(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(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(char *name, struct sockaddr_in *addr, struct netinfo *ntp)
|
||||
{
|
||||
struct hosttbl *ret, *p, *b, *f;
|
||||
|
||||
ret = findhost(name);
|
||||
if (ret == NULL) {
|
||||
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)strlcpy(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(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 = NULL;
|
||||
lasthfree->l_fwd = NULL;
|
||||
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(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(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, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
newslave(struct tsp *msg)
|
||||
{
|
||||
struct hosttbl *htp;
|
||||
struct tsp *answer, to;
|
||||
struct timeval now, tmptv;
|
||||
|
||||
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, NULL);
|
||||
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(&tmptv, NULL);
|
||||
to.tsp_time.tv_sec = tmptv.tv_sec;
|
||||
to.tsp_time.tv_usec = tmptv.tv_usec;
|
||||
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(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(void)
|
||||
{
|
||||
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(char *msg)
|
||||
{
|
||||
get_goodgroup(1);
|
||||
setstatus();
|
||||
prthp(CLK_TCK);
|
||||
if (trace) {
|
||||
fprintf(fd, msg, date());
|
||||
(void)fclose(fd);
|
||||
fd = NULL;
|
||||
}
|
||||
#ifdef GPROF
|
||||
moncontrol(0);
|
||||
_mcleanup();
|
||||
moncontrol(1);
|
||||
#endif
|
||||
trace = OFF;
|
||||
}
|
@ -1,338 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* 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. 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[] =
|
||||
"$FreeBSD$";
|
||||
#endif /* not lint */
|
||||
|
||||
#include "globals.h"
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_icmp.h>
|
||||
|
||||
#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.
|
||||
* maxmsec wait this many msec at most
|
||||
* wmsec msec to wait for an answer
|
||||
* print print complaints on stderr
|
||||
*/
|
||||
int /* status val defined in globals.h */
|
||||
measure(u_long maxmsec, u_long wmsec, char *hname, struct sockaddr_in *addr, int print)
|
||||
{
|
||||
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;
|
||||
trials = 0;
|
||||
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);
|
||||
|
||||
(void)gettimeofday(&tdone, NULL);
|
||||
mstotvround(&tout, maxmsec);
|
||||
timevaladd(&tdone, &tout); /* when we give up */
|
||||
|
||||
mstotvround(&twait, wmsec);
|
||||
|
||||
rcvcount = 0;
|
||||
while (rcvcount < MSGS) {
|
||||
(void)gettimeofday(&tcur, NULL);
|
||||
|
||||
/*
|
||||
* keep sending until we have sent the max
|
||||
*/
|
||||
if (trials < TRIALS) {
|
||||
trials++;
|
||||
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, NULL);
|
||||
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)
|
||||
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(struct timeval *res, long x)
|
||||
{
|
||||
if (x < 0)
|
||||
x = -((-x + 3)/5);
|
||||
else
|
||||
x = (x+3)/5;
|
||||
x *= 5;
|
||||
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(struct timeval *tv1, struct timeval *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(struct timeval *res, struct timeval *tv1, struct timeval *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;
|
||||
}
|
||||
}
|
@ -1,262 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* 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. 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
|
||||
static const char rcsid[] =
|
||||
"$FreeBSD$";
|
||||
#endif /* not lint */
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
static long median(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(void)
|
||||
{
|
||||
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 %td 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 <<Numerical Recipes>>.
|
||||
*/
|
||||
static long
|
||||
median(float a, float *eps_ptr, long *x, long *xlim, unsigned int 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;
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* 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. 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.
|
||||
*
|
||||
* @(#)pathnames.h 8.1 (Berkeley) 6/6/93
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <paths.h>
|
||||
|
||||
#define _PATH_MASTERLOG "/var/log/timed.masterlog"
|
||||
#define _PATH_TIMEDLOG "/var/log/timed.log"
|
@ -1,504 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* 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. 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
|
||||
static const char rcsid[] =
|
||||
"$FreeBSD$";
|
||||
#endif /* not lint */
|
||||
|
||||
#define TSPTYPES
|
||||
#include "globals.h"
|
||||
|
||||
/*
|
||||
* 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(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;
|
||||
ssize_t n;
|
||||
|
||||
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 != NULL) {
|
||||
length = 1;
|
||||
for (ptr = head->p; ptr != NULL; 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, NULL);
|
||||
timevaladd(&rtout, intvl);
|
||||
FD_ZERO(&ready);
|
||||
for (;;) {
|
||||
(void)gettimeofday(&rtime, NULL);
|
||||
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 %jd.%6ld at %s\n",
|
||||
(intmax_t)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 ((n = recvfrom(sock, (char *)&msgin, sizeof(struct tsp), 0,
|
||||
(struct sockaddr*)&from, &length)) < 0) {
|
||||
syslog(LOG_ERR, "recvfrom: %m");
|
||||
exit(1);
|
||||
}
|
||||
/*
|
||||
* The 4.3BSD protocol spec had a 32-byte tsp_name field, and
|
||||
* this is still OS-dependent. Demand that the packet is at
|
||||
* least long enough to hold a 4.3BSD packet.
|
||||
*/
|
||||
if (n < (ssize_t)(sizeof(struct tsp) - MAXHOSTNAMELEN + 32)) {
|
||||
syslog(LOG_NOTICE,
|
||||
"short packet (%zd/%zu bytes) from %s",
|
||||
n, sizeof(struct tsp) - MAXHOSTNAMELEN + 32,
|
||||
inet_ntoa(from.sin_addr));
|
||||
continue;
|
||||
}
|
||||
(void)gettimeofday(&from_when, NULL);
|
||||
bytehostorder(&msgin);
|
||||
|
||||
if (msgin.tsp_vers > TSPVERSION) {
|
||||
if (trace) {
|
||||
fprintf(fd,"readmsg: version mismatch\n");
|
||||
/* should do a dump of the packet */
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (memchr(msgin.tsp_name,
|
||||
'\0', sizeof msgin.tsp_name) == NULL) {
|
||||
syslog(LOG_NOTICE, "hostname field not NUL terminated "
|
||||
"in packet from %s", inet_ntoa(from.sin_addr));
|
||||
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(void)
|
||||
{
|
||||
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(void)
|
||||
{
|
||||
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(void)
|
||||
{
|
||||
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(struct tsp *msg, struct sockaddr_in *addr)
|
||||
{
|
||||
char tm[26];
|
||||
time_t tsp_time_sec;
|
||||
|
||||
if (msg->tsp_type >= TSPTYPENUMBER) {
|
||||
fprintf(fd, "bad type (%u) on packet from %s\n",
|
||||
msg->tsp_type, inet_ntoa(addr->sin_addr));
|
||||
return;
|
||||
}
|
||||
|
||||
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:
|
||||
tsp_time_sec = msg->tsp_time.tv_sec;
|
||||
strncpy(tm, ctime(&tsp_time_sec)+3+1, sizeof(tm));
|
||||
tm[15] = '\0'; /* ugh */
|
||||
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 (%d,%d) %-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;
|
||||
}
|
||||
}
|
@ -1,695 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* 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. 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[] =
|
||||
"$FreeBSD$";
|
||||
#endif /* not lint */
|
||||
|
||||
#include "globals.h"
|
||||
#include <setjmp.h>
|
||||
#include <utmpx.h>
|
||||
#include "pathnames.h"
|
||||
|
||||
extern jmp_buf jmpenv;
|
||||
extern int Mflag;
|
||||
extern int justquit;
|
||||
|
||||
extern u_short sequence;
|
||||
|
||||
static char master_name[MAXHOSTNAMELEN];
|
||||
static struct netinfo *old_slavenet;
|
||||
static int old_status;
|
||||
|
||||
static void schgdate(struct tsp *, char *);
|
||||
static void setmaster(struct tsp *);
|
||||
static void answerdelay(void);
|
||||
|
||||
void
|
||||
slave(void)
|
||||
{
|
||||
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, tmptv;
|
||||
time_t tsp_time_sec;
|
||||
struct tsp *answer;
|
||||
int timeout();
|
||||
char olddate[32];
|
||||
char newdate[32];
|
||||
struct netinfo *ntp;
|
||||
struct hosttbl *htp;
|
||||
struct utmpx utx;
|
||||
|
||||
|
||||
old_slavenet = NULL;
|
||||
seq = 0;
|
||||
refusetime = 0;
|
||||
adjtime = 0;
|
||||
|
||||
(void)gettimeofday(&ntime, NULL);
|
||||
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, NULL);
|
||||
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, NULL);
|
||||
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, NULL);
|
||||
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, NULL);
|
||||
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, NULL);
|
||||
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, NULL);
|
||||
adj_msg_time(msg,&otime);
|
||||
/*
|
||||
* the following line is necessary due to syslog
|
||||
* calling ctime() which clobbers the static buffer
|
||||
*/
|
||||
(void)strlcpy(olddate, date(), sizeof(olddate));
|
||||
tsp_time_sec = msg->tsp_time.tv_sec;
|
||||
(void)strlcpy(newdate, ctime(&tsp_time_sec),
|
||||
sizeof(newdate));
|
||||
|
||||
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);
|
||||
tmptv.tv_sec = msg->tsp_time.tv_sec;
|
||||
tmptv.tv_usec = msg->tsp_time.tv_usec;
|
||||
timevalsub(&ntime, &tmptv, &otime);
|
||||
if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) {
|
||||
/*
|
||||
* do not change the clock if we can adjust it
|
||||
*/
|
||||
synch(tvtomsround(ntime));
|
||||
} else {
|
||||
utx.ut_type = OLD_TIME;
|
||||
gettimeofday(&utx.ut_tv, NULL);
|
||||
pututxline(&utx);
|
||||
(void)settimeofday(&tmptv, 0);
|
||||
utx.ut_type = NEW_TIME;
|
||||
gettimeofday(&utx.ut_tv, NULL);
|
||||
pututxline(&utx);
|
||||
syslog(LOG_NOTICE,
|
||||
"date changed by %s from %s",
|
||||
msg->tsp_name, olddate);
|
||||
if (status & MASTER)
|
||||
spreadtime();
|
||||
}
|
||||
(void)gettimeofday(&ntime, NULL);
|
||||
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, NULL);
|
||||
electiontime = ntime.tv_sec + delay2;
|
||||
fastelection = ntime.tv_sec + FASTTOUT;
|
||||
refusetime = 0;
|
||||
break;
|
||||
|
||||
case TSP_MASTERREQ:
|
||||
if (fromnet->status != SLAVE)
|
||||
break;
|
||||
(void)gettimeofday(&ntime, NULL);
|
||||
electiontime = ntime.tv_sec + delay2;
|
||||
break;
|
||||
|
||||
case TSP_SETDATE:
|
||||
tsp_time_sec = msg->tsp_time.tv_sec;
|
||||
(void)strlcpy(newdate, ctime(&tsp_time_sec),
|
||||
sizeof(newdate));
|
||||
schgdate(msg, newdate);
|
||||
break;
|
||||
|
||||
case TSP_SETDATEREQ:
|
||||
if (fromnet->status != MASTER)
|
||||
break;
|
||||
tsp_time_sec = msg->tsp_time.tv_sec;
|
||||
(void)strlcpy(newdate, ctime(&tsp_time_sec),
|
||||
sizeof(newdate));
|
||||
htp = findhost(msg->tsp_name);
|
||||
if (htp == NULL) {
|
||||
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, NULL);
|
||||
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) {
|
||||
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, NULL);
|
||||
looptime = ntime.tv_sec + FASTTOUT;
|
||||
} else {
|
||||
if (msg->tsp_hopcnt-- < 1)
|
||||
break;
|
||||
bytenetorder(msg);
|
||||
for (ntp = nettab; ntp != NULL; 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, NULL);
|
||||
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(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(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, NULL);
|
||||
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(void)
|
||||
{
|
||||
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;
|
||||
}
|
@ -1,288 +0,0 @@
|
||||
.\" 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. 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
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd February 11, 2008
|
||||
.Dt TIMED 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm timed
|
||||
.Nd time server daemon
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl dtM
|
||||
.Op Fl i Ar network | Fl n Ar network
|
||||
.Op Fl F Ar host ...
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility is a time server daemon
|
||||
which is normally invoked at boot time from the
|
||||
.Xr rc.conf 5
|
||||
file.
|
||||
It synchronizes the host's time with the time of other
|
||||
machines, which are also running
|
||||
.Nm ,
|
||||
in a local area network.
|
||||
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 following options are available:
|
||||
.Bl -tag -width indent
|
||||
.It Fl d
|
||||
Enable debugging mode;
|
||||
do not detach from the terminal.
|
||||
.It Fl i Ar network
|
||||
Add
|
||||
.Ar network
|
||||
to the list of networks to ignore.
|
||||
All other networks
|
||||
to which the machine is directly connected
|
||||
are used by
|
||||
.Nm .
|
||||
This option may be specified multiple times
|
||||
to add more than one network to the list.
|
||||
.It Fl F Ar host ...
|
||||
.Bl -dash -compact
|
||||
.It
|
||||
Create a list of trusted hosts.
|
||||
.It
|
||||
Can take one or more parameters.
|
||||
.It
|
||||
.Nm
|
||||
will only accept trusted hosts as masters.
|
||||
If it finds an untrusted host claiming to be master,
|
||||
.Nm
|
||||
will suppress incoming messages from that host
|
||||
and call for a new election.
|
||||
.It
|
||||
Use real host names (resolvable by RDNS) not aliases (eg in
|
||||
.Xr named 8
|
||||
parlance: use A names, not C names).
|
||||
.It
|
||||
Use full names eg time1.domain.com not time1.
|
||||
.It
|
||||
.Fl F
|
||||
automatically includes the functionality of
|
||||
.Fl M
|
||||
(so
|
||||
.Fl M
|
||||
does not need to asserted).
|
||||
.It
|
||||
If
|
||||
.Fl F
|
||||
is not specified,
|
||||
all hosts on connected networks are treated as trustworthy.
|
||||
.El
|
||||
.It Fl M
|
||||
Allow this host to become a
|
||||
.Nm
|
||||
master if necessary.
|
||||
.It Fl n Ar network
|
||||
Add
|
||||
.Ar network
|
||||
to the list of allowed networks.
|
||||
All other networks
|
||||
to which the machine is directly connected
|
||||
are ignored by
|
||||
.Nm .
|
||||
This option may be specified multiple times
|
||||
to add more than one network to the list.
|
||||
.It Fl t
|
||||
Enable tracing of received messages
|
||||
and log to the file
|
||||
.Pa /var/log/timed.log .
|
||||
Tracing can be turned on or off while
|
||||
.Nm
|
||||
is running with the
|
||||
.Xr timedc 8
|
||||
utility.
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Fl n
|
||||
and
|
||||
.Fl i
|
||||
flags are mutually exclusive
|
||||
and require as arguments real networks to which
|
||||
the host is connected
|
||||
(see
|
||||
.Xr networks 5 ) .
|
||||
If neither flag is specified,
|
||||
.Nm
|
||||
will listen on all connected networks.
|
||||
.Pp
|
||||
A
|
||||
.Nm
|
||||
running without the
|
||||
.Fl M
|
||||
nor
|
||||
.Fl F
|
||||
flags will always remain a slave.
|
||||
If the
|
||||
.Fl F
|
||||
flag is not used,
|
||||
.Nm
|
||||
will treat all machines as trustworthy.
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
utility is based on a master-slave
|
||||
scheme.
|
||||
When
|
||||
.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
|
||||
.Nm
|
||||
control utility.
|
||||
If the machine running the master becomes unreachable,
|
||||
the slaves will elect a new master
|
||||
from among those slaves
|
||||
which are running with at least one of the
|
||||
.Fl M
|
||||
and
|
||||
.Fl F
|
||||
flags.
|
||||
.Pp
|
||||
At startup
|
||||
.Nm
|
||||
normally 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.
|
||||
It will request synchronization service from the first master server
|
||||
located.
|
||||
If permitted by the
|
||||
.Fl M
|
||||
or
|
||||
.Fl F
|
||||
flags, it will provide synchronization service on any attached networks
|
||||
on which no trusted master server was detected.
|
||||
Such a server propagates the time computed by the top-level master.
|
||||
The
|
||||
.Nm
|
||||
utility will periodically check for the presence of a master
|
||||
on those networks for which it is operating as a slave.
|
||||
If it finds that there are no trusted masters on a network,
|
||||
it will begin the election process on that network.
|
||||
.Pp
|
||||
One way to synchronize a group of machines is to use
|
||||
.Xr ntpd 8
|
||||
to
|
||||
synchronize the clock of one machine to a distant standard or a radio
|
||||
receiver and
|
||||
.Fl F Ar hostname
|
||||
to tell its
|
||||
.Nm
|
||||
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
|
||||
.Dq 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 WARNINGS
|
||||
Temporal chaos will result if two or more time daemons attempt
|
||||
to adjust the same clock.
|
||||
If both
|
||||
.Nm
|
||||
and another time daemon are run on the same machine,
|
||||
ensure that the
|
||||
.Fl F
|
||||
flag is used, so that
|
||||
.Nm
|
||||
never attempts to adjust the local clock.
|
||||
.Pp
|
||||
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
|
||||
.Dq 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
|
||||
.Nm
|
||||
.It Pa /var/log/timed.masterlog
|
||||
log file for master
|
||||
.Nm
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr date 1 ,
|
||||
.Xr adjtime 2 ,
|
||||
.Xr gettimeofday 2 ,
|
||||
.Xr icmp 4 ,
|
||||
.Xr networks 5 ,
|
||||
.Xr ntpd 8 ,
|
||||
.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
|
||||
utility appeared in
|
||||
.Bx 4.3 .
|
@ -1,832 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* 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. 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 const char copyright[] =
|
||||
"@(#) Copyright (c) 1985, 1993\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#if 0
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)timed.c 8.1 (Berkeley) 6/6/93";
|
||||
#endif /* not lint */
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "globals.h"
|
||||
#include <net/if.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <setjmp.h>
|
||||
#include "pathnames.h"
|
||||
#include <math.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/times.h>
|
||||
|
||||
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 = NULL;
|
||||
struct netinfo *slavenet;
|
||||
int Mflag;
|
||||
int justquit = 0;
|
||||
int debug;
|
||||
|
||||
static struct nets {
|
||||
char *name;
|
||||
long net;
|
||||
struct nets *next;
|
||||
} *nets = NULL;
|
||||
|
||||
struct hosttbl hosttbl[NHOSTS+1]; /* known hosts */
|
||||
|
||||
static struct goodhost { /* hosts that we trust */
|
||||
char name[MAXHOSTNAMELEN];
|
||||
struct goodhost *next;
|
||||
char perm;
|
||||
} *goodhosts;
|
||||
|
||||
static char *goodgroup; /* net group of trusted hosts */
|
||||
static void checkignorednets(void);
|
||||
static void pickslavenet(struct netinfo *);
|
||||
static void add_good_host(char *, int);
|
||||
static void usage(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(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;
|
||||
int c;
|
||||
|
||||
#ifdef lint
|
||||
ntip = NULL;
|
||||
#endif
|
||||
|
||||
on = 1;
|
||||
nflag = OFF;
|
||||
iflag = OFF;
|
||||
|
||||
|
||||
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) {
|
||||
errx(1, "-i and -n make no sense together");
|
||||
} else {
|
||||
nflag = ON;
|
||||
addnetname(optarg);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
if (nflag) {
|
||||
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 != NULL)
|
||||
errx(1, "only one net group");
|
||||
goodgroup = optarg;
|
||||
break;
|
||||
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (optind < argc)
|
||||
usage();
|
||||
|
||||
/* If we care about which machine is the master, then we must
|
||||
* be willing to be a master
|
||||
*/
|
||||
if (goodgroup != NULL || goodhosts != NULL)
|
||||
Mflag = 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 != NULL) /* trust ourself */
|
||||
add_good_host(hostname,1);
|
||||
|
||||
srvp = getservbyname("timed", "udp");
|
||||
if (srvp == NULL)
|
||||
errx(1, "timed/udp: unknown service");
|
||||
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)
|
||||
err(1, "socket");
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on,
|
||||
sizeof(on)) < 0)
|
||||
err(1, "setsockopt");
|
||||
if (bind(sock, (struct sockaddr*)&server, sizeof(server))) {
|
||||
if (errno == EADDRINUSE)
|
||||
warnx("time daemon already running");
|
||||
else
|
||||
warn("bind");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sequence = arc4random(); /* initial seq number */
|
||||
|
||||
(void)gettimeofday(&ntime, NULL);
|
||||
/* 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);
|
||||
|
||||
for (nt = nets; nt; nt = nt->next) {
|
||||
nentp = getnetbyname(nt->name);
|
||||
if (nentp == NULL) {
|
||||
nt->net = inet_network(nt->name);
|
||||
if (nt->net != INADDR_NONE)
|
||||
nentp = getnetbyaddr(nt->net, AF_INET);
|
||||
}
|
||||
if (nentp != NULL) {
|
||||
nt->net = nentp->n_net;
|
||||
} else if (nt->net == INADDR_NONE) {
|
||||
errx(1, "unknown net %s", nt->name);
|
||||
} else if (nt->net == INADDR_ANY) {
|
||||
errx(1, "bad net %s", nt->name);
|
||||
} else {
|
||||
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)
|
||||
err(1, "get interface configuration");
|
||||
ntp = NULL;
|
||||
#define size(p) max((p).sa_len, sizeof(p))
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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))
|
||||
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)
|
||||
errx(1, "no network usable");
|
||||
|
||||
/* microseconds to delay before responding to a broadcast */
|
||||
delay1 = casual(1, 100*1000);
|
||||
|
||||
/* election timer delay in secs. */
|
||||
delay2 = casual(MINTOUT, MAXTOUT);
|
||||
|
||||
if (!debug)
|
||||
daemon(debug, 0);
|
||||
|
||||
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 != NULL)
|
||||
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 */
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
#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 */
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* suppress an upstart, untrustworthy, self-appointed master
|
||||
*/
|
||||
void
|
||||
suppress(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)strlcpy(tname, name, sizeof(tname));
|
||||
|
||||
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(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 != NULL && !good_host_name(answer->tsp_name)) {
|
||||
suppress(&from, answer->tsp_name, ntp);
|
||||
ntp->status = NOMASTER;
|
||||
answer = NULL;
|
||||
}
|
||||
if (answer == NULL) {
|
||||
/*
|
||||
* 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 != NULL) {
|
||||
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 != NULL) {
|
||||
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 != NULL) {
|
||||
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(void)
|
||||
{
|
||||
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=%ld\n",
|
||||
nnets, nmasternets, nslavenets, nignorednets, delay2);
|
||||
}
|
||||
|
||||
void
|
||||
makeslave(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(void)
|
||||
{
|
||||
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(struct netinfo *ntp)
|
||||
{
|
||||
if (slavenet != NULL && slavenet->status == SLAVE) {
|
||||
makeslave(slavenet); /* prune extras */
|
||||
return;
|
||||
}
|
||||
|
||||
if (ntp == NULL || ntp->status != SLAVE) {
|
||||
for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
|
||||
if (ntp->status == SLAVE)
|
||||
break;
|
||||
}
|
||||
}
|
||||
makeslave(ntp);
|
||||
}
|
||||
|
||||
/*
|
||||
* returns a random number in the range [inf, sup]
|
||||
*/
|
||||
long
|
||||
casual(long inf, long sup)
|
||||
{
|
||||
double value;
|
||||
|
||||
value = ((double)(random() & 0x7fffffff)) / (0x7fffffff*1.0);
|
||||
return(inf + (sup - inf)*value);
|
||||
}
|
||||
|
||||
char *
|
||||
date(void)
|
||||
{
|
||||
time_t tv_sec;
|
||||
|
||||
tv_sec = time(NULL);
|
||||
return (ctime(&tv_sec));
|
||||
}
|
||||
|
||||
void
|
||||
addnetname(char *name)
|
||||
{
|
||||
register struct nets **netlist = &nets;
|
||||
|
||||
while (*netlist)
|
||||
netlist = &((*netlist)->next);
|
||||
*netlist = (struct nets *)malloc(sizeof **netlist);
|
||||
if (*netlist == NULL)
|
||||
errx(1, "malloc failed");
|
||||
bzero((char *)*netlist, sizeof(**netlist));
|
||||
(*netlist)->name = name;
|
||||
}
|
||||
|
||||
/* note a host as trustworthy
|
||||
* perm 1=not part of the netgroup
|
||||
*/
|
||||
static void
|
||||
add_good_host(char *name, int perm)
|
||||
{
|
||||
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 (hentp == NULL && perm)
|
||||
warnx("unknown host %s", name);
|
||||
}
|
||||
|
||||
|
||||
/* update our image of the net-group of trustworthy hosts
|
||||
*/
|
||||
void
|
||||
get_goodgroup(int force)
|
||||
{
|
||||
# define NG_DELAY (30*60*CLK_TCK) /* 30 minutes */
|
||||
static unsigned long last_update = -NG_DELAY;
|
||||
unsigned long new_update;
|
||||
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 == NULL || !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 ((ghp = *ghpp) != NULL) {
|
||||
if (!ghp->perm) {
|
||||
*ghpp = ghp->next;
|
||||
free(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 (mach != NULL)
|
||||
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(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 ((ghp = ghp->next) != NULL);
|
||||
|
||||
if (!strcasecmp(name,hostname)) /* trust ourself */
|
||||
return 1;
|
||||
|
||||
return 0; /* did not find him */
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
# @(#)Makefile 8.1 (Berkeley) 6/6/93
|
||||
# $FreeBSD$
|
||||
|
||||
.PATH: ${.CURDIR:H}/timed
|
||||
|
||||
PROG= timedc
|
||||
MAN= timedc.8
|
||||
SRCS= cmds.c cmdtab.c timedc.c byteorder.c measure.c cksum.c
|
||||
BINOWN= root
|
||||
BINMODE= 4555
|
||||
|
||||
WARNS?= 1
|
||||
|
||||
.include "../../Makefile.inc"
|
||||
.include <bsd.prog.mk>
|
@ -1,19 +0,0 @@
|
||||
# $FreeBSD$
|
||||
# Autogenerated - do NOT edit!
|
||||
|
||||
DIRDEPS = \
|
||||
gnu/lib/csu \
|
||||
include \
|
||||
include/arpa \
|
||||
include/protocols \
|
||||
include/xlocale \
|
||||
lib/${CSU_DIR} \
|
||||
lib/libc \
|
||||
lib/libcompiler_rt \
|
||||
|
||||
|
||||
.include <dirdeps.mk>
|
||||
|
||||
.if ${DEP_RELDIR} == ${_DEP_RELDIR}
|
||||
# local dependencies - needed for -jN in clean tree
|
||||
.endif
|
@ -1,544 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* 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. 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.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)cmds.c 8.1 (Berkeley) 6/6/93";
|
||||
#endif /* not lint */
|
||||
#endif
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "timedc.h"
|
||||
#include <sys/file.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_icmp.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define TSPTYPES
|
||||
#include <protocols/timed.h>
|
||||
|
||||
#define SECHR (60*60)
|
||||
#define SECDAY (24*SECHR)
|
||||
|
||||
# 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(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) {
|
||||
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)
|
||||
continue;
|
||||
warn("select(date read)");
|
||||
return 0;
|
||||
}
|
||||
if (0 == i)
|
||||
break;
|
||||
|
||||
fromlen = sizeof(from);
|
||||
if (recvfrom(sock,&sec,sizeof(sec),0,
|
||||
&from,&fromlen) < 0) {
|
||||
warn("recvfrom(date read)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
sec = ntohl(sec);
|
||||
if (sec < BU) {
|
||||
warnx("%s says it is before 1970: %lu",
|
||||
hostname, sec);
|
||||
return 0;
|
||||
}
|
||||
sec -= BU;
|
||||
|
||||
(void)gettimeofday(&now, NULL);
|
||||
return (sec - now.tv_sec);
|
||||
}
|
||||
}
|
||||
|
||||
/* if we get here, we tried too many times */
|
||||
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(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: timedc clockdiff host ...\n");
|
||||
return;
|
||||
}
|
||||
|
||||
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) {
|
||||
warnx("%s/%s: 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) {
|
||||
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 transmits 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(int argc, char *argv[])
|
||||
{
|
||||
ssize_t cc;
|
||||
fd_set ready;
|
||||
struct sockaddr_in dest;
|
||||
int i, length;
|
||||
struct sockaddr_in from;
|
||||
struct timeval tout;
|
||||
struct tsp msg;
|
||||
struct servent *srvp;
|
||||
char *tgtname;
|
||||
|
||||
if (argc < 1) {
|
||||
printf("usage: timedc msite [host ...]\n");
|
||||
return;
|
||||
}
|
||||
|
||||
srvp = getservbyname("timed", "udp");
|
||||
if (srvp == NULL) {
|
||||
warnx("timed/udp: unknown service");
|
||||
return;
|
||||
}
|
||||
dest.sin_port = srvp->s_port;
|
||||
dest.sin_family = AF_INET;
|
||||
|
||||
if (gethostname(myname, sizeof(myname) - 1) < 0)
|
||||
err(1, "gethostname");
|
||||
i = 1;
|
||||
do {
|
||||
tgtname = (i >= argc) ? myname : argv[i];
|
||||
hp = gethostbyname(tgtname);
|
||||
if (hp == NULL) {
|
||||
warnx("%s: %s", tgtname, hstrerror(h_errno));
|
||||
continue;
|
||||
}
|
||||
bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
|
||||
|
||||
(void)strlcpy(msg.tsp_name, myname, sizeof(msg.tsp_name));
|
||||
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) {
|
||||
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(from);
|
||||
cc = recvfrom(sock, &msg, sizeof(struct tsp), 0,
|
||||
(struct sockaddr *)&from, &length);
|
||||
if (cc < 0) {
|
||||
warn("recvfrom");
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* The 4.3BSD protocol spec had a 32-byte tsp_name field, and
|
||||
* this is still OS-dependent. Demand that the packet is at
|
||||
* least long enough to hold a 4.3BSD packet.
|
||||
*/
|
||||
if (cc < (sizeof(struct tsp) - MAXHOSTNAMELEN + 32)) {
|
||||
fprintf(stderr,
|
||||
"short packet (%zd/%zu bytes) from %s\n",
|
||||
cc, sizeof(struct tsp) - MAXHOSTNAMELEN + 32,
|
||||
inet_ntoa(from.sin_addr));
|
||||
continue;
|
||||
}
|
||||
bytehostorder(&msg);
|
||||
if (msg.tsp_type == TSP_ACK) {
|
||||
printf("master timedaemon at %s is %s\n",
|
||||
tgtname, msg.tsp_name);
|
||||
} else {
|
||||
if (msg.tsp_type >= TSPTYPENUMBER)
|
||||
printf("unknown ack received: %u\n",
|
||||
msg.tsp_type);
|
||||
else
|
||||
printf("wrong ack received: %s\n",
|
||||
tsptype[msg.tsp_type]);
|
||||
}
|
||||
} else {
|
||||
printf("communication error with %s\n", tgtname);
|
||||
}
|
||||
} while (++i < argc);
|
||||
}
|
||||
|
||||
/*
|
||||
* quits timedc
|
||||
*/
|
||||
void
|
||||
quit(void)
|
||||
{
|
||||
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(int argc, char *argv[])
|
||||
{
|
||||
struct servent *srvp;
|
||||
struct sockaddr_in sin;
|
||||
struct tsp msg;
|
||||
|
||||
if (argc < 2) {
|
||||
printf("usage: timedc election host1 [host2 ...]\n");
|
||||
return;
|
||||
}
|
||||
|
||||
srvp = getservbyname("timed", "udp");
|
||||
if (srvp == NULL) {
|
||||
warnx("timed/udp: unknown service");
|
||||
return;
|
||||
}
|
||||
|
||||
while (argc > 1) {
|
||||
argc--; argv++;
|
||||
hp = gethostbyname(*argv);
|
||||
if (hp == NULL) {
|
||||
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;
|
||||
if (gethostname(myname, sizeof(myname) - 1) < 0)
|
||||
err(1, "gethostname");
|
||||
(void)strlcpy(msg.tsp_name, myname, sizeof(msg.tsp_name));
|
||||
bytenetorder(&msg);
|
||||
if (sendto(sock, &msg, sizeof(struct tsp), 0,
|
||||
(struct sockaddr*)&sin,
|
||||
sizeof(struct sockaddr)) < 0) {
|
||||
warn("sendto");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Enables or disables tracing on local timedaemon
|
||||
*/
|
||||
void
|
||||
tracing(int argc, char *argv[])
|
||||
{
|
||||
int onflag;
|
||||
int length;
|
||||
ssize_t cc;
|
||||
fd_set ready;
|
||||
struct sockaddr_in dest;
|
||||
struct sockaddr_in from;
|
||||
struct timeval tout;
|
||||
struct tsp msg;
|
||||
struct servent *srvp;
|
||||
|
||||
if (argc != 2) {
|
||||
printf("usage: timedc trace { on | off }\n");
|
||||
return;
|
||||
}
|
||||
|
||||
srvp = getservbyname("timed", "udp");
|
||||
if (srvp == NULL) {
|
||||
warnx("timed/udp: unknown service");
|
||||
return;
|
||||
}
|
||||
dest.sin_port = srvp->s_port;
|
||||
dest.sin_family = AF_INET;
|
||||
|
||||
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) {
|
||||
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(from);
|
||||
cc = recvfrom(sock, &msg, sizeof(struct tsp), 0,
|
||||
(struct sockaddr *)&from, &length);
|
||||
if (cc < 0) {
|
||||
warn("recvfrom");
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* The 4.3BSD protocol spec had a 32-byte tsp_name field, and
|
||||
* this is still OS-dependent. Demand that the packet is at
|
||||
* least long enough to hold a 4.3BSD packet.
|
||||
*/
|
||||
if (cc < (sizeof(struct tsp) - MAXHOSTNAMELEN + 32)) {
|
||||
fprintf(stderr, "short packet (%zd/%zu bytes) from %s\n",
|
||||
cc, sizeof(struct tsp) - MAXHOSTNAMELEN + 32,
|
||||
inet_ntoa(from.sin_addr));
|
||||
return;
|
||||
}
|
||||
bytehostorder(&msg);
|
||||
if (msg.tsp_type == TSP_ACK)
|
||||
if (onflag)
|
||||
printf("timed tracing enabled\n");
|
||||
else
|
||||
printf("timed tracing disabled\n");
|
||||
else {
|
||||
if (msg.tsp_type >= TSPTYPENUMBER)
|
||||
printf("unknown ack received: %u\n",
|
||||
msg.tsp_type);
|
||||
else
|
||||
printf("wrong ack received: %s\n",
|
||||
tsptype[msg.tsp_type]);
|
||||
}
|
||||
} else
|
||||
printf("communication error\n");
|
||||
}
|
||||
|
||||
int
|
||||
priv_resources(void)
|
||||
{
|
||||
int port;
|
||||
struct sockaddr_in sin;
|
||||
|
||||
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sock < 0) {
|
||||
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) {
|
||||
warn("bind");
|
||||
(void) close(sock);
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
if (port == IPPORT_RESERVED / 2) {
|
||||
warnx("all reserved ports in use");
|
||||
(void) close(sock);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
|
||||
if (sock_raw < 0) {
|
||||
warn("opening raw socket");
|
||||
(void) close(sock);
|
||||
return(-1);
|
||||
}
|
||||
return(1);
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* 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. 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[] =
|
||||
"$FreeBSD$";
|
||||
#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]);
|
@ -1,52 +0,0 @@
|
||||
/* $FreeBSD$ */
|
||||
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright (c) 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. 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.
|
||||
*
|
||||
* @(#)extern.h 8.1 (Berkeley) 6/6/93
|
||||
*/
|
||||
|
||||
#if __STDC__
|
||||
struct tsp;
|
||||
#endif
|
||||
|
||||
extern struct cmd cmdtab[];
|
||||
|
||||
void bytehostorder(struct tsp *);
|
||||
void bytenetorder(struct tsp *);
|
||||
void clockdiff(int, char *[]);
|
||||
void help(int, char *[]);
|
||||
void intr(int);
|
||||
void makeargv(void);
|
||||
void msite(int, char *[]);
|
||||
int priv_resources(void);
|
||||
void quit(void);
|
||||
void testing(int, char *[]);
|
||||
void tracing(int, char *[]);
|
@ -1,141 +0,0 @@
|
||||
.\" 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. 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
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd June 6, 1993
|
||||
.Dt TIMEDC 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm timedc
|
||||
.Nd timed control program
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Ar command Op Ar argument ...
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility 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 8 ,
|
||||
and
|
||||
.It
|
||||
Perform various debugging actions.
|
||||
.El
|
||||
.Pp
|
||||
Without any arguments,
|
||||
.Nm
|
||||
will prompt for commands from the standard input.
|
||||
If arguments are supplied,
|
||||
.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
|
||||
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 8
|
||||
in the file
|
||||
.Pa /var/log/timed.log .
|
||||
.Pp
|
||||
.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 DIAGNOSTICS
|
||||
.Bl -diag
|
||||
.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 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 HISTORY
|
||||
The
|
||||
.Nm
|
||||
utility appeared in
|
||||
.Bx 4.3 .
|
@ -1,254 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* 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. 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 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[] =
|
||||
"$FreeBSD$";
|
||||
#endif /* not lint */
|
||||
|
||||
#include "timedc.h"
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int trace = 0;
|
||||
FILE *fd = NULL;
|
||||
int margc;
|
||||
int fromatty;
|
||||
#define MAX_MARGV 20
|
||||
char *margv[MAX_MARGV];
|
||||
char cmdline[200];
|
||||
jmp_buf toplevel;
|
||||
static struct cmd *getcmd(char *);
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
register struct cmd *c;
|
||||
|
||||
openlog("timedc", 0, LOG_AUTH);
|
||||
|
||||
/*
|
||||
* security dictates!
|
||||
*/
|
||||
if (priv_resources() < 0)
|
||||
errx(1, "could not get privileged resources");
|
||||
if (setuid(getuid()) != 0)
|
||||
err(1, "setuid()");
|
||||
|
||||
if (--argc > 0) {
|
||||
c = getcmd(*++argv);
|
||||
if (c == (struct cmd *)-1) {
|
||||
printf("?Ambiguous command\n");
|
||||
exit(1);
|
||||
}
|
||||
if (c == NULL) {
|
||||
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) == NULL)
|
||||
quit();
|
||||
if (cmdline[0] == 0)
|
||||
break;
|
||||
makeargv();
|
||||
if (margv[0] == NULL)
|
||||
continue;
|
||||
c = getcmd(margv[0]);
|
||||
if (c == (struct cmd *)-1) {
|
||||
printf("?Ambiguous command\n");
|
||||
continue;
|
||||
}
|
||||
if (c == NULL) {
|
||||
printf("?Invalid command\n");
|
||||
continue;
|
||||
}
|
||||
if (c->c_priv && getuid()) {
|
||||
printf("?Privileged command\n");
|
||||
continue;
|
||||
}
|
||||
(*c->c_handler)(margc, margv);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
intr(int signo __unused)
|
||||
{
|
||||
if (!fromatty)
|
||||
exit(0);
|
||||
longjmp(toplevel, 1);
|
||||
}
|
||||
|
||||
|
||||
static struct cmd *
|
||||
getcmd(char *name)
|
||||
{
|
||||
register char *p, *q;
|
||||
register struct cmd *c, *found;
|
||||
register int nmatches, longest;
|
||||
extern int NCMDS;
|
||||
|
||||
longest = 0;
|
||||
nmatches = 0;
|
||||
found = NULL;
|
||||
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(void)
|
||||
{
|
||||
register char *cp;
|
||||
register char **argp = margv;
|
||||
|
||||
margc = 0;
|
||||
for (cp = cmdline; margc < MAX_MARGV - 1 && *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++ = NULL;
|
||||
}
|
||||
|
||||
#define HELPINDENT (sizeof ("directory"))
|
||||
|
||||
/*
|
||||
* Help command.
|
||||
*/
|
||||
void
|
||||
help(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);
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* 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. 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
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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"
|
Loading…
Reference in New Issue
Block a user