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