]>
Commit | Line | Data |
---|---|---|
7ba0088d A |
1 | /* $FreeBSD: src/usr.sbin/setkey/setkey.c,v 1.1.2.2 2001/07/03 11:02:17 ume Exp $ */ |
2 | /* $KAME: setkey.c,v 1.18 2001/05/08 04:36:39 itojun Exp $ */ | |
3 | ||
4 | /* | |
5 | * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. | |
6 | * All rights reserved. | |
7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | |
11 | * 1. Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | |
13 | * 2. Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in the | |
15 | * documentation and/or other materials provided with the distribution. | |
16 | * 3. Neither the name of the project nor the names of its contributors | |
17 | * may be used to endorse or promote products derived from this software | |
18 | * without specific prior written permission. | |
19 | * | |
20 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND | |
21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE | |
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
30 | * SUCH DAMAGE. | |
31 | */ | |
32 | ||
33 | #include <sys/types.h> | |
34 | #include <sys/param.h> | |
35 | #include <sys/socket.h> | |
36 | #include <sys/time.h> | |
37 | #include <err.h> | |
38 | #include <net/route.h> | |
39 | #include <netinet/in.h> | |
40 | #include <net/pfkeyv2.h> | |
41 | #include <netkey/keydb.h> | |
42 | #include <netkey/key_debug.h> | |
43 | #include <netinet6/ipsec.h> | |
44 | ||
45 | #include <stdio.h> | |
46 | #include <stdlib.h> | |
47 | #include <limits.h> | |
48 | #include <string.h> | |
49 | #include <ctype.h> | |
50 | #include <unistd.h> | |
51 | #include <errno.h> | |
52 | #include <netdb.h> | |
53 | ||
54 | #include "libpfkey.h" | |
55 | ||
56 | void Usage __P((void)); | |
57 | int main __P((int, char **)); | |
58 | int get_supported __P((void)); | |
59 | void sendkeyshort __P((u_int)); | |
60 | void promisc __P((void)); | |
61 | int sendkeymsg __P((void)); | |
62 | int postproc __P((struct sadb_msg *, int)); | |
63 | const char *numstr __P((int)); | |
64 | void shortdump_hdr __P((void)); | |
65 | void shortdump __P((struct sadb_msg *)); | |
66 | static void printdate __P((void)); | |
67 | static int32_t gmt2local __P((time_t)); | |
68 | ||
69 | #define MODE_SCRIPT 1 | |
70 | #define MODE_CMDDUMP 2 | |
71 | #define MODE_CMDFLUSH 3 | |
72 | #define MODE_PROMISC 4 | |
73 | ||
74 | int so; | |
75 | ||
76 | int f_forever = 0; | |
77 | int f_all = 0; | |
78 | int f_debug = 0; | |
79 | int f_verbose = 0; | |
80 | int f_mode = 0; | |
81 | int f_cmddump = 0; | |
82 | int f_policy = 0; | |
83 | int f_hexdump = 0; | |
84 | int f_tflag = 0; | |
85 | char *pname; | |
86 | ||
87 | u_char m_buf[BUFSIZ]; | |
88 | u_int m_len; | |
89 | ||
90 | static time_t thiszone; | |
91 | ||
92 | extern int lineno; | |
93 | ||
94 | extern int parse __P((FILE **)); | |
95 | ||
96 | void | |
97 | Usage() | |
98 | { | |
99 | printf("Usage:\t%s [-dv] -c\n", pname); | |
100 | printf("\t%s [-dv] -f (file)\n", pname); | |
101 | printf("\t%s [-Padlv] -D\n", pname); | |
102 | printf("\t%s [-Pdv] -F\n", pname); | |
103 | printf("\t%s [-h] -x\n", pname); | |
104 | pfkey_close(so); | |
105 | exit(1); | |
106 | } | |
107 | ||
108 | int | |
109 | main(ac, av) | |
110 | int ac; | |
111 | char **av; | |
112 | { | |
113 | FILE *fp = stdin; | |
114 | int c; | |
115 | ||
116 | pname = *av; | |
117 | ||
118 | if (ac == 1) Usage(); | |
119 | ||
120 | thiszone = gmt2local(0); | |
121 | ||
122 | while ((c = getopt(ac, av, "acdf:hlvxDFP")) != -1) { | |
123 | switch (c) { | |
124 | case 'c': | |
125 | f_mode = MODE_SCRIPT; | |
126 | fp = stdin; | |
127 | break; | |
128 | case 'f': | |
129 | f_mode = MODE_SCRIPT; | |
130 | if ((fp = fopen(optarg, "r")) == NULL) { | |
131 | err(-1, "fopen"); | |
132 | /*NOTREACHED*/ | |
133 | } | |
134 | break; | |
135 | case 'D': | |
136 | f_mode = MODE_CMDDUMP; | |
137 | break; | |
138 | case 'F': | |
139 | f_mode = MODE_CMDFLUSH; | |
140 | break; | |
141 | case 'a': | |
142 | f_all = 1; | |
143 | break; | |
144 | case 'l': | |
145 | f_forever = 1; | |
146 | break; | |
147 | case 'h': | |
148 | f_hexdump = 1; | |
149 | break; | |
150 | case 'x': | |
151 | f_mode = MODE_PROMISC; | |
152 | f_tflag++; | |
153 | break; | |
154 | case 'P': | |
155 | f_policy = 1; | |
156 | break; | |
157 | case 'd': | |
158 | f_debug = 1; | |
159 | break; | |
160 | case 'v': | |
161 | f_verbose = 1; | |
162 | break; | |
163 | default: | |
164 | Usage(); | |
165 | /*NOTREACHED*/ | |
166 | } | |
167 | } | |
168 | ||
169 | switch (f_mode) { | |
170 | case MODE_CMDDUMP: | |
171 | sendkeyshort(f_policy ? SADB_X_SPDDUMP: SADB_DUMP); | |
172 | break; | |
173 | case MODE_CMDFLUSH: | |
174 | sendkeyshort(f_policy ? SADB_X_SPDFLUSH: SADB_FLUSH); | |
175 | pfkey_close(so); | |
176 | break; | |
177 | case MODE_SCRIPT: | |
178 | if (get_supported() < 0) { | |
179 | errx(-1, "%s", ipsec_strerror()); | |
180 | /*NOTREACHED*/ | |
181 | } | |
182 | if (parse(&fp)) | |
183 | exit (1); | |
184 | break; | |
185 | case MODE_PROMISC: | |
186 | promisc(); | |
187 | /*NOTREACHED*/ | |
188 | default: | |
189 | Usage(); | |
190 | /*NOTREACHED*/ | |
191 | } | |
192 | ||
193 | exit(0); | |
194 | } | |
195 | ||
196 | int | |
197 | get_supported() | |
198 | { | |
199 | int so; | |
200 | ||
201 | if ((so = pfkey_open()) < 0) { | |
202 | perror("pfkey_open"); | |
203 | return -1; | |
204 | } | |
205 | ||
206 | /* debug mode ? */ | |
207 | if (f_debug) | |
208 | return 0; | |
209 | ||
210 | if (pfkey_send_register(so, SADB_SATYPE_UNSPEC) < 0) | |
211 | return -1; | |
212 | ||
213 | if (pfkey_recv_register(so) < 0) | |
214 | return -1; | |
215 | ||
216 | return 0; | |
217 | } | |
218 | ||
219 | void | |
220 | sendkeyshort(type) | |
221 | u_int type; | |
222 | { | |
223 | struct sadb_msg *m_msg = (struct sadb_msg *)m_buf; | |
224 | ||
225 | m_len = sizeof(struct sadb_msg); | |
226 | ||
227 | m_msg->sadb_msg_version = PF_KEY_V2; | |
228 | m_msg->sadb_msg_type = type; | |
229 | m_msg->sadb_msg_errno = 0; | |
230 | m_msg->sadb_msg_satype = SADB_SATYPE_UNSPEC; | |
231 | m_msg->sadb_msg_len = PFKEY_UNIT64(m_len); | |
232 | m_msg->sadb_msg_reserved = 0; | |
233 | m_msg->sadb_msg_seq = 0; | |
234 | m_msg->sadb_msg_pid = getpid(); | |
235 | ||
236 | sendkeymsg(); | |
237 | ||
238 | return; | |
239 | } | |
240 | ||
241 | void | |
242 | promisc() | |
243 | { | |
244 | struct sadb_msg *m_msg = (struct sadb_msg *)m_buf; | |
245 | u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */ | |
246 | int so, len; | |
247 | ||
248 | m_len = sizeof(struct sadb_msg); | |
249 | ||
250 | m_msg->sadb_msg_version = PF_KEY_V2; | |
251 | m_msg->sadb_msg_type = SADB_X_PROMISC; | |
252 | m_msg->sadb_msg_errno = 0; | |
253 | m_msg->sadb_msg_satype = 1; | |
254 | m_msg->sadb_msg_len = PFKEY_UNIT64(m_len); | |
255 | m_msg->sadb_msg_reserved = 0; | |
256 | m_msg->sadb_msg_seq = 0; | |
257 | m_msg->sadb_msg_pid = getpid(); | |
258 | ||
259 | if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) { | |
260 | err(1, "socket(PF_KEY)"); | |
261 | /*NOTREACHED*/ | |
262 | } | |
263 | ||
264 | if ((len = send(so, m_buf, m_len, 0)) < 0) { | |
265 | err(1, "send"); | |
266 | /*NOTREACHED*/ | |
267 | } | |
268 | ||
269 | while (1) { | |
270 | struct sadb_msg *base; | |
271 | ||
272 | if ((len = recv(so, rbuf, sizeof(*base), MSG_PEEK)) < 0) { | |
273 | err(1, "recv"); | |
274 | /*NOTREACHED*/ | |
275 | } | |
276 | ||
277 | if (len != sizeof(*base)) | |
278 | continue; | |
279 | ||
280 | base = (struct sadb_msg *)rbuf; | |
281 | if ((len = recv(so, rbuf, PFKEY_UNUNIT64(base->sadb_msg_len), | |
282 | 0)) < 0) { | |
283 | err(1, "recv"); | |
284 | /*NOTREACHED*/ | |
285 | } | |
286 | printdate(); | |
287 | if (f_hexdump) { | |
288 | int i; | |
289 | for (i = 0; i < len; i++) { | |
290 | if (i % 16 == 0) | |
291 | printf("%08x: ", i); | |
292 | printf("%02x ", rbuf[i] & 0xff); | |
293 | if (i % 16 == 15) | |
294 | printf("\n"); | |
295 | } | |
296 | if (len % 16) | |
297 | printf("\n"); | |
298 | } | |
299 | /* adjust base pointer for promisc mode */ | |
300 | if (base->sadb_msg_type == SADB_X_PROMISC) { | |
301 | if (sizeof(*base) < len) | |
302 | base++; | |
303 | else | |
304 | base = NULL; | |
305 | } | |
306 | if (base) { | |
307 | kdebug_sadb(base); | |
308 | printf("\n"); | |
309 | fflush(stdout); | |
310 | } | |
311 | } | |
312 | } | |
313 | ||
314 | int | |
315 | sendkeymsg() | |
316 | { | |
317 | int so; | |
318 | ||
319 | u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */ | |
320 | int len; | |
321 | struct sadb_msg *msg; | |
322 | ||
323 | if ((so = pfkey_open()) < 0) { | |
324 | perror("pfkey_open"); | |
325 | return -1; | |
326 | } | |
327 | ||
328 | { | |
329 | struct timeval tv; | |
330 | tv.tv_sec = 1; | |
331 | tv.tv_usec = 0; | |
332 | if (setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { | |
333 | perror("setsockopt"); | |
334 | goto end; | |
335 | } | |
336 | } | |
337 | ||
338 | if (f_forever) | |
339 | shortdump_hdr(); | |
340 | again: | |
341 | if (f_verbose) { | |
342 | kdebug_sadb((struct sadb_msg *)m_buf); | |
343 | printf("\n"); | |
344 | } | |
345 | ||
346 | if ((len = send(so, m_buf, m_len, 0)) < 0) { | |
347 | perror("send"); | |
348 | goto end; | |
349 | } | |
350 | ||
351 | msg = (struct sadb_msg *)rbuf; | |
352 | do { | |
353 | if ((len = recv(so, rbuf, sizeof(rbuf), 0)) < 0) { | |
354 | perror("recv"); | |
355 | goto end; | |
356 | } | |
357 | ||
358 | if (PFKEY_UNUNIT64(msg->sadb_msg_len) != len) { | |
359 | warnx("invalid keymsg length"); | |
360 | break; | |
361 | } | |
362 | ||
363 | if (f_verbose) { | |
364 | kdebug_sadb((struct sadb_msg *)rbuf); | |
365 | printf("\n"); | |
366 | } | |
367 | if (postproc(msg, len) < 0) | |
368 | break; | |
369 | } while (msg->sadb_msg_errno || msg->sadb_msg_seq); | |
370 | ||
371 | if (f_forever) { | |
372 | fflush(stdout); | |
373 | sleep(1); | |
374 | goto again; | |
375 | } | |
376 | ||
377 | end: | |
378 | pfkey_close(so); | |
379 | return(0); | |
380 | } | |
381 | ||
382 | int | |
383 | postproc(msg, len) | |
384 | struct sadb_msg *msg; | |
385 | int len; | |
386 | { | |
387 | ||
388 | if (msg->sadb_msg_errno != 0) { | |
389 | char inf[80]; | |
390 | char *errmsg = NULL; | |
391 | ||
392 | if (f_mode == MODE_SCRIPT) | |
393 | snprintf(inf, sizeof(inf), "The result of line %d: ", lineno); | |
394 | else | |
395 | inf[0] = '\0'; | |
396 | ||
397 | switch (msg->sadb_msg_errno) { | |
398 | case ENOENT: | |
399 | switch (msg->sadb_msg_type) { | |
400 | case SADB_DELETE: | |
401 | case SADB_GET: | |
402 | case SADB_X_SPDDELETE: | |
403 | errmsg = "No entry"; | |
404 | break; | |
405 | case SADB_DUMP: | |
406 | errmsg = "No SAD entries"; | |
407 | break; | |
408 | case SADB_X_SPDDUMP: | |
409 | errmsg = "No SPD entries"; | |
410 | break; | |
411 | } | |
412 | break; | |
413 | default: | |
414 | errmsg = strerror(msg->sadb_msg_errno); | |
415 | } | |
416 | printf("%s%s.\n", inf, errmsg); | |
417 | return(-1); | |
418 | } | |
419 | ||
420 | switch (msg->sadb_msg_type) { | |
421 | case SADB_GET: | |
422 | pfkey_sadump(msg); | |
423 | break; | |
424 | ||
425 | case SADB_DUMP: | |
426 | /* filter out DEAD SAs */ | |
427 | if (!f_all) { | |
428 | caddr_t mhp[SADB_EXT_MAX + 1]; | |
429 | struct sadb_sa *sa; | |
430 | pfkey_align(msg, mhp); | |
431 | pfkey_check(mhp); | |
432 | if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) { | |
433 | if (sa->sadb_sa_state == SADB_SASTATE_DEAD) | |
434 | break; | |
435 | } | |
436 | } | |
437 | if (f_forever) | |
438 | shortdump(msg); | |
439 | else | |
440 | pfkey_sadump(msg); | |
441 | msg = (struct sadb_msg *)((caddr_t)msg + | |
442 | PFKEY_UNUNIT64(msg->sadb_msg_len)); | |
443 | if (f_verbose) { | |
444 | kdebug_sadb((struct sadb_msg *)msg); | |
445 | printf("\n"); | |
446 | } | |
447 | break; | |
448 | ||
449 | case SADB_X_SPDDUMP: | |
450 | pfkey_spdump(msg); | |
451 | if (msg->sadb_msg_seq == 0) break; | |
452 | msg = (struct sadb_msg *)((caddr_t)msg + | |
453 | PFKEY_UNUNIT64(msg->sadb_msg_len)); | |
454 | if (f_verbose) { | |
455 | kdebug_sadb((struct sadb_msg *)msg); | |
456 | printf("\n"); | |
457 | } | |
458 | break; | |
459 | } | |
460 | ||
461 | return(0); | |
462 | } | |
463 | ||
464 | /*------------------------------------------------------------*/ | |
465 | static char *satype[] = { | |
466 | NULL, NULL, "ah", "esp" | |
467 | }; | |
468 | static char *sastate[] = { | |
469 | "L", "M", "D", "d" | |
470 | }; | |
471 | static char *ipproto[] = { | |
472 | /*0*/ "ip", "icmp", "igmp", "ggp", "ip4", | |
473 | NULL, "tcp", NULL, "egp", NULL, | |
474 | /*10*/ NULL, NULL, NULL, NULL, NULL, | |
475 | NULL, NULL, "udp", NULL, NULL, | |
476 | /*20*/ NULL, NULL, "idp", NULL, NULL, | |
477 | NULL, NULL, NULL, NULL, "tp", | |
478 | /*30*/ NULL, NULL, NULL, NULL, NULL, | |
479 | NULL, NULL, NULL, NULL, NULL, | |
480 | /*40*/ NULL, "ip6", NULL, "rt6", "frag6", | |
481 | NULL, "rsvp", "gre", NULL, NULL, | |
482 | /*50*/ "esp", "ah", NULL, NULL, NULL, | |
483 | NULL, NULL, NULL, "icmp6", "none", | |
484 | /*60*/ "dst6", | |
485 | }; | |
486 | ||
487 | #define STR_OR_ID(x, tab) \ | |
488 | (((x) < sizeof(tab)/sizeof(tab[0]) && tab[(x)]) ? tab[(x)] : numstr(x)) | |
489 | ||
490 | const char * | |
491 | numstr(x) | |
492 | int x; | |
493 | { | |
494 | static char buf[20]; | |
495 | snprintf(buf, sizeof(buf), "#%d", x); | |
496 | return buf; | |
497 | } | |
498 | ||
499 | void | |
500 | shortdump_hdr() | |
501 | { | |
502 | printf("%-4s %-3s %-1s %-8s %-7s %s -> %s\n", | |
503 | "time", "p", "s", "spi", "ltime", "src", "dst"); | |
504 | } | |
505 | ||
506 | void | |
507 | shortdump(msg) | |
508 | struct sadb_msg *msg; | |
509 | { | |
510 | caddr_t mhp[SADB_EXT_MAX + 1]; | |
ac2f15b3 | 511 | char buf[NI_MAXHOST], pbuf[NI_MAXSERV]; |
7ba0088d A |
512 | struct sadb_sa *sa; |
513 | struct sadb_address *saddr; | |
514 | struct sadb_lifetime *lts, *lth, *ltc; | |
515 | struct sockaddr *s; | |
516 | u_int t; | |
517 | time_t cur = time(0); | |
518 | ||
519 | pfkey_align(msg, mhp); | |
520 | pfkey_check(mhp); | |
521 | ||
522 | printf("%02lu%02lu", (u_long)(cur % 3600) / 60, (u_long)(cur % 60)); | |
523 | ||
524 | printf(" %-3s", STR_OR_ID(msg->sadb_msg_satype, satype)); | |
525 | ||
526 | if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) { | |
527 | printf(" %-1s", STR_OR_ID(sa->sadb_sa_state, sastate)); | |
528 | printf(" %08x", (u_int32_t)ntohl(sa->sadb_sa_spi)); | |
529 | } else | |
530 | printf("%-1s %-8s", "?", "?"); | |
531 | ||
532 | lts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT]; | |
533 | lth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD]; | |
534 | ltc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT]; | |
535 | if (lts && lth && ltc) { | |
536 | if (ltc->sadb_lifetime_addtime == 0) | |
537 | t = (u_long)0; | |
538 | else | |
539 | t = (u_long)(cur - ltc->sadb_lifetime_addtime); | |
540 | if (t >= 1000) | |
541 | strcpy(buf, " big/"); | |
542 | else | |
543 | snprintf(buf, sizeof(buf), " %3lu/", (u_long)t); | |
544 | printf("%s", buf); | |
545 | ||
546 | t = (u_long)lth->sadb_lifetime_addtime; | |
547 | if (t >= 1000) | |
548 | strcpy(buf, "big"); | |
549 | else | |
550 | snprintf(buf, sizeof(buf), "%-3lu", (u_long)t); | |
551 | printf("%s", buf); | |
552 | } else | |
553 | printf(" ??\?/???"); /* backslash to avoid trigraph ??/ */ | |
554 | ||
555 | printf(" "); | |
556 | ||
557 | if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]) != NULL) { | |
558 | if (saddr->sadb_address_proto) | |
559 | printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto)); | |
560 | s = (struct sockaddr *)(saddr + 1); | |
561 | getnameinfo(s, s->sa_len, buf, sizeof(buf), | |
562 | pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV); | |
563 | if (strcmp(pbuf, "0") != 0) | |
564 | printf("%s[%s]", buf, pbuf); | |
565 | else | |
566 | printf("%s", buf); | |
567 | } else | |
568 | printf("?"); | |
569 | ||
570 | printf(" -> "); | |
571 | ||
572 | if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]) != NULL) { | |
573 | if (saddr->sadb_address_proto) | |
574 | printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto)); | |
575 | ||
576 | s = (struct sockaddr *)(saddr + 1); | |
577 | getnameinfo(s, s->sa_len, buf, sizeof(buf), | |
578 | pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV); | |
579 | if (strcmp(pbuf, "0") != 0) | |
580 | printf("%s[%s]", buf, pbuf); | |
581 | else | |
582 | printf("%s", buf); | |
583 | } else | |
584 | printf("?"); | |
585 | ||
586 | printf("\n"); | |
587 | } | |
588 | ||
589 | /* From: tcpdump(1):gmt2local.c and util.c */ | |
590 | /* | |
591 | * Print the timestamp | |
592 | */ | |
593 | static void | |
594 | printdate() | |
595 | { | |
596 | struct timeval tp; | |
597 | int s; | |
598 | ||
599 | if (gettimeofday(&tp, NULL) == -1) { | |
600 | perror("gettimeofday"); | |
601 | return; | |
602 | } | |
603 | ||
604 | if (f_tflag == 1) { | |
605 | /* Default */ | |
606 | s = (tp.tv_sec + thiszone ) % 86400; | |
607 | (void)printf("%02d:%02d:%02d.%06u ", | |
608 | s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tp.tv_usec); | |
609 | } else if (f_tflag > 1) { | |
610 | /* Unix timeval style */ | |
611 | (void)printf("%u.%06u ", | |
612 | (u_int32_t)tp.tv_sec, (u_int32_t)tp.tv_usec); | |
613 | } | |
614 | ||
615 | printf("\n"); | |
616 | } | |
617 | ||
618 | /* | |
619 | * Returns the difference between gmt and local time in seconds. | |
620 | * Use gmtime() and localtime() to keep things simple. | |
621 | */ | |
622 | int32_t | |
623 | gmt2local(time_t t) | |
624 | { | |
625 | register int dt, dir; | |
626 | register struct tm *gmt, *loc; | |
627 | struct tm sgmt; | |
628 | ||
629 | if (t == 0) | |
630 | t = time(NULL); | |
631 | gmt = &sgmt; | |
632 | *gmt = *gmtime(&t); | |
633 | loc = localtime(&t); | |
634 | dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 + | |
635 | (loc->tm_min - gmt->tm_min) * 60; | |
636 | ||
637 | /* | |
638 | * If the year or julian day is different, we span 00:00 GMT | |
639 | * and must add or subtract a day. Check the year first to | |
640 | * avoid problems when the julian day wraps. | |
641 | */ | |
642 | dir = loc->tm_year - gmt->tm_year; | |
643 | if (dir == 0) | |
644 | dir = loc->tm_yday - gmt->tm_yday; | |
645 | dt += dir * 24 * 60 * 60; | |
646 | ||
647 | return (dt); | |
648 | } |