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