summaryrefslogtreecommitdiffstats
path: root/usr.sbin/timed
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/timed')
-rw-r--r--usr.sbin/timed/Makefile5
-rw-r--r--usr.sbin/timed/SMM.doc/timed/Makefile11
-rw-r--r--usr.sbin/timed/SMM.doc/timed/date53
-rw-r--r--usr.sbin/timed/SMM.doc/timed/loop54
-rw-r--r--usr.sbin/timed/SMM.doc/timed/spell.ok34
-rw-r--r--usr.sbin/timed/SMM.doc/timed/time53
-rw-r--r--usr.sbin/timed/SMM.doc/timed/timed.ms504
-rw-r--r--usr.sbin/timed/SMM.doc/timed/unused53
-rw-r--r--usr.sbin/timed/SMM.doc/timedop/Makefile7
-rw-r--r--usr.sbin/timed/SMM.doc/timedop/timed.ms279
-rw-r--r--usr.sbin/timed/timed/CHANGES144
-rw-r--r--usr.sbin/timed/timed/Makefile13
-rw-r--r--usr.sbin/timed/timed/acksend.c132
-rw-r--r--usr.sbin/timed/timed/byteorder.c86
-rw-r--r--usr.sbin/timed/timed/candidate.c167
-rw-r--r--usr.sbin/timed/timed/cksum.c87
-rw-r--r--usr.sbin/timed/timed/correct.c294
-rw-r--r--usr.sbin/timed/timed/extern.h89
-rw-r--r--usr.sbin/timed/timed/globals.h186
-rw-r--r--usr.sbin/timed/timed/master.c907
-rw-r--r--usr.sbin/timed/timed/measure.c353
-rw-r--r--usr.sbin/timed/timed/networkdelta.c264
-rw-r--r--usr.sbin/timed/timed/pathnames.h44
-rw-r--r--usr.sbin/timed/timed/readmsg.c488
-rw-r--r--usr.sbin/timed/timed/slave.c715
-rw-r--r--usr.sbin/timed/timed/timed.8219
-rw-r--r--usr.sbin/timed/timed/timed.c980
-rw-r--r--usr.sbin/timed/timedc/Makefile11
-rw-r--r--usr.sbin/timed/timedc/cmds.c526
-rw-r--r--usr.sbin/timed/timedc/cmdtab.c57
-rw-r--r--usr.sbin/timed/timedc/extern.h52
-rw-r--r--usr.sbin/timed/timedc/timedc.8145
-rw-r--r--usr.sbin/timed/timedc/timedc.c261
-rw-r--r--usr.sbin/timed/timedc/timedc.h66
34 files changed, 7339 insertions, 0 deletions
diff --git a/usr.sbin/timed/Makefile b/usr.sbin/timed/Makefile
new file mode 100644
index 0000000..a89ab16
--- /dev/null
+++ b/usr.sbin/timed/Makefile
@@ -0,0 +1,5 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+SUBDIR= timed timedc
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/timed/SMM.doc/timed/Makefile b/usr.sbin/timed/SMM.doc/timed/Makefile
new file mode 100644
index 0000000..22ff6e6
--- /dev/null
+++ b/usr.sbin/timed/SMM.doc/timed/Makefile
@@ -0,0 +1,11 @@
+# @(#)Makefile 8.1 (Berkeley) 6/8/93
+
+DIR= smm/12.timed
+SRCS= timed.ms
+MACROS= -ms
+PRINTER=Pdp
+
+paper.${PRINTER}: ${SRCS}
+ ${SOELIM} ${SRCS} | ${TBL} | ${ROFF} > ${.TARGET}
+
+.include <bsd.doc.mk>
diff --git a/usr.sbin/timed/SMM.doc/timed/date b/usr.sbin/timed/SMM.doc/timed/date
new file mode 100644
index 0000000..e4e4d58
--- /dev/null
+++ b/usr.sbin/timed/SMM.doc/timed/date
@@ -0,0 +1,53 @@
+.\" Copyright (c) 1986, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)date 8.1 (Berkeley) 6/8/93
+.\"
+.ft B
+.TS
+center;
+ce | ce | ce | ce
+| c | c | c | s |
+| c s s s |.
+Byte 1 Byte 2 Byte 3 Byte 4
+=
+Type Version No. Sequence No.
+_
+Seconds of Time to Set
+_
+Microseconds of Time to Set
+_
+Machine Name
+_
+\&. . .
+_
+.TE
+.ft R
diff --git a/usr.sbin/timed/SMM.doc/timed/loop b/usr.sbin/timed/SMM.doc/timed/loop
new file mode 100644
index 0000000..11ccb4d
--- /dev/null
+++ b/usr.sbin/timed/SMM.doc/timed/loop
@@ -0,0 +1,54 @@
+.\" Copyright (c) 1986, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)loop 8.1 (Berkeley) 6/8/93
+.\"
+.ft B
+.TS
+center;
+ce | ce | ce | ce
+| c | c | c | s |
+| c | c s s |
+| c s s s |.
+Byte 1 Byte 2 Byte 3 Byte 4
+=
+Type Version No. Sequence No.
+_
+Hop Count ( unused )
+_
+( unused )
+_
+Machine Name
+_
+\&. . .
+_
+.TE
+.ft R
diff --git a/usr.sbin/timed/SMM.doc/timed/spell.ok b/usr.sbin/timed/SMM.doc/timed/spell.ok
new file mode 100644
index 0000000..8ecfe15
--- /dev/null
+++ b/usr.sbin/timed/SMM.doc/timed/spell.ok
@@ -0,0 +1,34 @@
+ACK
+ADJTIME
+Adjtime
+CS
+CSELT
+Candidature
+DATEACK
+DoD
+Gusella
+MASTERACK
+MASTERREQ
+MASTERUP
+MSITE
+MSITEREQ
+Protocol''SMM:22
+Riccardo
+SETDATE
+SETDATEREQ
+SETTIME
+SLAVEUP
+SMM:22
+Stefano
+TRACEOFF
+TRACEON
+TSP
+Timedc
+UDP
+USENIX
+Zatti
+candidature
+ce
+daemon
+daemons
+timedc
diff --git a/usr.sbin/timed/SMM.doc/timed/time b/usr.sbin/timed/SMM.doc/timed/time
new file mode 100644
index 0000000..619d171
--- /dev/null
+++ b/usr.sbin/timed/SMM.doc/timed/time
@@ -0,0 +1,53 @@
+.\" Copyright (c) 1986, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)time 8.1 (Berkeley) 6/8/93
+.\"
+.ft B
+.TS
+center;
+ce | ce | ce | ce
+| c | c | c | s |
+| c s s s |.
+Byte 1 Byte 2 Byte 3 Byte 4
+=
+Type Version No. Sequence No.
+_
+Seconds of Adjustment
+_
+Microseconds of Adjustment
+_
+Machine Name
+_
+\&. . .
+_
+.TE
+.ft R
diff --git a/usr.sbin/timed/SMM.doc/timed/timed.ms b/usr.sbin/timed/SMM.doc/timed/timed.ms
new file mode 100644
index 0000000..f5a3b19
--- /dev/null
+++ b/usr.sbin/timed/SMM.doc/timed/timed.ms
@@ -0,0 +1,504 @@
+.\" Copyright (c) 1986, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)timed.ms 8.1 (Berkeley) 6/8/93
+.\"
+.TL
+The Berkeley
+.UX
+.br
+Time Synchronization Protocol
+.AU
+Riccardo Gusella, Stefano Zatti, and James M. Bloom
+.AI
+Computer Systems Research Group
+Computer Science Division
+Department of Electrical Engineering and Computer Science
+University of California, Berkeley
+Berkeley, CA 94720
+.FS
+This work was sponsored by the Defense Advanced Research Projects Agency
+(DoD), monitored by the Naval Electronics Systems
+Command under contract No. N00039-84-C-0089, and by the Italian CSELT
+Corporation.
+The views and conclusions contained in this document are those of the
+authors and should not be interpreted as representing official policies,
+either expressed or implied, of the Defense Research Projects Agency,
+of the US Government, or of CSELT.
+.FE
+.LP
+.OH 'The Berkeley UNIX Time Synchronization Protocol''SMM:12-%'
+.EH 'SMM:12-%''The Berkeley UNIX Time Synchronization Protocol'
+.SH
+Introduction
+.PP
+The Time Synchronization Protocol (TSP)
+has been designed for specific use by the program \fItimed\fP,
+a local area network clock synchronizer for
+the UNIX 4.3BSD operating
+system.
+Timed is built on the DARPA UDP protocol [4] and
+is based on a master slave scheme.
+.PP
+TSP serves a dual purpose.
+First, it supports messages for the synchronization of the clocks
+of the various hosts in a local area network.
+Second, it supports messages for the election that occurs
+among slave time daemons when, for any reason, the master disappears.
+The synchronization mechanism and the election procedure
+employed by the program timed are described
+in other documents [1,2,3].
+.PP
+Briefly, the synchronization software, which works in a
+local area network, consists of a collection of \fItime daemons\fP
+(one per machine) and is based on a master-slave
+structure.
+The present implementation keeps processor clocks synchronized
+within 20 milliseconds.
+A \fImaster time daemon\fP measures the time
+difference between the clock of the machine on which it
+is running and those of all other machines. The current implementation
+uses ICMP \fITime Stamp Requests\fP [5] to measure the clock difference
+between machines.
+The master computes the \fInetwork time\fP as the average of the
+times provided by nonfaulty clocks.\**
+.FS
+A clock is considered to be faulty when its value
+is more than a small specified
+interval apart from the majority of the clocks
+of the machines on the same network.
+See [1,2] for more details.
+.FE
+It then sends to each \fIslave time daemon\fP the
+correction that should be performed on the clock of its machine.
+This process is repeated periodically.
+Since the correction is expressed as a time difference rather than an
+absolute time, transmission delays do not interfere with synchronization.
+When a machine comes up and joins the network,
+it starts a slave time daemon, which
+will ask the master for the correct time and will reset the machine's clock
+before any user activity can begin.
+The time daemons therefore maintain a single network time in spite of
+the drift of clocks away from each other.
+.PP
+Additionally, a time daemon on gateway machines may run as
+a \fIsubmaster\fP.
+A submaster time daemon functions as a slave on one network that
+already has a master and as master on other networks.
+In addition, a submaster is responsible for propagating broadcast
+packets from one network to the other.
+.PP
+To ensure that service provided is continuous and reliable,
+it is necessary to implement an election algorithm that will elect a
+new master should the machine running the current master crash, the master
+terminate (for example, because of a run-time error), or the network be
+partitioned.
+Under our algorithm, slaves are able to realize when the master has
+stopped functioning and to elect a new master from among themselves.
+It is important to note that since the failure of the master results
+only in a gradual divergence of clock values, the election
+need not occur immediately.
+.PP
+All the communication occurring among time daemons uses the TSP
+protocol.
+While some messages need not be sent in a reliable way,
+most communication in TSP requires reliability not provided by the underlying
+protocol.
+Reliability is achieved by the use of acknowledgements, sequence numbers, and
+retransmission when message losses occur.
+When a message that requires acknowledgment is not acknowledged after
+multiple attempts,
+the time daemon that has sent the message will assume that the
+addressee is down.
+This document will not describe the details of how reliability is
+implemented, but will only point out when
+a message type requires a reliable transport mechanism.
+.PP
+The message format in TSP is the same for all message types;
+however, in some instances, one or more fields are not used.
+The next section describes the message format.
+The following sections describe
+in detail the different message types, their use and the contents
+of each field. NOTE: The message format is likely to change in
+future versions of timed.
+.sp 2
+.SH
+Message Format
+.PP
+All fields are based upon 8-bit bytes. Fields should be sent in
+network byte order if they are more than one byte long.
+The structure of a TSP message is the following:
+.IP 1)
+A one byte message type.
+.IP 2)
+A one byte version number, specifying the protocol version which the
+message uses.
+.IP 3)
+A two byte sequence number to be used for recognizing duplicate messages
+that occur when messages are retransmitted.
+.IP 4)
+Eight bytes of packet specific data. This field contains two 4 byte time
+values, a one byte hop count, or may be unused depending on the type
+of the packet.
+.IP 5)
+A zero-terminated string of up to 256 \s-2ASCII\s+2 characters with the name of
+the machine sending the message.
+.PP
+The following charts describe the message types,
+show their fields, and explain their usages.
+For the purpose of the following discussion, a time daemon can
+be considered to be in
+one of three states: slave, master, or candidate for election to master.
+Also, the term \fIbroadcast\fP refers to
+the sending of a message to all active time daemons.
+.sp 1
+.DS L
+.SH
+Adjtime Message
+.so time
+.LP
+Type: TSP_ADJTIME (1)
+.sp 1
+.PP
+The master sends this message to a slave to communicate
+the difference between
+the clock of the slave and
+the network time the master has just computed.
+The slave will accordingly
+adjust the time of its machine.
+This message requires an acknowledgment.
+.sp 1
+.DE
+.DS L
+.SH
+Acknowledgment Message
+.so unused
+.LP
+Type: TSP_ACK (2)
+.sp 1
+.PP
+Both the master and the slaves use this message for
+acknowledgment only.
+It is used in several different contexts, for example
+in reply to an Adjtime message.
+.sp 1
+.DE
+.DS L
+.SH
+Master Request Message
+.so unused
+.LP
+Type: TSP_MASTERREQ (3)
+.sp 1
+.PP
+A newly-started time daemon broadcasts this message to
+locate a master. No other action is implied by this packet.
+It requires a Master Acknowledgment.
+.sp 1
+.DE
+.DS L
+.SH
+Master Acknowledgement
+.so unused
+.LP
+Type: TSP_MASTERACK (4)
+.sp 1
+.PP
+The master sends this message to acknowledge the Master Request message
+and the Conflict Resolution Message.
+.sp 1
+.DE
+.DS L
+.SH
+Set Network Time Message
+.so date
+.LP
+Type: TSP_SETTIME (5)
+.sp 1
+.PP
+The master sends this message to slave time daemons to set their time.
+This packet is sent to newly started time daemons and when the network
+date is changed.
+It contains the master's time as an approximation of the network time.
+It requires an acknowledgment.
+The next
+synchronization round will eliminate the small time difference
+caused by the random delay in the communication channel.
+.sp 1
+.DE
+.DS L
+.SH
+Master Active Message
+.so unused
+.LP
+Type: TSP_MASTERUP (6)
+.sp 1
+.PP
+The master broadcasts this message to
+solicit the names of the active slaves.
+Slaves will reply with a Slave Active message.
+.sp 1
+.DE
+.DS L
+.SH
+Slave Active Message
+.so unused
+.LP
+Type: TSP_SLAVEUP (7)
+.sp 1
+.PP
+A slave sends this message to the master in answer to a Master Active message.
+This message is also sent when a new slave starts up to inform the master that
+it wants to be synchronized.
+.sp 1
+.DE
+.DS L
+.SH
+Master Candidature Message
+.so unused
+.LP
+Type: TSP_ELECTION (8)
+.sp 1
+.PP
+A slave eligible to become a master broadcasts this message when its election
+timer expires.
+The message declares that the slave wishes to become the new master.
+.sp 1
+.DE
+.DS L
+.SH
+Candidature Acceptance Message
+.so unused
+.LP
+Type: TSP_ACCEPT (9)
+.sp 1
+.PP
+A slave sends this message to accept the candidature of the time daemon
+that has broadcast an Election message.
+The candidate will add the slave's name to the list of machines that it
+will control should it become the master.
+.sp 1
+.DE
+.DS L
+.SH
+Candidature Rejection Message
+.so unused
+.LP
+Type: TSP_REFUSE (10)
+.sp 1
+.PP
+After a slave accepts the candidature of a time daemon, it will reply
+to any election messages from other slaves
+with this message.
+This rejects any candidature other than the first received.
+.sp 1
+.DE
+.DS L
+.SH
+Multiple Master Notification Message
+.so unused
+.LP
+Type: TSP_CONFLICT (11)
+.sp 1
+.PP
+When two or more masters reply to a Master Request message, the slave
+uses this message to inform one of them that more than one master exists.
+.sp 1
+.DE
+.DS L
+.SH
+Conflict Resolution Message
+.so unused
+.LP
+Type: TSP_RESOLVE (12)
+.sp 1
+.PP
+A master which has been informed of the existence of other masters
+broadcasts this message to determine who the other masters are.
+.sp 1
+.DE
+.DS L
+.SH
+Quit Message
+.so unused
+.LP
+Type: TSP_QUIT (13)
+.sp 1
+.PP
+This message is sent by the master in three different contexts:
+1) to a candidate that broadcasts an Master Candidature message,
+2) to another master when notified of its existence,
+3) to another master if a loop is detected.
+In all cases, the recipient time daemon will become a slave.
+This message requires an acknowledgement.
+.sp 1
+.DE
+.DS L
+.SH
+Set Date Message
+.so date
+.LP
+Type: TSP_SETDATE (22)
+.sp 1
+.PP
+The program \fIdate\fP\|(1) sends this message to the local time daemon
+when a super-user wants to set the network date.
+If the local time daemon is the master, it will set the date;
+if it is a slave, it will communicate the desired date to the master.
+.sp 1
+.DE
+.DS L
+.SH
+Set Date Request Message
+.so date
+.LP
+Type: TSP_SETDATEREQ (23)
+.sp 1
+.PP
+A slave that has received a Set Date message will communicate the
+desired date to the master using this message.
+.sp 1
+.DE
+.DS L
+.SH
+Set Date Acknowledgment Message
+.so unused
+.LP
+Type: TSP_DATEACK (16)
+.sp 1
+.PP
+The master sends this message to a slave in acknowledgment of a
+Set Date Request Message.
+The same message is sent by the local time daemon to the program
+\fIdate(1)\fP to confirm that the network date has been set by the
+master.
+.sp 1
+.DE
+.DS L
+.SH
+Start Tracing Message
+.so unused
+.LP
+Type: TSP_TRACEON (17)
+.sp 1
+.PP
+The controlling program \fItimedc\fP sends this message to the local
+time daemon to start the recording in a system file of
+all messages received.
+.sp 1
+.DE
+.DS L
+.SH
+Stop Tracing Message
+.so unused
+.LP
+Type: TSP_TRACEOFF (18)
+.sp 1
+.PP
+\fITimedc\fP sends this message to the local
+time daemon to stop the recording of
+messages received.
+.sp 1
+.DE
+.DS L
+.SH
+Master Site Message
+.so unused
+.LP
+Type: TSP_MSITE (19)
+.sp 1
+.PP
+\fITimedc\fP sends this message to the local time daemon to find out
+where the master is running.
+.sp 1
+.DE
+.DS L
+.SH
+Remote Master Site Message
+.so unused
+.LP
+Type: TSP_MSITEREQ (20)
+.sp 1
+.PP
+A local time daemon broadcasts this message to find the location
+of the master.
+It then uses the Acknowledgement message to
+communicate this location to \fItimedc\fP.
+.sp 1
+.DE
+.DS L
+.SH
+Test Message
+.so unused
+.LP
+Type: TSP_TEST (21)
+.sp 1
+.PP
+For testing purposes, \fItimedc\fP sends this message to a slave
+to cause its election timer to expire. NOTE: \fItimed\fP
+is not normally compiled to support this.
+.sp 1
+.DE
+.SH
+.DS L
+.SH
+Loop Detection Message
+.so loop
+.LP
+Type: TSP_LOOP (24)
+.sp 1
+.PP
+This packet is initiated by all masters occasionally to attempt to detect loops.
+All submasters forward this packet onto the networks over which they are master.
+If a master receives a packet it sent out initially,
+it knows that a loop exists and tries to correct the problem.
+.DE
+.SH
+References
+.IP 1.
+R. Gusella and S. Zatti,
+\fITEMPO: A Network Time Controller for Distributed Berkeley UNIX System\fP,
+USENIX Summer Conference Proceedings, Salt Lake City, June 1984.
+.IP 2.
+R. Gusella and S. Zatti, \fIClock Synchronization in a Local Area Network\fP,
+University of California, Berkeley, Technical Report, \fIto appear\fP.
+.IP 3.
+R. Gusella and S. Zatti,
+\fIAn Election Algorithm for a Distributed Clock Synchronization Program\fP,
+University of California, Berkeley, CS Technical Report #275, Dec. 1985.
+.IP 4.
+Postel, J., \fIUser Datagram Protocol\fP, RFC 768.
+Network Information Center, SRI International, Menlo Park, California,
+August 1980.
+.IP 5.
+Postel, J., \fIInternet Control Message Protocol\fP, RFC 792.
+Network Information Center, SRI International, Menlo Park, California,
+September 1981.
diff --git a/usr.sbin/timed/SMM.doc/timed/unused b/usr.sbin/timed/SMM.doc/timed/unused
new file mode 100644
index 0000000..adadfc3
--- /dev/null
+++ b/usr.sbin/timed/SMM.doc/timed/unused
@@ -0,0 +1,53 @@
+.\" Copyright (c) 1986, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)unused 8.1 (Berkeley) 6/8/93
+.\"
+.ft B
+.TS
+center;
+ce | ce | ce | ce
+| c | c | c | s |
+| c s s s |.
+Byte 1 Byte 2 Byte 3 Byte 4
+=
+Type Version No. Sequence No.
+_
+( unused )
+_
+( unused )
+_
+Machine Name
+_
+\&. . .
+_
+.TE
+.ft R
diff --git a/usr.sbin/timed/SMM.doc/timedop/Makefile b/usr.sbin/timed/SMM.doc/timedop/Makefile
new file mode 100644
index 0000000..ae43850
--- /dev/null
+++ b/usr.sbin/timed/SMM.doc/timedop/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 8.1 (Berkeley) 6/8/93
+
+DIR= smm/11.timedop
+SRCS= timed.ms
+MACROS= -ms
+
+.include <bsd.doc.mk>
diff --git a/usr.sbin/timed/SMM.doc/timedop/timed.ms b/usr.sbin/timed/SMM.doc/timedop/timed.ms
new file mode 100644
index 0000000..feea0b5
--- /dev/null
+++ b/usr.sbin/timed/SMM.doc/timedop/timed.ms
@@ -0,0 +1,279 @@
+.\" Copyright (c) 1986, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)timed.ms 8.1 (Berkeley) 6/8/93
+.\"
+.TL
+Timed Installation and Operation Guide
+.AU
+Riccardo Gusella, Stefano Zatti, James M. Bloom
+.AI
+Computer Systems Research Group
+Computer Science Division
+Department of Electrical Engineering and Computer Science
+University of California, Berkeley
+Berkeley, CA 94720
+.AU
+Kirk Smith
+.AI
+Engineering Computer Network
+Department of Electrical Engineering
+Purdue University
+West Lafayette, IN 47906
+.FS
+This work was sponsored by the Defense Advanced Research Projects Agency
+(DoD), monitored by the Naval Electronics Systems
+Command under contract No. N00039-84-C-0089, and by the CSELT
+Corporation of Italy.
+The views and conclusions contained in this document are those of the
+authors and should not be interpreted as representing official policies,
+either expressed or implied, of the Defense Research Projects Agency,
+of the US Government, or of CSELT.
+.FE
+.LP
+.EH 'SMM:11-%''Timed Installation and Operation'
+.OH 'Timed Installation and Operation''SMM:11-%'
+.SH
+Introduction
+.PP
+The clock synchronization service for
+the UNIX 4.3BSD operating system is composed of a collection of
+time daemons (\fItimed\fP) running on the machines in a local
+area network.
+The algorithms implemented by the service is based on a master-slave scheme.
+The time daemons communicate with each other using the
+\fITime Synchronization Protocol\fP (TSP) which
+is built on the DARPA UDP protocol and described in detail in [4].
+.PP
+A time daemon has a twofold function.
+First, it supports the synchronization of the clocks
+of the various hosts in a local area network.
+Second, it starts (or takes part in) the election that occurs
+among slave time daemons when, for any reason, the master disappears.
+The synchronization mechanism and the election procedure
+employed by the program \fItimed\fP are described
+in other documents [1,2,3].
+The next paragraphs are a brief overview of how the time daemon works.
+This document is mainly concerned with the administrative and technical
+issues of running \fItimed\fP at a particular site.
+.PP
+A \fImaster time daemon\fP measures the time
+differences between the clock of the machine on which it
+is running and those of all other machines.
+The master computes the \fInetwork time\fP as the average of the
+times provided by nonfaulty clocks.\**
+.FS
+A clock is considered to be faulty when its value
+is more than a small specified
+interval apart from the majority of the clocks
+of the other machines [1,2].
+.FE
+It then sends to each \fIslave time daemon\fP the
+correction that should be performed on the clock of its machine.
+This process is repeated periodically.
+Since the correction is expressed as a time difference rather than an
+absolute time, transmission delays do not interfere with
+the accuracy of the synchronization.
+When a machine comes up and joins the network,
+it starts a slave time daemon which
+will ask the master for the correct time and will reset the machine's clock
+before any user activity can begin.
+The time daemons are able to maintain a single network time in spite of
+the drift of clocks away from each other.
+The present implementation keeps processor clocks synchronized
+within 20 milliseconds.
+.PP
+To ensure that the service provided is continuous and reliable,
+it is necessary to implement an election algorithm to elect a
+new master should the machine running the current master crash, the master
+terminate (for example, because of a run-time error), or
+the network be partitioned.
+Under our algorithm, slaves are able to realize when the master has
+stopped functioning and to elect a new master from among themselves.
+It is important to note that, since the failure of the master results
+only in a gradual divergence of clock values, the election
+need not occur immediately.
+.PP
+The machines that are gateways between distinct local area
+networks require particular care.
+A time daemon on such machines may act as a \fIsubmaster\fP.
+This artifact depends on the current inability of
+transmission protocols to broadcast a message on a network
+other than the one to which the broadcasting machine is connected.
+The submaster appears as a slave on one network, and as a master
+on one or more of the other networks to which it is connected.
+.PP
+A submaster classifies each network as one of three types.
+A \fIslave network\fP is a network on which the submaster acts as a slave.
+There can only be one slave network.
+A \fImaster network\fP is a network on which the submaster acts as a master.
+An \fIignored network\fP is any other network which already has a valid master.
+The submaster tries periodically to become master on an ignored
+network, but gives up immediately if a master already exists.
+.SH
+Guidelines
+.PP
+While the synchronization algorithm is quite general, the election
+one, requiring a broadcast mechanism, puts constraints on
+the kind of network on which time daemons can run.
+The time daemon will only work on networks with broadcast capability
+augmented with point-to-point links.
+Machines that are only connected to point-to-point,
+non-broadcast networks may not use the time daemon.
+.PP
+If we exclude submasters, there will normally be, at most, one master time
+daemon in a local area internetwork.
+During an election, only one of the slave time daemons
+will become the new master.
+However, because of the characteristics of its machine,
+a slave can be prevented from becoming the master.
+Therefore, a subset of machines must be designated as potential
+master time daemons.
+A master time daemon will require CPU resources
+proportional to the number of slaves, in general, more than
+a slave time daemon, so it may be advisable to limit master time
+daemons to machines with more powerful processors or lighter loads.
+Also, machines with inaccurate clocks should not be used as masters.
+This is a purely administrative decision: an organization may
+well allow all of its machines to run master time daemons.
+.PP
+At the administrative level, a time daemon on a machine
+with multiple network interfaces, may be told to ignore all
+but one network or to ignore one network.
+This is done with the \fI\-n network\fP and \fI\-i network\fP
+options respectively at start-up time.
+Typically, the time daemon would be instructed to ignore all but
+the networks belonging to the local administrative control.
+.PP
+There are some limitations to the current
+implementation of the time daemon.
+It is expected that these limitations will be removed in future releases.
+The constant NHOSTS in /usr/src/etc/timed/globals.h limits the
+maximum number of machines that may be directly controlled by one
+master time daemon.
+The current maximum is 29 (NHOSTS \- 1).
+The constant must be changed and the program recompiled if a site wishes to
+run \fItimed\fP on a larger (inter)network.
+.PP
+In addition, there is a \fIpathological situation\fP to
+be avoided at all costs, that might occur when
+time daemons run on multiply-connected local area networks.
+In this case, as we have seen, time daemons running on gateway machines
+will be submasters and they will act on some of those
+networks as master time daemons.
+Consider machines A and B that are both gateways between
+networks X and Y.
+If time daemons were started on both A and B without constraints, it would be
+possible for submaster time daemon A to be a slave on network X
+and the master on network Y, while submaster time daemon B is a slave on
+network Y and the master on network X.
+This \fIloop\fP of master time daemons will not function properly
+or guarantee a unique time on both networks, and will cause
+the submasters to use large amounts of system resources in the form
+of network bandwidth and CPU time.
+In fact, this kind of \fIloop\fP can also be generated with more
+than two master time daemons,
+when several local area networks are interconnected.
+.SH
+Installation
+.PP
+In order to start the time daemon on a given machine,
+the following lines should be
+added to the \fIlocal daemons\fP section in the file \fI/etc/rc.local\fP:
+.sp 2
+.in 1i
+.nf
+if [ -f /etc/timed ]; then
+ /etc/timed \fIflags\fP & echo -n ' timed' >/dev/console
+fi
+.fi
+.in -1i
+.sp
+.LP
+In any case, they must appear after the network
+is configured via ifconfig(8).
+.PP
+Also, the file \fI/etc/services\fP should contain the following
+line:
+.sp 2
+.ti 1i
+timed 525/udp timeserver
+.sp
+.LP
+The \fIflags\fP are:
+.IP "-n network" 13
+to consider the named network.
+.IP "-i network"
+to ignore the named network.
+.IP -t
+to place tracing information in \fI/usr/adm/timed.log\fP.
+.IP -M
+to allow this time daemon to become a master.
+A time daemon run without this option will be forced in the state of
+slave during an election.
+.SH
+Daily Operation
+.PP
+\fITimedc(8)\fP is used to control the operation of the time daemon.
+It may be used to:
+.IP \(bu
+measure the differences between machines' clocks,
+.IP \(bu
+find the location where the master \fItimed\fP is running,
+.IP \(bu
+cause election timers on several machines to expire at the same time,
+.IP \(bu
+enable or disable tracing of messages received by \fItimed\fP.
+.LP
+See the manual page on \fItimed\fP\|(8) and \fItimedc\fP\|(8)
+for more detailed information.
+.PP
+The \fIdate(1)\fP command can be used to set the network date.
+In order to set the time on a single machine, the \fI-n\fP flag
+can be given to date(1).
+.bp
+.SH
+References
+.IP 1.
+R. Gusella and S. Zatti,
+\fITEMPO: A Network Time Controller for Distributed Berkeley UNIX System\fP,
+USENIX Summer Conference Proceedings, Salt Lake City, June 1984.
+.IP 2.
+R. Gusella and S. Zatti, \fIClock Synchronization in a Local Area Network\fP,
+University of California, Berkeley, Technical Report, \fIto appear\fP.
+.IP 3.
+R. Gusella and S. Zatti,
+\fIAn Election Algorithm for a Distributed Clock Synchronization Program\fP,
+University of California, Berkeley, CS Technical Report #275, Dec. 1985.
+.IP 4.
+R. Gusella and S. Zatti,
+\fIThe Berkeley UNIX 4.3BSD Time Synchronization Protocol\fP,
+UNIX Programmer's Manual, 4.3 Berkeley Software Distribution, Volume 2c.
diff --git a/usr.sbin/timed/timed/CHANGES b/usr.sbin/timed/timed/CHANGES
new file mode 100644
index 0000000..773f477
--- /dev/null
+++ b/usr.sbin/timed/timed/CHANGES
@@ -0,0 +1,144 @@
+# @(#)CHANGES 5.1 (Berkeley) 5/11/93
+
+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
+ compatiblity 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 preceeded by a plus or minus,
+ the change is relative, otherwise it is absolute.
+
+
+Vernon Schryver.
+vjs@sgi.com
diff --git a/usr.sbin/timed/timed/Makefile b/usr.sbin/timed/timed/Makefile
new file mode 100644
index 0000000..08b41f3
--- /dev/null
+++ b/usr.sbin/timed/timed/Makefile
@@ -0,0 +1,13 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+#
+# optional flags are: MEASURE TESTING DEBUG
+
+PROG= timed
+SRCS= acksend.c candidate.c correct.c master.c networkdelta.c readmsg.c \
+ slave.c timed.c byteorder.c measure.c cksum.c
+DPADD= ${LIBUTIL}
+LDADD= -lutil
+MAN8= timed.0
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/timed/timed/acksend.c b/usr.sbin/timed/timed/acksend.c
new file mode 100644
index 0000000..c84f52d
--- /dev/null
+++ b/usr.sbin/timed/timed/acksend.c
@@ -0,0 +1,132 @@
+/*-
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)acksend.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.6 $"
+#endif
+
+#include "globals.h"
+
+struct tsp *answer;
+
+extern u_short sequence;
+
+void
+xmit(type, seq, addr)
+ int type;
+ u_int seq;
+ struct sockaddr_in *addr;
+{
+ static struct tsp msg;
+
+ msg.tsp_type = type;
+ msg.tsp_seq = seq;
+ msg.tsp_vers = TSPVERSION;
+ (void)strcpy(msg.tsp_name, hostname);
+ bytenetorder(&msg);
+ if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
+ (struct sockaddr*)addr, sizeof(struct sockaddr)) < 0) {
+ trace_sendto_err(addr->sin_addr);
+ }
+}
+
+
+/*
+ * Acksend implements reliable datagram transmission by using sequence
+ * numbers and retransmission when necessary.
+ * If `name' is ANYADDR, this routine implements reliable broadcast.
+ *
+ * Because this function calls readmsg(), none of its args may be in
+ * a message provided by readmsg().
+ */
+struct tsp *
+acksend(message, addr, name, ack, net, bad)
+ struct tsp *message; /* this message */
+ struct sockaddr_in *addr; /* to here */
+ char *name;
+ int ack; /* look for this ack */
+ struct netinfo *net; /* receive from this network */
+ int bad; /* 1=losing patience */
+{
+ struct timeval twait;
+ int count;
+ long msec;
+
+ message->tsp_vers = TSPVERSION;
+ message->tsp_seq = sequence;
+ if (trace) {
+ fprintf(fd, "acksend: to %s: ",
+ (name == ANYADDR ? "broadcast" : name));
+ print(message, addr);
+ }
+ bytenetorder(message);
+
+ msec = 200;
+ count = bad ? 1 : 5; /* 5 packets in 6.4 seconds */
+ answer = 0;
+ do {
+ if (!answer) {
+ /* do not go crazy transmitting just because the
+ * other guy cannot keep our sequence numbers
+ * straight.
+ */
+ if (sendto(sock, (char *)message, sizeof(struct tsp),
+ 0, (struct sockaddr*)addr,
+ sizeof(struct sockaddr)) < 0) {
+ trace_sendto_err(addr->sin_addr);
+ break;
+ }
+ }
+
+ mstotvround(&twait, msec);
+ answer = readmsg(ack, name, &twait, net);
+ if (answer != 0) {
+ if (answer->tsp_seq != sequence) {
+ if (trace)
+ fprintf(fd,"acksend: seq # %u!=%u\n",
+ answer->tsp_seq, sequence);
+ continue;
+ }
+ break;
+ }
+
+ msec *= 2;
+ } while (--count > 0);
+ sequence++;
+
+ return(answer);
+}
diff --git a/usr.sbin/timed/timed/byteorder.c b/usr.sbin/timed/timed/byteorder.c
new file mode 100644
index 0000000..9cbd665
--- /dev/null
+++ b/usr.sbin/timed/timed/byteorder.c
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)byteorder.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.3 $"
+#endif
+
+#include "globals.h"
+
+/*
+ * Two routines to do the necessary byte swapping for timed protocol
+ * messages. Protocol is defined in /usr/include/protocols/timed.h
+ */
+void
+bytenetorder(ptr)
+ struct tsp *ptr;
+{
+ ptr->tsp_seq = htons((u_short)ptr->tsp_seq);
+ switch (ptr->tsp_type) {
+
+ case TSP_SETTIME:
+ case TSP_ADJTIME:
+ case TSP_SETDATE:
+ case TSP_SETDATEREQ:
+ ptr->tsp_time.tv_sec = htonl((u_long)ptr->tsp_time.tv_sec);
+ ptr->tsp_time.tv_usec = htonl((u_long)ptr->tsp_time.tv_usec);
+ break;
+
+ default:
+ break; /* nothing more needed */
+ }
+}
+
+void
+bytehostorder(ptr)
+ struct tsp *ptr;
+{
+ ptr->tsp_seq = ntohs((u_short)ptr->tsp_seq);
+ switch (ptr->tsp_type) {
+
+ case TSP_SETTIME:
+ case TSP_ADJTIME:
+ case TSP_SETDATE:
+ case TSP_SETDATEREQ:
+ ptr->tsp_time.tv_sec = ntohl((u_long)ptr->tsp_time.tv_sec);
+ ptr->tsp_time.tv_usec = ntohl((u_long)ptr->tsp_time.tv_usec);
+ break;
+
+ default:
+ break; /* nothing more needed */
+ }
+}
diff --git a/usr.sbin/timed/timed/candidate.c b/usr.sbin/timed/timed/candidate.c
new file mode 100644
index 0000000..294eb9b
--- /dev/null
+++ b/usr.sbin/timed/timed/candidate.c
@@ -0,0 +1,167 @@
+/*-
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)candidate.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.9 $"
+#endif
+
+#include "globals.h"
+
+/*
+ * `election' candidates a host as master: it is called by a slave
+ * which runs with the -M option set when its election timeout expires.
+ * Note the conservative approach: if a new timed comes up, or another
+ * candidate sends an election request, the candidature is withdrawn.
+ */
+int
+election(net)
+ struct netinfo *net;
+{
+ struct tsp *resp, msg;
+ struct timeval then, wait;
+ struct tsp *answer;
+ struct hosttbl *htp;
+ char loop_lim = 0;
+
+/* This code can get totally confused if it gets slightly behind. For
+ * example, if readmsg() has some QUIT messages waiting from the last
+ * round, we would send an ELECTION message, get the stale QUIT,
+ * and give up. This results in network storms when several machines
+ * do it at once.
+ */
+ wait.tv_sec = 0;
+ wait.tv_usec = 0;
+ while (0 != readmsg(TSP_REFUSE, ANYADDR, &wait, net)) {
+ if (trace)
+ fprintf(fd, "election: discarded stale REFUSE\n");
+ }
+ while (0 != readmsg(TSP_QUIT, ANYADDR, &wait, net)) {
+ if (trace)
+ fprintf(fd, "election: discarded stale QUIT\n");
+ }
+
+again:
+ syslog(LOG_INFO, "This machine is a candidate time master");
+ if (trace)
+ fprintf(fd, "This machine is a candidate time master\n");
+ msg.tsp_type = TSP_ELECTION;
+ msg.tsp_vers = TSPVERSION;
+ (void)strcpy(msg.tsp_name, hostname);
+ bytenetorder(&msg);
+ if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
+ (struct sockaddr*)&net->dest_addr,
+ sizeof(struct sockaddr)) < 0) {
+ trace_sendto_err(net->dest_addr.sin_addr);
+ return(SLAVE);
+ }
+
+ (void)gettimeofday(&then, 0);
+ then.tv_sec += 3;
+ for (;;) {
+ (void)gettimeofday(&wait, 0);
+ timevalsub(&wait,&then,&wait);
+ resp = readmsg(TSP_ANY, ANYADDR, &wait, net);
+ if (!resp)
+ return(MASTER);
+
+ switch (resp->tsp_type) {
+
+ case TSP_ACCEPT:
+ (void)addmach(resp->tsp_name, &from,fromnet);
+ break;
+
+ case TSP_MASTERUP:
+ case TSP_MASTERREQ:
+ /*
+ * If another timedaemon is coming up at the same
+ * time, give up, and let it be the master.
+ */
+ if (++loop_lim < 5
+ && !good_host_name(resp->tsp_name)) {
+ (void)addmach(resp->tsp_name, &from,fromnet);
+ suppress(&from, resp->tsp_name, net);
+ goto again;
+ }
+ rmnetmachs(net);
+ return(SLAVE);
+
+ case TSP_QUIT:
+ case TSP_REFUSE:
+ /*
+ * Collision: change value of election timer
+ * using exponential backoff.
+ *
+ * Fooey.
+ * An exponential backoff on a delay starting at
+ * 6 to 15 minutes for a process that takes
+ * milliseconds is silly. It is particularly
+ * strange that the original code would increase
+ * the backoff without bound.
+ */
+ rmnetmachs(net);
+ return(SLAVE);
+
+ case TSP_ELECTION:
+ /* no master for another round */
+ htp = addmach(resp->tsp_name,&from,fromnet);
+ msg.tsp_type = TSP_REFUSE;
+ (void)strcpy(msg.tsp_name, hostname);
+ answer = acksend(&msg, &htp->addr, htp->name,
+ TSP_ACK, 0, htp->noanswer);
+ if (!answer) {
+ syslog(LOG_ERR, "error in election from %s",
+ htp->name);
+ }
+ break;
+
+ case TSP_SLAVEUP:
+ (void)addmach(resp->tsp_name, &from,fromnet);
+ break;
+
+ case TSP_SETDATE:
+ case TSP_SETDATEREQ:
+ break;
+
+ default:
+ if (trace) {
+ fprintf(fd, "candidate: ");
+ print(resp, &from);
+ }
+ break;
+ }
+ }
+}
diff --git a/usr.sbin/timed/timed/cksum.c b/usr.sbin/timed/timed/cksum.c
new file mode 100644
index 0000000..3d15af3
--- /dev/null
+++ b/usr.sbin/timed/timed/cksum.c
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)cksum.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.3 $"
+#endif
+
+#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(addr, len)
+ u_short *addr;
+ int len;
+{
+ register int nleft = len;
+ register u_short *w = addr;
+ register u_short answer;
+ register int sum = 0;
+
+ /*
+ * Our algorithm is simple, using a 32 bit accumulator (sum),
+ * we add sequential 16 bit words to it, and at the end, fold
+ * back all the carry bits from the top 16 bits into the lower
+ * 16 bits.
+ */
+ while( nleft > 1 ) {
+ sum += *w++;
+ nleft -= 2;
+ }
+
+ /* mop up an odd byte, if necessary */
+ if( nleft == 1 )
+ sum += (*(u_char *)w) << 8;
+
+ /*
+ * add back carry outs from top 16 bits to low 16 bits
+ */
+ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
+ sum += (sum >> 16); /* add carry */
+ answer = ~sum; /* truncate to 16 bits */
+ return (answer);
+}
diff --git a/usr.sbin/timed/timed/correct.c b/usr.sbin/timed/timed/correct.c
new file mode 100644
index 0000000..569d2e1
--- /dev/null
+++ b/usr.sbin/timed/timed/correct.c
@@ -0,0 +1,294 @@
+/*-
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)correct.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.16 $"
+#endif
+
+#include "globals.h"
+#include <math.h>
+#include <sys/types.h>
+#include <sys/times.h>
+#ifdef sgi
+#include <sys/syssgi.h>
+#endif /* sgi */
+
+static void adjclock __P((struct timeval *));
+
+/*
+ * sends to the slaves the corrections for their clocks after fixing our
+ * own
+ */
+void
+correct(avdelta)
+ long avdelta;
+{
+ struct hosttbl *htp;
+ int corr;
+ struct timeval adjlocal;
+ struct tsp to;
+ struct tsp *answer;
+
+ mstotvround(&adjlocal, avdelta);
+
+ for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
+ if (htp->delta != HOSTDOWN) {
+ corr = avdelta - htp->delta;
+/* If the other machine is off in the weeds, set its time directly.
+ * If a slave gets the wrong day, the original code would simply
+ * fix the minutes. If you fix a network partition, you can get
+ * into such situations.
+ */
+ if (htp->need_set
+ || corr >= MAXADJ*1000
+ || corr <= -MAXADJ*1000) {
+ htp->need_set = 0;
+ (void)gettimeofday(&to.tsp_time,0);
+ timevaladd(&to.tsp_time, &adjlocal);
+ to.tsp_type = TSP_SETTIME;
+ } else {
+ mstotvround(&to.tsp_time, corr);
+ to.tsp_type = TSP_ADJTIME;
+ }
+ (void)strcpy(to.tsp_name, hostname);
+ answer = acksend(&to, &htp->addr, htp->name,
+ TSP_ACK, 0, 0);
+ if (!answer) {
+ htp->delta = HOSTDOWN;
+ syslog(LOG_WARNING,
+ "no reply to time correction from %s",
+ htp->name);
+ if (++htp->noanswer >= LOSTHOST) {
+ if (trace) {
+ fprintf(fd,
+ "purging %s for not answering\n",
+ htp->name);
+ (void)fflush(fd);
+ }
+ htp = remmach(htp);
+ }
+ }
+ }
+ }
+
+ /*
+ * adjust our own clock now that we are not sending it out
+ */
+ adjclock(&adjlocal);
+}
+
+
+static void
+adjclock(corr)
+ struct timeval *corr;
+{
+ static int passes = 0;
+ static int smoother = 0;
+ long delta; /* adjustment in usec */
+ long ndelta;
+ struct timeval now;
+ struct timeval adj;
+
+ if (!timerisset(corr))
+ return;
+
+ adj = *corr;
+ if (adj.tv_sec < MAXADJ && adj.tv_sec > - MAXADJ) {
+ delta = adj.tv_sec*1000000 + adj.tv_usec;
+ /* If the correction is less than the minimum round
+ * trip time for an ICMP packet, and thus
+ * less than the likely error in the measurement,
+ * do not do the entire correction. Do half
+ * or a quarter of it.
+ */
+
+ if (delta > -MIN_ROUND*1000
+ && delta < MIN_ROUND*1000) {
+ if (smoother <= 4)
+ smoother++;
+ ndelta = delta >> smoother;
+ if (trace)
+ fprintf(fd,
+ "trimming delta %ld usec to %ld\n",
+ delta, ndelta);
+ adj.tv_usec = ndelta;
+ adj.tv_sec = 0;
+ } else if (smoother > 0) {
+ smoother--;
+ }
+ if (0 > adjtime(corr, 0)) {
+ syslog(LOG_ERR, "adjtime: %m");
+ }
+ if (passes > 1
+ && (delta < -BIG_ADJ || delta > BIG_ADJ)) {
+ smoother = 0;
+ passes = 0;
+ syslog(LOG_WARNING,
+ "large time adjustment of %+.3f sec",
+ delta/1000000.0);
+ }
+ } else {
+ syslog(LOG_WARNING,
+ "clock correction %d sec too large to adjust",
+ adj.tv_sec);
+ (void) gettimeofday(&now, 0);
+ timevaladd(&now, corr);
+ if (settimeofday(&now, 0) < 0)
+ syslog(LOG_ERR, "settimeofday: %m");
+ }
+
+#ifdef sgi
+ /* Accumulate the total change, and use it to adjust the basic
+ * clock rate.
+ */
+ if (++passes > 2) {
+#define F_USEC_PER_SEC (1000000*1.0) /* reduce typos */
+#define F_NSEC_PER_SEC (F_USEC_PER_SEC*1000.0)
+
+ extern char *timetrim_fn;
+ extern char *timetrim_wpat;
+ extern long timetrim;
+ extern double tot_adj, hr_adj; /* totals in nsec */
+ extern double tot_ticks, hr_ticks;
+
+ static double nag_tick;
+ double cur_ticks, hr_delta_ticks, tot_delta_ticks;
+ double tru_tot_adj, tru_hr_adj; /* nsecs of adjustment */
+ double tot_trim, hr_trim; /* nsec/sec */
+ struct tms tm;
+ FILE *timetrim_st;
+
+ cur_ticks = times(&tm);
+ tot_adj += delta*1000.0;
+ hr_adj += delta*1000.0;
+
+ tot_delta_ticks = cur_ticks-tot_ticks;
+ if (tot_delta_ticks >= 16*SECDAY*CLK_TCK) {
+ tot_adj -= rint(tot_adj/16);
+ tot_ticks += rint(tot_delta_ticks/16);
+ tot_delta_ticks = cur_ticks-tot_ticks;
+ }
+ hr_delta_ticks = cur_ticks-hr_ticks;
+
+ tru_hr_adj = hr_adj + timetrim*rint(hr_delta_ticks/CLK_TCK);
+ tru_tot_adj = (tot_adj
+ + timetrim*rint(tot_delta_ticks/CLK_TCK));
+
+ if (hr_delta_ticks >= SECDAY*CLK_TCK
+ || (tot_delta_ticks < 4*SECDAY*CLK_TCK
+ && hr_delta_ticks >= SECHR*CLK_TCK)
+ || (trace && hr_delta_ticks >= (SECHR/10)*CLK_TCK)) {
+
+ tot_trim = rint(tru_tot_adj*CLK_TCK/tot_delta_ticks);
+ hr_trim = rint(tru_hr_adj*CLK_TCK/hr_delta_ticks);
+
+ if (trace
+ || (abs(timetrim - hr_trim) > 100000.0
+ && 0 == timetrim_fn
+ && ((cur_ticks - nag_tick)
+ >= 24*SECDAY*CLK_TCK))) {
+ nag_tick = cur_ticks;
+ syslog(LOG_NOTICE,
+ "%+.3f/%.2f or %+.3f/%.2f sec/hr; timetrim=%+.0f or %+.0f",
+ tru_tot_adj/F_NSEC_PER_SEC,
+ tot_delta_ticks/(SECHR*CLK_TCK*1.0),
+ tru_hr_adj/F_NSEC_PER_SEC,
+ hr_delta_ticks/(SECHR*CLK_TCK*1.0),
+ tot_trim,
+ hr_trim);
+ }
+
+ if (tot_trim < -MAX_TRIM || tot_trim > MAX_TRIM) {
+ tot_ticks = hr_ticks;
+ tot_adj = hr_adj;
+ } else if (0 > syssgi(SGI_SETTIMETRIM,
+ (long)tot_trim)) {
+ syslog(LOG_ERR, "SETTIMETRIM(%d): %m",
+ (long)tot_trim);
+ } else {
+ if (0 != timetrim_fn) {
+ timetrim_st = fopen(timetrim_fn, "w");
+ if (0 == timetrim_st) {
+ syslog(LOG_ERR, "fopen(%s): %m",
+ timetrim_fn);
+ } else {
+ if (0 > fprintf(timetrim_st,
+ timetrim_wpat,
+ (long)tot_trim,
+ tru_tot_adj,
+ tot_delta_ticks)) {
+ syslog(LOG_ERR,
+ "fprintf(%s): %m",
+ timetrim_fn);
+ }
+ (void)fclose(timetrim_st);
+ }
+ }
+
+ tot_adj -= ((tot_trim - timetrim)
+ * rint(tot_delta_ticks/CLK_TCK));
+ timetrim = tot_trim;
+ }
+
+ hr_ticks = cur_ticks;
+ hr_adj = 0;
+ }
+ }
+#endif /* sgi */
+}
+
+
+/* adjust the time in a message by the time it
+ * spent in the queue
+ */
+void
+adj_msg_time(msg, now)
+ struct tsp *msg;
+ struct timeval *now;
+{
+ msg->tsp_time.tv_sec += (now->tv_sec - from_when.tv_sec);
+ msg->tsp_time.tv_usec += (now->tv_usec - from_when.tv_usec);
+
+ while (msg->tsp_time.tv_usec < 0) {
+ msg->tsp_time.tv_sec--;
+ msg->tsp_time.tv_usec += 1000000;
+ }
+ while (msg->tsp_time.tv_usec >= 1000000) {
+ msg->tsp_time.tv_sec++;
+ msg->tsp_time.tv_usec -= 1000000;
+ }
+}
diff --git a/usr.sbin/timed/timed/extern.h b/usr.sbin/timed/timed/extern.h
new file mode 100644
index 0000000..09dfaaa
--- /dev/null
+++ b/usr.sbin/timed/timed/extern.h
@@ -0,0 +1,89 @@
+/*-
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.1 (Berkeley) 6/6/93
+ */
+
+struct hosttbl;
+struct netinfo;
+struct sockaddr_in;
+struct timeval;
+struct tsp;
+
+struct hosttbl *addmach __P((char *, struct sockaddr_in *, struct netinfo *));
+struct hosttbl *findhost __P((char *));
+struct hosttbl *remmach __P((struct hosttbl *));
+
+struct tsp *readmsg __P((int,
+ char *, struct timeval *, struct netinfo *));
+struct tsp *acksend __P((struct tsp *,
+ struct sockaddr_in *, char *, int, struct netinfo *, int));
+
+void addnetname __P((char *));
+void adj_msg_time __P((struct tsp *, struct timeval *));
+void bytehostorder __P((struct tsp *));
+void bytenetorder __P((struct tsp *));
+void byteorder __P((struct tsp *));
+long casual __P((long, long));
+int cksum __P((u_short *, int));
+void correct __P((long));
+char *date __P((void));
+void doquit __P((struct tsp *));
+int election __P((struct netinfo *));
+void get_goodgroup __P((int));
+int good_host_name __P((char *));
+void ignoreack __P((void));
+int in_cksum __P((u_short *, int));
+void lookformaster __P((struct netinfo *));
+void makeslave __P((struct netinfo *));
+int master __P((void));
+void masterack __P((void));
+void masterup __P((struct netinfo *));
+int measure __P((u_long, u_long, char *, struct sockaddr_in *, int));
+void msterup __P((struct netinfo *));
+void mstotvround __P((struct timeval *, long));
+long networkdelta __P((void));
+void newslave __P((struct tsp *));
+void print __P((struct tsp *, struct sockaddr_in *));
+void prthp __P((clock_t));
+void rmnetmachs __P((struct netinfo *));
+void setstatus __P((void));
+int slave __P((void));
+void slaveack __P((void));
+void spreadtime __P((void));
+void suppress __P((struct sockaddr_in *, char *, struct netinfo *));
+void synch __P((long));
+void timevaladd __P((struct timeval *, struct timeval *));
+void timevalsub __P((struct timeval *, struct timeval *, struct timeval *));
+void traceoff __P((char *));
+void traceon __P((void));
+void xmit __P((int, u_int, struct sockaddr_in *));
diff --git a/usr.sbin/timed/timed/globals.h b/usr.sbin/timed/timed/globals.h
new file mode 100644
index 0000000..92aed3e
--- /dev/null
+++ b/usr.sbin/timed/timed/globals.h
@@ -0,0 +1,186 @@
+/*-
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)globals.h 8.1 (Berkeley) 6/6/93
+ */
+
+#ifdef sgi
+#ident "$Revision: 1.15 $"
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <protocols/timed.h>
+#ifdef sgi
+#include <bstring.h>
+#include <sys/clock.h>
+/* use the constant HZ instead of the function CLK_TCK */
+#undef CLK_TCK
+#define CLK_TCK HZ
+#else
+#define SECHR (60*60)
+#define SECDAY (24*SECHR)
+#endif /* sgi */
+
+extern int errno;
+extern int sock;
+
+/* Best expected round trip for a measurement.
+ * This is essentially the number of milliseconds per CPU tick (CLK_TCK?).
+ * All delays shorter than this are usually reported as 0.
+ */
+#define MIN_ROUND ((1000-1)/CLK_TCK)
+
+
+#define SAMPLEINTVL 240 /* synch() freq for master in sec */
+#define MAXADJ 20 /* max adjtime() correction in sec */
+
+#define MAX_TRIM 3000000 /* max drift in nsec/sec, 0.3% */
+#define BIG_ADJ (MAX_TRIM/1000*SAMPLEINTVL*2) /* max good adj */
+
+#define MINTOUT 360 /* election delays, 6-15 minutes */
+#define MAXTOUT 900
+
+#define BAD_STATUS (-1)
+#define GOOD 1
+#define UNREACHABLE 2
+#define NONSTDTIME 3
+#define HOSTDOWN 0x7fffffff
+
+#define OFF 0
+#define ON 1
+
+#define MAX_HOPCNT 10 /* max value for tsp_hpcnt */
+
+#define LOSTHOST 3 /* forget after this many failures */
+
+#define VALID_RANGE (MAXADJ*1000) /* good times in milliseconds */
+#define GOOD_RANGE (MIN_ROUND*2)
+#define VGOOD_RANGE (MIN_ROUND-1)
+
+
+/*
+ * Global and per-network states.
+ */
+#define NOMASTER 0 /* no good master */
+#define SLAVE 1
+#define MASTER 2
+#define IGNORE 4
+#define ALL (SLAVE|MASTER|IGNORE)
+#define SUBMASTER (SLAVE|MASTER)
+
+#define NHOSTS 1013 /* max of hosts controlled by timed
+ * This must be a prime number.
+ */
+struct hosttbl {
+ struct hosttbl *h_bak; /* hash chain */
+ struct hosttbl *h_fwd;
+ struct hosttbl *l_bak; /* "sequential" list */
+ struct hosttbl *l_fwd;
+ struct netinfo *ntp;
+ struct sockaddr_in addr;
+ char name[MAXHOSTNAMELEN+1];
+ u_char head; /* 1=head of hash chain */
+ u_char good; /* 0=trusted host, for averaging */
+ u_char noanswer; /* count of failures to answer */
+ u_char need_set; /* need a SETTIME */
+ u_short seq;
+ long delta;
+};
+
+/* closed hash table with internal chaining */
+extern struct hosttbl hosttbl[NHOSTS+1];
+#define self hosttbl[0]
+#define hostname (self.name)
+
+
+struct netinfo {
+ struct netinfo *next;
+ struct in_addr net;
+ u_long mask;
+ struct in_addr my_addr;
+ struct sockaddr_in dest_addr; /* broadcast addr or point-point */
+ long status;
+ struct timeval slvwait; /* delay before sending our time */
+ int quit_count; /* recent QUITs */
+};
+
+#include "extern.h"
+
+#define tvtomsround(tv) ((tv).tv_sec*1000 + ((tv).tv_usec + 500)/1000)
+
+extern struct netinfo *nettab;
+extern int status;
+extern int trace;
+extern int sock;
+extern struct sockaddr_in from;
+extern struct timeval from_when; /* when the last msg arrived */
+extern u_short sequence; /* TSP message sequence number */
+extern struct netinfo *fromnet, *slavenet;
+extern FILE *fd;
+extern long delay1, delay2;
+extern int nslavenets; /* nets were I could be a slave */
+extern int nmasternets; /* nets were I could be a master */
+extern int nignorednets; /* ignored nets */
+extern int nnets; /* nets I am connected to */
+
+
+#define trace_msg(msg) {if (trace) fprintf(fd, msg);}
+
+#define trace_sendto_err(addr) { \
+ int st_errno = errno; \
+ syslog(LOG_ERR, "%s %d: sendto %s: %m", \
+ __FILE__, __LINE__, inet_ntoa(addr)); \
+ if (trace) \
+ fprintf(fd, "%s %d: sendto %s: %d", __FILE__, __LINE__, \
+ inet_ntoa(addr), st_errno); \
+}
+
+
+# define max(a,b) (a<b ? b : a)
+# define min(a,b) (a>b ? b : a)
+# define abs(x) (x>=0 ? x : -(x))
diff --git a/usr.sbin/timed/timed/master.c b/usr.sbin/timed/timed/master.c
new file mode 100644
index 0000000..3397173
--- /dev/null
+++ b/usr.sbin/timed/timed/master.c
@@ -0,0 +1,907 @@
+/*-
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)master.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.21 $"
+#endif
+
+#include "globals.h"
+#include <sys/file.h>
+#include <sys/types.h>
+#include <sys/times.h>
+#include <setjmp.h>
+#ifdef sgi
+#include <sys/schedctl.h>
+#endif /* sgi */
+#include <utmp.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 __P((struct tsp *));
+
+#ifdef sgi
+extern void logwtmp __P((struct timeval *, struct timeval *));
+#else
+extern void logwtmp __P((char *, char *, char *));
+#endif /* sgi */
+
+/*
+ * The main function of `master' is to periodically compute the differences
+ * (deltas) between its clock and the clocks of the slaves, to compute the
+ * network average delta, and to send to the slaves the differences between
+ * their individual deltas and the network delta.
+ * While waiting, it receives messages from the slaves (i.e. requests for
+ * master's name, remote requests to set the network time, ...), and
+ * takes the appropriate action.
+ */
+int
+master()
+{
+ struct hosttbl *htp;
+ long pollingtime;
+#define POLLRATE 4
+ int polls;
+ struct timeval wait, ntime;
+ struct tsp *msg, *answer, to;
+ char newdate[32];
+ struct sockaddr_in taddr;
+ char tname[MAXHOSTNAMELEN];
+ struct netinfo *ntp;
+ int i;
+
+ syslog(LOG_NOTICE, "This machine is master");
+ if (trace)
+ fprintf(fd, "This machine is master\n");
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+ if (ntp->status == MASTER)
+ masterup(ntp);
+ }
+ (void)gettimeofday(&ntime, 0);
+ pollingtime = ntime.tv_sec+3;
+ if (justquit)
+ polls = 0;
+ else
+ polls = POLLRATE-1;
+
+/* Process all outstanding messages before spending the long time necessary
+ * to update all timers.
+ */
+loop:
+ (void)gettimeofday(&ntime, 0);
+ wait.tv_sec = pollingtime - ntime.tv_sec;
+ if (wait.tv_sec < 0)
+ wait.tv_sec = 0;
+ wait.tv_usec = 0;
+ msg = readmsg(TSP_ANY, ANYADDR, &wait, 0);
+ if (!msg) {
+ (void)gettimeofday(&ntime, 0);
+ if (ntime.tv_sec >= pollingtime) {
+ pollingtime = ntime.tv_sec + SAMPLEINTVL;
+ get_goodgroup(0);
+
+/* If a bogus master told us to quit, we can have decided to ignore a
+ * network. Therefore, periodically try to take over everything.
+ */
+ polls = (polls + 1) % POLLRATE;
+ if (0 == polls && nignorednets > 0) {
+ trace_msg("Looking for nets to re-master\n");
+ for (ntp = nettab; ntp; ntp = ntp->next) {
+ if (ntp->status == IGNORE
+ || ntp->status == NOMASTER) {
+ lookformaster(ntp);
+ if (ntp->status == MASTER) {
+ masterup(ntp);
+ polls = POLLRATE-1;
+ }
+ }
+ if (ntp->status == MASTER
+ && --ntp->quit_count < 0)
+ ntp->quit_count = 0;
+ }
+ if (polls != 0)
+ setstatus();
+ }
+
+ synch(0L);
+
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+ to.tsp_type = TSP_LOOP;
+ to.tsp_vers = TSPVERSION;
+ to.tsp_seq = sequence++;
+ to.tsp_hopcnt = MAX_HOPCNT;
+ (void)strcpy(to.tsp_name, hostname);
+ bytenetorder(&to);
+ if (sendto(sock, (char *)&to,
+ sizeof(struct tsp), 0,
+ (struct sockaddr*)&ntp->dest_addr,
+ sizeof(ntp->dest_addr)) < 0) {
+ trace_sendto_err(ntp->dest_addr.sin_addr);
+ }
+ }
+ }
+
+
+ } else {
+ switch (msg->tsp_type) {
+
+ case TSP_MASTERREQ:
+ break;
+
+ case TSP_SLAVEUP:
+ newslave(msg);
+ break;
+
+ case TSP_SETDATE:
+ /*
+ * XXX check to see it is from ourself
+ */
+#ifdef sgi
+ (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
+#else
+ (void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec));
+#endif /* sgi */
+ if (!good_host_name(msg->tsp_name)) {
+ syslog(LOG_NOTICE,
+ "attempted date change by %s to %s",
+ msg->tsp_name, newdate);
+ spreadtime();
+ break;
+ }
+
+ mchgdate(msg);
+ (void)gettimeofday(&ntime, 0);
+ pollingtime = ntime.tv_sec + SAMPLEINTVL;
+ break;
+
+ case TSP_SETDATEREQ:
+ if (!fromnet || fromnet->status != MASTER)
+ break;
+#ifdef sgi
+ (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
+#else
+ (void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec));
+#endif /* sgi */
+ htp = findhost(msg->tsp_name);
+ if (htp == 0) {
+ syslog(LOG_ERR,
+ "attempted SET DATEREQ by uncontrolled %s to %s",
+ msg->tsp_name, newdate);
+ break;
+ }
+ if (htp->seq == msg->tsp_seq)
+ break;
+ htp->seq = msg->tsp_seq;
+ if (!htp->good) {
+ syslog(LOG_NOTICE,
+ "attempted SET DATEREQ by untrusted %s to %s",
+ msg->tsp_name, newdate);
+ spreadtime();
+ break;
+ }
+
+ mchgdate(msg);
+ (void)gettimeofday(&ntime, 0);
+ pollingtime = ntime.tv_sec + SAMPLEINTVL;
+ break;
+
+ case TSP_MSITE:
+ xmit(TSP_ACK, msg->tsp_seq, &from);
+ break;
+
+ case TSP_MSITEREQ:
+ break;
+
+ case TSP_TRACEON:
+ traceon();
+ break;
+
+ case TSP_TRACEOFF:
+ traceoff("Tracing ended at %s\n");
+ break;
+
+ case TSP_ELECTION:
+ if (!fromnet)
+ break;
+ if (fromnet->status == MASTER) {
+ pollingtime = 0;
+ (void)addmach(msg->tsp_name, &from,fromnet);
+ }
+ taddr = from;
+ (void)strcpy(tname, msg->tsp_name);
+ to.tsp_type = TSP_QUIT;
+ (void)strcpy(to.tsp_name, hostname);
+ answer = acksend(&to, &taddr, tname,
+ TSP_ACK, 0, 1);
+ if (answer == NULL) {
+ syslog(LOG_ERR, "election error by %s",
+ tname);
+ }
+ break;
+
+ case TSP_CONFLICT:
+ /*
+ * After a network partition, there can be
+ * more than one master: the first slave to
+ * come up will notify here the situation.
+ */
+ if (!fromnet || fromnet->status != MASTER)
+ break;
+ (void)strcpy(to.tsp_name, hostname);
+
+ /* The other master often gets into the same state,
+ * with boring results if we stay at it forever.
+ */
+ ntp = fromnet; /* (acksend() can leave fromnet=0 */
+ for (i = 0; i < 3; i++) {
+ to.tsp_type = TSP_RESOLVE;
+ (void)strcpy(to.tsp_name, hostname);
+ answer = acksend(&to, &ntp->dest_addr,
+ ANYADDR, TSP_MASTERACK,
+ ntp, 0);
+ if (!answer)
+ break;
+ htp = addmach(answer->tsp_name,&from,ntp);
+ to.tsp_type = TSP_QUIT;
+ msg = acksend(&to, &htp->addr, htp->name,
+ TSP_ACK, 0, htp->noanswer);
+ if (msg == NULL) {
+ syslog(LOG_ERR,
+ "no response from %s to CONFLICT-QUIT",
+ htp->name);
+ }
+ }
+ masterup(ntp);
+ pollingtime = 0;
+ break;
+
+ case TSP_RESOLVE:
+ if (!fromnet || fromnet->status != MASTER)
+ break;
+ /*
+ * do not want to call synch() while waiting
+ * to be killed!
+ */
+ (void)gettimeofday(&ntime, (struct timezone *)0);
+ pollingtime = ntime.tv_sec + SAMPLEINTVL;
+ break;
+
+ case TSP_QUIT:
+ doquit(msg); /* become a slave */
+ break;
+
+ case TSP_LOOP:
+ if (!fromnet || fromnet->status != MASTER
+ || !strcmp(msg->tsp_name, hostname))
+ break;
+ /*
+ * We should not have received this from a net
+ * we are master on. There must be two masters.
+ */
+ htp = addmach(msg->tsp_name, &from,fromnet);
+ to.tsp_type = TSP_QUIT;
+ (void)strcpy(to.tsp_name, hostname);
+ answer = acksend(&to, &htp->addr, htp->name,
+ TSP_ACK, 0, 1);
+ if (!answer) {
+ syslog(LOG_WARNING,
+ "loop breakage: no reply from %s=%s to QUIT",
+ htp->name, inet_ntoa(htp->addr.sin_addr));
+ (void)remmach(htp);
+ }
+
+ case TSP_TEST:
+ if (trace) {
+ fprintf(fd,
+ "\tnets = %d, masters = %d, slaves = %d, ignored = %d\n",
+ nnets, nmasternets, nslavenets, nignorednets);
+ setstatus();
+ }
+ pollingtime = 0;
+ polls = POLLRATE-1;
+ break;
+
+ default:
+ if (trace) {
+ fprintf(fd, "garbage message: ");
+ print(msg, &from);
+ }
+ break;
+ }
+ }
+ goto loop;
+}
+
+
+/*
+ * change the system date on the master
+ */
+static void
+mchgdate(msg)
+ struct tsp *msg;
+{
+ char tname[MAXHOSTNAMELEN];
+ char olddate[32];
+ struct timeval otime, ntime;
+
+ (void)strcpy(tname, msg->tsp_name);
+
+ xmit(TSP_DATEACK, msg->tsp_seq, &from);
+
+ (void)strcpy(olddate, date());
+
+ /* adjust time for residence on the queue */
+ (void)gettimeofday(&otime, 0);
+ adj_msg_time(msg,&otime);
+
+ timevalsub(&ntime, &msg->tsp_time, &otime);
+ if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) {
+ /*
+ * do not change the clock if we can adjust it
+ */
+ dictate = 3;
+ synch(tvtomsround(ntime));
+ } else {
+#ifdef sgi
+ if (0 > settimeofday(&msg->tsp_time, 0)) {
+ syslog(LOG_ERR, "settimeofday(): %m");
+ }
+ logwtmp(&otime, &msg->tsp_time);
+#else
+ logwtmp("|", "date", "");
+ (void)settimeofday(&msg->tsp_time, 0);
+ logwtmp("}", "date", "");
+#endif /* sgi */
+ spreadtime();
+ }
+
+ syslog(LOG_NOTICE, "date changed by %s from %s",
+ tname, olddate);
+}
+
+
+/*
+ * synchronize all of the slaves
+ */
+void
+synch(mydelta)
+ long mydelta;
+{
+ struct hosttbl *htp;
+ int measure_status;
+ struct timeval check, stop, wait;
+#ifdef sgi
+ int pri;
+#endif /* sgi */
+
+ if (slvcount > 0) {
+ if (trace)
+ fprintf(fd, "measurements starting at %s\n", date());
+ (void)gettimeofday(&check, 0);
+#ifdef sgi
+ /* run fast to get good time */
+ pri = schedctl(NDPRI,0,NDPHIMIN);
+ if (pri < 0)
+ syslog(LOG_ERR, "schedctl(): %m");
+#endif /* sgi */
+ for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
+ if (htp->noanswer != 0) {
+ measure_status = measure(500, 100,
+ htp->name,
+ &htp->addr,0);
+ } else {
+ measure_status = measure(3000, 100,
+ htp->name,
+ &htp->addr,0);
+ }
+ if (measure_status != GOOD) {
+ /* The slave did not respond. We have
+ * just wasted lots of time on it.
+ */
+ htp->delta = HOSTDOWN;
+ if (++htp->noanswer >= LOSTHOST) {
+ if (trace) {
+ fprintf(fd,
+ "purging %s for not answering ICMP\n",
+ htp->name);
+ (void)fflush(fd);
+ }
+ htp = remmach(htp);
+ }
+ } else {
+ htp->delta = measure_delta;
+ }
+ (void)gettimeofday(&stop, 0);
+ timevalsub(&stop, &stop, &check);
+ if (stop.tv_sec >= 1) {
+ if (trace)
+ (void)fflush(fd);
+ /*
+ * ack messages periodically
+ */
+ wait.tv_sec = 0;
+ wait.tv_usec = 0;
+ if (0 != readmsg(TSP_TRACEON,ANYADDR,
+ &wait,0))
+ traceon();
+ (void)gettimeofday(&check, 0);
+ }
+ }
+#ifdef sgi
+ if (pri >= 0)
+ (void)schedctl(NDPRI,0,pri);
+#endif /* sgi */
+ if (trace)
+ fprintf(fd, "measurements finished at %s\n", date());
+ }
+ if (!(status & SLAVE)) {
+ if (!dictate) {
+ mydelta = networkdelta();
+ } else {
+ dictate--;
+ }
+ }
+ if (trace && (mydelta != 0 || (status & SLAVE)))
+ fprintf(fd,"local correction of %ld ms.\n", mydelta);
+ correct(mydelta);
+}
+
+/*
+ * sends the time to each slave after the master
+ * has received the command to set the network time
+ */
+void
+spreadtime()
+{
+ struct hosttbl *htp;
+ struct tsp to;
+ struct tsp *answer;
+
+/* Do not listen to the consensus after forcing the time. This is because
+ * the consensus takes a while to reach the time we are dictating.
+ */
+ dictate = 2;
+ for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
+ to.tsp_type = TSP_SETTIME;
+ (void)strcpy(to.tsp_name, hostname);
+ (void)gettimeofday(&to.tsp_time, 0);
+ answer = acksend(&to, &htp->addr, htp->name,
+ TSP_ACK, 0, htp->noanswer);
+ if (answer == 0) {
+ /* We client does not respond, then we have
+ * just wasted lots of time on it.
+ */
+ syslog(LOG_WARNING,
+ "no reply to SETTIME from %s", htp->name);
+ if (++htp->noanswer >= LOSTHOST) {
+ if (trace) {
+ fprintf(fd,
+ "purging %s for not answering",
+ htp->name);
+ (void)fflush(fd);
+ }
+ htp = remmach(htp);
+ }
+ }
+ }
+}
+
+void
+prthp(delta)
+ clock_t delta;
+{
+ static time_t next_time;
+ time_t this_time;
+ struct tms tm;
+ struct hosttbl *htp;
+ int length, l;
+ int i;
+
+ if (!fd) /* quit if tracing already off */
+ return;
+
+ this_time = times(&tm);
+ if (this_time + delta < next_time)
+ return;
+ next_time = this_time + CLK_TCK;
+
+ fprintf(fd, "host table: %d entries at %s\n", slvcount, date());
+ htp = self.l_fwd;
+ length = 1;
+ for (i = 1; i <= slvcount; i++, htp = htp->l_fwd) {
+ l = strlen(htp->name) + 1;
+ if (length+l >= 80) {
+ fprintf(fd, "\n");
+ length = 0;
+ }
+ length += l;
+ fprintf(fd, " %s", htp->name);
+ }
+ fprintf(fd, "\n");
+}
+
+
+static struct hosttbl *newhost_hash;
+static struct hosttbl *lasthfree = &hosttbl[0];
+
+
+struct hosttbl * /* answer or 0 */
+findhost(name)
+ char *name;
+{
+ int i, j;
+ struct hosttbl *htp;
+ char *p;
+
+ j= 0;
+ for (p = name, i = 0; i < 8 && *p != '\0'; i++, p++)
+ j = (j << 2) ^ *p;
+ newhost_hash = &hosttbl[j % NHOSTS];
+
+ htp = newhost_hash;
+ if (htp->name[0] == '\0')
+ return(0);
+ do {
+ if (!strcmp(name, htp->name))
+ return(htp);
+ htp = htp->h_fwd;
+ } while (htp != newhost_hash);
+ return(0);
+}
+
+/*
+ * add a host to the list of controlled machines if not already there
+ */
+struct hosttbl *
+addmach(name, addr, ntp)
+ char *name;
+ struct sockaddr_in *addr;
+ struct netinfo *ntp;
+{
+ struct hosttbl *ret, *p, *b, *f;
+
+ ret = findhost(name);
+ if (ret == 0) {
+ if (slvcount >= NHOSTS) {
+ if (trace) {
+ fprintf(fd, "no more slots in host table\n");
+ prthp(CLK_TCK);
+ }
+ syslog(LOG_ERR, "no more slots in host table");
+ Mflag = 0;
+ longjmp(jmpenv, 2); /* give up and be a slave */
+ }
+
+ /* if our home hash slot is occupied, find a free entry
+ * in the hash table
+ */
+ if (newhost_hash->name[0] != '\0') {
+ do {
+ ret = lasthfree;
+ if (++lasthfree > &hosttbl[NHOSTS])
+ lasthfree = &hosttbl[1];
+ } while (ret->name[0] != '\0');
+
+ if (!newhost_hash->head) {
+ /* Move an interloper using our home. Use
+ * scratch pointers in case the new head is
+ * pointing to itself.
+ */
+ f = newhost_hash->h_fwd;
+ b = newhost_hash->h_bak;
+ f->h_bak = ret;
+ b->h_fwd = ret;
+ f = newhost_hash->l_fwd;
+ b = newhost_hash->l_bak;
+ f->l_bak = ret;
+ b->l_fwd = ret;
+ bcopy(newhost_hash,ret,sizeof(*ret));
+ ret = newhost_hash;
+ ret->head = 1;
+ ret->h_fwd = ret;
+ ret->h_bak = ret;
+ } else {
+ /* link to an existing chain in our home
+ */
+ ret->head = 0;
+ p = newhost_hash->h_bak;
+ ret->h_fwd = newhost_hash;
+ ret->h_bak = p;
+ p->h_fwd = ret;
+ newhost_hash->h_bak = ret;
+ }
+ } else {
+ ret = newhost_hash;
+ ret->head = 1;
+ ret->h_fwd = ret;
+ ret->h_bak = ret;
+ }
+ ret->addr = *addr;
+ ret->ntp = ntp;
+ (void)strncpy(ret->name, name, sizeof(ret->name));
+ ret->good = good_host_name(name);
+ ret->l_fwd = &self;
+ ret->l_bak = self.l_bak;
+ self.l_bak->l_fwd = ret;
+ self.l_bak = ret;
+ slvcount++;
+
+ ret->noanswer = 0;
+ ret->need_set = 1;
+
+ } else {
+ ret->noanswer = (ret->noanswer != 0);
+ }
+
+ /* need to clear sequence number anyhow */
+ ret->seq = 0;
+ return(ret);
+}
+
+/*
+ * remove the machine with the given index in the host table.
+ */
+struct hosttbl *
+remmach(htp)
+ struct hosttbl *htp;
+{
+ struct hosttbl *lprv, *hnxt, *f, *b;
+
+ if (trace)
+ fprintf(fd, "remove %s\n", htp->name);
+
+ /* get out of the lists */
+ htp->l_fwd->l_bak = lprv = htp->l_bak;
+ htp->l_bak->l_fwd = htp->l_fwd;
+ htp->h_fwd->h_bak = htp->h_bak;
+ htp->h_bak->h_fwd = hnxt = htp->h_fwd;
+
+ /* If we are in the home slot, pull up the chain */
+ if (htp->head && hnxt != htp) {
+ if (lprv == hnxt)
+ lprv = htp;
+
+ /* Use scratch pointers in case the new head is pointing to
+ * itself.
+ */
+ f = hnxt->h_fwd;
+ b = hnxt->h_bak;
+ f->h_bak = htp;
+ b->h_fwd = htp;
+ f = hnxt->l_fwd;
+ b = hnxt->l_bak;
+ f->l_bak = htp;
+ b->l_fwd = htp;
+ hnxt->head = 1;
+ bcopy(hnxt, htp, sizeof(*htp));
+ lasthfree = hnxt;
+ } else {
+ lasthfree = htp;
+ }
+
+ lasthfree->name[0] = '\0';
+ lasthfree->h_fwd = 0;
+ lasthfree->l_fwd = 0;
+ slvcount--;
+
+ return lprv;
+}
+
+
+/*
+ * Remove all the machines from the host table that exist on the given
+ * network. This is called when a master transitions to a slave on a
+ * given network.
+ */
+void
+rmnetmachs(ntp)
+ struct netinfo *ntp;
+{
+ struct hosttbl *htp;
+
+ if (trace)
+ prthp(CLK_TCK);
+ for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
+ if (ntp == htp->ntp)
+ htp = remmach(htp);
+ }
+ if (trace)
+ prthp(CLK_TCK);
+}
+
+void
+masterup(net)
+ struct netinfo *net;
+{
+ xmit(TSP_MASTERUP, 0, &net->dest_addr);
+
+ /*
+ * Do not tell new slaves our time for a while. This ensures
+ * we do not tell them to start using our time, before we have
+ * found a good master.
+ */
+ (void)gettimeofday(&net->slvwait, 0);
+}
+
+void
+newslave(msg)
+ struct tsp *msg;
+{
+ struct hosttbl *htp;
+ struct tsp *answer, to;
+ struct timeval now;
+
+ if (!fromnet || fromnet->status != MASTER)
+ return;
+
+ htp = addmach(msg->tsp_name, &from,fromnet);
+ htp->seq = msg->tsp_seq;
+ if (trace)
+ prthp(0);
+
+ /*
+ * If we are stable, send our time to the slave.
+ * Do not go crazy if the date has been changed.
+ */
+ (void)gettimeofday(&now, 0);
+ if (now.tv_sec >= fromnet->slvwait.tv_sec+3
+ || now.tv_sec < fromnet->slvwait.tv_sec) {
+ to.tsp_type = TSP_SETTIME;
+ (void)strcpy(to.tsp_name, hostname);
+ (void)gettimeofday(&to.tsp_time, 0);
+ answer = acksend(&to, &htp->addr,
+ htp->name, TSP_ACK,
+ 0, htp->noanswer);
+ if (answer) {
+ htp->need_set = 0;
+ } else {
+ syslog(LOG_WARNING,
+ "no reply to initial SETTIME from %s",
+ htp->name);
+ htp->noanswer = LOSTHOST;
+ }
+ }
+}
+
+
+/*
+ * react to a TSP_QUIT:
+ */
+void
+doquit(msg)
+ struct tsp *msg;
+{
+ if (fromnet->status == MASTER) {
+ if (!good_host_name(msg->tsp_name)) {
+ if (fromnet->quit_count <= 0) {
+ syslog(LOG_NOTICE,"untrusted %s told us QUIT",
+ msg->tsp_name);
+ suppress(&from, msg->tsp_name, fromnet);
+ fromnet->quit_count = 1;
+ return;
+ }
+ syslog(LOG_NOTICE, "untrusted %s told us QUIT twice",
+ msg->tsp_name);
+ fromnet->quit_count = 2;
+ fromnet->status = NOMASTER;
+ } else {
+ fromnet->status = SLAVE;
+ }
+ rmnetmachs(fromnet);
+ longjmp(jmpenv, 2); /* give up and be a slave */
+
+ } else {
+ if (!good_host_name(msg->tsp_name)) {
+ syslog(LOG_NOTICE, "untrusted %s told us QUIT",
+ msg->tsp_name);
+ fromnet->quit_count = 2;
+ }
+ }
+}
+
+void
+traceon()
+{
+ if (!fd) {
+ fd = fopen(_PATH_TIMEDLOG, "w");
+ if (!fd) {
+ trace = 0;
+ return;
+ }
+ fprintf(fd,"Tracing started at %s\n", date());
+ }
+ trace = 1;
+ get_goodgroup(1);
+ setstatus();
+ prthp(CLK_TCK);
+}
+
+
+void
+traceoff(msg)
+ char *msg;
+{
+ get_goodgroup(1);
+ setstatus();
+ prthp(CLK_TCK);
+ if (trace) {
+ fprintf(fd, msg, date());
+ (void)fclose(fd);
+ fd = 0;
+ }
+#ifdef GPROF
+ moncontrol(0);
+ _mcleanup();
+ moncontrol(1);
+#endif
+ trace = OFF;
+}
+
+
+#ifdef sgi
+void
+logwtmp(otime, ntime)
+ struct timeval *otime, *ntime;
+{
+ static struct utmp wtmp[2] = {
+ {"","",OTIME_MSG,0,OLD_TIME,0,0,0},
+ {"","",NTIME_MSG,0,NEW_TIME,0,0,0}
+ };
+ static char *wtmpfile = WTMP_FILE;
+ int f;
+
+ wtmp[0].ut_time = otime->tv_sec + (otime->tv_usec + 500000) / 1000000;
+ wtmp[1].ut_time = ntime->tv_sec + (ntime->tv_usec + 500000) / 1000000;
+ if (wtmp[0].ut_time == wtmp[1].ut_time)
+ return;
+
+ setutent();
+ (void)pututline(&wtmp[0]);
+ (void)pututline(&wtmp[1]);
+ endutent();
+ if ((f = open(wtmpfile, O_WRONLY|O_APPEND)) >= 0) {
+ (void) write(f, (char *)wtmp, sizeof(wtmp));
+ (void) close(f);
+ }
+}
+#endif /* sgi */
diff --git a/usr.sbin/timed/timed/measure.c b/usr.sbin/timed/timed/measure.c
new file mode 100644
index 0000000..4066d10
--- /dev/null
+++ b/usr.sbin/timed/timed/measure.c
@@ -0,0 +1,353 @@
+/*-
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)measure.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.8 $"
+#endif
+
+#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.
+ */
+int /* status val defined in globals.h */
+measure(maxmsec, wmsec, hname, addr, print)
+ u_long maxmsec; /* wait this many msec at most */
+ u_long wmsec; /* msec to wait for an answer */
+ char *hname;
+ struct sockaddr_in *addr;
+ int print; /* print complaints on stderr */
+{
+ int length;
+ int measure_status;
+ int rcvcount, trials;
+ int cc, count;
+ fd_set ready;
+ long sendtime, recvtime, histime1, histime2;
+ long idelta, odelta, total;
+ long min_idelta, min_odelta;
+ struct timeval tdone, tcur, ttrans, twait, tout;
+ u_char packet[PACKET_IN], opacket[64];
+ register struct icmp *icp = (struct icmp *) packet;
+ register struct icmp *oicp = (struct icmp *) opacket;
+ struct ip *ip = (struct ip *) packet;
+
+ min_idelta = min_odelta = 0x7fffffff;
+ measure_status = HOSTDOWN;
+ measure_delta = HOSTDOWN;
+ errno = 0;
+
+ /* open raw socket used to measure time differences */
+ if (sock_raw < 0) {
+ sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+ if (sock_raw < 0) {
+ syslog(LOG_ERR, "opening raw socket: %m");
+ goto quit;
+ }
+ }
+
+
+ /*
+ * empty the icmp input queue
+ */
+ FD_ZERO(&ready);
+ for (;;) {
+ tout.tv_sec = tout.tv_usec = 0;
+ FD_SET(sock_raw, &ready);
+ if (select(sock_raw+1, &ready, 0,0, &tout)) {
+ length = sizeof(struct sockaddr_in);
+ cc = recvfrom(sock_raw, (char *)packet, PACKET_IN, 0,
+ 0,&length);
+ if (cc < 0)
+ goto quit;
+ continue;
+ }
+ break;
+ }
+
+ /*
+ * Choose the smallest transmission time in each of the two
+ * directions. Use these two latter quantities to compute the delta
+ * between the two clocks.
+ */
+
+ oicp->icmp_type = ICMP_TSTAMP;
+ oicp->icmp_code = 0;
+ oicp->icmp_id = getpid();
+ oicp->icmp_rtime = 0;
+ oicp->icmp_ttime = 0;
+ oicp->icmp_seq = seqno;
+
+ FD_ZERO(&ready);
+
+#ifdef sgi
+ sginap(1); /* start at a clock tick */
+#endif /* sgi */
+
+ (void)gettimeofday(&tdone, 0);
+ mstotvround(&tout, maxmsec);
+ timevaladd(&tdone, &tout); /* when we give up */
+
+ mstotvround(&twait, wmsec);
+
+ rcvcount = 0;
+ trials = 0;
+ while (rcvcount < MSGS) {
+ (void)gettimeofday(&tcur, 0);
+
+ /*
+ * keep sending until we have sent the max
+ */
+ if (trials < TRIALS) {
+ trials++;
+ oicp->icmp_otime = ((tcur.tv_sec % SECDAY) * 1000
+ + tcur.tv_usec / 1000);
+ oicp->icmp_cksum = 0;
+ oicp->icmp_cksum = in_cksum((u_short*)oicp,
+ sizeof(*oicp));
+
+ count = sendto(sock_raw, opacket, sizeof(*oicp), 0,
+ (struct sockaddr*)addr,
+ sizeof(struct sockaddr));
+ if (count < 0) {
+ if (measure_status == HOSTDOWN)
+ measure_status = UNREACHABLE;
+ goto quit;
+ }
+ ++oicp->icmp_seq;
+
+ ttrans = tcur;
+ timevaladd(&ttrans, &twait);
+ } else {
+ ttrans = tdone;
+ }
+
+ while (rcvcount < trials) {
+ timevalsub(&tout, &ttrans, &tcur);
+ if (tout.tv_sec < 0)
+ tout.tv_sec = 0;
+
+ FD_SET(sock_raw, &ready);
+ count = select(sock_raw+1, &ready, (fd_set *)0,
+ (fd_set *)0, &tout);
+ (void)gettimeofday(&tcur, (struct timezone *)0);
+ if (count <= 0)
+ break;
+
+ length = sizeof(struct sockaddr_in);
+ cc = recvfrom(sock_raw, (char *)packet, PACKET_IN, 0,
+ 0,&length);
+ if (cc < 0)
+ goto quit;
+
+ /*
+ * got something. See if it is ours
+ */
+ icp = (struct icmp *)(packet + (ip->ip_hl << 2));
+ if (cc < sizeof(*ip)
+ || icp->icmp_type != ICMP_TSTAMPREPLY
+ || icp->icmp_id != oicp->icmp_id
+ || icp->icmp_seq < seqno
+ || icp->icmp_seq >= oicp->icmp_seq)
+ continue;
+
+
+ sendtime = ntohl(icp->icmp_otime);
+ recvtime = ((tcur.tv_sec % SECDAY) * 1000 +
+ tcur.tv_usec / 1000);
+
+ total = recvtime-sendtime;
+ if (total < 0) /* do not hassle midnight */
+ continue;
+
+ rcvcount++;
+ histime1 = ntohl(icp->icmp_rtime);
+ histime2 = ntohl(icp->icmp_ttime);
+ /*
+ * a host using a time format different from
+ * msec. since midnight UT (as per RFC792) should
+ * set the high order bit of the 32-bit time
+ * value it transmits.
+ */
+ if ((histime1 & 0x80000000) != 0) {
+ measure_status = NONSTDTIME;
+ goto quit;
+ }
+ measure_status = GOOD;
+
+ idelta = recvtime-histime2;
+ odelta = histime1-sendtime;
+
+ /* do not be confused by midnight */
+ if (idelta < -MSEC_DAY/2) idelta += MSEC_DAY;
+ else if (idelta > MSEC_DAY/2) idelta -= MSEC_DAY;
+
+ if (odelta < -MSEC_DAY/2) odelta += MSEC_DAY;
+ else if (odelta > MSEC_DAY/2) odelta -= MSEC_DAY;
+
+ /* save the quantization error so that we can get a
+ * measurement finer than our system clock.
+ */
+ if (total < MIN_ROUND) {
+ measure_delta = (odelta - idelta)/2;
+ goto quit;
+ }
+
+ if (idelta < min_idelta)
+ min_idelta = idelta;
+ if (odelta < min_odelta)
+ min_odelta = odelta;
+
+ measure_delta = (min_odelta - min_idelta)/2;
+ }
+
+ if (tcur.tv_sec > tdone.tv_sec
+ || (tcur.tv_sec == tdone.tv_sec
+ && tcur.tv_usec >= tdone.tv_usec))
+ break;
+ }
+
+quit:
+ seqno += TRIALS; /* allocate our sequence numbers */
+
+ /*
+ * If no answer is received for TRIALS consecutive times,
+ * the machine is assumed to be down
+ */
+ if (measure_status == GOOD) {
+ if (trace) {
+ fprintf(fd,
+ "measured delta %4d, %d trials to %-15s %s\n",
+ measure_delta, trials,
+ inet_ntoa(addr->sin_addr), hname);
+ }
+ } else if (print) {
+ if (errno != 0)
+ fprintf(stderr, "measure %s: %s\n", hname,
+ strerror(errno));
+ } else {
+ if (errno != 0) {
+ syslog(LOG_ERR, "measure %s: %m", hname);
+ } else {
+ syslog(LOG_ERR, "measure: %s did not respond", hname);
+ }
+ if (trace) {
+ fprintf(fd,
+ "measure: %s failed after %d trials\n",
+ hname, trials);
+ (void)fflush(fd);
+ }
+ }
+
+ return(measure_status);
+}
+
+
+
+
+
+/*
+ * round a number of milliseconds into a struct timeval
+ */
+void
+mstotvround(res, x)
+ struct timeval *res;
+ long x;
+{
+#ifndef sgi
+ if (x < 0)
+ x = -((-x + 3)/5);
+ else
+ x = (x+3)/5;
+ x *= 5;
+#endif /* sgi */
+ res->tv_sec = x/1000;
+ res->tv_usec = (x-res->tv_sec*1000)*1000;
+ if (res->tv_usec < 0) {
+ res->tv_usec += 1000000;
+ res->tv_sec--;
+ }
+}
+
+void
+timevaladd(tv1, tv2)
+ struct timeval *tv1, *tv2;
+{
+ tv1->tv_sec += tv2->tv_sec;
+ tv1->tv_usec += tv2->tv_usec;
+ if (tv1->tv_usec >= 1000000) {
+ tv1->tv_sec++;
+ tv1->tv_usec -= 1000000;
+ }
+ if (tv1->tv_usec < 0) {
+ tv1->tv_sec--;
+ tv1->tv_usec += 1000000;
+ }
+}
+
+void
+timevalsub(res, tv1, tv2)
+ struct timeval *res, *tv1, *tv2;
+{
+ res->tv_sec = tv1->tv_sec - tv2->tv_sec;
+ res->tv_usec = tv1->tv_usec - tv2->tv_usec;
+ if (res->tv_usec >= 1000000) {
+ res->tv_sec++;
+ res->tv_usec -= 1000000;
+ }
+ if (res->tv_usec < 0) {
+ res->tv_sec--;
+ res->tv_usec += 1000000;
+ }
+}
diff --git a/usr.sbin/timed/timed/networkdelta.c b/usr.sbin/timed/timed/networkdelta.c
new file mode 100644
index 0000000..d64640a
--- /dev/null
+++ b/usr.sbin/timed/timed/networkdelta.c
@@ -0,0 +1,264 @@
+/*-
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)networkdelta.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.4 $"
+#endif
+
+#include "globals.h"
+
+static long median __P((float, float *, long *, long *, unsigned int));
+
+/*
+ * Compute a corrected date.
+ * Compute the median of the reasonable differences. First compute
+ * the median of all authorized differences, and then compute the
+ * median of all differences that are reasonably close to the first
+ * median.
+ *
+ * This differs from the original BSD implementation, which looked for
+ * the largest group of machines with essentially the same date.
+ * That assumed that machines with bad clocks would be uniformly
+ * distributed. Unfortunately, in real life networks, the distribution
+ * of machines is not uniform among models of machines, and the
+ * distribution of errors in clocks tends to be quite consistent
+ * for a given model. In other words, all model VI Supre Servres
+ * from GoFast Inc. tend to have about the same error.
+ * The original BSD implementation would chose the clock of the
+ * most common model, and discard all others.
+ *
+ * Therefore, get best we can do is to try to average over all
+ * of the machines in the network, while discarding "obviously"
+ * bad values.
+ */
+long
+networkdelta()
+{
+ struct hosttbl *htp;
+ long med;
+ long lodelta, hidelta;
+ long logood, higood;
+ long x[NHOSTS];
+ long *xp;
+ int numdelta;
+ float eps;
+
+ /*
+ * compute the median of the good values
+ */
+ med = 0;
+ numdelta = 1;
+ xp = &x[0];
+ *xp = 0; /* account for ourself */
+ for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
+ if (htp->good
+ && htp->noanswer == 0
+ && htp->delta != HOSTDOWN) {
+ med += htp->delta;
+ numdelta++;
+ *++xp = htp->delta;
+ }
+ }
+
+ /*
+ * If we are the only trusted time keeper, then do not change our
+ * clock. There may be another time keeping service active.
+ */
+ if (numdelta == 1)
+ return 0;
+
+ med /= numdelta;
+ eps = med - x[0];
+ if (trace)
+ fprintf(fd, "median of %d values starting at %ld is about ",
+ numdelta, med);
+ med = median(med, &eps, &x[0], xp+1, VALID_RANGE);
+
+ /*
+ * compute the median of all values near the good median
+ */
+ hidelta = med + GOOD_RANGE;
+ lodelta = med - GOOD_RANGE;
+ higood = med + VGOOD_RANGE;
+ logood = med - VGOOD_RANGE;
+ xp = &x[0];
+ htp = &self;
+ do {
+ if (htp->noanswer == 0
+ && htp->delta >= lodelta
+ && htp->delta <= hidelta
+ && (htp->good
+ || (htp->delta >= logood
+ && htp->delta <= higood))) {
+ *xp++ = htp->delta;
+ }
+ } while (&self != (htp = htp->l_fwd));
+
+ if (xp == &x[0]) {
+ if (trace)
+ fprintf(fd, "nothing close to median %ld\n", med);
+ return med;
+ }
+
+ if (xp == &x[1]) {
+ if (trace)
+ fprintf(fd, "only value near median is %ld\n", x[0]);
+ return x[0];
+ }
+
+ if (trace)
+ fprintf(fd, "median of %d values starting at %ld is ",
+ xp-&x[0], med);
+ return median(med, &eps, &x[0], xp, 1);
+}
+
+
+/*
+ * compute the median of an array of signed integers, using the idea
+ * in <<Numerical Recipes>>.
+ */
+static long
+median(a, eps_ptr, x, xlim, gnuf)
+ float a; /* initial guess for the median */
+ float *eps_ptr; /* spacing near the median */
+ long *x, *xlim; /* the data */
+ unsigned int gnuf; /* good enough estimate */
+{
+ long *xptr;
+ float ap = LONG_MAX; /* bounds on the median */
+ float am = -LONG_MAX;
+ float aa;
+ int npts; /* # of points above & below guess */
+ float xp; /* closet point above the guess */
+ float xm; /* closet point below the guess */
+ float eps;
+ float dum, sum, sumx;
+ int pass;
+#define AMP 1.5 /* smoothing constants */
+#define AFAC 1.5
+
+ eps = *eps_ptr;
+ if (eps < 1.0) {
+ eps = -eps;
+ if (eps < 1.0)
+ eps = 1.0;
+ }
+
+ for (pass = 1; ; pass++) { /* loop over the data */
+ sum = 0.0;
+ sumx = 0.0;
+ npts = 0;
+ xp = LONG_MAX;
+ xm = -LONG_MAX;
+
+ for (xptr = x; xptr != xlim; xptr++) {
+ float xx = *xptr;
+
+ dum = xx - a;
+ if (dum != 0.0) { /* avoid dividing by 0 */
+ if (dum > 0.0) {
+ npts++;
+ if (xx < xp)
+ xp = xx;
+ } else {
+ npts--;
+ if (xx > xm)
+ xm = xx;
+ dum = -dum;
+ }
+ dum = 1.0/(eps + dum);
+ sum += dum;
+ sumx += xx * dum;
+ }
+ }
+
+ if (ap-am < gnuf || sum == 0) {
+ if (trace)
+ fprintf(fd,
+ "%ld in %d passes; early out balance=%d\n",
+ (long)a, pass, npts);
+ return a; /* guess was good enough */
+ }
+
+ aa = (sumx/sum-a)*AMP;
+ if (npts >= 2) { /* guess was too low */
+ am = a;
+ aa = xp + max(0.0, aa);;
+ if (aa > ap)
+ aa = (a + ap)/2;
+
+ } else if (npts <= -2) { /* guess was two high */
+ ap = a;
+ aa = xm + min(0.0, aa);;
+ if (aa < am)
+ aa = (a + am)/2;
+
+ } else {
+ break; /* got it */
+ }
+
+ if (a == aa) {
+ if (trace)
+ fprintf(fd,
+ "%ld in %d passes; force out balance=%d\n",
+ (long)a, pass, npts);
+ return a;
+ }
+ eps = AFAC*abs(aa - a);
+ *eps_ptr = eps;
+ a = aa;
+ }
+
+ if (((x - xlim) % 2) != 0) { /* even number of points? */
+ if (npts == 0) /* yes, return an average */
+ a = (xp+xm)/2;
+ else if (npts > 0)
+ a = (a+xp)/2;
+ else
+ a = (xm+a)/2;
+
+ } else if (npts != 0) { /* odd number of points */
+ if (npts > 0)
+ a = xp;
+ else
+ a = xm;
+ }
+
+ if (trace)
+ fprintf(fd, "%ld in %d passes\n", (long)a, pass);
+ return a;
+}
diff --git a/usr.sbin/timed/timed/pathnames.h b/usr.sbin/timed/timed/pathnames.h
new file mode 100644
index 0000000..ae5e1c5
--- /dev/null
+++ b/usr.sbin/timed/timed/pathnames.h
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/6/93
+ */
+
+#include <paths.h>
+
+#ifdef sgi
+#define _PATH_MASTERLOG "/usr/adm/timed.masterlog"
+#define _PATH_TIMEDLOG "/usr/adm/timed.log"
+#else
+#define _PATH_MASTERLOG "/var/log/timed.masterlog"
+#define _PATH_TIMEDLOG "/var/log/timed.log"
+#endif
diff --git a/usr.sbin/timed/timed/readmsg.c b/usr.sbin/timed/timed/readmsg.c
new file mode 100644
index 0000000..3e8f4d2
--- /dev/null
+++ b/usr.sbin/timed/timed/readmsg.c
@@ -0,0 +1,488 @@
+/*-
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)readmsg.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.17 $"
+#endif
+
+#include "globals.h"
+
+extern char *tsptype[];
+
+/*
+ * LOOKAT checks if the message is of the requested type and comes from
+ * the right machine, returning 1 in case of affirmative answer
+ */
+#define LOOKAT(msg, mtype, mfrom, netp, froms) \
+ (((mtype) == TSP_ANY || (mtype) == (msg).tsp_type) && \
+ ((mfrom) == 0 || !strcmp((mfrom), (msg).tsp_name)) && \
+ ((netp) == 0 || \
+ ((netp)->mask & (froms).sin_addr.s_addr) == (netp)->net.s_addr))
+
+struct timeval rtime, rwait, rtout;
+struct tsp msgin;
+static struct tsplist {
+ struct tsp info;
+ struct timeval when;
+ struct sockaddr_in addr;
+ struct tsplist *p;
+} msgslist;
+struct sockaddr_in from;
+struct netinfo *fromnet;
+struct timeval from_when;
+
+/*
+ * `readmsg' returns message `type' sent by `machfrom' if it finds it
+ * either in the receive queue, or in a linked list of previously received
+ * messages that it maintains.
+ * Otherwise it waits to see if the appropriate message arrives within
+ * `intvl' seconds. If not, it returns NULL.
+ */
+
+struct tsp *
+readmsg(type, machfrom, intvl, netfrom)
+ int type;
+ char *machfrom;
+ struct timeval *intvl;
+ struct netinfo *netfrom;
+{
+ int length;
+ fd_set ready;
+ static struct tsplist *head = &msgslist;
+ static struct tsplist *tail = &msgslist;
+ static int msgcnt = 0;
+ struct tsplist *prev;
+ register struct netinfo *ntp;
+ register struct tsplist *ptr;
+
+ if (trace) {
+ fprintf(fd, "readmsg: looking for %s from %s, %s\n",
+ tsptype[type], machfrom == NULL ? "ANY" : machfrom,
+ netfrom == NULL ? "ANYNET" : inet_ntoa(netfrom->net));
+ if (head->p != 0) {
+ length = 1;
+ for (ptr = head->p; ptr != 0; ptr = ptr->p) {
+ /* do not repeat the hundreds of messages */
+ if (++length > 3) {
+ if (ptr == tail) {
+ fprintf(fd,"\t ...%d skipped\n",
+ length);
+ } else {
+ continue;
+ }
+ }
+ fprintf(fd, length > 1 ? "\t" : "queue:\t");
+ print(&ptr->info, &ptr->addr);
+ }
+ }
+ }
+
+ ptr = head->p;
+ prev = head;
+
+ /*
+ * Look for the requested message scanning through the
+ * linked list. If found, return it and free the space
+ */
+
+ while (ptr != NULL) {
+ if (LOOKAT(ptr->info, type, machfrom, netfrom, ptr->addr)) {
+again:
+ msgin = ptr->info;
+ from = ptr->addr;
+ from_when = ptr->when;
+ prev->p = ptr->p;
+ if (ptr == tail)
+ tail = prev;
+ free((char *)ptr);
+ fromnet = NULL;
+ if (netfrom == NULL)
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+ if ((ntp->mask & from.sin_addr.s_addr) ==
+ ntp->net.s_addr) {
+ fromnet = ntp;
+ break;
+ }
+ }
+ else
+ fromnet = netfrom;
+ if (trace) {
+ fprintf(fd, "readmsg: found ");
+ print(&msgin, &from);
+ }
+
+/* The protocol can get far behind. When it does, it gets
+ * hopelessly confused. So delete duplicate messages.
+ */
+ for (ptr = prev; (ptr = ptr->p) != NULL; prev = ptr) {
+ if (ptr->addr.sin_addr.s_addr
+ == from.sin_addr.s_addr
+ && ptr->info.tsp_type == msgin.tsp_type) {
+ if (trace)
+ fprintf(fd, "\tdup ");
+ goto again;
+ }
+ }
+ msgcnt--;
+ return(&msgin);
+ } else {
+ prev = ptr;
+ ptr = ptr->p;
+ }
+ }
+
+ /*
+ * If the message was not in the linked list, it may still be
+ * coming from the network. Set the timer and wait
+ * on a select to read the next incoming message: if it is the
+ * right one, return it, otherwise insert it in the linked list.
+ */
+
+ (void)gettimeofday(&rtout, 0);
+ timevaladd(&rtout, intvl);
+ FD_ZERO(&ready);
+ for (;;) {
+ (void)gettimeofday(&rtime, 0);
+ timevalsub(&rwait, &rtout, &rtime);
+ if (rwait.tv_sec < 0)
+ rwait.tv_sec = rwait.tv_usec = 0;
+ else if (rwait.tv_sec == 0
+ && rwait.tv_usec < 1000000/CLK_TCK)
+ rwait.tv_usec = 1000000/CLK_TCK;
+
+ if (trace) {
+ fprintf(fd, "readmsg: wait %ld.%6ld at %s\n",
+ rwait.tv_sec, rwait.tv_usec, date());
+ /* Notice a full disk, as we flush trace info.
+ * It is better to flush periodically than at
+ * every line because the tracing consists of bursts
+ * of many lines. Without care, tracing slows
+ * down the code enough to break the protocol.
+ */
+ if (rwait.tv_sec != 0
+ && EOF == fflush(fd))
+ traceoff("Tracing ended for cause at %s\n");
+ }
+
+ FD_SET(sock, &ready);
+ if (!select(sock+1, &ready, (fd_set *)0, (fd_set *)0,
+ &rwait)) {
+ if (rwait.tv_sec == 0 && rwait.tv_usec == 0)
+ return(0);
+ continue;
+ }
+ length = sizeof(from);
+ if (recvfrom(sock, (char *)&msgin, sizeof(struct tsp), 0,
+ (struct sockaddr*)&from, &length) < 0) {
+ syslog(LOG_ERR, "recvfrom: %m");
+ exit(1);
+ }
+ (void)gettimeofday(&from_when, (struct timezone *)0);
+ bytehostorder(&msgin);
+
+ if (msgin.tsp_vers > TSPVERSION) {
+ if (trace) {
+ fprintf(fd,"readmsg: version mismatch\n");
+ /* should do a dump of the packet */
+ }
+ continue;
+ }
+
+ fromnet = NULL;
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next)
+ if ((ntp->mask & from.sin_addr.s_addr) ==
+ ntp->net.s_addr) {
+ fromnet = ntp;
+ break;
+ }
+
+ /*
+ * drop packets from nets we are ignoring permanently
+ */
+ if (fromnet == NULL) {
+ /*
+ * The following messages may originate on
+ * this host with an ignored network address
+ */
+ if (msgin.tsp_type != TSP_TRACEON &&
+ msgin.tsp_type != TSP_SETDATE &&
+ msgin.tsp_type != TSP_MSITE &&
+ msgin.tsp_type != TSP_TEST &&
+ msgin.tsp_type != TSP_TRACEOFF) {
+ if (trace) {
+ fprintf(fd,"readmsg: discard null net ");
+ print(&msgin, &from);
+ }
+ continue;
+ }
+ }
+
+ /*
+ * Throw away messages coming from this machine,
+ * unless they are of some particular type.
+ * This gets rid of broadcast messages and reduces
+ * master processing time.
+ */
+ if (!strcmp(msgin.tsp_name, hostname)
+ && msgin.tsp_type != TSP_SETDATE
+ && msgin.tsp_type != TSP_TEST
+ && msgin.tsp_type != TSP_MSITE
+ && msgin.tsp_type != TSP_TRACEON
+ && msgin.tsp_type != TSP_TRACEOFF
+ && msgin.tsp_type != TSP_LOOP) {
+ if (trace) {
+ fprintf(fd, "readmsg: discard own ");
+ print(&msgin, &from);
+ }
+ continue;
+ }
+
+ /*
+ * Send acknowledgements here; this is faster and
+ * avoids deadlocks that would occur if acks were
+ * sent from a higher level routine. Different
+ * acknowledgements are necessary, depending on
+ * status.
+ */
+ if (fromnet == NULL) /* do not de-reference 0 */
+ ignoreack();
+ else if (fromnet->status == MASTER)
+ masterack();
+ else if (fromnet->status == SLAVE)
+ slaveack();
+ else
+ ignoreack();
+
+ if (LOOKAT(msgin, type, machfrom, netfrom, from)) {
+ if (trace) {
+ fprintf(fd, "readmsg: ");
+ print(&msgin, &from);
+ }
+ return(&msgin);
+ } else if (++msgcnt > NHOSTS*3) {
+
+/* The protocol gets hopelessly confused if it gets too far
+* behind. However, it seems able to recover from all cases of lost
+* packets. Therefore, if we are swamped, throw everything away.
+*/
+ if (trace)
+ fprintf(fd,
+ "readmsg: discarding %d msgs\n",
+ msgcnt);
+ msgcnt = 0;
+ while ((ptr=head->p) != NULL) {
+ head->p = ptr->p;
+ free((char *)ptr);
+ }
+ tail = head;
+ } else {
+ tail->p = (struct tsplist *)
+ malloc(sizeof(struct tsplist));
+ tail = tail->p;
+ tail->p = NULL;
+ tail->info = msgin;
+ tail->addr = from;
+ /* timestamp msgs so SETTIMEs are correct */
+ tail->when = from_when;
+ }
+ }
+}
+
+/*
+ * Send the necessary acknowledgements:
+ * only the type ACK is to be sent by a slave
+ */
+void
+slaveack()
+{
+ switch(msgin.tsp_type) {
+
+ case TSP_ADJTIME:
+ case TSP_SETTIME:
+ case TSP_ACCEPT:
+ case TSP_REFUSE:
+ case TSP_TRACEON:
+ case TSP_TRACEOFF:
+ case TSP_QUIT:
+ if (trace) {
+ fprintf(fd, "Slaveack: ");
+ print(&msgin, &from);
+ }
+ xmit(TSP_ACK,msgin.tsp_seq, &from);
+ break;
+
+ default:
+ if (trace) {
+ fprintf(fd, "Slaveack: no ack: ");
+ print(&msgin, &from);
+ }
+ break;
+ }
+}
+
+/*
+ * Certain packets may arrive from this machine on ignored networks.
+ * These packets should be acknowledged.
+ */
+void
+ignoreack()
+{
+ switch(msgin.tsp_type) {
+
+ case TSP_TRACEON:
+ case TSP_TRACEOFF:
+ case TSP_QUIT:
+ if (trace) {
+ fprintf(fd, "Ignoreack: ");
+ print(&msgin, &from);
+ }
+ xmit(TSP_ACK,msgin.tsp_seq, &from);
+ break;
+
+ default:
+ if (trace) {
+ fprintf(fd, "Ignoreack: no ack: ");
+ print(&msgin, &from);
+ }
+ break;
+ }
+}
+
+/*
+ * `masterack' sends the necessary acknowledgments
+ * to the messages received by a master
+ */
+void
+masterack()
+{
+ struct tsp resp;
+
+ resp = msgin;
+ resp.tsp_vers = TSPVERSION;
+ (void)strcpy(resp.tsp_name, hostname);
+
+ switch(msgin.tsp_type) {
+
+ case TSP_QUIT:
+ case TSP_TRACEON:
+ case TSP_TRACEOFF:
+ case TSP_MSITEREQ:
+ if (trace) {
+ fprintf(fd, "Masterack: ");
+ print(&msgin, &from);
+ }
+ xmit(TSP_ACK,msgin.tsp_seq, &from);
+ break;
+
+ case TSP_RESOLVE:
+ case TSP_MASTERREQ:
+ if (trace) {
+ fprintf(fd, "Masterack: ");
+ print(&msgin, &from);
+ }
+ xmit(TSP_MASTERACK,msgin.tsp_seq, &from);
+ break;
+
+ default:
+ if (trace) {
+ fprintf(fd,"Masterack: no ack: ");
+ print(&msgin, &from);
+ }
+ break;
+ }
+}
+
+/*
+ * Print a TSP message
+ */
+void
+print(msg, addr)
+ struct tsp *msg;
+ struct sockaddr_in *addr;
+{
+ char tm[26];
+ switch (msg->tsp_type) {
+
+ case TSP_LOOP:
+ fprintf(fd, "%s %d %-6u #%d %-15s %s\n",
+ tsptype[msg->tsp_type],
+ msg->tsp_vers,
+ msg->tsp_seq,
+ msg->tsp_hopcnt,
+ inet_ntoa(addr->sin_addr),
+ msg->tsp_name);
+ break;
+
+ case TSP_SETTIME:
+ case TSP_SETDATE:
+ case TSP_SETDATEREQ:
+#ifdef sgi
+ (void)cftime(tm, "%D %T", &msg->tsp_time.tv_sec);
+#else
+ strncpy(tm, ctime(&msg->tsp_time.tv_sec)+3+1, sizeof(tm));
+ tm[15] = '\0'; /* ugh */
+#endif /* sgi */
+ fprintf(fd, "%s %d %-6u %s %-15s %s\n",
+ tsptype[msg->tsp_type],
+ msg->tsp_vers,
+ msg->tsp_seq,
+ tm,
+ inet_ntoa(addr->sin_addr),
+ msg->tsp_name);
+ break;
+
+ case TSP_ADJTIME:
+ fprintf(fd, "%s %d %-6u (%ld,%ld) %-15s %s\n",
+ tsptype[msg->tsp_type],
+ msg->tsp_vers,
+ msg->tsp_seq,
+ msg->tsp_time.tv_sec,
+ msg->tsp_time.tv_usec,
+ inet_ntoa(addr->sin_addr),
+ msg->tsp_name);
+ break;
+
+ default:
+ fprintf(fd, "%s %d %-6u %-15s %s\n",
+ tsptype[msg->tsp_type],
+ msg->tsp_vers,
+ msg->tsp_seq,
+ inet_ntoa(addr->sin_addr),
+ msg->tsp_name);
+ break;
+ }
+}
diff --git a/usr.sbin/timed/timed/slave.c b/usr.sbin/timed/timed/slave.c
new file mode 100644
index 0000000..3bb6d85
--- /dev/null
+++ b/usr.sbin/timed/timed/slave.c
@@ -0,0 +1,715 @@
+/*-
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)slave.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.20 $"
+#endif
+
+#include "globals.h"
+#include <setjmp.h>
+#include "pathnames.h"
+
+extern jmp_buf jmpenv;
+extern int Mflag;
+extern int justquit;
+
+extern u_short sequence;
+
+static char master_name[MAXHOSTNAMELEN+1];
+static struct netinfo *old_slavenet;
+static int old_status;
+
+static void schgdate __P((struct tsp *, char *));
+static void setmaster __P((struct tsp *));
+static void answerdelay __P((void));
+
+#ifdef sgi
+extern void logwtmp __P((struct timeval *, struct timeval *));
+#else
+extern void logwtmp __P((char *, char *, char *));
+#endif /* sgi */
+
+int
+slave()
+{
+ int tries;
+ long electiontime, refusetime, looktime, looptime, adjtime;
+ u_short seq;
+ long fastelection;
+#define FASTTOUT 3
+ struct in_addr cadr;
+ struct timeval otime;
+ struct sockaddr_in taddr;
+ char tname[MAXHOSTNAMELEN];
+ struct tsp *msg, to;
+ struct timeval ntime, wait;
+ struct tsp *answer;
+ int timeout();
+ char olddate[32];
+ char newdate[32];
+ struct netinfo *ntp;
+ struct hosttbl *htp;
+
+
+ old_slavenet = 0;
+ seq = 0;
+ refusetime = 0;
+ adjtime = 0;
+
+ (void)gettimeofday(&ntime, 0);
+ electiontime = ntime.tv_sec + delay2;
+ fastelection = ntime.tv_sec + FASTTOUT;
+ if (justquit)
+ looktime = electiontime;
+ else
+ looktime = fastelection;
+ looptime = fastelection;
+
+ if (slavenet)
+ xmit(TSP_SLAVEUP, 0, &slavenet->dest_addr);
+ if (status & MASTER) {
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+ if (ntp->status == MASTER)
+ masterup(ntp);
+ }
+ }
+
+loop:
+ get_goodgroup(0);
+ (void)gettimeofday(&ntime, (struct timezone *)0);
+ if (ntime.tv_sec > electiontime) {
+ if (trace)
+ fprintf(fd, "election timer expired\n");
+ longjmp(jmpenv, 1);
+ }
+
+ if (ntime.tv_sec >= looktime) {
+ if (trace)
+ fprintf(fd, "Looking for nets to master\n");
+
+ if (Mflag && nignorednets > 0) {
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+ if (ntp->status == IGNORE
+ || ntp->status == NOMASTER) {
+ lookformaster(ntp);
+ if (ntp->status == MASTER) {
+ masterup(ntp);
+ } else if (ntp->status == MASTER) {
+ ntp->status = NOMASTER;
+ }
+ }
+ if (ntp->status == MASTER
+ && --ntp->quit_count < 0)
+ ntp->quit_count = 0;
+ }
+ makeslave(slavenet); /* prune extras */
+ setstatus();
+ }
+ (void)gettimeofday(&ntime, 0);
+ looktime = ntime.tv_sec + delay2;
+ }
+ if (ntime.tv_sec >= looptime) {
+ if (trace)
+ fprintf(fd, "Looking for loops\n");
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+ if (ntp->status == MASTER) {
+ to.tsp_type = TSP_LOOP;
+ to.tsp_vers = TSPVERSION;
+ to.tsp_seq = sequence++;
+ to.tsp_hopcnt = MAX_HOPCNT;
+ (void)strcpy(to.tsp_name, hostname);
+ bytenetorder(&to);
+ if (sendto(sock, (char *)&to, sizeof(struct tsp), 0,
+ (struct sockaddr*)&ntp->dest_addr,
+ sizeof(ntp->dest_addr)) < 0) {
+ trace_sendto_err(ntp->dest_addr.sin_addr);
+ }
+ }
+ }
+ (void)gettimeofday(&ntime, 0);
+ looptime = ntime.tv_sec + delay2;
+ }
+
+ wait.tv_sec = min(electiontime,min(looktime,looptime)) - ntime.tv_sec;
+ if (wait.tv_sec < 0)
+ wait.tv_sec = 0;
+ wait.tv_sec += FASTTOUT;
+ wait.tv_usec = 0;
+ msg = readmsg(TSP_ANY, ANYADDR, &wait, 0);
+
+ if (msg != NULL) {
+ /*
+ * filter stuff not for us
+ */
+ switch (msg->tsp_type) {
+ case TSP_SETDATE:
+ case TSP_TRACEOFF:
+ case TSP_TRACEON:
+ /*
+ * XXX check to see they are from ourself
+ */
+ break;
+
+ case TSP_TEST:
+ case TSP_MSITE:
+ break;
+
+ case TSP_MASTERUP:
+ if (!fromnet) {
+ if (trace) {
+ fprintf(fd, "slave ignored: ");
+ print(msg, &from);
+ }
+ goto loop;
+ }
+ break;
+
+ default:
+ if (!fromnet
+ || fromnet->status == IGNORE
+ || fromnet->status == NOMASTER) {
+ if (trace) {
+ fprintf(fd, "slave ignored: ");
+ print(msg, &from);
+ }
+ goto loop;
+ }
+ break;
+ }
+
+
+ /*
+ * now process the message
+ */
+ switch (msg->tsp_type) {
+
+ case TSP_ADJTIME:
+ if (fromnet != slavenet)
+ break;
+ if (!good_host_name(msg->tsp_name)) {
+ syslog(LOG_NOTICE,
+ "attempted time adjustment by %s",
+ msg->tsp_name);
+ suppress(&from, msg->tsp_name, fromnet);
+ break;
+ }
+ /*
+ * Speed up loop detection in case we have a loop.
+ * Otherwise the clocks can race until the loop
+ * is found.
+ */
+ (void)gettimeofday(&otime, 0);
+ if (adjtime < otime.tv_sec)
+ looptime -= (looptime-otime.tv_sec)/2 + 1;
+
+ setmaster(msg);
+ if (seq != msg->tsp_seq) {
+ seq = msg->tsp_seq;
+ synch(tvtomsround(msg->tsp_time));
+ }
+ (void)gettimeofday(&ntime, 0);
+ electiontime = ntime.tv_sec + delay2;
+ fastelection = ntime.tv_sec + FASTTOUT;
+ adjtime = ntime.tv_sec + SAMPLEINTVL*2;
+ break;
+
+ case TSP_SETTIME:
+ if (fromnet != slavenet)
+ break;
+ if (seq == msg->tsp_seq)
+ break;
+ seq = msg->tsp_seq;
+
+ /* adjust time for residence on the queue */
+ (void)gettimeofday(&otime, 0);
+ adj_msg_time(msg,&otime);
+#ifdef sgi
+ (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
+ (void)cftime(olddate, "%D %T", &otime.tv_sec);
+#else
+ /*
+ * the following line is necessary due to syslog
+ * calling ctime() which clobbers the static buffer
+ */
+ (void)strcpy(olddate, date());
+ (void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec));
+#endif /* sgi */
+
+ if (!good_host_name(msg->tsp_name)) {
+ syslog(LOG_NOTICE,
+ "attempted time setting by untrusted %s to %s",
+ msg->tsp_name, newdate);
+ suppress(&from, msg->tsp_name, fromnet);
+ break;
+ }
+
+ setmaster(msg);
+ timevalsub(&ntime, &msg->tsp_time, &otime);
+ if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) {
+ /*
+ * do not change the clock if we can adjust it
+ */
+ synch(tvtomsround(ntime));
+ } else {
+#ifdef sgi
+ if (0 > settimeofday(&msg->tsp_time, 0)) {
+ syslog(LOG_ERR,"settimeofdate(): %m");
+ break;
+ }
+ logwtmp(&otime, &msg->tsp_time);
+#else
+ logwtmp("|", "date", "");
+ (void)settimeofday(&msg->tsp_time, 0);
+ logwtmp("}", "date", "");
+#endif /* sgi */
+ syslog(LOG_NOTICE,
+ "date changed by %s from %s",
+ msg->tsp_name, olddate);
+ if (status & MASTER)
+ spreadtime();
+ }
+ (void)gettimeofday(&ntime, 0);
+ electiontime = ntime.tv_sec + delay2;
+ fastelection = ntime.tv_sec + FASTTOUT;
+
+/* This patches a bad protocol bug. Imagine a system with several networks,
+ * where there are a pair of redundant gateways between a pair of networks,
+ * each running timed. Assume that we start with a third machine mastering
+ * one of the networks, and one of the gateways mastering the other.
+ * Imagine that the third machine goes away and the non-master gateway
+ * decides to replace it. If things are timed just 'right,' we will have
+ * each gateway mastering one network for a little while. If a SETTIME
+ * message gets into the network at that time, perhaps from the newly
+ * masterful gateway as it was taking control, the SETTIME will loop
+ * forever. Each time a gateway receives it on its slave side, it will
+ * call spreadtime to forward it on its mastered network. We are now in
+ * a permanent loop, since the SETTIME msgs will keep any clock
+ * in the network from advancing. Normally, the 'LOOP' stuff will detect
+ * and correct the situation. However, with the clocks stopped, the
+ * 'looptime' timer cannot expire. While they are in this state, the
+ * masters will try to saturate the network with SETTIME packets.
+ */
+ looptime = ntime.tv_sec + (looptime-otime.tv_sec)/2-1;
+ break;
+
+ case TSP_MASTERUP:
+ if (slavenet && fromnet != slavenet)
+ break;
+ if (!good_host_name(msg->tsp_name)) {
+ suppress(&from, msg->tsp_name, fromnet);
+ if (electiontime > fastelection)
+ electiontime = fastelection;
+ break;
+ }
+ makeslave(fromnet);
+ setmaster(msg);
+ setstatus();
+ answerdelay();
+ xmit(TSP_SLAVEUP, 0, &from);
+ (void)gettimeofday(&ntime, 0);
+ electiontime = ntime.tv_sec + delay2;
+ fastelection = ntime.tv_sec + FASTTOUT;
+ refusetime = 0;
+ break;
+
+ case TSP_MASTERREQ:
+ if (fromnet->status != SLAVE)
+ break;
+ (void)gettimeofday(&ntime, 0);
+ electiontime = ntime.tv_sec + delay2;
+ break;
+
+ case TSP_SETDATE:
+#ifdef sgi
+ (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
+#else
+ (void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec));
+#endif /* sgi */
+ schgdate(msg, newdate);
+ break;
+
+ case TSP_SETDATEREQ:
+ if (fromnet->status != MASTER)
+ break;
+#ifdef sgi
+ (void)cftime(newdate, "%D %T", &msg->tsp_time.tv_sec);
+#else
+ (void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec));
+#endif /* sgi */
+ htp = findhost(msg->tsp_name);
+ if (0 == htp) {
+ syslog(LOG_WARNING,
+ "DATEREQ from uncontrolled machine");
+ break;
+ }
+ if (!htp->good) {
+ syslog(LOG_WARNING,
+ "attempted date change by untrusted %s to %s",
+ htp->name, newdate);
+ spreadtime();
+ break;
+ }
+ schgdate(msg, newdate);
+ break;
+
+ case TSP_TRACEON:
+ traceon();
+ break;
+
+ case TSP_TRACEOFF:
+ traceoff("Tracing ended at %s\n");
+ break;
+
+ case TSP_SLAVEUP:
+ newslave(msg);
+ break;
+
+ case TSP_ELECTION:
+ if (fromnet->status == SLAVE) {
+ (void)gettimeofday(&ntime, 0);
+ electiontime = ntime.tv_sec + delay2;
+ fastelection = ntime.tv_sec + FASTTOUT;
+ seq = 0;
+ if (!good_host_name(msg->tsp_name)) {
+ syslog(LOG_NOTICE,
+ "suppress election of %s",
+ msg->tsp_name);
+ to.tsp_type = TSP_QUIT;
+ electiontime = fastelection;
+ } else if (cadr.s_addr != from.sin_addr.s_addr
+ && ntime.tv_sec < refusetime) {
+/* if the candidate has to repeat itself, the old code would refuse it
+ * the second time. That would prevent elections.
+ */
+ to.tsp_type = TSP_REFUSE;
+ } else {
+ cadr.s_addr = from.sin_addr.s_addr;
+ to.tsp_type = TSP_ACCEPT;
+ refusetime = ntime.tv_sec + 30;
+ }
+ taddr = from;
+ (void)strcpy(tname, msg->tsp_name);
+ (void)strcpy(to.tsp_name, hostname);
+ answerdelay();
+ if (!acksend(&to, &taddr, tname,
+ TSP_ACK, 0, 0))
+ syslog(LOG_WARNING,
+ "no answer from candidate %s\n",
+ tname);
+
+ } else { /* fromnet->status == MASTER */
+ htp = addmach(msg->tsp_name, &from,fromnet);
+ to.tsp_type = TSP_QUIT;
+ (void)strcpy(to.tsp_name, hostname);
+ if (!acksend(&to, &htp->addr, htp->name,
+ TSP_ACK, 0, htp->noanswer)) {
+ syslog(LOG_ERR,
+ "no reply from %s to ELECTION-QUIT",
+ htp->name);
+ (void)remmach(htp);
+ }
+ }
+ break;
+
+ case TSP_CONFLICT:
+ if (fromnet->status != MASTER)
+ break;
+ /*
+ * After a network partition, there can be
+ * more than one master: the first slave to
+ * come up will notify here the situation.
+ */
+ (void)strcpy(to.tsp_name, hostname);
+
+ /* The other master often gets into the same state,
+ * with boring results.
+ */
+ ntp = fromnet; /* (acksend() can leave fromnet=0 */
+ for (tries = 0; tries < 3; tries++) {
+ to.tsp_type = TSP_RESOLVE;
+ answer = acksend(&to, &ntp->dest_addr,
+ ANYADDR, TSP_MASTERACK,
+ ntp, 0);
+ if (answer == NULL)
+ break;
+ htp = addmach(answer->tsp_name,&from,ntp);
+ to.tsp_type = TSP_QUIT;
+ answer = acksend(&to, &htp->addr, htp->name,
+ TSP_ACK, 0, htp->noanswer);
+ if (!answer) {
+ syslog(LOG_WARNING,
+ "conflict error: no reply from %s to QUIT",
+ htp->name);
+ (void)remmach(htp);
+ }
+ }
+ masterup(ntp);
+ break;
+
+ case TSP_MSITE:
+ if (!slavenet)
+ break;
+ taddr = from;
+ to.tsp_type = TSP_MSITEREQ;
+ to.tsp_vers = TSPVERSION;
+ to.tsp_seq = 0;
+ (void)strcpy(to.tsp_name, hostname);
+ answer = acksend(&to, &slavenet->dest_addr,
+ ANYADDR, TSP_ACK,
+ slavenet, 0);
+ if (answer != NULL
+ && good_host_name(answer->tsp_name)) {
+ setmaster(answer);
+ to.tsp_type = TSP_ACK;
+ (void)strcpy(to.tsp_name, answer->tsp_name);
+ bytenetorder(&to);
+ if (sendto(sock, (char *)&to,
+ sizeof(struct tsp), 0,
+ (struct sockaddr*)&taddr, sizeof(taddr)) < 0) {
+ trace_sendto_err(taddr.sin_addr);
+ }
+ }
+ break;
+
+ case TSP_MSITEREQ:
+ break;
+
+ case TSP_ACCEPT:
+ case TSP_REFUSE:
+ case TSP_RESOLVE:
+ break;
+
+ case TSP_QUIT:
+ doquit(msg); /* become a slave */
+ break;
+
+ case TSP_TEST:
+ electiontime = 0;
+ break;
+
+ case TSP_LOOP:
+ /* looking for loops of masters */
+ if (!(status & MASTER))
+ break;
+ if (fromnet->status == SLAVE) {
+ if (!strcmp(msg->tsp_name, hostname)) {
+ /*
+ * Someone forwarded our message back to
+ * us. There must be a loop. Tell the
+ * master of this network to quit.
+ *
+ * The other master often gets into
+ * the same state, with boring results.
+ */
+ ntp = fromnet;
+ for (tries = 0; tries < 3; tries++) {
+ to.tsp_type = TSP_RESOLVE;
+ answer = acksend(&to, &ntp->dest_addr,
+ ANYADDR, TSP_MASTERACK,
+ ntp,0);
+ if (answer == NULL)
+ break;
+ taddr = from;
+ (void)strcpy(tname, answer->tsp_name);
+ to.tsp_type = TSP_QUIT;
+ (void)strcpy(to.tsp_name, hostname);
+ if (!acksend(&to, &taddr, tname,
+ TSP_ACK, 0, 1)) {
+ syslog(LOG_ERR,
+ "no reply from %s to slave LOOP-QUIT",
+ tname);
+ } else {
+ electiontime = 0;
+ }
+ }
+ (void)gettimeofday(&ntime, 0);
+ looptime = ntime.tv_sec + FASTTOUT;
+ } else {
+ if (msg->tsp_hopcnt-- < 1)
+ break;
+ bytenetorder(msg);
+ for (ntp = nettab; ntp != 0; ntp = ntp->next) {
+ if (ntp->status == MASTER
+ && 0 > sendto(sock, (char *)msg,
+ sizeof(struct tsp), 0,
+ (struct sockaddr*)&ntp->dest_addr,
+ sizeof(ntp->dest_addr)))
+ trace_sendto_err(ntp->dest_addr.sin_addr);
+ }
+ }
+ } else { /* fromnet->status == MASTER */
+ /*
+ * We should not have received this from a net
+ * we are master on. There must be two masters,
+ * unless the packet was really from us.
+ */
+ if (from.sin_addr.s_addr
+ == fromnet->my_addr.s_addr) {
+ if (trace)
+ fprintf(fd,"discarding forwarded LOOP\n");
+ break;
+ }
+
+ /*
+ * The other master often gets into the same
+ * state, with boring results.
+ */
+ ntp = fromnet;
+ for (tries = 0; tries < 3; tries++) {
+ to.tsp_type = TSP_RESOLVE;
+ answer = acksend(&to, &ntp->dest_addr,
+ ANYADDR, TSP_MASTERACK,
+ ntp,0);
+ if (!answer)
+ break;
+ htp = addmach(answer->tsp_name,
+ &from,ntp);
+ to.tsp_type = TSP_QUIT;
+ (void)strcpy(to.tsp_name, hostname);
+ if (!acksend(&to,&htp->addr,htp->name,
+ TSP_ACK, 0, htp->noanswer)) {
+ syslog(LOG_ERR,
+ "no reply from %s to master LOOP-QUIT",
+ htp->name);
+ (void)remmach(htp);
+ }
+ }
+ (void)gettimeofday(&ntime, 0);
+ looptime = ntime.tv_sec + FASTTOUT;
+ }
+ break;
+ default:
+ if (trace) {
+ fprintf(fd, "garbage message: ");
+ print(msg, &from);
+ }
+ break;
+ }
+ }
+ goto loop;
+}
+
+
+/*
+ * tell the world who our master is
+ */
+static void
+setmaster(msg)
+ struct tsp *msg;
+{
+ if (slavenet
+ && (slavenet != old_slavenet
+ || strcmp(msg->tsp_name, master_name)
+ || old_status != status)) {
+ (void)strcpy(master_name, msg->tsp_name);
+ old_slavenet = slavenet;
+ old_status = status;
+
+ if (status & MASTER) {
+ syslog(LOG_NOTICE, "submaster to %s", master_name);
+ if (trace)
+ fprintf(fd, "submaster to %s\n", master_name);
+
+ } else {
+ syslog(LOG_NOTICE, "slave to %s", master_name);
+ if (trace)
+ fprintf(fd, "slave to %s\n", master_name);
+ }
+ }
+}
+
+
+
+/*
+ * handle date change request on a slave
+ */
+static void
+schgdate(msg, newdate)
+ struct tsp *msg;
+ char *newdate;
+{
+ struct tsp to;
+ u_short seq;
+ struct sockaddr_in taddr;
+ struct timeval otime;
+
+ if (!slavenet)
+ return; /* no where to forward */
+
+ taddr = from;
+ seq = msg->tsp_seq;
+
+ syslog(LOG_INFO,
+ "forwarding date change by %s to %s",
+ msg->tsp_name, newdate);
+
+ /* adjust time for residence on the queue */
+ (void)gettimeofday(&otime, 0);
+ adj_msg_time(msg, &otime);
+
+ to.tsp_type = TSP_SETDATEREQ;
+ to.tsp_time = msg->tsp_time;
+ (void)strcpy(to.tsp_name, hostname);
+ if (!acksend(&to, &slavenet->dest_addr,
+ ANYADDR, TSP_DATEACK,
+ slavenet, 0))
+ return; /* no answer */
+
+ xmit(TSP_DATEACK, seq, &taddr);
+}
+
+
+/*
+ * Used before answering a broadcast message to avoid network
+ * contention and likely collisions.
+ */
+static void
+answerdelay()
+{
+#ifdef sgi
+ sginap(delay1);
+#else
+ struct timeval timeout;
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = delay1;
+
+ (void)select(0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL,
+ &timeout);
+ return;
+#endif /* sgi */
+}
diff --git a/usr.sbin/timed/timed/timed.8 b/usr.sbin/timed/timed/timed.8
new file mode 100644
index 0000000..8f8798d
--- /dev/null
+++ b/usr.sbin/timed/timed/timed.8
@@ -0,0 +1,219 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)timed.8 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt TIMED 8
+.Os BSD 4.3
+.Sh NAME
+.Nm timed
+.Nd time server daemon
+.Sh SYNOPSIS
+.Nm timed
+.Op Fl M
+.Op Fl t
+.Op Fl d
+.Op Fl i Ar network
+.Op Fl n Ar network
+.Op Fl F Ar host1 host2 ...
+.Sh DESCRIPTION
+This
+is a time server daemon and is normally invoked
+at boot time from the
+.Xr rc 8
+file.
+It synchronizes the host's time with the time of other
+machines in a local area network running
+.Nm timed 8 .
+These time servers will slow down the clocks of some machines
+and speed up the clocks of others to bring them to the average network time.
+The average network time is computed from measurements of clock differences
+using the
+.Tn ICMP
+timestamp request message.
+.Pp
+The service provided by
+.Nm timed
+is based on a master-slave
+scheme.
+When
+.Nm timed 8
+is started on a machine, it asks the master for the network time
+and sets the host's clock to that time.
+After that, it accepts synchronization messages periodically sent by
+the master and calls
+.Xr adjtime 2
+to perform the needed corrections on the host's clock.
+.Pp
+It also communicates with
+.Xr date 1
+in order to set the date globally,
+and with
+.Xr timedc 8 ,
+a timed control program.
+If the machine running the master crashes, then the slaves will elect
+a new master from among slaves running with the
+.Fl M
+flag.
+A
+.Nm timed
+running without the
+.Fl M
+or
+.Fl F
+flags will remain a slave.
+The
+.Fl t
+flag enables
+.Nm timed
+to trace the messages it receives in the
+file
+.Pa /var/log/timed.log .
+Tracing can be turned on or off by the program
+.Xr timedc 8 .
+The
+.Fl d
+flag is for debugging the daemon.
+It causes the program to not put itself into the background.
+Normally
+.Nm timed
+checks for a master time server on each network to which
+it is connected, except as modified by the options described below.
+It will request synchronization service from the first master server
+located.
+If permitted by the
+.Fl M
+flag, it will provide synchronization service on any attached networks
+on which no current master server was detected.
+Such a server propagates the time computed by the top-level master.
+The
+.Fl n
+flag, followed by the name of a network which the host is connected to
+(see
+.Xr networks 5 ) ,
+overrides the default choice of the
+network addresses made by the program.
+Each time the
+.Fl n
+flag appears, that network name is added to a list of valid networks.
+All other networks are ignored.
+The
+.Fl i
+flag, followed by the name of a network to which the host is connected
+(see
+.Xr networks 5 ) ,
+overrides the default choice of the network addresses made by the program.
+Each time the
+.Fl i
+flag appears, that network name is added to a list of networks to ignore.
+All other networks are used by the time daemon.
+The
+.Fl n
+and
+.Fl i
+flags are meaningless if used together.
+.Pp
+.Nm Timed
+checks for a master time server on each network to which
+it is connected, except as modified by the
+.Fl n
+and
+.Fl i
+options described above.
+If it finds masters on more than one network, it chooses one network
+on which to be a "slave," and then periodically checks the other
+networks to see if the masters there have disappeared.
+.Pp
+One way to synchronize a group of machines is to use an NTP daemon to
+synchronize the clock of one machine to a distant standard or a radio
+receiver and
+.Fl F Ar hostname
+to tell its timed daemon to trust only itself.
+.Pp
+Messages printed by the kernel on the system console occur with
+interrupts disabled.
+This means that the clock stops while they are printing.
+A machine with many disk or network hardware problems and consequent
+messages cannot keep good time by itself. Each message typically causes
+the clock to lose a dozen milliseconds. A time daemon can
+correct the result.
+.Pp
+Messages in the system log about machines that failed to respond
+usually indicate machines that crashed or were turned off.
+Complaints about machines that failed to respond to initial time
+settings are often associated with "multi-homed" machines
+that looked for time masters on more than one network and eventually
+chose to become a slave on the other network.
+.SH WARNING
+If two or more time daemons, whether
+.Nm timed ,
+.Xr NTP ,
+try to adjust the same clock, temporal chaos will result.
+If both
+.Nm
+and another time daemon are run on the same machine,
+ensure that the
+.Fl F
+flag is used, so that
+.Nm timed
+never attempts to adjust the local clock.
+.Pp
+The protocol is based on UDP/IP broadcasts. All machines within
+the range of a broadcast that are using the TSP protocol must cooperate.
+There cannot be more than a single administrative domain using the
+.Fl F
+flag among all machines reached by a broadcast packet.
+Failure to follow this rule is usually indicated by complaints concerning
+"untrusted" machines in the system log.
+.Sh FILES
+.Bl -tag -width /var/log/timed.masterlog -compact
+.It Pa /var/log/timed.log
+tracing file for timed
+.It Pa /var/log/timed.masterlog
+log file for master timed
+.El
+.Sh SEE ALSO
+.Xr date 1 ,
+.Xr adjtime 2 ,
+.Xr gettimeofday 2 ,
+.Xr icmp 4 ,
+.Xr timedc 8 ,
+.Rs
+.%T "TSP: The Time Synchronization Protocol for UNIX 4.3BSD"
+.%A R. Gusella
+.%A S. Zatti
+.Re
+.Sh HISTORY
+The
+.Nm
+daemon appeared in
+.Bx 4.3 .
diff --git a/usr.sbin/timed/timed/timed.c b/usr.sbin/timed/timed/timed.c
new file mode 100644
index 0000000..b8f7dc7
--- /dev/null
+++ b/usr.sbin/timed/timed/timed.c
@@ -0,0 +1,980 @@
+/*-
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1985, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)timed.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.25 $"
+#endif /* sgi */
+
+#define TSPTYPES
+#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>
+#ifdef sgi
+#include <unistd.h>
+#include <sys/syssgi.h>
+#include <sys/schedctl.h>
+#endif /* sgi */
+
+int trace = 0;
+int sock, sock_raw = -1;
+int status = 0;
+u_short sequence; /* sequence number */
+long delay1;
+long delay2;
+
+int nslavenets; /* nets were I could be a slave */
+int nmasternets; /* nets were I could be a master */
+int nignorednets; /* ignored nets */
+int nnets; /* nets I am connected to */
+
+FILE *fd; /* trace file FD */
+
+jmp_buf jmpenv;
+
+struct netinfo *nettab = 0;
+struct netinfo *slavenet;
+int Mflag;
+int justquit = 0;
+int debug;
+
+static struct nets {
+ char *name;
+ long net;
+ struct nets *next;
+} *nets = 0;
+
+struct hosttbl hosttbl[NHOSTS+1]; /* known hosts */
+
+static struct goodhost { /* hosts that we trust */
+ char name[MAXHOSTNAMELEN+1];
+ struct goodhost *next;
+ char perm;
+} *goodhosts;
+
+static char *goodgroup; /* net group of trusted hosts */
+static void checkignorednets __P((void));
+static void pickslavenet __P((struct netinfo *));
+static void add_good_host __P((char *, int));
+
+#ifdef sgi
+char *timetrim_fn;
+char *timetrim_wpat = "long timetrim = %ld;\ndouble tot_adj = %.0f;\ndouble tot_ticks = %.0f;\n/* timed version 2 */\n";
+char *timetrim_rpat = "long timetrim = %ld;\ndouble tot_adj = %lf;\ndouble tot_ticks = %lf;";
+long timetrim;
+double tot_adj, hr_adj; /* totals in nsec */
+double tot_ticks, hr_ticks;
+
+int bufspace = 60*1024;
+#endif
+
+
+/*
+ * The timedaemons synchronize the clocks of hosts in a local area network.
+ * One daemon runs as master, all the others as slaves. The master
+ * performs the task of computing clock differences and sends correction
+ * values to the slaves.
+ * Slaves start an election to choose a new master when the latter disappears
+ * because of a machine crash, network partition, or when killed.
+ * A resolution protocol is used to kill all but one of the masters
+ * that happen to exist in segments of a partitioned network when the
+ * network partition is fixed.
+ *
+ * Authors: Riccardo Gusella & Stefano Zatti
+ *
+ * overhauled at Silicon Graphics
+ */
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int on;
+ int ret;
+ int nflag, iflag;
+ struct timeval ntime;
+ struct servent *srvp;
+ char buf[BUFSIZ], *cp, *cplim;
+ struct ifconf ifc;
+ struct ifreq ifreq, ifreqf, *ifr;
+ register struct netinfo *ntp;
+ struct netinfo *ntip;
+ struct netinfo *savefromnet;
+ struct netent *nentp;
+ struct nets *nt;
+ struct sockaddr_in server;
+ u_short port;
+ char c;
+ extern char *optarg;
+ extern int optind, opterr;
+#ifdef sgi
+ FILE *timetrim_st;
+#endif
+
+#define IN_MSG "timed: -i and -n make no sense together\n"
+#ifdef sgi
+ struct tms tms;
+#define USAGE "timed: [-dtM] [-i net|-n net] [-F host1 host2 ...] [-G netgp] [-P trimfile]\n"
+#else
+#ifdef HAVENIS
+#define USAGE "timed: [-dtM] [-i net|-n net] [-F host1 host2 ...] [-G netgp]\n"
+#else
+#define USAGE "timed: [-dtM] [-i net|-n net] [-F host1 host2 ...]\n"
+#endif /* HAVENIS */
+#endif /* sgi */
+
+#ifdef lint
+ ntip = NULL;
+#endif
+
+ on = 1;
+ nflag = OFF;
+ iflag = OFF;
+
+#ifdef sgi
+ if (0 > syssgi(SGI_GETTIMETRIM, &timetrim)) {
+ perror("timed: syssgi(GETTIMETRIM)");
+ timetrim = 0;
+ }
+ tot_ticks = hr_ticks = times(&tms);
+#endif /* sgi */
+
+ opterr = 0;
+ while ((c = getopt(argc, argv, "Mtdn:i:F:G:P:")) != EOF) {
+ switch (c) {
+ case 'M':
+ Mflag = 1;
+ break;
+
+ case 't':
+ trace = 1;
+ break;
+
+ case 'n':
+ if (iflag) {
+ fprintf(stderr, IN_MSG);
+ exit(1);
+ } else {
+ nflag = ON;
+ addnetname(optarg);
+ }
+ break;
+
+ case 'i':
+ if (nflag) {
+ fprintf(stderr, IN_MSG);
+ exit(1);
+ } else {
+ iflag = ON;
+ addnetname(optarg);
+ }
+ break;
+
+ case 'F':
+ add_good_host(optarg,1);
+ while (optind < argc && argv[optind][0] != '-')
+ add_good_host(argv[optind++], 1);
+ break;
+
+ case 'd':
+ debug = 1;
+ break;
+ case 'G':
+ if (goodgroup != 0) {
+ fprintf(stderr,"timed: only one net group\n");
+ exit(1);
+ }
+ goodgroup = optarg;
+ break;
+#ifdef sgi
+ case 'P':
+ timetrim_fn = optarg;
+ timetrim_st = fopen(timetrim_fn, "r+");
+ if (0 == timetrim_st) {
+ if (errno != ENOENT) {
+ (void)fprintf(stderr,"timed: ");
+ perror(timetrim_fn);
+ timetrim_fn = 0;
+ }
+ } else {
+ int i;
+ long trim;
+ double adj, ticks;
+
+ i = fscanf(timetrim_st, timetrim_rpat,
+ &trim, &adj, &ticks);
+ if (i < 1
+ || trim > MAX_TRIM
+ || trim < -MAX_TRIM
+ || i == 2
+ || (i == 3
+ && trim != rint(adj*CLK_TCK/ticks))) {
+ if (trace && i != EOF)
+ (void)fprintf(stderr,
+ "timed: unrecognized contents in %s\n",
+ timetrim_fn);
+ } else {
+ if (0 > syssgi(SGI_SETTIMETRIM,
+ trim)) {
+ perror("timed: syssgi(SETTIMETRIM)");
+ } else {
+ timetrim = trim;
+ }
+ if (i == 3) {
+ tot_adj = adj;
+ tot_ticks -= ticks;
+ }
+ }
+ (void)fclose(timetrim_st);
+ }
+ break;
+#endif /* sgi */
+
+ default:
+ fprintf(stderr, USAGE);
+ exit(1);
+ break;
+ }
+ }
+ if (optind < argc) {
+ fprintf(stderr, USAGE);
+ exit(1);
+ }
+
+ /* If we care about which machine is the master, then we must
+ * be willing to be a master
+ */
+ if (0 != goodgroup || 0 != goodhosts)
+ Mflag = 1;
+
+ if (gethostname(hostname, sizeof(hostname) - 1) < 0) {
+ perror("gethostname");
+ exit(1);
+ }
+ self.l_bak = &self;
+ self.l_fwd = &self;
+ self.h_bak = &self;
+ self.h_fwd = &self;
+ self.head = 1;
+ self.good = 1;
+
+ if (goodhosts != 0) /* trust ourself */
+ add_good_host(hostname,1);
+
+ srvp = getservbyname("timed", "udp");
+ if (srvp == 0) {
+ fprintf(stderr, "unknown service 'timed/udp'\n");
+ exit(1);
+ }
+ port = srvp->s_port;
+ server.sin_port = srvp->s_port;
+ server.sin_family = AF_INET;
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0) {
+ perror("socket");
+ exit(1);
+ }
+ if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on,
+ sizeof(on)) < 0) {
+ perror("setsockopt");
+ exit(1);
+ }
+ if (bind(sock, (struct sockaddr*)&server, sizeof(server))) {
+ if (errno == EADDRINUSE)
+ fprintf(stderr,"timed: time daemon already running\n");
+ else
+ perror("bind");
+ exit(1);
+ }
+#ifdef sgi
+ /*
+ * handle many slaves with our buffer
+ */
+ if (0 > setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&bufspace,
+ sizeof(bufspace))) {
+ perror("setsockopt");
+ exit(1);
+ }
+#endif /* sgi */
+
+ /* choose a unique seed for random number generation */
+ (void)gettimeofday(&ntime, 0);
+ srandom(ntime.tv_sec + ntime.tv_usec);
+
+ sequence = random(); /* initial seq number */
+
+#ifndef sgi
+ /* rounds kernel variable time to multiple of 5 ms. */
+ ntime.tv_sec = 0;
+ ntime.tv_usec = -((ntime.tv_usec/1000) % 5) * 1000;
+ (void)adjtime(&ntime, (struct timeval *)0);
+#endif /* sgi */
+
+ for (nt = nets; nt; nt = nt->next) {
+ nentp = getnetbyname(nt->name);
+ if (nentp == 0) {
+ nt->net = inet_network(nt->name);
+ if (nt->net != INADDR_NONE)
+ nentp = getnetbyaddr(nt->net, AF_INET);
+ }
+ if (nentp != 0) {
+ nt->net = nentp->n_net;
+ } else if (nt->net == INADDR_NONE) {
+ fprintf(stderr, "timed: unknown net %s\n", nt->name);
+ exit(1);
+ } else if (nt->net == INADDR_ANY) {
+ fprintf(stderr, "timed: bad net %s\n", nt->name);
+ exit(1);
+ } else {
+ fprintf(stderr,
+ "timed: warning: %s unknown in /etc/networks\n",
+ nt->name);
+ }
+
+ if (0 == (nt->net & 0xff000000))
+ nt->net <<= 8;
+ if (0 == (nt->net & 0xff000000))
+ nt->net <<= 8;
+ if (0 == (nt->net & 0xff000000))
+ nt->net <<= 8;
+ }
+ ifc.ifc_len = sizeof(buf);
+ ifc.ifc_buf = buf;
+ if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
+ perror("timed: get interface configuration");
+ exit(1);
+ }
+ ntp = NULL;
+#ifdef sgi
+#define size(p) (sizeof(*ifr) - sizeof(ifr->ifr_name)) /* XXX hack. kludge */
+#else
+#define size(p) max((p).sa_len, sizeof(p))
+#endif
+ cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */
+ for (cp = buf; cp < cplim;
+ cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) {
+ ifr = (struct ifreq *)cp;
+ if (ifr->ifr_addr.sa_family != AF_INET)
+ continue;
+ if (!ntp)
+ ntp = (struct netinfo*)malloc(sizeof(struct netinfo));
+ bzero(ntp,sizeof(*ntp));
+ ntp->my_addr=((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
+ ntp->status = NOMASTER;
+ ifreq = *ifr;
+ ifreqf = *ifr;
+
+ if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreqf) < 0) {
+ perror("get interface flags");
+ continue;
+ }
+ if ((ifreqf.ifr_flags & IFF_UP) == 0)
+ continue;
+ if ((ifreqf.ifr_flags & IFF_BROADCAST) == 0 &&
+ (ifreqf.ifr_flags & IFF_POINTOPOINT) == 0) {
+ continue;
+ }
+
+
+ if (ioctl(sock, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
+ perror("get netmask");
+ continue;
+ }
+ ntp->mask = ((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr.s_addr;
+
+ if (ifreqf.ifr_flags & IFF_BROADCAST) {
+ if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
+ perror("get broadaddr");
+ continue;
+ }
+ ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_broadaddr;
+ /* What if the broadcast address is all ones?
+ * So we cannot just mask ntp->dest_addr. */
+ ntp->net = ntp->my_addr;
+ ntp->net.s_addr &= ntp->mask;
+ } else {
+ if (ioctl(sock, SIOCGIFDSTADDR,
+ (char *)&ifreq) < 0) {
+ perror("get destaddr");
+ 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 == 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) {
+ fprintf(stderr, "timed: no network usable\n");
+ exit(1);
+ }
+
+
+#ifdef sgi
+ (void)schedctl(RENICE,0,10); /* run fast to get good time */
+
+ /* ticks to delay before responding to a broadcast */
+ delay1 = casual(0, CLK_TCK/10);
+#else
+
+ /* microseconds to delay before responding to a broadcast */
+ delay1 = casual(1, 100*1000);
+#endif /* sgi */
+
+ /* election timer delay in secs. */
+ delay2 = casual(MINTOUT, MAXTOUT);
+
+
+#ifdef sgi
+ (void)_daemonize(debug ? _DF_NOFORK|_DF_NOCHDIR : 0, sock, -1, -1);
+#else
+ if (!debug)
+ daemon(debug, 0);
+#endif /* sgi */
+
+ if (trace)
+ traceon();
+ openlog("timed", LOG_CONS|LOG_PID, LOG_DAEMON);
+
+ /*
+ * keep returning here
+ */
+ ret = setjmp(jmpenv);
+ savefromnet = fromnet;
+ setstatus();
+
+ if (Mflag) {
+ switch (ret) {
+
+ case 0:
+ checkignorednets();
+ pickslavenet(0);
+ break;
+ case 1:
+ /* Just lost our master */
+ if (slavenet != 0)
+ slavenet->status = election(slavenet);
+ if (!slavenet || slavenet->status == MASTER) {
+ checkignorednets();
+ pickslavenet(0);
+ } else {
+ makeslave(slavenet); /* prune extras */
+ }
+ break;
+
+ case 2:
+ /* Just been told to quit */
+ justquit = 1;
+ pickslavenet(savefromnet);
+ break;
+ }
+
+ setstatus();
+ if (!(status & MASTER) && sock_raw != -1) {
+ /* sock_raw is not being used now */
+ (void)close(sock_raw);
+ sock_raw = -1;
+ }
+
+ if (status == MASTER)
+ master();
+ else
+ slave();
+
+ } else {
+ if (sock_raw != -1) {
+ (void)close(sock_raw);
+ sock_raw = -1;
+ }
+
+ if (ret) {
+ /* we just lost our master or were told to quit */
+ justquit = 1;
+ }
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+ if (ntp->status == MASTER)
+ rmnetmachs(ntp);
+ ntp->status = NOMASTER;
+ }
+ checkignorednets();
+ pickslavenet(0);
+ setstatus();
+
+ slave();
+ }
+ /* NOTREACHED */
+#ifdef lint
+ return(0);
+#endif
+}
+
+/*
+ * suppress an upstart, untrustworthy, self-appointed master
+ */
+void
+suppress(addr, name,net)
+ struct sockaddr_in *addr;
+ char *name;
+ struct netinfo *net;
+{
+ struct sockaddr_in tgt;
+ char tname[MAXHOSTNAMELEN];
+ struct tsp msg;
+ static struct timeval wait;
+
+ if (trace)
+ fprintf(fd, "suppress: %s\n", name);
+ tgt = *addr;
+ (void)strcpy(tname, name);
+
+ while (0 != readmsg(TSP_ANY, ANYADDR, &wait, net)) {
+ if (trace)
+ fprintf(fd, "suppress:\tdiscarded packet from %s\n",
+ name);
+ }
+
+ syslog(LOG_NOTICE, "suppressing false master %s", tname);
+ msg.tsp_type = TSP_QUIT;
+ (void)strcpy(msg.tsp_name, hostname);
+ (void)acksend(&msg, &tgt, tname, TSP_ACK, 0, 1);
+}
+
+void
+lookformaster(ntp)
+ struct netinfo *ntp;
+{
+ struct tsp resp, conflict, *answer;
+ struct timeval ntime;
+ char mastername[MAXHOSTNAMELEN];
+ struct sockaddr_in masteraddr;
+
+ get_goodgroup(0);
+ ntp->status = SLAVE;
+
+ /* look for master */
+ resp.tsp_type = TSP_MASTERREQ;
+ (void)strcpy(resp.tsp_name, hostname);
+ answer = acksend(&resp, &ntp->dest_addr, ANYADDR,
+ TSP_MASTERACK, ntp, 0);
+ if (answer != 0 && !good_host_name(answer->tsp_name)) {
+ suppress(&from, answer->tsp_name, ntp);
+ ntp->status = NOMASTER;
+ answer = 0;
+ }
+ if (answer == 0) {
+ /*
+ * Various conditions can cause conflict: races between
+ * two just started timedaemons when no master is
+ * present, or timedaemons started during an election.
+ * A conservative approach is taken. Give up and became a
+ * slave, postponing election of a master until first
+ * timer expires.
+ */
+ ntime.tv_sec = ntime.tv_usec = 0;
+ answer = readmsg(TSP_MASTERREQ, ANYADDR, &ntime, ntp);
+ if (answer != 0) {
+ if (!good_host_name(answer->tsp_name)) {
+ suppress(&from, answer->tsp_name, ntp);
+ ntp->status = NOMASTER;
+ }
+ return;
+ }
+
+ ntime.tv_sec = ntime.tv_usec = 0;
+ answer = readmsg(TSP_MASTERUP, ANYADDR, &ntime, ntp);
+ if (answer != 0) {
+ if (!good_host_name(answer->tsp_name)) {
+ suppress(&from, answer->tsp_name, ntp);
+ ntp->status = NOMASTER;
+ }
+ return;
+ }
+
+ ntime.tv_sec = ntime.tv_usec = 0;
+ answer = readmsg(TSP_ELECTION, ANYADDR, &ntime, ntp);
+ if (answer != 0) {
+ if (!good_host_name(answer->tsp_name)) {
+ suppress(&from, answer->tsp_name, ntp);
+ ntp->status = NOMASTER;
+ }
+ return;
+ }
+
+ if (Mflag)
+ ntp->status = MASTER;
+ else
+ ntp->status = NOMASTER;
+ return;
+ }
+
+ ntp->status = SLAVE;
+ (void)strcpy(mastername, answer->tsp_name);
+ masteraddr = from;
+
+ /*
+ * If network has been partitioned, there might be other
+ * masters; tell the one we have just acknowledged that
+ * it has to gain control over the others.
+ */
+ ntime.tv_sec = 0;
+ ntime.tv_usec = 300000;
+ answer = readmsg(TSP_MASTERACK, ANYADDR, &ntime, ntp);
+ /*
+ * checking also not to send CONFLICT to ack'ed master
+ * due to duplicated MASTERACKs
+ */
+ if (answer != NULL &&
+ strcmp(answer->tsp_name, mastername) != 0) {
+ conflict.tsp_type = TSP_CONFLICT;
+ (void)strcpy(conflict.tsp_name, hostname);
+ if (!acksend(&conflict, &masteraddr, mastername,
+ TSP_ACK, 0, 0)) {
+ syslog(LOG_ERR,
+ "error on sending TSP_CONFLICT");
+ }
+ }
+}
+
+/*
+ * based on the current network configuration, set the status, and count
+ * networks;
+ */
+void
+setstatus()
+{
+ struct netinfo *ntp;
+
+ status = 0;
+ nmasternets = nslavenets = nnets = nignorednets = 0;
+ if (trace)
+ fprintf(fd, "Net status:\n");
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+ switch ((int)ntp->status) {
+ case MASTER:
+ nmasternets++;
+ break;
+ case SLAVE:
+ nslavenets++;
+ break;
+ case NOMASTER:
+ case IGNORE:
+ nignorednets++;
+ break;
+ }
+ if (trace) {
+ fprintf(fd, "\t%-16s", inet_ntoa(ntp->net));
+ switch ((int)ntp->status) {
+ case NOMASTER:
+ fprintf(fd, "NOMASTER\n");
+ break;
+ case MASTER:
+ fprintf(fd, "MASTER\n");
+ break;
+ case SLAVE:
+ fprintf(fd, "SLAVE\n");
+ break;
+ case IGNORE:
+ fprintf(fd, "IGNORE\n");
+ break;
+ default:
+ fprintf(fd, "invalid state %d\n",
+ (int)ntp->status);
+ break;
+ }
+ }
+ nnets++;
+ status |= ntp->status;
+ }
+ status &= ~IGNORE;
+ if (trace)
+ fprintf(fd,
+ "\tnets=%d masters=%d slaves=%d ignored=%d delay2=%d\n",
+ nnets, nmasternets, nslavenets, nignorednets, delay2);
+}
+
+void
+makeslave(net)
+ struct netinfo *net;
+{
+ register struct netinfo *ntp;
+
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+ if (ntp->status == SLAVE && ntp != net)
+ ntp->status = IGNORE;
+ }
+ slavenet = net;
+}
+
+/*
+ * Try to become master over ignored nets..
+ */
+static void
+checkignorednets()
+{
+ register struct netinfo *ntp;
+
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+ if (!Mflag && ntp->status == SLAVE)
+ break;
+
+ if (ntp->status == IGNORE || ntp->status == NOMASTER) {
+ lookformaster(ntp);
+ if (!Mflag && ntp->status == SLAVE)
+ break;
+ }
+ }
+}
+
+/*
+ * choose a good network on which to be a slave
+ * The ignored networks must have already been checked.
+ * Take a hint about for a good network.
+ */
+static void
+pickslavenet(ntp)
+ struct netinfo *ntp;
+{
+ if (slavenet != 0 && slavenet->status == SLAVE) {
+ makeslave(slavenet); /* prune extras */
+ return;
+ }
+
+ if (ntp == 0 || ntp->status != SLAVE) {
+ for (ntp = nettab; ntp != 0; ntp = ntp->next) {
+ if (ntp->status == SLAVE)
+ break;
+ }
+ }
+ makeslave(ntp);
+}
+
+/*
+ * returns a random number in the range [inf, sup]
+ */
+long
+casual(inf, sup)
+ long inf, sup;
+{
+ double value;
+
+ value = ((double)(random() & 0x7fffffff)) / (0x7fffffff*1.0);
+ return(inf + (sup - inf)*value);
+}
+
+char *
+date()
+{
+#ifdef sgi
+ struct timeval tv;
+ static char tm[32];
+
+ (void)gettimeofday(&tv, (struct timezone *)0);
+ (void)cftime(tm, "%D %T", &tv.tv_sec);
+ return (tm);
+#else
+ struct timeval tv;
+
+ (void)gettimeofday(&tv, (struct timezone *)0);
+ return (ctime(&tv.tv_sec));
+#endif /* sgi */
+}
+
+void
+addnetname(name)
+ char *name;
+{
+ register struct nets **netlist = &nets;
+
+ while (*netlist)
+ netlist = &((*netlist)->next);
+ *netlist = (struct nets *)malloc(sizeof **netlist);
+ if (*netlist == 0) {
+ fprintf(stderr,"malloc failed\n");
+ exit(1);
+ }
+ bzero((char *)*netlist, sizeof(**netlist));
+ (*netlist)->name = name;
+}
+
+/* note a host as trustworthy */
+static void
+add_good_host(name, perm)
+ char *name;
+ int perm; /* 1=not part of the netgroup */
+{
+ register struct goodhost *ghp;
+ register struct hostent *hentp;
+
+ ghp = (struct goodhost*)malloc(sizeof(*ghp));
+ if (!ghp) {
+ syslog(LOG_ERR, "malloc failed");
+ exit(1);
+ }
+
+ bzero((char*)ghp, sizeof(*ghp));
+ (void)strncpy(&ghp->name[0], name, sizeof(ghp->name));
+ ghp->next = goodhosts;
+ ghp->perm = perm;
+ goodhosts = ghp;
+
+ hentp = gethostbyname(name);
+ if (0 == hentp && perm)
+ (void)fprintf(stderr, "unknown host %s\n", name);
+}
+
+
+/* update our image of the net-group of trustworthy hosts
+ */
+void
+get_goodgroup(force)
+ int force;
+{
+# define NG_DELAY (30*60*CLK_TCK) /* 30 minutes */
+ static unsigned long last_update = -NG_DELAY;
+ unsigned long new_update;
+ struct hosttbl *htp;
+ struct goodhost *ghp, **ghpp;
+ char *mach, *usr, *dom;
+ struct tms tm;
+
+
+ /* if no netgroup, then we are finished */
+ if (goodgroup == 0 || !Mflag)
+ return;
+
+ /* Do not chatter with the netgroup master too often.
+ */
+ new_update = times(&tm);
+ if (new_update < last_update + NG_DELAY
+ && !force)
+ return;
+ last_update = new_update;
+
+ /* forget the old temporary entries */
+ ghpp = &goodhosts;
+ while (0 != (ghp = *ghpp)) {
+ if (!ghp->perm) {
+ *ghpp = ghp->next;
+ free((char*)ghp);
+ } else {
+ ghpp = &ghp->next;
+ }
+ }
+
+#ifdef HAVENIS
+ /* quit now if we are not one of the trusted masters
+ */
+ if (!innetgr(goodgroup, &hostname[0], 0,0)) {
+ if (trace)
+ (void)fprintf(fd, "get_goodgroup: %s not in %s\n",
+ &hostname[0], goodgroup);
+ return;
+ }
+ if (trace)
+ (void)fprintf(fd, "get_goodgroup: %s in %s\n",
+ &hostname[0], goodgroup);
+
+ /* mark the entire netgroup as trusted */
+ (void)setnetgrent(goodgroup);
+ while (getnetgrent(&mach,&usr,&dom)) {
+ if (0 != mach)
+ add_good_host(mach,0);
+ }
+ (void)endnetgrent();
+
+ /* update list of slaves */
+ for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) {
+ htp->good = good_host_name(&htp->name[0]);
+ }
+#endif /* HAVENIS */
+}
+
+
+/* see if a machine is trustworthy
+ */
+int /* 1=trust hp to change our date */
+good_host_name(name)
+ char *name;
+{
+ register struct goodhost *ghp = goodhosts;
+ register char c;
+
+ if (!ghp || !Mflag) /* trust everyone if no one named */
+ return 1;
+
+ c = *name;
+ do {
+ if (c == ghp->name[0]
+ && !strcasecmp(name, ghp->name))
+ return 1; /* found him, so say so */
+ } while (0 != (ghp = ghp->next));
+
+ if (!strcasecmp(name,hostname)) /* trust ourself */
+ return 1;
+
+ return 0; /* did not find him */
+}
diff --git a/usr.sbin/timed/timedc/Makefile b/usr.sbin/timed/timedc/Makefile
new file mode 100644
index 0000000..a0b41ef
--- /dev/null
+++ b/usr.sbin/timed/timedc/Makefile
@@ -0,0 +1,11 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= timedc
+SRCS= cmds.c cmdtab.c timedc.c byteorder.c measure.c cksum.c
+MAN8= timedc.0
+BINOWN= root
+BINMODE=4555
+.PATH: ${.CURDIR}/../timed
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/timed/timedc/cmds.c b/usr.sbin/timed/timedc/cmds.c
new file mode 100644
index 0000000..557f721
--- /dev/null
+++ b/usr.sbin/timed/timedc/cmds.c
@@ -0,0 +1,526 @@
+/*-
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)cmds.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.10 $"
+#endif
+
+#include "timedc.h"
+#include <sys/file.h>
+
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+
+#define TSPTYPES
+#include <protocols/timed.h>
+
+#ifdef sgi
+#include <bstring.h>
+#include <sys/clock.h>
+#else
+#define SECHR (60*60)
+#define SECDAY (24*SECHR)
+#endif /* sgi */
+
+# define DATE_PROTO "udp"
+# define DATE_PORT "time"
+
+
+int sock;
+int sock_raw;
+char myname[MAXHOSTNAMELEN];
+struct hostent *hp;
+struct sockaddr_in server;
+struct sockaddr_in dayaddr;
+extern int measure_delta;
+
+void bytenetorder(struct tsp *);
+void bytehostorder(struct tsp *);
+
+
+#define BU ((unsigned long)2208988800) /* seconds before UNIX epoch */
+
+
+/* compute the difference between our date and another machine
+ */
+static int /* difference in days from our time */
+daydiff(hostname)
+ char *hostname;
+{
+ int i;
+ int trials;
+ struct timeval tout, now;
+ fd_set ready;
+ struct sockaddr from;
+ int fromlen;
+ unsigned long sec;
+
+
+ /* wait 2 seconds between 10 tries */
+ tout.tv_sec = 2;
+ tout.tv_usec = 0;
+ for (trials = 0; trials < 10; trials++) {
+ /* ask for the time */
+ sec = 0;
+ if (sendto(sock, &sec, sizeof(sec), 0,
+ (struct sockaddr*)&dayaddr, sizeof(dayaddr)) < 0) {
+ perror("sendto(sock)");
+ 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;
+ perror("select(date read)");
+ return 0;
+ }
+ if (0 == i)
+ break;
+
+ fromlen = sizeof(from);
+ if (recvfrom(sock,&sec,sizeof(sec),0,
+ &from,&fromlen) < 0) {
+ perror("recvfrom(date read)");
+ return 0;
+ }
+
+ sec = ntohl(sec);
+ if (sec < BU) {
+ fprintf(stderr,
+ "%s says it is before 1970: %lu",
+ hostname, sec);
+ return 0;
+ }
+ sec -= BU;
+
+ (void)gettimeofday(&now, (struct timezone*)0);
+ return (sec - now.tv_sec);
+ }
+ }
+
+ /* if we get here, we tried too many times */
+ fprintf(stderr,"%s will not tell us the date\n", hostname);
+ return 0;
+}
+
+
+/*
+ * Clockdiff computes the difference between the time of the machine on
+ * which it is called and the time of the machines given as argument.
+ * The time differences measured by clockdiff are obtained using a sequence
+ * of ICMP TSTAMP messages which are returned to the sender by the IP module
+ * in the remote machine.
+ * In order to compare clocks of machines in different time zones, the time
+ * is transmitted (as a 32-bit value) in milliseconds since midnight UT.
+ * If a hosts uses a different time format, it should set the high order
+ * bit of the 32-bit quantity it transmits.
+ * However, VMS apparently transmits the time in milliseconds since midnight
+ * local time (rather than GMT) without setting the high order bit.
+ * Furthermore, it does not understand daylight-saving time. This makes
+ * clockdiff behaving inconsistently with hosts running VMS.
+ *
+ * In order to reduce the sensitivity to the variance of message transmission
+ * time, clockdiff sends a sequence of messages. Yet, measures between
+ * two `distant' hosts can be affected by a small error. The error can,
+ * however, be reduced by increasing the number of messages sent in each
+ * measurement.
+ */
+void
+clockdiff(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int measure_status;
+ extern int measure(u_long, u_long, char *, struct sockaddr_in*, int);
+ register int avg_cnt;
+ register long avg;
+ struct servent *sp;
+
+ if (argc < 2) {
+ printf("Usage: clockdiff host ... \n");
+ return;
+ }
+
+ (void)gethostname(myname,sizeof(myname));
+
+ /* get the address for the date ready */
+ sp = getservbyname(DATE_PORT, DATE_PROTO);
+ if (!sp) {
+ (void)fprintf(stderr, "%s/%s is an unknown service\n",
+ DATE_PORT, DATE_PROTO);
+ dayaddr.sin_port = 0;
+ } else {
+ dayaddr.sin_port = sp->s_port;
+ }
+
+ while (argc > 1) {
+ argc--; argv++;
+ hp = gethostbyname(*argv);
+ if (hp == NULL) {
+ fprintf(stderr, "timedc: %s: ", *argv);
+ herror(0);
+ continue;
+ }
+
+ server.sin_family = hp->h_addrtype;
+ bcopy(hp->h_addr, &server.sin_addr.s_addr, hp->h_length);
+ for (avg_cnt = 0, avg = 0; avg_cnt < 16; avg_cnt++) {
+ measure_status = measure(10000,100, *argv, &server, 1);
+ if (measure_status != GOOD)
+ break;
+ avg += measure_delta;
+ }
+ if (measure_status == GOOD)
+ measure_delta = avg/avg_cnt;
+
+ switch (measure_status) {
+ case HOSTDOWN:
+ printf("%s is down\n", hp->h_name);
+ continue;
+ case NONSTDTIME:
+ printf("%s transmitts a non-standard time format\n",
+ hp->h_name);
+ continue;
+ case UNREACHABLE:
+ printf("%s is unreachable\n", hp->h_name);
+ continue;
+ }
+
+ /*
+ * Try to get the date only after using ICMP timestamps to
+ * get the time. This is because the date protocol
+ * is optional.
+ */
+ if (dayaddr.sin_port != 0) {
+ dayaddr.sin_family = hp->h_addrtype;
+ bcopy(hp->h_addr, &dayaddr.sin_addr.s_addr,
+ hp->h_length);
+ avg = daydiff(*argv);
+ if (avg > SECDAY) {
+ printf("time on %s is %ld days ahead %s\n",
+ hp->h_name, avg/SECDAY, myname);
+ continue;
+ } else if (avg < -SECDAY) {
+ printf("time on %s is %ld days behind %s\n",
+ hp->h_name, -avg/SECDAY, myname);
+ continue;
+ }
+ }
+
+ if (measure_delta > 0) {
+ printf("time on %s is %d ms. ahead of time on %s\n",
+ hp->h_name, measure_delta, myname);
+ } else if (measure_delta == 0) {
+ printf("%s and %s have the same time\n",
+ hp->h_name, myname);
+ } else {
+ printf("time on %s is %d ms. behind time on %s\n",
+ hp->h_name, -measure_delta, myname);
+ }
+ }
+ return;
+}
+
+
+/*
+ * finds location of master timedaemon
+ */
+void
+msite(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int cc;
+ fd_set ready;
+ struct sockaddr_in dest;
+ int i, length;
+ struct sockaddr from;
+ struct timeval tout;
+ struct tsp msg;
+ struct servent *srvp;
+ char *tgtname;
+
+ if (argc < 1) {
+ printf("Usage: msite [hostname]\n");
+ return;
+ }
+
+ srvp = getservbyname("timed", "udp");
+ if (srvp == 0) {
+ fprintf(stderr, "udp/timed: unknown service\n");
+ return;
+ }
+ dest.sin_port = srvp->s_port;
+ dest.sin_family = AF_INET;
+
+ (void)gethostname(myname, sizeof(myname));
+ i = 1;
+ do {
+ tgtname = (i >= argc) ? myname : argv[i];
+ hp = gethostbyname(tgtname);
+ if (hp == 0) {
+ fprintf(stderr, "timedc: %s: ", tgtname);
+ herror(0);
+ continue;
+ }
+ bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
+
+ (void)strcpy(msg.tsp_name, myname);
+ msg.tsp_type = TSP_MSITE;
+ msg.tsp_vers = TSPVERSION;
+ bytenetorder(&msg);
+ if (sendto(sock, &msg, sizeof(struct tsp), 0,
+ (struct sockaddr*)&dest,
+ sizeof(struct sockaddr)) < 0) {
+ perror("sendto");
+ continue;
+ }
+
+ tout.tv_sec = 15;
+ tout.tv_usec = 0;
+ FD_ZERO(&ready);
+ FD_SET(sock, &ready);
+ if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0,
+ &tout)) {
+ length = sizeof(struct sockaddr);
+ cc = recvfrom(sock, &msg, sizeof(struct tsp), 0,
+ &from, &length);
+ if (cc < 0) {
+ perror("recvfrom");
+ continue;
+ }
+ bytehostorder(&msg);
+ if (msg.tsp_type == TSP_ACK) {
+ printf("master timedaemon at %s is %s\n",
+ tgtname, msg.tsp_name);
+ } else {
+ printf("received wrong ack: %s\n",
+ tsptype[msg.tsp_type]);
+ }
+ } else {
+ printf("communication error with %s\n", tgtname);
+ }
+ } while (++i < argc);
+}
+
+/*
+ * quits timedc
+ */
+void
+quit()
+{
+ exit(0);
+}
+
+
+/*
+ * Causes the election timer to expire on the selected hosts
+ * It sends just one udp message per machine, relying on
+ * reliability of communication channel.
+ */
+void
+testing(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct servent *srvp;
+ struct sockaddr_in sin;
+ struct tsp msg;
+
+ if (argc < 2) {
+ printf("Usage: election host1 [host2 ...]\n");
+ return;
+ }
+
+ srvp = getservbyname("timed", "udp");
+ if (srvp == 0) {
+ fprintf(stderr, "udp/timed: unknown service\n");
+ return;
+ }
+
+ while (argc > 1) {
+ argc--; argv++;
+ hp = gethostbyname(*argv);
+ if (hp == NULL) {
+ fprintf(stderr, "timedc: %s: ", *argv);
+ herror(0);
+ argc--; argv++;
+ continue;
+ }
+ sin.sin_port = srvp->s_port;
+ sin.sin_family = hp->h_addrtype;
+ bcopy(hp->h_addr, &sin.sin_addr.s_addr, hp->h_length);
+
+ msg.tsp_type = TSP_TEST;
+ msg.tsp_vers = TSPVERSION;
+ (void)gethostname(myname, sizeof(myname));
+ (void)strncpy(msg.tsp_name, myname, sizeof(msg.tsp_name));
+ bytenetorder(&msg);
+ if (sendto(sock, &msg, sizeof(struct tsp), 0,
+ (struct sockaddr*)&sin,
+ sizeof(struct sockaddr)) < 0) {
+ perror("sendto");
+ }
+ }
+}
+
+
+/*
+ * Enables or disables tracing on local timedaemon
+ */
+void
+tracing(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int onflag;
+ int length;
+ int cc;
+ fd_set ready;
+ struct sockaddr_in dest;
+ struct sockaddr from;
+ struct timeval tout;
+ struct tsp msg;
+ struct servent *srvp;
+
+ if (argc != 2) {
+ printf("Usage: tracing { on | off }\n");
+ return;
+ }
+
+ srvp = getservbyname("timed", "udp");
+ if (srvp == 0) {
+ fprintf(stderr, "udp/timed: unknown service\n");
+ return;
+ }
+ dest.sin_port = srvp->s_port;
+ dest.sin_family = AF_INET;
+
+ (void)gethostname(myname,sizeof(myname));
+ hp = gethostbyname(myname);
+ bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
+
+ if (strcmp(argv[1], "on") == 0) {
+ msg.tsp_type = TSP_TRACEON;
+ onflag = ON;
+ } else {
+ msg.tsp_type = TSP_TRACEOFF;
+ onflag = OFF;
+ }
+
+ (void)strcpy(msg.tsp_name, myname);
+ msg.tsp_vers = TSPVERSION;
+ bytenetorder(&msg);
+ if (sendto(sock, &msg, sizeof(struct tsp), 0,
+ (struct sockaddr*)&dest, sizeof(struct sockaddr)) < 0) {
+ perror("sendto");
+ return;
+ }
+
+ tout.tv_sec = 5;
+ tout.tv_usec = 0;
+ FD_ZERO(&ready);
+ FD_SET(sock, &ready);
+ if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) {
+ length = sizeof(struct sockaddr);
+ cc = recvfrom(sock, &msg, sizeof(struct tsp), 0,
+ &from, &length);
+ if (cc < 0) {
+ perror("recvfrom");
+ return;
+ }
+ bytehostorder(&msg);
+ if (msg.tsp_type == TSP_ACK)
+ if (onflag)
+ printf("timed tracing enabled\n");
+ else
+ printf("timed tracing disabled\n");
+ else
+ printf("wrong ack received: %s\n",
+ tsptype[msg.tsp_type]);
+ } else
+ printf("communication error\n");
+}
+
+int
+priv_resources()
+{
+ int port;
+ struct sockaddr_in sin;
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0) {
+ perror("opening socket");
+ return(-1);
+ }
+
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = 0;
+ for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
+ sin.sin_port = htons((u_short)port);
+ if (bind(sock, (struct sockaddr*)&sin, sizeof (sin)) >= 0)
+ break;
+ if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) {
+ perror("bind");
+ (void) close(sock);
+ return(-1);
+ }
+ }
+ if (port == IPPORT_RESERVED / 2) {
+ fprintf(stderr, "all reserved ports in use\n");
+ (void) close(sock);
+ return(-1);
+ }
+
+ sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+ if (sock_raw < 0) {
+ perror("opening raw socket");
+ (void) close(sock);
+ return(-1);
+ }
+ return(1);
+}
diff --git a/usr.sbin/timed/timedc/cmdtab.c b/usr.sbin/timed/timedc/cmdtab.c
new file mode 100644
index 0000000..ad5bbb6
--- /dev/null
+++ b/usr.sbin/timed/timedc/cmdtab.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)cmdtab.c 8.1 (Berkeley) 6/6/93";
+#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]);
diff --git a/usr.sbin/timed/timedc/extern.h b/usr.sbin/timed/timedc/extern.h
new file mode 100644
index 0000000..7f33362
--- /dev/null
+++ b/usr.sbin/timed/timedc/extern.h
@@ -0,0 +1,52 @@
+/*-
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.1 (Berkeley) 6/6/93
+ */
+
+#if __STDC__
+struct tsp;
+#endif
+
+extern struct cmd cmdtab[];
+
+void bytehostorder __P((struct tsp *));
+void bytenetorder __P((struct tsp *));
+void clockdiff __P((int, char *[]));
+void help __P((int, char *[]));
+void intr __P((int));
+void makeargv __P((void));
+void msite __P((int, char *[]));
+int priv_resources __P((void));
+void quit __P((void));
+void testing __P((int, char *[]));
+void tracing __P((int, char *[]));
diff --git a/usr.sbin/timed/timedc/timedc.8 b/usr.sbin/timed/timedc/timedc.8
new file mode 100644
index 0000000..fd495e7
--- /dev/null
+++ b/usr.sbin/timed/timedc/timedc.8
@@ -0,0 +1,145 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)timedc.8 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt TIMEDC 8
+.Os BSD 4.3
+.ad
+.Sh NAME
+.Nm timedc
+.Nd timed control program
+.Sh SYNOPSIS
+.Nm timedc
+.Oo Ar command\ \&
+.Op Ar argument ...
+.Oc
+.Sh DESCRIPTION
+.Nm Timedc
+is used to control the operation of the
+.Xr timed 8
+program.
+It may be used to:
+.Bl -bullet
+.It
+Measure the differences between machines' clocks,
+.It
+Find the location where the master time server is running,
+.It
+Enable or disable tracing of messages received by
+.Xr timed ,
+and
+.It
+Perform various debugging actions.
+.El
+.Pp
+Without any arguments,
+.Nm timedc
+will prompt for commands from the standard input.
+If arguments are supplied,
+.Nm timedc
+interprets the first argument as a command and the remaining
+arguments as parameters to the command. The standard input
+may be redirected causing
+.Nm timedc
+to read commands from a file.
+Commands may be abbreviated;
+recognized commands are:
+.Pp
+.Bl -tag -width Ds -compact
+.It Ic \&? Op Ar command ...
+.Pp
+.It Ic help Op Ar command ...
+Print a short description of each command specified in the argument list,
+or, if no arguments are given, a list of the recognized commands.
+.Pp
+.It Ic clockdiff Ar host ...
+Compute the differences between the clock of the host machine
+and the clocks of the machines given as arguments.
+.Pp
+.It Ic msite Op Ar host ...
+Show the master time server for specified host(s).
+.Pp
+.It Xo
+.Ic trace
+.Li \&{ Ar on Li \&|
+.Ar off \&}
+.Xc
+Enable or disable the tracing of incoming messages to
+.Xr timed
+in the file
+.Pa /var/log/timed.log.
+.Pp
+.It Ic election Ar host
+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 ;
+the help command and
+the program source may be consulted for details.
+.Sh FILES
+.Bl -tag -width /var/log/timed.masterlog -compact
+.It Pa /var/log/timed.log
+tracing file for timed
+.It Pa /var/log/timed.masterlog
+log file for master timed
+.El
+.Sh SEE ALSO
+.Xr date 1 ,
+.Xr adjtime 2 ,
+.Xr icmp 4 ,
+.Xr timed 8 ,
+.Rs
+.%T "TSP: The Time Synchronization Protocol for UNIX 4.3BSD"
+.%A R. Gusella
+.%A S. Zatti
+.Re
+.Sh DIAGNOSTICS
+.Bl -tag -width Ds -compact
+.It ?Ambiguous command
+abbreviation matches more than one command
+.It ?Invalid command
+no match found
+.It ?Privileged command
+command can be executed by root only
+.El
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3 .
diff --git a/usr.sbin/timed/timedc/timedc.c b/usr.sbin/timed/timedc/timedc.c
new file mode 100644
index 0000000..02d086a
--- /dev/null
+++ b/usr.sbin/timed/timedc/timedc.c
@@ -0,0 +1,261 @@
+/*-
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1985, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)timedc.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.6 $"
+#endif
+
+#include "timedc.h"
+#include <strings.h>
+#include <signal.h>
+#include <ctype.h>
+#include <setjmp.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <syslog.h>
+
+int trace = 0;
+FILE *fd = 0;
+int margc;
+int fromatty;
+char *margv[20];
+char cmdline[200];
+jmp_buf toplevel;
+static struct cmd *getcmd __P((char *));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register struct cmd *c;
+
+ openlog("timedc", LOG_ODELAY, LOG_AUTH);
+
+ /*
+ * security dictates!
+ */
+ if (priv_resources() < 0) {
+ fprintf(stderr, "Could not get privileged resources\n");
+ exit(1);
+ }
+ (void) setuid(getuid());
+
+ if (--argc > 0) {
+ c = getcmd(*++argv);
+ if (c == (struct cmd *)-1) {
+ printf("?Ambiguous command\n");
+ exit(1);
+ }
+ if (c == 0) {
+ printf("?Invalid command\n");
+ exit(1);
+ }
+ if (c->c_priv && getuid()) {
+ printf("?Privileged command\n");
+ exit(1);
+ }
+ (*c->c_handler)(argc, argv);
+ exit(0);
+ }
+
+ fromatty = isatty(fileno(stdin));
+ if (setjmp(toplevel))
+ putchar('\n');
+ (void) signal(SIGINT, intr);
+ for (;;) {
+ if (fromatty) {
+ printf("timedc> ");
+ (void) fflush(stdout);
+ }
+ if (fgets(cmdline, sizeof(cmdline), stdin) == 0)
+ quit();
+ if (cmdline[0] == 0)
+ break;
+ makeargv();
+ if (margv[0] == 0)
+ continue;
+ c = getcmd(margv[0]);
+ if (c == (struct cmd *)-1) {
+ printf("?Ambiguous command\n");
+ continue;
+ }
+ if (c == 0) {
+ printf("?Invalid command\n");
+ continue;
+ }
+ if (c->c_priv && getuid()) {
+ printf("?Privileged command\n");
+ continue;
+ }
+ (*c->c_handler)(margc, margv);
+ }
+ return 0;
+}
+
+void
+intr(signo)
+ int signo;
+{
+ if (!fromatty)
+ exit(0);
+ longjmp(toplevel, 1);
+}
+
+
+static struct cmd *
+getcmd(name)
+ char *name;
+{
+ register char *p, *q;
+ register struct cmd *c, *found;
+ register int nmatches, longest;
+ extern int NCMDS;
+
+ longest = 0;
+ nmatches = 0;
+ found = 0;
+ for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
+ p = c->c_name;
+ for (q = name; *q == *p++; q++)
+ if (*q == 0) /* exact match? */
+ return(c);
+ if (!*q) { /* the name was a prefix */
+ if (q - name > longest) {
+ longest = q - name;
+ nmatches = 1;
+ found = c;
+ } else if (q - name == longest)
+ nmatches++;
+ }
+ }
+ if (nmatches > 1)
+ return((struct cmd *)-1);
+ return(found);
+}
+
+/*
+ * Slice a string up into argc/argv.
+ */
+void
+makeargv()
+{
+ register char *cp;
+ register char **argp = margv;
+
+ margc = 0;
+ for (cp = cmdline; *cp;) {
+ while (isspace(*cp))
+ cp++;
+ if (*cp == '\0')
+ break;
+ *argp++ = cp;
+ margc += 1;
+ while (*cp != '\0' && !isspace(*cp))
+ cp++;
+ if (*cp == '\0')
+ break;
+ *cp++ = '\0';
+ }
+ *argp++ = 0;
+}
+
+#define HELPINDENT (sizeof ("directory"))
+
+/*
+ * Help command.
+ */
+void
+help(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register struct cmd *c;
+
+ if (argc == 1) {
+ register int i, j, w;
+ int columns, width = 0, lines;
+ extern int NCMDS;
+
+ printf("Commands may be abbreviated. Commands are:\n\n");
+ for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
+ int len = strlen(c->c_name);
+
+ if (len > width)
+ width = len;
+ }
+ width = (width + 8) &~ 7;
+ columns = 80 / width;
+ if (columns == 0)
+ columns = 1;
+ lines = (NCMDS + columns - 1) / columns;
+ for (i = 0; i < lines; i++) {
+ for (j = 0; j < columns; j++) {
+ c = cmdtab + j * lines + i;
+ printf("%s", c->c_name);
+ if (c + lines >= &cmdtab[NCMDS]) {
+ printf("\n");
+ break;
+ }
+ w = strlen(c->c_name);
+ while (w < width) {
+ w = (w + 8) &~ 7;
+ putchar('\t');
+ }
+ }
+ }
+ return;
+ }
+ while (--argc > 0) {
+ register char *arg;
+ arg = *++argv;
+ c = getcmd(arg);
+ if (c == (struct cmd *)-1)
+ printf("?Ambiguous help command %s\n", arg);
+ else if (c == (struct cmd *)0)
+ printf("?Invalid help command %s\n", arg);
+ else
+ printf("%-*s\t%s\n", (int)HELPINDENT,
+ c->c_name, c->c_help);
+ }
+}
diff --git a/usr.sbin/timed/timedc/timedc.h b/usr.sbin/timed/timedc/timedc.h
new file mode 100644
index 0000000..6771680
--- /dev/null
+++ b/usr.sbin/timed/timedc/timedc.h
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)timedc.h 8.1 (Berkeley) 6/6/93
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#ifdef sgi
+#include <sys/uio.h>
+#endif
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+
+extern int errno;
+
+#define ON 1
+#define OFF 0
+
+#define GOOD 1
+#define UNREACHABLE 2
+#define NONSTDTIME 3
+#define HOSTDOWN 0x7fffffff
+
+struct cmd {
+ char *c_name; /* command name */
+ char *c_help; /* help message */
+ void (*c_handler)(); /* routine to do the work */
+ int c_priv; /* privileged command */
+};
+
+#include "extern.h"
OpenPOWER on IntegriCloud