diff options
Diffstat (limited to 'bin/date')
-rw-r--r-- | bin/date/date.1 | 262 | ||||
-rw-r--r-- | bin/date/date.c | 364 | ||||
-rw-r--r-- | bin/date/extern.h | 39 | ||||
-rw-r--r-- | bin/date/netdate.c | 200 |
4 files changed, 865 insertions, 0 deletions
diff --git a/bin/date/date.1 b/bin/date/date.1 new file mode 100644 index 0000000..f15119a --- /dev/null +++ b/bin/date/date.1 @@ -0,0 +1,262 @@ +.\" $NetBSD: date.1,v 1.47 2018/01/27 18:59:38 wiz Exp $ +.\" +.\" Copyright (c) 1980, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, Inc. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)date.1 8.3 (Berkeley) 4/28/95 +.\" +.Dd January 25, 2018 +.Dt DATE 1 +.Os +.Sh NAME +.Nm date +.Nd display or set date and time +.Sh SYNOPSIS +.Nm +.Op Fl ajnu +.Op Fl d Ar date +.Op Fl r Ar seconds +.Op Cm + Ns Ar format +.Sm off +.Oo Oo Oo Oo Oo Oo +.Ar CC Oc +.Ar yy Oc +.Ar mm Oc +.Ar dd Oc +.Ar HH Oc Ar MM Oo +.Li \&. Ar SS Oc Oc +.Sm on +.Sh DESCRIPTION +.Nm +displays the current date and time when invoked without arguments. +Providing arguments will format the date and time in a user-defined +way or set the date. +Only the superuser may set the date. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl a +Use +.Xr adjtime 2 +to change the local system time slowly, +maintaining it as a monotonically increasing function. +.Fl a +implies +.Fl n . +.It Fl d Ar date +Parse the provided human-described date and time and display the result without +actually changing the system clock. +(See +.Xr parsedate 3 +for examples.) +.It Fl j +Parse the provided canonical representation of date and time (described below) +and display the result without actually changing the system clock. +.It Fl n +The utility +.Xr timed 8 +is used to synchronize the clocks on groups of machines. +By default, if +.Xr timed 8 +is running, +.Nm +will set the time on all of the machines in the local group. +The +.Fl n +option stops +.Nm +from setting the time for other than the current machine. +.It Fl r Ar seconds +Print out the date and time that is +.Ar seconds +from the Epoch. +.It Fl u +Display or set the date in UTC (universal) time. +.El +.Pp +An operand with a leading plus +.Pq Cm + +sign signals a user-defined format +string which specifies the format in which to display the date and time. +The format string may contain any of the conversion specifications described +in the +.Xr strftime 3 +manual page, as well as any arbitrary text. +A <newline> character is always output after the characters +specified by the format string. +The format string for the default display is: +.Bd -literal -offset indent +%a %b %e %H:%M:%S %Z %Y +.Ed +.Pp +If an operand does not have a leading plus sign, it is interpreted as +a value for setting the system's notion of the current date and time. +The canonical representation for setting the date and time is: +.Pp +.Bl -tag -width Ds -compact -offset indent +.It Ar CC +The first two digits of the year (the century). +.It Ar yy +The second two digits of the year. +If +.Ar yy +is specified, but +.Ar CC +is not, a value for +.Ar yy +between 69 and 99 results in a +.Ar CC +value of 19. +Otherwise, a +.Ar CC +value of 20 is used. +.It Ar mm +The month of the year, from 01 to 12. +.It Ar dd +The day of the month, from 01 to 31. +.It Ar HH +The hour of the day, from 00 to 23. +.It Ar MM +The minute of the hour, from 00 to 59. +.It Ar SS +The second of the minute, from 00 to 60. +.El +.Pp +Everything but the minutes is optional. +.Pp +Time changes for Daylight Saving and Standard Time and leap seconds +and years are handled automatically. +.Sh ENVIRONMENT +The following environment variables affect the execution of +.Nm : +.Bl -tag -width iTZ +.It Ev TZ +The timezone to use when displaying dates. +See +.Xr environ 7 +for more information. +.El +.Sh FILES +.Bl -tag -width /usr/share/zoneinfo/posixrules -compact +.It Pa /etc/localtime +Symlink pointing to system's default timezone information file in +.Pa /usr/share/zoneinfo +directory. +.It Pa /usr/lib/locale/<L>/LC_TIME +Description of time locale <L>. +.It Pa /usr/share/zoneinfo +Time zone information directory. +.It Pa /usr/share/zoneinfo/posixrules +Used with POSIX-style TZ's. +.It Pa /usr/share/zoneinfo/GMT +For UTC leap seconds. +.It Pa /var/log/wtmp +A record of date resets and time changes. +.It Pa /var/log/messages +A record of the user setting the time. +.El +.Pp +If +.Pa /usr/share/zoneinfo/GMT +is absent, UTC leap seconds are loaded from +.Pa /usr/share/zoneinfo/posixrules . +.Sh EXAMPLES +The command: +.Bd -literal -offset indent +date '+DATE: %m/%d/%y%nTIME: %H:%M:%S' +.Ed +.Pp +will display: +.Bd -literal -offset indent +DATE: 11/21/87 +TIME: 13:36:16 +.Ed +.Pp +The command: +.Bd -literal -offset indent +date 8506131627 +.Ed +.Pp +sets the date to +.Dq Li "June 13, 1985, 4:27 PM" . +.Pp +The command: +.Bd -literal -offset indent +date 1432 +.Ed +.Pp +sets the time to +.Li "2:32 PM" , +without modifying the date. +.Sh DIAGNOSTICS +Exit status is 0 on success, 1 if unable to set the date, and 2 +if able to set the local date, but unable to set it globally. +.Pp +Occasionally, when +.Xr timed 8 +synchronizes the time on many hosts, the setting of a new time value may +require more than a few seconds. +On these occasions, +.Nm +prints: +.Ql Network time being set . +The message +.Ql Communication error with +.Xr timed 8 +occurs when the communication +between +.Nm +and +.Xr timed 8 +fails. +.Sh SEE ALSO +.Xr adjtime 2 , +.Xr gettimeofday 2 , +.Xr settimeofday 2 , +.Xr parsedate 3 , +.Xr strftime 3 , +.Xr utmp 5 , +.Xr environ 7 , +.Xr timed 8 +.Rs +.%T "TSP: The Time Synchronization Protocol for UNIX 4.3BSD" +.%A R. Gusella +.%A S. Zatti +.Re +.Sh STANDARDS +The +.Nm +utility is expected to be compatible with +.St -p1003.2 . +.Sh HISTORY +A +.Nm +utility appeared in +.At v1 . diff --git a/bin/date/date.c b/bin/date/date.c new file mode 100644 index 0000000..a067457 --- /dev/null +++ b/bin/date/date.c @@ -0,0 +1,364 @@ +/* $NetBSD: date.c,v 1.61 2014/09/01 21:42:21 dholland Exp $ */ + +/* + * Copyright (c) 1985, 1987, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#ifndef lint +__COPYRIGHT( +"@(#) Copyright (c) 1985, 1987, 1988, 1993\ + The Regents of the University of California. All rights reserved."); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)date.c 8.2 (Berkeley) 4/28/95"; +#else +__RCSID("$NetBSD: date.c,v 1.61 2014/09/01 21:42:21 dholland Exp $"); +#endif +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/time.h> + +#include <ctype.h> +#include <err.h> +#include <fcntl.h> +#include <errno.h> +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <time.h> +#include <tzfile.h> +#include <unistd.h> +#include <util.h> + +#include "extern.h" + +static time_t tval; +static int aflag, jflag, rflag, nflag; + +__dead static void badcanotime(const char *, const char *, size_t); +static void setthetime(const char *); +__dead static void usage(void); + +int +main(int argc, char *argv[]) +{ + char *buf; + size_t bufsiz; + const char *format; + int ch; + long long val; + struct tm *tm; + + setprogname(argv[0]); + (void)setlocale(LC_ALL, ""); + + while ((ch = getopt(argc, argv, "ad:jnr:u")) != -1) { + switch (ch) { + case 'a': /* adjust time slowly */ + aflag = 1; + nflag = 1; + break; + case 'd': + rflag = 1; + tval = parsedate(optarg, NULL, NULL); + if (tval == -1) { + errx(EXIT_FAILURE, + "%s: Unrecognized date format", optarg); + } + break; + case 'j': /* don't set time */ + jflag = 1; + break; + case 'n': /* don't set network */ + nflag = 1; + break; + case 'r': /* user specified seconds */ + if (optarg[0] == '\0') { + errx(EXIT_FAILURE, "<empty>: Invalid number"); + } + errno = 0; + val = strtoll(optarg, &buf, 0); + if (errno) { + err(EXIT_FAILURE, "%s", optarg); + } + if (optarg[0] == '\0' || *buf != '\0') { + errx(EXIT_FAILURE, + "%s: Invalid number", optarg); + } + rflag = 1; + tval = (time_t)val; + break; + case 'u': /* do everything in UTC */ + (void)setenv("TZ", "UTC0", 1); + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (!rflag && time(&tval) == -1) + err(EXIT_FAILURE, "time"); + + + /* allow the operands in any order */ + if (*argv && **argv == '+') { + format = *argv; + ++argv; + } else + format = "+%a %b %e %H:%M:%S %Z %Y"; + + if (*argv) { + setthetime(*argv); + ++argv; + } + + if (*argv && **argv == '+') + format = *argv; + + if ((buf = malloc(bufsiz = 1024)) == NULL) + goto bad; + + if ((tm = localtime(&tval)) == NULL) + err(EXIT_FAILURE, "%lld: localtime", (long long)tval); + + while (strftime(buf, bufsiz, format, tm) == 0) + if ((buf = realloc(buf, bufsiz <<= 1)) == NULL) + goto bad; + + (void)printf("%s\n", buf + 1); + free(buf); + return 0; +bad: + err(EXIT_FAILURE, "Cannot allocate format buffer"); +} + +static void +badcanotime(const char *msg, const char *val, size_t where) +{ + warnx("%s in canonical time", msg); + warnx("%s", val); + warnx("%*s", (int)where + 1, "^"); + usage(); +} + +#define ATOI2(s) ((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0')) + +static void +setthetime(const char *p) +{ + struct timeval tv; + time_t new_time; + struct tm *lt; + const char *dot, *t, *op; + size_t len; + int yearset; + + for (t = p, dot = NULL; *t; ++t) { + if (*t == '.') { + if (dot == NULL) { + dot = t; + } else { + badcanotime("Unexpected dot", p, t - p); + } + } else if (!isdigit((unsigned char)*t)) { + badcanotime("Expected digit", p, t - p); + } + } + + if ((lt = localtime(&tval)) == NULL) + err(EXIT_FAILURE, "%lld: localtime", (long long)tval); + + lt->tm_isdst = -1; /* Divine correct DST */ + + if (dot != NULL) { /* .ss */ + len = strlen(dot); + if (len > 3) { + badcanotime("Unexpected digit after seconds field", + p, strlen(p) - 1); + } else if (len < 3) { + badcanotime("Expected digit in seconds field", + p, strlen(p)); + } + ++dot; + lt->tm_sec = ATOI2(dot); + if (lt->tm_sec > 61) + badcanotime("Seconds out of range", p, strlen(p) - 1); + } else { + len = 0; + lt->tm_sec = 0; + } + + op = p; + yearset = 0; + switch (strlen(p) - len) { + case 12: /* cc */ + lt->tm_year = ATOI2(p) * 100 - TM_YEAR_BASE; + if (lt->tm_year < 0) + badcanotime("Year before 1900", op, p - op + 1); + yearset = 1; + /* FALLTHROUGH */ + case 10: /* yy */ + if (yearset) { + lt->tm_year += ATOI2(p); + } else { + yearset = ATOI2(p); + if (yearset < 69) + lt->tm_year = yearset + 2000 - TM_YEAR_BASE; + else + lt->tm_year = yearset + 1900 - TM_YEAR_BASE; + } + /* FALLTHROUGH */ + case 8: /* mm */ + lt->tm_mon = ATOI2(p); + if (lt->tm_mon > 12 || lt->tm_mon == 0) + badcanotime("Month out of range", op, p - op - 1); + --lt->tm_mon; /* time struct is 0 - 11 */ + /* FALLTHROUGH */ + case 6: /* dd */ + lt->tm_mday = ATOI2(p); + switch (lt->tm_mon) { + case 0: + case 2: + case 4: + case 6: + case 7: + case 9: + case 11: + if (lt->tm_mday > 31 || lt->tm_mday == 0) + badcanotime("Day out of range (max 31)", + op, p - op - 1); + break; + case 3: + case 5: + case 8: + case 10: + if (lt->tm_mday > 30 || lt->tm_mday == 0) + badcanotime("Day out of range (max 30)", + op, p - op - 1); + break; + case 1: + if (isleap(lt->tm_year + TM_YEAR_BASE)) { + if (lt->tm_mday > 29 || lt->tm_mday == 0) { + badcanotime("Day out of range " + "(max 29)", + op, p - op - 1); + } + } else { + if (lt->tm_mday > 28 || lt->tm_mday == 0) { + badcanotime("Day out of range " + "(max 28)", + op, p - op - 1); + } + } + break; + default: + /* + * If the month was given, it's already been + * checked. If a bad value came back from + * localtime, something's badly broken. + * (make this an assertion?) + */ + errx(EXIT_FAILURE, "localtime gave invalid month %d", + lt->tm_mon); + } + /* FALLTHROUGH */ + case 4: /* hh */ + lt->tm_hour = ATOI2(p); + if (lt->tm_hour > 23) + badcanotime("Hour out of range", op, p - op - 1); + /* FALLTHROUGH */ + case 2: /* mm */ + lt->tm_min = ATOI2(p); + if (lt->tm_min > 59) + badcanotime("Minute out of range", op, p - op - 1); + break; + case 0: /* was just .sss */ + if (len != 0) + break; + /* FALLTHROUGH */ + default: + if (strlen(p) - len > 12) { + badcanotime("Too many digits", p, 12); + } else { + badcanotime("Not enough digits", p, strlen(p) - len); + } + } + + /* convert broken-down time to UTC clock time */ + if ((new_time = mktime(lt)) == -1) { + /* Can this actually happen? */ + err(EXIT_FAILURE, "%s: mktime", op); + } + + /* if jflag is set, don't actually change the time, just return */ + if (jflag) { + tval = new_time; + return; + } + + /* set the time */ + if (nflag || netsettime(new_time)) { + logwtmp("|", "date", ""); + if (aflag) { + tv.tv_sec = new_time - tval; + tv.tv_usec = 0; + if (adjtime(&tv, NULL)) + err(EXIT_FAILURE, "adjtime"); + } else { + tval = new_time; + tv.tv_sec = tval; + tv.tv_usec = 0; + if (settimeofday(&tv, NULL)) + err(EXIT_FAILURE, "settimeofday"); + } + logwtmp("{", "date", ""); + } + + if ((p = getlogin()) == NULL) + p = "???"; + syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", p); +} + +static void +usage(void) +{ + (void)fprintf(stderr, + "Usage: %s [-ajnu] [-d date] [-r seconds] [+format]", + getprogname()); + (void)fprintf(stderr, " [[[[[[CC]yy]mm]dd]HH]MM[.SS]]\n"); + exit(EXIT_FAILURE); + /* NOTREACHED */ +} diff --git a/bin/date/extern.h b/bin/date/extern.h new file mode 100644 index 0000000..bbb786f --- /dev/null +++ b/bin/date/extern.h @@ -0,0 +1,39 @@ +/* $NetBSD: extern.h,v 1.8 2006/11/17 22:11:28 christos Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)extern.h 8.1 (Berkeley) 5/31/93 + */ + +#ifndef _EXTERN_H_ +#define _EXTERN_H_ + +int netsettime(time_t); + +#endif /* !_EXTERN_H_ */ diff --git a/bin/date/netdate.c b/bin/date/netdate.c new file mode 100644 index 0000000..5b5857c --- /dev/null +++ b/bin/date/netdate.c @@ -0,0 +1,200 @@ +/* $NetBSD: netdate.c,v 1.30 2011/01/29 02:16:52 christos Exp $ */ + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#ifndef lint +#if 0 +static char sccsid[] = "@(#)netdate.c 8.2 (Berkeley) 4/28/95"; +#else +__RCSID("$NetBSD: netdate.c,v 1.30 2011/01/29 02:16:52 christos Exp $"); +#endif +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/time.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <netdb.h> +#define TSPTYPES +#include <protocols/timed.h> + +#include <err.h> +#include <errno.h> +#include <poll.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include "extern.h" + +#define WAITACK 2000 /* milliseconds */ +#define WAITDATEACK 5000 /* milliseconds */ + +static const char * +tsp_type_to_string(const struct tsp *msg) +{ + unsigned i; + + i = msg->tsp_type; + return i < TSPTYPENUMBER ? tsptype[i] : "unknown"; +} + +/* + * Set the date in the machines controlled by timedaemons by communicating the + * new date to the local timedaemon. If the timedaemon is in the master state, + * it performs the correction on all slaves. If it is in the slave state, it + * notifies the master that a correction is needed. + * Returns 0 on success. Returns > 0 on failure. + */ +int +netsettime(time_t tval) +{ + struct sockaddr_in dest; + struct tsp msg; + char hostname[MAXHOSTNAMELEN]; + struct servent *sp; + struct pollfd ready; + int found, s, timed_ack, waittime; + + if ((sp = getservbyname("timed", "udp")) == NULL) { + warnx("udp/timed: unknown service"); + return 2; + } + + (void)memset(&dest, 0, sizeof(dest)); +#ifdef BSD4_4 + dest.sin_len = sizeof(dest); +#endif + dest.sin_family = AF_INET; + dest.sin_port = sp->s_port; + dest.sin_addr.s_addr = htonl(INADDR_ANY); + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s == -1) { + if (errno != EAFNOSUPPORT) + warn("timed"); + return 2; + } + +#ifdef IP_PORTRANGE + { + static const int on = IP_PORTRANGE_LOW; + + if (setsockopt(s, IPPROTO_IP, IP_PORTRANGE, &on, + sizeof(on)) == -1) { + warn("setsockopt"); + goto bad; + } + } +#endif + + msg.tsp_type = TSP_SETDATE; + msg.tsp_vers = TSPVERSION; + if (gethostname(hostname, sizeof(hostname)) == -1) { + warn("gethostname"); + goto bad; + } + (void)strlcpy(msg.tsp_name, hostname, sizeof(msg.tsp_name)); + msg.tsp_seq = htons((in_port_t)0); + msg.tsp_time.tv_sec = htonl((in_addr_t)tval); /* XXX: y2038 */ + msg.tsp_time.tv_usec = htonl((in_addr_t)0); + if (connect(s, (const void *)&dest, sizeof(dest)) == -1) { + warn("connect"); + goto bad; + } + if (send(s, &msg, sizeof(msg), 0) == -1) { + if (errno != ECONNREFUSED) + warn("send"); + goto bad; + } + + timed_ack = -1; + waittime = WAITACK; + ready.fd = s; + ready.events = POLLIN; +loop: + found = poll(&ready, 1, waittime); + + { + socklen_t len; + int error; + + len = sizeof(error); + if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) == -1) { + warn("getsockopt"); + goto bad; + } + if (error) { + if (error != ECONNREFUSED) { + errno = error; + warn("send (delayed error)"); + } + goto bad; + } + } + + if (found > 0 && ready.revents & POLLIN) { + ssize_t ret; + + if ((ret = recv(s, &msg, sizeof(msg), 0)) == -1) { + if (errno != ECONNREFUSED) + warn("recv"); + goto bad; + } else if ((size_t)ret < sizeof(msg)) { + warnx("recv: incomplete packet"); + goto bad; + } + + msg.tsp_seq = ntohs(msg.tsp_seq); + msg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec); + msg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec); + switch (msg.tsp_type) { + case TSP_ACK: + timed_ack = TSP_ACK; + waittime = WAITDATEACK; + goto loop; + case TSP_DATEACK: + (void)close(s); + return 0; + default: + warnx("wrong ack received from timed: %s", + tsp_type_to_string(&msg)); + timed_ack = -1; + break; + } + } + if (timed_ack == -1) + warnx("can't reach time daemon, time set locally"); + +bad: + (void)close(s); + return 2; +} |