main.c revision 1.3 1 1.3 kardel /* $NetBSD: main.c,v 1.3 2012/02/01 07:46:23 kardel Exp $ */
2 1.1 kardel
3 1.3 kardel #include <config.h>
4 1.1 kardel
5 1.3 kardel #include "main.h"
6 1.1 kardel #include "kod_management.h"
7 1.1 kardel #include "networking.h"
8 1.1 kardel #include "utilities.h"
9 1.1 kardel #include "log.h"
10 1.1 kardel
11 1.1 kardel int ai_fam_pref = AF_UNSPEC;
12 1.1 kardel
13 1.1 kardel struct key *keys = NULL;
14 1.1 kardel
15 1.1 kardel void set_li_vn_mode (struct pkt *spkt, char leap, char version, char mode);
16 1.1 kardel int sntp_main (int argc, char **argv);
17 1.3 kardel int on_wire (struct addrinfo *host, struct addrinfo *bcastaddr);
18 1.1 kardel int set_time (double offset);
19 1.1 kardel
20 1.3 kardel #define NORMALIZE_TIMEVAL(tv) \
21 1.3 kardel do { \
22 1.3 kardel while ((tv).tv_usec < 0) { \
23 1.3 kardel (tv).tv_usec += 1000000; \
24 1.3 kardel (tv).tv_sec--; \
25 1.3 kardel } \
26 1.3 kardel while ((tv).tv_usec > 999999) { \
27 1.3 kardel (tv).tv_usec -= 1000000; \
28 1.3 kardel (tv).tv_sec++; \
29 1.3 kardel } \
30 1.3 kardel } while (0)
31 1.1 kardel
32 1.1 kardel
33 1.1 kardel /*
34 1.1 kardel * The actual main function.
35 1.1 kardel */
36 1.1 kardel int
37 1.1 kardel sntp_main (
38 1.3 kardel int argc,
39 1.3 kardel char **argv
40 1.3 kardel )
41 1.1 kardel {
42 1.1 kardel register int c;
43 1.1 kardel struct kod_entry *reason = NULL;
44 1.1 kardel int optct;
45 1.3 kardel /* boolean, u_int quiets gcc4 signed overflow warning */
46 1.3 kardel u_int sync_data_suc;
47 1.3 kardel struct addrinfo **bcastaddr = NULL;
48 1.1 kardel struct addrinfo **resh = NULL;
49 1.1 kardel struct addrinfo *ai;
50 1.1 kardel int resc;
51 1.1 kardel int kodc;
52 1.1 kardel int ow_ret;
53 1.3 kardel int bcast = 0;
54 1.1 kardel char *hostname;
55 1.1 kardel
56 1.3 kardel optct = optionProcess(&sntpOptions, argc, argv);
57 1.3 kardel argc -= optct;
58 1.3 kardel argv += optct;
59 1.3 kardel
60 1.3 kardel /* Initialize logging system */
61 1.3 kardel init_logging();
62 1.3 kardel if (HAVE_OPT(LOGFILE))
63 1.3 kardel open_logfile(OPT_ARG(LOGFILE));
64 1.3 kardel
65 1.3 kardel msyslog(LOG_NOTICE, "Started sntp");
66 1.3 kardel
67 1.1 kardel /* IPv6 available? */
68 1.1 kardel if (isc_net_probeipv6() != ISC_R_SUCCESS) {
69 1.1 kardel ai_fam_pref = AF_INET;
70 1.1 kardel #ifdef DEBUG
71 1.1 kardel printf("No ipv6 support available, forcing ipv4\n");
72 1.1 kardel #endif
73 1.3 kardel } else {
74 1.1 kardel /* Check for options -4 and -6 */
75 1.1 kardel if (HAVE_OPT(IPV4))
76 1.1 kardel ai_fam_pref = AF_INET;
77 1.1 kardel else if (HAVE_OPT(IPV6))
78 1.1 kardel ai_fam_pref = AF_INET6;
79 1.1 kardel }
80 1.1 kardel
81 1.1 kardel /* Parse config file if declared TODO */
82 1.1 kardel
83 1.1 kardel /*
84 1.1 kardel * If there's a specified KOD file init KOD system. If not use
85 1.1 kardel * default file. For embedded systems with no writable
86 1.1 kardel * filesystem, -K /dev/null can be used to disable KoD storage.
87 1.1 kardel */
88 1.1 kardel if (HAVE_OPT(KOD))
89 1.1 kardel kod_init_kod_db(OPT_ARG(KOD));
90 1.1 kardel else
91 1.1 kardel kod_init_kod_db("/var/db/ntp-kod");
92 1.1 kardel
93 1.1 kardel if (HAVE_OPT(KEYFILE))
94 1.1 kardel auth_init(OPT_ARG(KEYFILE), &keys);
95 1.1 kardel
96 1.1 kardel #ifdef EXERCISE_KOD_DB
97 1.1 kardel add_entry("192.168.169.170", "DENY");
98 1.1 kardel add_entry("192.168.169.171", "DENY");
99 1.1 kardel add_entry("192.168.169.172", "DENY");
100 1.1 kardel add_entry("192.168.169.173", "DENY");
101 1.1 kardel add_entry("192.168.169.174", "DENY");
102 1.1 kardel delete_entry("192.168.169.174", "DENY");
103 1.1 kardel delete_entry("192.168.169.172", "DENY");
104 1.1 kardel delete_entry("192.168.169.170", "DENY");
105 1.1 kardel if ((kodc = search_entry("192.168.169.173", &reason)) == 0)
106 1.1 kardel printf("entry for 192.168.169.173 not found but should have been!\n");
107 1.1 kardel else
108 1.1 kardel free(reason);
109 1.1 kardel #endif
110 1.1 kardel
111 1.1 kardel /* Considering employing a variable that prevents functions of doing anything until
112 1.1 kardel * everything is initialized properly
113 1.1 kardel */
114 1.3 kardel resc = resolve_hosts((const char **)argv, argc, &resh, ai_fam_pref);
115 1.1 kardel if (resc < 1) {
116 1.1 kardel printf("Unable to resolve hostname(s)\n");
117 1.1 kardel return -1;
118 1.1 kardel }
119 1.3 kardel bcast = ENABLED_OPT(BROADCAST);
120 1.3 kardel if (bcast) {
121 1.3 kardel const char * myargv[2];
122 1.3 kardel
123 1.3 kardel myargv[0] = OPT_ARG(BROADCAST);
124 1.3 kardel myargv[1] = NULL;
125 1.3 kardel bcast = resolve_hosts(myargv, 1, &bcastaddr, ai_fam_pref);
126 1.3 kardel }
127 1.1 kardel
128 1.1 kardel /* Select a certain ntp server according to simple criteria? For now
129 1.1 kardel * let's just pay attention to previous KoDs.
130 1.1 kardel */
131 1.3 kardel sync_data_suc = FALSE;
132 1.1 kardel for (c = 0; c < resc && !sync_data_suc; c++) {
133 1.1 kardel ai = resh[c];
134 1.1 kardel do {
135 1.1 kardel hostname = addrinfo_to_str(ai);
136 1.1 kardel if ((kodc = search_entry(hostname, &reason)) == 0) {
137 1.1 kardel if (is_reachable(ai)) {
138 1.3 kardel ow_ret = on_wire(ai, bcast ? bcastaddr[0] : NULL);
139 1.3 kardel if (0 == ow_ret)
140 1.3 kardel sync_data_suc = TRUE;
141 1.1 kardel }
142 1.1 kardel } else {
143 1.1 kardel printf("%d prior KoD%s for %s, skipping.\n",
144 1.1 kardel kodc, (kodc > 1) ? "s" : "", hostname);
145 1.1 kardel free(reason);
146 1.1 kardel }
147 1.1 kardel free(hostname);
148 1.1 kardel ai = ai->ai_next;
149 1.1 kardel } while (NULL != ai);
150 1.1 kardel freeaddrinfo(resh[c]);
151 1.1 kardel }
152 1.1 kardel free(resh);
153 1.1 kardel
154 1.3 kardel if (!sync_data_suc)
155 1.3 kardel return 1;
156 1.1 kardel return 0;
157 1.1 kardel }
158 1.1 kardel
159 1.3 kardel static union {
160 1.3 kardel struct pkt pkt;
161 1.3 kardel char buf[1500];
162 1.3 kardel } rbuf;
163 1.3 kardel
164 1.3 kardel #define r_pkt rbuf.pkt
165 1.3 kardel
166 1.3 kardel int
167 1.3 kardel generate_pkt (
168 1.3 kardel struct pkt *x_pkt,
169 1.3 kardel const struct timeval *tv_xmt,
170 1.3 kardel int key_id,
171 1.3 kardel struct key *pkt_key
172 1.3 kardel )
173 1.3 kardel {
174 1.3 kardel l_fp xmt;
175 1.3 kardel int pkt_len = LEN_PKT_NOMAC;
176 1.3 kardel memset(x_pkt, 0, sizeof(struct pkt));
177 1.3 kardel TVTOTS(tv_xmt, &xmt);
178 1.3 kardel HTONL_FP(&xmt, &(x_pkt->xmt));
179 1.3 kardel x_pkt->stratum = STRATUM_TO_PKT(STRATUM_UNSPEC);
180 1.3 kardel x_pkt->ppoll = 8;
181 1.3 kardel /* FIXME! Modus broadcast + adr. check -> bdr. pkt */
182 1.3 kardel set_li_vn_mode(x_pkt, LEAP_NOTINSYNC, 4, 3);
183 1.3 kardel if (pkt_key != NULL) {
184 1.3 kardel int mac_size = 20; /* max room for MAC */
185 1.3 kardel x_pkt->exten[0] = htonl(key_id);
186 1.3 kardel mac_size = make_mac((char *)x_pkt, pkt_len, mac_size, pkt_key, (char *)&x_pkt->exten[1]);
187 1.3 kardel if (mac_size)
188 1.3 kardel pkt_len += mac_size + 4;
189 1.3 kardel }
190 1.3 kardel return pkt_len;
191 1.3 kardel }
192 1.3 kardel
193 1.1 kardel int
194 1.3 kardel handle_pkt (
195 1.3 kardel int rpktl,
196 1.3 kardel struct pkt *rpkt,
197 1.3 kardel struct addrinfo *host
198 1.3 kardel )
199 1.1 kardel {
200 1.3 kardel struct timeval tv_dst;
201 1.3 kardel int sw_case, digits;
202 1.3 kardel char *hostname = NULL, *ref, *ts_str = NULL;
203 1.3 kardel double offset, precision, root_dispersion;
204 1.1 kardel char addr_buf[INET6_ADDRSTRLEN];
205 1.3 kardel char *p_SNTP_PRETEND_TIME;
206 1.3 kardel time_t pretend_time;
207 1.1 kardel
208 1.3 kardel if(rpktl > 0)
209 1.3 kardel sw_case = 1;
210 1.3 kardel else
211 1.3 kardel sw_case = rpktl;
212 1.1 kardel
213 1.3 kardel switch(sw_case) {
214 1.3 kardel case SERVER_UNUSEABLE:
215 1.3 kardel return -1;
216 1.3 kardel break;
217 1.1 kardel
218 1.3 kardel case PACKET_UNUSEABLE:
219 1.3 kardel break;
220 1.3 kardel
221 1.3 kardel case SERVER_AUTH_FAIL:
222 1.3 kardel break;
223 1.3 kardel
224 1.3 kardel case KOD_DEMOBILIZE:
225 1.3 kardel /* Received a DENY or RESTR KOD packet */
226 1.3 kardel hostname = addrinfo_to_str(host);
227 1.3 kardel ref = (char *)&rpkt->refid;
228 1.3 kardel add_entry(hostname, ref);
229 1.3 kardel
230 1.3 kardel if (ENABLED_OPT(NORMALVERBOSE))
231 1.3 kardel printf("sntp handle_pkt: Received KOD packet with code: %c%c%c%c from %s, demobilizing all connections\n",
232 1.3 kardel ref[0], ref[1], ref[2], ref[3],
233 1.3 kardel hostname);
234 1.3 kardel
235 1.3 kardel msyslog(LOG_WARNING, "Received a KOD packet with code %c%c%c%c from %s, demobilizing all connections",
236 1.3 kardel ref[0], ref[1], ref[2], ref[3], hostname);
237 1.3 kardel break;
238 1.3 kardel
239 1.3 kardel case KOD_RATE:
240 1.3 kardel /* Hmm... probably we should sleep a bit here */
241 1.3 kardel break;
242 1.3 kardel
243 1.3 kardel case 1:
244 1.3 kardel if (ENABLED_OPT(NORMALVERBOSE)) {
245 1.3 kardel getnameinfo(host->ai_addr, host->ai_addrlen, addr_buf,
246 1.3 kardel sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
247 1.3 kardel printf("sntp handle_pkt: Received %i bytes from %s\n", rpktl, addr_buf);
248 1.3 kardel }
249 1.1 kardel
250 1.3 kardel GETTIMEOFDAY(&tv_dst, (struct timezone *)NULL);
251 1.1 kardel
252 1.3 kardel p_SNTP_PRETEND_TIME = getenv("SNTP_PRETEND_TIME");
253 1.3 kardel if (p_SNTP_PRETEND_TIME) {
254 1.3 kardel #if SIZEOF_TIME_T == 4
255 1.3 kardel sscanf(p_SNTP_PRETEND_TIME, "%ld", &pretend_time);
256 1.3 kardel #elif SIZEOF_TIME_T == 8
257 1.3 kardel sscanf(p_SNTP_PRETEND_TIME, "%lld", &pretend_time);
258 1.3 kardel #else
259 1.3 kardel # include "GRONK: unexpected value for SIZEOF_TIME_T"
260 1.1 kardel #endif
261 1.3 kardel tv_dst.tv_sec = pretend_time;
262 1.3 kardel }
263 1.1 kardel
264 1.3 kardel offset_calculation(rpkt, rpktl, &tv_dst, &offset,
265 1.3 kardel &precision, &root_dispersion);
266 1.1 kardel
267 1.3 kardel for (digits = 0; (precision *= 10.) < 1.; ++digits)
268 1.3 kardel /* empty */ ;
269 1.3 kardel if (digits > 6)
270 1.3 kardel digits = 6;
271 1.3 kardel
272 1.3 kardel ts_str = tv_to_str(&tv_dst);
273 1.3 kardel printf("%s ", ts_str);
274 1.3 kardel if (offset > 0)
275 1.3 kardel printf("+");
276 1.3 kardel printf("%.*f", digits, offset);
277 1.3 kardel if (root_dispersion > 0.)
278 1.3 kardel printf(" +/- %f secs", root_dispersion);
279 1.3 kardel printf("\n");
280 1.3 kardel free(ts_str);
281 1.1 kardel
282 1.3 kardel if (p_SNTP_PRETEND_TIME)
283 1.3 kardel return 0;
284 1.3 kardel
285 1.3 kardel if (ENABLED_OPT(SETTOD) || ENABLED_OPT(ADJTIME))
286 1.3 kardel return set_time(offset);
287 1.3 kardel
288 1.3 kardel return 0;
289 1.3 kardel }
290 1.3 kardel
291 1.3 kardel return 1;
292 1.3 kardel }
293 1.3 kardel
294 1.3 kardel void
295 1.3 kardel offset_calculation (
296 1.3 kardel struct pkt *rpkt,
297 1.3 kardel int rpktl,
298 1.3 kardel struct timeval *tv_dst,
299 1.3 kardel double *offset,
300 1.3 kardel double *precision,
301 1.3 kardel double *root_dispersion
302 1.3 kardel )
303 1.3 kardel {
304 1.3 kardel l_fp p_rec, p_xmt, p_ref, p_org, tmp, dst;
305 1.3 kardel u_fp p_rdly, p_rdsp;
306 1.3 kardel double t21, t34, delta;
307 1.3 kardel
308 1.3 kardel /* Convert timestamps from network to host byte order */
309 1.3 kardel p_rdly = NTOHS_FP(rpkt->rootdelay);
310 1.3 kardel p_rdsp = NTOHS_FP(rpkt->rootdisp);
311 1.3 kardel NTOHL_FP(&rpkt->reftime, &p_ref);
312 1.3 kardel NTOHL_FP(&rpkt->org, &p_org);
313 1.3 kardel NTOHL_FP(&rpkt->rec, &p_rec);
314 1.3 kardel NTOHL_FP(&rpkt->xmt, &p_xmt);
315 1.1 kardel
316 1.3 kardel *precision = LOGTOD(rpkt->precision);
317 1.1 kardel #ifdef DEBUG
318 1.3 kardel printf("sntp precision: %f\n", *precision);
319 1.1 kardel #endif /* DEBUG */
320 1.1 kardel
321 1.3 kardel *root_dispersion = FPTOD(p_rdsp);
322 1.1 kardel
323 1.1 kardel #ifdef DEBUG
324 1.3 kardel printf("sntp rootdelay: %f\n", FPTOD(p_rdly));
325 1.3 kardel printf("sntp rootdisp: %f\n", *root_dispersion);
326 1.1 kardel
327 1.3 kardel pkt_output(rpkt, rpktl, stdout);
328 1.1 kardel
329 1.3 kardel printf("sntp offset_calculation: rpkt->reftime:\n");
330 1.3 kardel l_fp_output(&(rpkt->reftime), stdout);
331 1.3 kardel printf("sntp offset_calculation: rpkt->org:\n");
332 1.3 kardel l_fp_output(&(rpkt->org), stdout);
333 1.3 kardel printf("sntp offset_calculation: rpkt->rec:\n");
334 1.3 kardel l_fp_output(&(rpkt->rec), stdout);
335 1.3 kardel printf("sntp offset_calculation: rpkt->rec:\n");
336 1.3 kardel l_fp_output_bin(&(rpkt->rec), stdout);
337 1.3 kardel printf("sntp offset_calculation: rpkt->rec:\n");
338 1.3 kardel l_fp_output_dec(&(rpkt->rec), stdout);
339 1.3 kardel printf("sntp offset_calculation: rpkt->xmt:\n");
340 1.3 kardel l_fp_output(&(rpkt->xmt), stdout);
341 1.1 kardel #endif
342 1.1 kardel
343 1.3 kardel /* Compute offset etc. */
344 1.3 kardel tmp = p_rec;
345 1.3 kardel L_SUB(&tmp, &p_org);
346 1.3 kardel LFPTOD(&tmp, t21);
347 1.3 kardel TVTOTS(tv_dst, &dst);
348 1.3 kardel dst.l_ui += JAN_1970;
349 1.3 kardel tmp = p_xmt;
350 1.3 kardel L_SUB(&tmp, &dst);
351 1.3 kardel LFPTOD(&tmp, t34);
352 1.3 kardel *offset = (t21 + t34) / 2.;
353 1.3 kardel delta = t21 - t34;
354 1.1 kardel
355 1.3 kardel if (ENABLED_OPT(NORMALVERBOSE))
356 1.3 kardel printf("sntp offset_calculation:\tt21: %.6f\t\t t34: %.6f\n\t\tdelta: %.6f\t offset: %.6f\n",
357 1.3 kardel t21, t34, delta, *offset);
358 1.3 kardel }
359 1.1 kardel
360 1.3 kardel /* The heart of (S)NTP, exchange NTP packets and compute values to correct the local clock */
361 1.3 kardel int
362 1.3 kardel on_wire (
363 1.3 kardel struct addrinfo *host,
364 1.3 kardel struct addrinfo *bcast
365 1.3 kardel )
366 1.3 kardel {
367 1.3 kardel char addr_buf[INET6_ADDRSTRLEN];
368 1.3 kardel register int try;
369 1.3 kardel SOCKET sock;
370 1.3 kardel struct key *pkt_key = NULL;
371 1.3 kardel int key_id = 0;
372 1.3 kardel struct timeval tv_xmt;
373 1.3 kardel struct pkt x_pkt;
374 1.3 kardel int error, rpktl, handle_pkt_res;
375 1.1 kardel
376 1.1 kardel
377 1.3 kardel if (ENABLED_OPT(AUTHENTICATION)) {
378 1.3 kardel key_id = (int) atol(OPT_ARG(AUTHENTICATION));
379 1.3 kardel get_key(key_id, &pkt_key);
380 1.3 kardel }
381 1.3 kardel for (try=0; try<5; try++) {
382 1.3 kardel memset(&r_pkt, 0, sizeof rbuf);
383 1.3 kardel
384 1.3 kardel error = GETTIMEOFDAY(&tv_xmt, (struct timezone *)NULL);
385 1.3 kardel tv_xmt.tv_sec += JAN_1970;
386 1.1 kardel
387 1.3 kardel #ifdef DEBUG
388 1.3 kardel printf("sntp on_wire: Current time sec: %i msec: %i\n", (unsigned int) tv_xmt.tv_sec,
389 1.3 kardel (unsigned int) tv_xmt.tv_usec);
390 1.3 kardel #endif
391 1.1 kardel
392 1.3 kardel if (bcast) {
393 1.3 kardel create_socket(&sock, (sockaddr_u *)bcast->ai_addr);
394 1.3 kardel rpktl = recv_bcst_pkt(sock, &r_pkt, sizeof rbuf, (sockaddr_u *)bcast->ai_addr);
395 1.3 kardel closesocket(sock);
396 1.3 kardel } else {
397 1.3 kardel int pkt_len = generate_pkt(&x_pkt, &tv_xmt, key_id, pkt_key);
398 1.3 kardel
399 1.3 kardel create_socket(&sock, (sockaddr_u *)host->ai_addr);
400 1.3 kardel sendpkt(sock, (sockaddr_u *)host->ai_addr, &x_pkt, pkt_len);
401 1.3 kardel rpktl = recvpkt(sock, &r_pkt, sizeof rbuf, &x_pkt);
402 1.3 kardel closesocket(sock);
403 1.3 kardel }
404 1.1 kardel
405 1.3 kardel handle_pkt_res = handle_pkt(rpktl, &r_pkt, host);
406 1.3 kardel if (handle_pkt_res < 1)
407 1.3 kardel return handle_pkt_res;
408 1.1 kardel }
409 1.1 kardel
410 1.1 kardel getnameinfo(host->ai_addr, host->ai_addrlen, addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
411 1.3 kardel msyslog(LOG_DEBUG, "Received no useable packet from %s!", addr_buf);
412 1.1 kardel
413 1.1 kardel return -1;
414 1.1 kardel }
415 1.1 kardel
416 1.1 kardel /* Compute the 8 bits for li_vn_mode */
417 1.1 kardel void
418 1.1 kardel set_li_vn_mode (
419 1.3 kardel struct pkt *spkt,
420 1.3 kardel char leap,
421 1.3 kardel char version,
422 1.3 kardel char mode
423 1.3 kardel )
424 1.1 kardel {
425 1.3 kardel if (leap > 3) {
426 1.3 kardel msyslog(LOG_DEBUG, "set_li_vn_mode: leap > 3 using max. 3");
427 1.1 kardel leap = 3;
428 1.1 kardel }
429 1.1 kardel
430 1.3 kardel if (mode > 7) {
431 1.3 kardel msyslog(LOG_DEBUG, "set_li_vn_mode: mode > 7, using client mode 3");
432 1.1 kardel mode = 3;
433 1.1 kardel }
434 1.1 kardel
435 1.1 kardel spkt->li_vn_mode = leap << 6;
436 1.1 kardel spkt->li_vn_mode |= version << 3;
437 1.1 kardel spkt->li_vn_mode |= mode;
438 1.1 kardel }
439 1.1 kardel
440 1.1 kardel /* set_time corrects the local clock by offset with either settimeofday() or by default
441 1.1 kardel * with adjtime()/adjusttimeofday().
442 1.1 kardel */
443 1.1 kardel int
444 1.3 kardel set_time(
445 1.3 kardel double offset
446 1.3 kardel )
447 1.1 kardel {
448 1.1 kardel struct timeval tp;
449 1.1 kardel
450 1.3 kardel if (ENABLED_OPT(SETTOD)) {
451 1.3 kardel GETTIMEOFDAY(&tp, NULL);
452 1.1 kardel
453 1.3 kardel tp.tv_sec += (long)offset;
454 1.3 kardel tp.tv_usec += 1e6 * (offset - (long)offset);
455 1.3 kardel NORMALIZE_TIMEVAL(tp);
456 1.1 kardel
457 1.3 kardel if (SETTIMEOFDAY(&tp, NULL) < 0) {
458 1.3 kardel msyslog(LOG_ERR, "Time not set: settimeofday(): %m");
459 1.1 kardel return -1;
460 1.1 kardel }
461 1.3 kardel return 0;
462 1.1 kardel }
463 1.3 kardel
464 1.3 kardel tp.tv_sec = (long)offset;
465 1.3 kardel tp.tv_usec = 1e6 * (offset - (long)offset);
466 1.3 kardel NORMALIZE_TIMEVAL(tp);
467 1.3 kardel
468 1.3 kardel if (ADJTIMEOFDAY(&tp, NULL) < 0) {
469 1.3 kardel msyslog(LOG_ERR, "Time not set: adjtime(): %m");
470 1.3 kardel return -1;
471 1.1 kardel }
472 1.3 kardel return 0;
473 1.1 kardel }
474