1 /* 2 * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include <stdlib.h> 27 #include <stdio.h> 28 #include <strings.h> 29 #include <time.h> 30 #include <limits.h> 31 #include <errno.h> 32 #include <stddef.h> 33 #include <sys/stat.h> 34 #include <sys/types.h> 35 #include <string.h> 36 #include <dirent.h> 37 #include <unistd.h> 38 #if defined(__solaris__) 39 #include <libscf.h> 40 #endif 41 42 #include "jvm.h" 43 #include "TimeZone_md.h" 44 45 #define SKIP_SPACE(p) while (*p == ' ' || *p == '\t') p++; 46 47 #define RESTARTABLE(_cmd, _result) do { \ 48 do { \ 49 _result = _cmd; \ 50 } while((_result == -1) && (errno == EINTR)); \ 51 } while(0) 52 53 #if defined(_ALLBSD_SOURCE) 54 #define dirent64 dirent 55 #define readdir64 readdir 56 #endif 57 58 #if defined(_AIX) 59 #define DIR DIR64 60 #define opendir opendir64 61 #define closedir closedir64 62 #endif 63 64 #if !defined(__solaris__) || defined(__sparcv9) || defined(amd64) 65 #define fileopen fopen 66 #define filegets fgets 67 #define fileclose fclose 68 #endif 69 70 #if defined(__linux__) || defined(_ALLBSD_SOURCE) 71 static const char *ETC_TIMEZONE_FILE = "/etc/timezone"; 72 static const char *ZONEINFO_DIR = "/usr/share/zoneinfo"; 73 static const char *DEFAULT_ZONEINFO_FILE = "/etc/localtime"; 74 #else 75 static const char *SYS_INIT_FILE = "/etc/default/init"; 76 static const char *ZONEINFO_DIR = "/usr/share/lib/zoneinfo"; 77 static const char *DEFAULT_ZONEINFO_FILE = "/usr/share/lib/zoneinfo/localtime"; 78 #endif /* defined(__linux__) || defined(_ALLBSD_SOURCE) */ 79 80 #if defined(_AIX) 81 static const char *ETC_ENVIRONMENT_FILE = "/etc/environment"; 82 #endif 83 84 #if defined(__linux__) || defined(MACOSX) || defined(__solaris__) 85 86 /* 87 * Returns a pointer to the zone ID portion of the given zoneinfo file 88 * name, or NULL if the given string doesn't contain "zoneinfo/". 89 */ 90 static char * 91 getZoneName(char *str) 92 { 93 static const char *zidir = "zoneinfo/"; 94 95 char *pos = strstr((const char *)str, zidir); 96 if (pos == NULL) { 97 return NULL; 98 } 99 return pos + strlen(zidir); 100 } 101 102 /* 103 * Returns a path name created from the given 'dir' and 'name' under 104 * UNIX. This function allocates memory for the pathname calling 105 * malloc(). NULL is returned if malloc() fails. 106 */ 107 static char * 108 getPathName(const char *dir, const char *name) { 109 char *path; 110 111 path = (char *) malloc(strlen(dir) + strlen(name) + 2); 112 if (path == NULL) { 113 return NULL; 114 } 115 return strcat(strcat(strcpy(path, dir), "/"), name); 116 } 117 118 /* 119 * Scans the specified directory and its subdirectories to find a 120 * zoneinfo file which has the same content as /etc/localtime on Linux 121 * or /usr/share/lib/zoneinfo/localtime on Solaris given in 'buf'. 122 * If file is symbolic link, then the contents it points to are in buf. 123 * Returns a zone ID if found, otherwise, NULL is returned. 124 */ 125 static char * 126 findZoneinfoFile(char *buf, size_t size, const char *dir) 127 { 128 DIR *dirp = NULL; 129 struct stat statbuf; 130 struct dirent64 *dp = NULL; 131 char *pathname = NULL; 132 int fd = -1; 133 char *dbuf = NULL; 134 char *tz = NULL; 135 int res; 136 137 dirp = opendir(dir); 138 if (dirp == NULL) { 139 return NULL; 140 } 141 142 while ((dp = readdir64(dirp)) != NULL) { 143 /* 144 * Skip '.' and '..' (and possibly other .* files) 145 */ 146 if (dp->d_name[0] == '.') { 147 continue; 148 } 149 150 /* 151 * Skip "ROC", "posixrules", and "localtime". 152 */ 153 if ((strcmp(dp->d_name, "ROC") == 0) 154 || (strcmp(dp->d_name, "posixrules") == 0) 155 #if defined(__solaris__) 156 /* 157 * Skip the "src" and "tab" directories on Solaris. 158 */ 159 || (strcmp(dp->d_name, "src") == 0) 160 || (strcmp(dp->d_name, "tab") == 0) 161 #endif 162 || (strcmp(dp->d_name, "localtime") == 0)) { 163 continue; 164 } 165 166 pathname = getPathName(dir, dp->d_name); 167 if (pathname == NULL) { 168 break; 169 } 170 RESTARTABLE(stat(pathname, &statbuf), res); 171 if (res == -1) { 172 break; 173 } 174 175 if (S_ISDIR(statbuf.st_mode)) { 176 tz = findZoneinfoFile(buf, size, pathname); 177 if (tz != NULL) { 178 break; 179 } 180 } else if (S_ISREG(statbuf.st_mode) && (size_t)statbuf.st_size == size) { 181 dbuf = (char *) malloc(size); 182 if (dbuf == NULL) { 183 break; 184 } 185 RESTARTABLE(open(pathname, O_RDONLY), fd); 186 if (fd == -1) { 187 break; 188 } 189 RESTARTABLE(read(fd, dbuf, size), res); 190 if (res != (ssize_t) size) { 191 break; 192 } 193 if (memcmp(buf, dbuf, size) == 0) { 194 tz = getZoneName(pathname); 195 if (tz != NULL) { 196 tz = strdup(tz); 197 } 198 break; 199 } 200 free((void *) dbuf); 201 dbuf = NULL; 202 (void) close(fd); 203 fd = -1; 204 } 205 free((void *) pathname); 206 pathname = NULL; 207 } 208 209 if (dirp != NULL) { 210 (void) closedir(dirp); 211 } 212 if (pathname != NULL) { 213 free((void *) pathname); 214 } 215 if (fd != -1) { 216 (void) close(fd); 217 } 218 if (dbuf != NULL) { 219 free((void *) dbuf); 220 } 221 return tz; 222 } 223 224 #if defined(__linux__) || defined(MACOSX) 225 226 /* 227 * Performs Linux specific mapping and returns a zone ID 228 * if found. Otherwise, NULL is returned. 229 */ 230 static char * 231 getPlatformTimeZoneID() 232 { 233 struct stat statbuf; 234 char *tz = NULL; 235 FILE *fp; 236 int fd; 237 char *buf; 238 size_t size; 239 int res; 240 241 #if defined(__linux__) 242 /* 243 * Try reading the /etc/timezone file for Debian distros. There's 244 * no spec of the file format available. This parsing assumes that 245 * there's one line of an Olson tzid followed by a '\n', no 246 * leading or trailing spaces, no comments. 247 */ 248 if ((fp = fopen(ETC_TIMEZONE_FILE, "r")) != NULL) { 249 char line[256]; 250 251 if (fgets(line, sizeof(line), fp) != NULL) { 252 char *p = strchr(line, '\n'); 253 if (p != NULL) { 254 *p = '\0'; 255 } 256 if (strlen(line) > 0) { 257 tz = strdup(line); 258 } 259 } 260 (void) fclose(fp); 261 if (tz != NULL) { 262 return tz; 263 } 264 } 265 #endif /* defined(__linux__) */ 266 267 /* 268 * Next, try /etc/localtime to find the zone ID. 269 */ 270 RESTARTABLE(lstat(DEFAULT_ZONEINFO_FILE, &statbuf), res); 271 if (res == -1) { 272 return NULL; 273 } 274 275 /* 276 * If it's a symlink, get the link name and its zone ID part. (The 277 * older versions of timeconfig created a symlink as described in 278 * the Red Hat man page. It was changed in 1999 to create a copy 279 * of a zoneinfo file. It's no longer possible to get the zone ID 280 * from /etc/localtime.) 281 */ 282 if (S_ISLNK(statbuf.st_mode)) { 283 char linkbuf[PATH_MAX+1]; 284 int len; 285 286 if ((len = readlink(DEFAULT_ZONEINFO_FILE, linkbuf, sizeof(linkbuf)-1)) == -1) { 287 jio_fprintf(stderr, (const char *) "can't get a symlink of %s\n", 288 DEFAULT_ZONEINFO_FILE); 289 return NULL; 290 } 291 linkbuf[len] = '\0'; 292 tz = getZoneName(linkbuf); 293 if (tz != NULL) { 294 tz = strdup(tz); 295 return tz; 296 } 297 } 298 299 /* 300 * If it's a regular file, we need to find out the same zoneinfo file 301 * that has been copied as /etc/localtime. 302 * If initial symbolic link resolution failed, we should treat target 303 * file as a regular file. 304 */ 305 RESTARTABLE(open(DEFAULT_ZONEINFO_FILE, O_RDONLY), fd); 306 if (fd == -1) { 307 return NULL; 308 } 309 310 RESTARTABLE(fstat(fd, &statbuf), res); 311 if (res == -1) { 312 (void) close(fd); 313 return NULL; 314 } 315 size = (size_t) statbuf.st_size; 316 buf = (char *) malloc(size); 317 if (buf == NULL) { 318 (void) close(fd); 319 return NULL; 320 } 321 322 RESTARTABLE(read(fd, buf, size), res); 323 if (res != (ssize_t) size) { 324 (void) close(fd); 325 free((void *) buf); 326 return NULL; 327 } 328 (void) close(fd); 329 330 tz = findZoneinfoFile(buf, size, ZONEINFO_DIR); 331 free((void *) buf); 332 return tz; 333 } 334 335 #elif defined(__solaris__) 336 337 #if !defined(__sparcv9) && !defined(amd64) 338 339 /* 340 * Those file* functions mimic the UNIX stream io functions. This is 341 * because of the limitation of the number of open files on Solaris 342 * (32-bit mode only) due to the System V ABI. 343 */ 344 345 #define BUFFER_SIZE 4096 346 347 static struct iobuffer { 348 int magic; /* -1 to distinguish from the real FILE */ 349 int fd; /* file descriptor */ 350 char *buffer; /* pointer to buffer */ 351 char *ptr; /* current read pointer */ 352 char *endptr; /* end pointer */ 353 }; 354 355 static int 356 fileclose(FILE *stream) 357 { 358 struct iobuffer *iop = (struct iobuffer *) stream; 359 360 if (iop->magic != -1) { 361 return fclose(stream); 362 } 363 364 if (iop == NULL) { 365 return 0; 366 } 367 close(iop->fd); 368 free((void *)iop->buffer); 369 free((void *)iop); 370 return 0; 371 } 372 373 static FILE * 374 fileopen(const char *fname, const char *fmode) 375 { 376 FILE *fp; 377 int fd; 378 struct iobuffer *iop; 379 380 if ((fp = fopen(fname, fmode)) != NULL) { 381 return fp; 382 } 383 384 /* 385 * It assumes read open. 386 */ 387 RESTARTABLE(open(fname, O_RDONLY), fd); 388 if (fd == -1) { 389 return NULL; 390 } 391 392 /* 393 * Allocate struct iobuffer and its buffer 394 */ 395 iop = malloc(sizeof(struct iobuffer)); 396 if (iop == NULL) { 397 (void) close(fd); 398 errno = ENOMEM; 399 return NULL; 400 } 401 iop->magic = -1; 402 iop->fd = fd; 403 iop->buffer = malloc(BUFFER_SIZE); 404 if (iop->buffer == NULL) { 405 (void) close(fd); 406 free((void *) iop); 407 errno = ENOMEM; 408 return NULL; 409 } 410 iop->ptr = iop->buffer; 411 iop->endptr = iop->buffer; 412 return (FILE *)iop; 413 } 414 415 /* 416 * This implementation assumes that n is large enough and the line 417 * separator is '\n'. 418 */ 419 static char * 420 filegets(char *s, int n, FILE *stream) 421 { 422 struct iobuffer *iop = (struct iobuffer *) stream; 423 char *p; 424 425 if (iop->magic != -1) { 426 return fgets(s, n, stream); 427 } 428 429 p = s; 430 for (;;) { 431 char c; 432 433 if (iop->ptr == iop->endptr) { 434 ssize_t len; 435 436 RESTARTABLE(read(iop->fd, (void *)iop->buffer, BUFFER_SIZE), len); 437 if (len == -1) { 438 return NULL; 439 } 440 if (len == 0) { 441 *p = 0; 442 if (s == p) { 443 return NULL; 444 } 445 return s; 446 } 447 iop->ptr = iop->buffer; 448 iop->endptr = iop->buffer + len; 449 } 450 c = *iop->ptr++; 451 *p++ = c; 452 if ((p - s) == (n - 1)) { 453 *p = 0; 454 return s; 455 } 456 if (c == '\n') { 457 *p = 0; 458 return s; 459 } 460 } 461 /*NOTREACHED*/ 462 } 463 #endif /* !defined(__sparcv9) && !defined(amd64) */ 464 465 /* 466 * Performs Solaris dependent mapping. Returns a zone ID if 467 * found. Otherwise, NULL is returned. Solaris libc looks up 468 * "/etc/default/init" to get the default TZ value if TZ is not defined 469 * as an environment variable. 470 */ 471 static char * 472 getPlatformTimeZoneID() 473 { 474 char *tz = NULL; 475 FILE *fp; 476 477 /* 478 * Try the TZ entry in /etc/default/init. 479 */ 480 if ((fp = fileopen(SYS_INIT_FILE, "r")) != NULL) { 481 char line[256]; 482 char quote = '\0'; 483 484 while (filegets(line, sizeof(line), fp) != NULL) { 485 char *p = line; 486 char *s; 487 char c; 488 489 /* quick check for comment lines */ 490 if (*p == '#') { 491 continue; 492 } 493 if (strncmp(p, "TZ=", 3) == 0) { 494 p += 3; 495 SKIP_SPACE(p); 496 c = *p; 497 if (c == '"' || c == '\'') { 498 quote = c; 499 p++; 500 } 501 502 /* 503 * PSARC/2001/383: quoted string support 504 */ 505 for (s = p; (c = *s) != '\0' && c != '\n'; s++) { 506 /* No '\\' is supported here. */ 507 if (c == quote) { 508 quote = '\0'; 509 break; 510 } 511 if (c == ' ' && quote == '\0') { 512 break; 513 } 514 } 515 if (quote != '\0') { 516 jio_fprintf(stderr, "ZoneInfo: unterminated time zone name in /etc/TIMEZONE\n"); 517 } 518 *s = '\0'; 519 tz = strdup(p); 520 break; 521 } 522 } 523 (void) fileclose(fp); 524 } 525 return tz; 526 } 527 528 #define TIMEZONE_FMRI "svc:/system/timezone:default" 529 #define TIMEZONE_PG "timezone" 530 #define LOCALTIME_PROP "localtime" 531 532 static void 533 cleanupScf(scf_handle_t *h, 534 scf_snapshot_t *snap, 535 scf_instance_t *inst, 536 scf_propertygroup_t *pg, 537 scf_property_t *prop, 538 scf_value_t *val, 539 char *buf) { 540 if (buf != NULL) { 541 free(buf); 542 } 543 if (snap != NULL) { 544 scf_snapshot_destroy(snap); 545 } 546 if (val != NULL) { 547 scf_value_destroy(val); 548 } 549 if (prop != NULL) { 550 scf_property_destroy(prop); 551 } 552 if (pg != NULL) { 553 scf_pg_destroy(pg); 554 } 555 if (inst != NULL) { 556 scf_instance_destroy(inst); 557 } 558 if (h != NULL) { 559 scf_handle_destroy(h); 560 } 561 } 562 563 /* 564 * Returns a zone ID of Solaris when the TZ value is "localtime". 565 * First, it tries scf. If scf fails, it looks for the same file as 566 * /usr/share/lib/zoneinfo/localtime under /usr/share/lib/zoneinfo/. 567 */ 568 static char * 569 getSolarisDefaultZoneID() { 570 char *tz = NULL; 571 struct stat statbuf; 572 size_t size; 573 char *buf; 574 int fd; 575 int res; 576 /* scf specific variables */ 577 scf_handle_t *h = NULL; 578 scf_snapshot_t *snap = NULL; 579 scf_instance_t *inst = NULL; 580 scf_propertygroup_t *pg = NULL; 581 scf_property_t *prop = NULL; 582 scf_value_t *val = NULL; 583 584 if ((h = scf_handle_create(SCF_VERSION)) != NULL 585 && scf_handle_bind(h) == 0 586 && (inst = scf_instance_create(h)) != NULL 587 && (snap = scf_snapshot_create(h)) != NULL 588 && (pg = scf_pg_create(h)) != NULL 589 && (prop = scf_property_create(h)) != NULL 590 && (val = scf_value_create(h)) != NULL 591 && scf_handle_decode_fmri(h, TIMEZONE_FMRI, NULL, NULL, inst, 592 NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) == 0 593 && scf_instance_get_snapshot(inst, "running", snap) == 0 594 && scf_instance_get_pg_composed(inst, snap, TIMEZONE_PG, pg) == 0 595 && scf_pg_get_property(pg, LOCALTIME_PROP, prop) == 0 596 && scf_property_get_value(prop, val) == 0) { 597 ssize_t len; 598 599 /* Gets the length of the zone ID string */ 600 len = scf_value_get_astring(val, NULL, 0); 601 if (len != -1) { 602 tz = malloc(++len); /* +1 for a null byte */ 603 if (tz != NULL && scf_value_get_astring(val, tz, len) != -1) { 604 cleanupScf(h, snap, inst, pg, prop, val, NULL); 605 return tz; 606 } 607 } 608 } 609 cleanupScf(h, snap, inst, pg, prop, val, tz); 610 611 RESTARTABLE(stat(DEFAULT_ZONEINFO_FILE, &statbuf), res); 612 if (res == -1) { 613 return NULL; 614 } 615 size = (size_t) statbuf.st_size; 616 buf = malloc(size); 617 if (buf == NULL) { 618 return NULL; 619 } 620 RESTARTABLE(open(DEFAULT_ZONEINFO_FILE, O_RDONLY), fd); 621 if (fd == -1) { 622 free((void *) buf); 623 return NULL; 624 } 625 626 RESTARTABLE(read(fd, buf, size), res); 627 if (res != (ssize_t) size) { 628 (void) close(fd); 629 free((void *) buf); 630 return NULL; 631 } 632 (void) close(fd); 633 tz = findZoneinfoFile(buf, size, ZONEINFO_DIR); 634 free((void *) buf); 635 return tz; 636 } 637 638 #endif /* defined(__solaris__) */ 639 640 #elif defined(_AIX) 641 642 static char * 643 getPlatformTimeZoneID() 644 { 645 FILE *fp; 646 char *tz = NULL; 647 char *tz_key = "TZ="; 648 char line[256]; 649 size_t tz_key_len = strlen(tz_key); 650 651 if ((fp = fopen(ETC_ENVIRONMENT_FILE, "r")) != NULL) { 652 while (fgets(line, sizeof(line), fp) != NULL) { 653 char *p = strchr(line, '\n'); 654 if (p != NULL) { 655 *p = '\0'; 656 } 657 if (0 == strncmp(line, tz_key, tz_key_len)) { 658 tz = strdup(line + tz_key_len); 659 break; 660 } 661 } 662 (void) fclose(fp); 663 } 664 665 return tz; 666 } 667 668 static char * 669 mapPlatformToJavaTimezone(const char *java_home_dir, const char *tz) { 670 FILE *tzmapf; 671 char mapfilename[PATH_MAX + 1]; 672 char line[256]; 673 int linecount = 0; 674 char *tz_buf = NULL; 675 char *temp_tz = NULL; 676 char *javatz = NULL; 677 size_t tz_len = 0; 678 679 /* On AIX, the TZ environment variable may end with a comma 680 * followed by modifier fields. These are ignored here. */ 681 temp_tz = strchr(tz, ','); 682 tz_len = (temp_tz == NULL) ? strlen(tz) : temp_tz - tz; 683 tz_buf = (char *)malloc(tz_len + 1); 684 memcpy(tz_buf, tz, tz_len); 685 tz_buf[tz_len] = 0; 686 687 /* Open tzmappings file, with buffer overrun check */ 688 if ((strlen(java_home_dir) + 15) > PATH_MAX) { 689 jio_fprintf(stderr, "Path %s/lib/tzmappings exceeds maximum path length\n", java_home_dir); 690 goto tzerr; 691 } 692 strcpy(mapfilename, java_home_dir); 693 strcat(mapfilename, "/lib/tzmappings"); 694 if ((tzmapf = fopen(mapfilename, "r")) == NULL) { 695 jio_fprintf(stderr, "can't open %s\n", mapfilename); 696 goto tzerr; 697 } 698 699 while (fgets(line, sizeof(line), tzmapf) != NULL) { 700 char *p = line; 701 char *sol = line; 702 char *java; 703 int result; 704 705 linecount++; 706 /* 707 * Skip comments and blank lines 708 */ 709 if (*p == '#' || *p == '\n') { 710 continue; 711 } 712 713 /* 714 * Get the first field, platform zone ID 715 */ 716 while (*p != '\0' && *p != '\t') { 717 p++; 718 } 719 if (*p == '\0') { 720 /* mapping table is broken! */ 721 jio_fprintf(stderr, "tzmappings: Illegal format at near line %d.\n", linecount); 722 break; 723 } 724 725 *p++ = '\0'; 726 if ((result = strncmp(tz_buf, sol, tz_len)) == 0) { 727 /* 728 * If this is the current platform zone ID, 729 * take the Java time zone ID (2nd field). 730 */ 731 java = p; 732 while (*p != '\0' && *p != '\n') { 733 p++; 734 } 735 736 if (*p == '\0') { 737 /* mapping table is broken! */ 738 jio_fprintf(stderr, "tzmappings: Illegal format at line %d.\n", linecount); 739 break; 740 } 741 742 *p = '\0'; 743 javatz = strdup(java); 744 break; 745 } else if (result < 0) { 746 break; 747 } 748 } 749 (void) fclose(tzmapf); 750 751 tzerr: 752 if (tz_buf != NULL ) { 753 free((void *) tz_buf); 754 } 755 756 if (javatz == NULL) { 757 return getGMTOffsetID(); 758 } 759 760 return javatz; 761 } 762 763 #endif /* defined(_AIX) */ 764 765 /* 766 * findJavaTZ_md() maps platform time zone ID to Java time zone ID 767 * using <java_home>/lib/tzmappings. If the TZ value is not found, it 768 * trys some libc implementation dependent mappings. If it still 769 * can't map to a Java time zone ID, it falls back to the GMT+/-hh:mm 770 * form. 771 */ 772 /*ARGSUSED1*/ 773 char * 774 findJavaTZ_md(const char *java_home_dir) 775 { 776 char *tz; 777 char *javatz = NULL; 778 char *freetz = NULL; 779 780 tz = getenv("TZ"); 781 782 if (tz == NULL || *tz == '\0') { 783 tz = getPlatformTimeZoneID(); 784 freetz = tz; 785 } 786 787 if (tz != NULL) { 788 /* Ignore preceding ':' */ 789 if (*tz == ':') { 790 tz++; 791 } 792 #if defined(__linux__) 793 /* Ignore "posix/" prefix on Linux. */ 794 if (strncmp(tz, "posix/", 6) == 0) { 795 tz += 6; 796 } 797 #endif 798 799 #if defined(_AIX) 800 /* On AIX do the platform to Java mapping. */ 801 javatz = mapPlatformToJavaTimezone(java_home_dir, tz); 802 if (freetz != NULL) { 803 free((void *) freetz); 804 } 805 #else 806 #if defined(__solaris__) 807 /* Solaris might use localtime, so handle it here. */ 808 if (strcmp(tz, "localtime") == 0) { 809 javatz = getSolarisDefaultZoneID(); 810 if (freetz != NULL) { 811 free((void *) freetz); 812 } 813 } else 814 #endif 815 if (freetz == NULL) { 816 /* strdup if we are still working on getenv result. */ 817 javatz = strdup(tz); 818 } else if (freetz != tz) { 819 /* strdup and free the old buffer, if we moved the pointer. */ 820 javatz = strdup(tz); 821 free((void *) freetz); 822 } else { 823 /* we are good if we already work on a freshly allocated buffer. */ 824 javatz = tz; 825 } 826 #endif 827 } 828 829 return javatz; 830 } 831 832 /** 833 * Returns a GMT-offset-based zone ID. (e.g., "GMT-08:00") 834 */ 835 836 #if defined(MACOSX) 837 838 char * 839 getGMTOffsetID() 840 { 841 time_t offset; 842 char sign, buf[32]; 843 struct tm local_tm; 844 time_t clock; 845 846 clock = time(NULL); 847 if (localtime_r(&clock, &local_tm) == NULL) { 848 return strdup("GMT"); 849 } 850 offset = (time_t)local_tm.tm_gmtoff; 851 if (offset == 0) { 852 return strdup("GMT"); 853 } 854 if (offset > 0) { 855 sign = '+'; 856 } else { 857 offset = -offset; 858 sign = '-'; 859 } 860 sprintf(buf, (const char *)"GMT%c%02d:%02d", 861 sign, (int)(offset/3600), (int)((offset%3600)/60)); 862 return strdup(buf); 863 } 864 865 #else 866 867 char * 868 getGMTOffsetID() 869 { 870 time_t offset; 871 char sign, buf[32]; 872 #if defined(__solaris__) 873 struct tm localtm; 874 time_t currenttime; 875 876 currenttime = time(NULL); 877 if (localtime_r(¤ttime, &localtm) == NULL) { 878 return strdup("GMT"); 879 } 880 881 offset = localtm.tm_isdst ? altzone : timezone; 882 #else 883 offset = timezone; 884 #endif 885 886 if (offset == 0) { 887 return strdup("GMT"); 888 } 889 890 /* Note that the time offset direction is opposite. */ 891 if (offset > 0) { 892 sign = '-'; 893 } else { 894 offset = -offset; 895 sign = '+'; 896 } 897 sprintf(buf, (const char *)"GMT%c%02d:%02d", 898 sign, (int)(offset/3600), (int)((offset%3600)/60)); 899 return strdup(buf); 900 } 901 #endif /* MACOSX */