MFC r1.6 r1.30 r1.28 (HEAD):
[dragonfly.git] / usr.sbin / rdate / ntpleaps.c
bloba12d8e64f51cca60830048d3aa6e07e213385c00
1 /* $OpenBSD: src/usr.sbin/rdate/ntpleaps.c,v 1.7 2004/05/05 20:29:54 jakob Exp $ */
2 /* $DragonFly: src/usr.sbin/rdate/ntpleaps.c,v 1.1 2004/12/01 15:04:43 joerg Exp $ */
4 /*
5 * Copyright (c) 2002 Thorsten Glaser. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 /* Leap second support for NTP clients (generic) */
36 * I could include tzfile.h, but this would make the code unportable
37 * at no real benefit. Read tzfile.h for why.
40 #include <sys/types.h>
41 #include <netinet/in.h>
43 #include <fcntl.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
49 #include "ntpleaps.h"
51 static uint32_t read_be_dword(uint8_t *ptr);
53 static uint64_t *leapsecs = NULL;
54 static unsigned int leapsecs_num = 0;
55 static int flaginit = -1;
56 static int flagwarn = 0;
58 int
59 ntpleaps_init(void)
61 if (!flaginit)
62 return(0);
64 if (!ntpleaps_read()) {
65 flaginit = 0;
66 return(0);
69 /* This does not really hurt, but users will complain about
70 * off-by-22-seconds (at time of coding) errors if we don't warn.
72 if (!flagwarn) {
73 fputs("Warning: error reading tzfile. You will NOT be\n"
74 "able to get legal time or posix compliance!\n", stderr);
75 flagwarn = 1; /* put it only once */
78 return(-1);
81 int
82 ntpleaps_sub(uint64_t *t)
84 unsigned int i = 0;
85 u_int64_t u;
86 int r = 1;
88 if ((flaginit ? ntpleaps_init() : 0) == -1)
89 return(-1);
91 u = *t;
93 while (i < leapsecs_num) {
94 if (u < leapsecs[i])
95 break;
96 if (u == leapsecs[i++])
97 goto do_sub;
99 --r;
101 do_sub:
102 *t = u - i;
103 return(r);
106 uint32_t
107 read_be_dword(uint8_t *ptr)
109 uint32_t res;
111 memcpy(&res, ptr, 4);
112 return(ntohl(res));
116 ntpleaps_read(void)
118 int fd;
119 unsigned int r;
120 uint8_t buf[32];
121 uint32_t m1, m2, m3;
122 uint64_t s;
123 uint64_t *l;
125 fd = open("/usr/share/zoneinfo/Etc/UTC", O_RDONLY | O_NDELAY);
126 if (fd == -1)
127 return (-1);
129 /* Check signature */
130 read(fd, buf, 4);
131 buf[4] = 0;
132 if (strcmp((const char *)buf, "TZif")) {
133 close(fd);
134 return (-1);
137 /* Pre-initalize buf[24..27] so we need not check read(2) result */
138 buf[24] = 0;
139 buf[25] = 0;
140 buf[26] = 0;
141 buf[27] = 0;
143 /* Skip uninteresting parts of header */
144 read(fd, buf, 28);
146 /* Read number of leap second entries */
147 r = read_be_dword(&buf[24]);
148 /* Check for plausibility - arbitrary values */
149 if ((r < 20) || (r > 60000)) {
150 close(fd);
151 return (-1);
153 if ((l = (uint64_t *)malloc(r << 3)) == NULL) {
154 close(fd);
155 return (-1);
158 /* Skip further uninteresting stuff */
159 read(fd, buf, 12);
160 m1 = read_be_dword(buf);
161 m2 = read_be_dword(&buf[4]);
162 m3 = read_be_dword(&buf[8]);
163 m3 += (m1 << 2) + m1 + (m2 << 2) + (m2 << 1);
164 lseek(fd, (off_t)m3, SEEK_CUR);
166 /* Now go parse the tzfile leap second info */
167 for (m1 = 0; m1 < r; m1++) {
168 if (read(fd, buf, 8) != 8) {
169 free(l);
170 close(fd);
171 return(-1);
173 s = SEC_TO_TAI64(read_be_dword(buf));
175 * Assume just _one_ leap second on each entry, and compensate
176 * the lacking error checking by validating the first entry
177 * against the known value
179 if (!m1 && s != 0x4000000004B2580AULL)
180 return(-1);
181 l[m1] = s;
184 /* Clean up and activate the table */
185 close(fd);
186 if (leapsecs != NULL)
187 free(leapsecs);
188 leapsecs = l;
189 leapsecs_num = r;
190 return(0);