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