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