0N/A/*
5003N/A * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A#include <stdlib.h>
0N/A#include <stdio.h>
0N/A#include <strings.h>
0N/A#include <time.h>
0N/A#include <limits.h>
0N/A#include <errno.h>
0N/A#include <stddef.h>
4481N/A#include <sys/stat.h>
4481N/A#include <sys/types.h>
0N/A#include <string.h>
0N/A#include <dirent.h>
0N/A#include <unistd.h>
4481N/A#ifdef __solaris__
4481N/A#include <libscf.h>
0N/A#endif
0N/A
0N/A#include "jvm.h"
0N/A
0N/A#define SKIP_SPACE(p) while (*p == ' ' || *p == '\t') p++;
0N/A
0N/A#if !defined(__solaris__) || defined(__sparcv9) || defined(amd64)
0N/A#define fileopen fopen
0N/A#define filegets fgets
0N/A#define fileclose fclose
0N/A#endif
0N/A
4632N/A#if defined(__linux__) || defined(_ALLBSD_SOURCE)
4632N/A
0N/A
1628N/Astatic const char *ETC_TIMEZONE_FILE = "/etc/timezone";
1628N/Astatic const char *ZONEINFO_DIR = "/usr/share/zoneinfo";
1628N/Astatic const char *DEFAULT_ZONEINFO_FILE = "/etc/localtime";
4481N/A#else
4481N/Astatic const char *SYS_INIT_FILE = "/etc/default/init";
4481N/Astatic const char *ZONEINFO_DIR = "/usr/share/lib/zoneinfo";
4481N/Astatic const char *DEFAULT_ZONEINFO_FILE = "/usr/share/lib/zoneinfo/localtime";
4481N/A#endif /*__linux__*/
0N/A
0N/A/*
4481N/A * Returns a pointer to the zone ID portion of the given zoneinfo file
4481N/A * name, or NULL if the given string doesn't contain "zoneinfo/".
0N/A */
0N/Astatic char *
0N/AgetZoneName(char *str)
0N/A{
0N/A static const char *zidir = "zoneinfo/";
0N/A
4481N/A char *pos = strstr((const char *)str, zidir);
0N/A if (pos == NULL) {
0N/A return NULL;
0N/A }
0N/A return pos + strlen(zidir);
0N/A}
0N/A
0N/A/*
0N/A * Returns a path name created from the given 'dir' and 'name' under
0N/A * UNIX. This function allocates memory for the pathname calling
4481N/A * malloc(). NULL is returned if malloc() fails.
0N/A */
0N/Astatic char *
0N/AgetPathName(const char *dir, const char *name) {
0N/A char *path;
0N/A
0N/A path = (char *) malloc(strlen(dir) + strlen(name) + 2);
0N/A if (path == NULL) {
0N/A return NULL;
0N/A }
0N/A return strcat(strcat(strcpy(path, dir), "/"), name);
0N/A}
0N/A
0N/A/*
0N/A * Scans the specified directory and its subdirectories to find a
4481N/A * zoneinfo file which has the same content as /etc/localtime on Linux
5066N/A * or /usr/share/lib/zoneinfo/localtime on Solaris given in 'buf'.
5066N/A * If file is symbolic link, then the contents it points to are in buf.
5066N/A * Returns a zone ID if found, otherwise, NULL is returned.
0N/A */
0N/Astatic char *
0N/AfindZoneinfoFile(char *buf, size_t size, const char *dir)
0N/A{
0N/A DIR *dirp = NULL;
0N/A struct stat statbuf;
4481N/A struct dirent *dp = NULL;
4481N/A struct dirent *entry = NULL;
0N/A char *pathname = NULL;
0N/A int fd = -1;
0N/A char *dbuf = NULL;
0N/A char *tz = NULL;
0N/A
0N/A dirp = opendir(dir);
0N/A if (dirp == NULL) {
0N/A return NULL;
0N/A }
0N/A
4481N/A entry = (struct dirent *) malloc((size_t) pathconf(dir, _PC_NAME_MAX));
4481N/A if (entry == NULL) {
4481N/A (void) closedir(dirp);
4481N/A return NULL;
4481N/A }
4481N/A
4632N/A#if defined(__linux__) || defined(MACOSX) || (defined(__solaris__) \
4632N/A && (defined(_POSIX_PTHREAD_SEMANTICS) || defined(_LP64)))
4481N/A while (readdir_r(dirp, entry, &dp) == 0 && dp != NULL) {
4481N/A#else
4481N/A while ((dp = readdir_r(dirp, entry)) != NULL) {
4481N/A#endif
4481N/A
0N/A /*
0N/A * Skip '.' and '..' (and possibly other .* files)
0N/A */
0N/A if (dp->d_name[0] == '.') {
0N/A continue;
0N/A }
0N/A
0N/A /*
4481N/A * Skip "ROC", "posixrules", and "localtime".
0N/A */
0N/A if ((strcmp(dp->d_name, "ROC") == 0)
0N/A || (strcmp(dp->d_name, "posixrules") == 0)
4481N/A#ifdef __solaris__
4481N/A /*
4481N/A * Skip the "src" and "tab" directories on Solaris.
4481N/A */
4481N/A || (strcmp(dp->d_name, "src") == 0)
4481N/A || (strcmp(dp->d_name, "tab") == 0)
4481N/A#endif
0N/A || (strcmp(dp->d_name, "localtime") == 0)) {
0N/A continue;
0N/A }
0N/A
0N/A pathname = getPathName(dir, dp->d_name);
0N/A if (pathname == NULL) {
0N/A break;
0N/A }
0N/A if (stat(pathname, &statbuf) == -1) {
0N/A break;
0N/A }
0N/A
0N/A if (S_ISDIR(statbuf.st_mode)) {
0N/A tz = findZoneinfoFile(buf, size, pathname);
0N/A if (tz != NULL) {
0N/A break;
0N/A }
0N/A } else if (S_ISREG(statbuf.st_mode) && (size_t)statbuf.st_size == size) {
0N/A dbuf = (char *) malloc(size);
0N/A if (dbuf == NULL) {
0N/A break;
0N/A }
0N/A if ((fd = open(pathname, O_RDONLY)) == -1) {
0N/A fd = 0;
0N/A break;
0N/A }
0N/A if (read(fd, dbuf, size) != (ssize_t) size) {
0N/A break;
0N/A }
0N/A if (memcmp(buf, dbuf, size) == 0) {
0N/A tz = getZoneName(pathname);
0N/A if (tz != NULL) {
0N/A tz = strdup(tz);
0N/A }
0N/A break;
0N/A }
0N/A free((void *) dbuf);
0N/A dbuf = NULL;
0N/A (void) close(fd);
0N/A fd = 0;
0N/A }
0N/A free((void *) pathname);
0N/A pathname = NULL;
0N/A }
0N/A
4481N/A if (entry != NULL) {
4481N/A free((void *) entry);
4481N/A }
0N/A if (dirp != NULL) {
0N/A (void) closedir(dirp);
0N/A }
0N/A if (pathname != NULL) {
0N/A free((void *) pathname);
0N/A }
0N/A if (fd != 0) {
0N/A (void) close(fd);
0N/A }
0N/A if (dbuf != NULL) {
0N/A free((void *) dbuf);
0N/A }
0N/A return tz;
0N/A}
0N/A
4632N/A#if defined(__linux__) || defined(MACOSX)
4481N/A
0N/A/*
4481N/A * Performs Linux specific mapping and returns a zone ID
0N/A * if found. Otherwise, NULL is returned.
0N/A */
0N/Astatic char *
0N/AgetPlatformTimeZoneID()
0N/A{
0N/A struct stat statbuf;
0N/A char *tz = NULL;
0N/A FILE *fp;
0N/A int fd;
0N/A char *buf;
0N/A size_t size;
0N/A
4632N/A#ifdef __linux__
0N/A /*
1628N/A * Try reading the /etc/timezone file for Debian distros. There's
1628N/A * no spec of the file format available. This parsing assumes that
1628N/A * there's one line of an Olson tzid followed by a '\n', no
1628N/A * leading or trailing spaces, no comments.
0N/A */
1628N/A if ((fp = fopen(ETC_TIMEZONE_FILE, "r")) != NULL) {
0N/A char line[256];
0N/A
1628N/A if (fgets(line, sizeof(line), fp) != NULL) {
1628N/A char *p = strchr(line, '\n');
1628N/A if (p != NULL) {
1628N/A *p = '\0';
0N/A }
1628N/A if (strlen(line) > 0) {
1628N/A tz = strdup(line);
0N/A }
0N/A }
0N/A (void) fclose(fp);
0N/A if (tz != NULL) {
0N/A return tz;
0N/A }
0N/A }
4632N/A#endif /* __linux__ */
0N/A
0N/A /*
0N/A * Next, try /etc/localtime to find the zone ID.
0N/A */
1628N/A if (lstat(DEFAULT_ZONEINFO_FILE, &statbuf) == -1) {
0N/A return NULL;
0N/A }
0N/A
0N/A /*
0N/A * If it's a symlink, get the link name and its zone ID part. (The
0N/A * older versions of timeconfig created a symlink as described in
0N/A * the Red Hat man page. It was changed in 1999 to create a copy
0N/A * of a zoneinfo file. It's no longer possible to get the zone ID
0N/A * from /etc/localtime.)
0N/A */
0N/A if (S_ISLNK(statbuf.st_mode)) {
0N/A char linkbuf[PATH_MAX+1];
0N/A int len;
0N/A
1628N/A if ((len = readlink(DEFAULT_ZONEINFO_FILE, linkbuf, sizeof(linkbuf)-1)) == -1) {
0N/A jio_fprintf(stderr, (const char *) "can't get a symlink of %s\n",
1628N/A DEFAULT_ZONEINFO_FILE);
0N/A return NULL;
0N/A }
0N/A linkbuf[len] = '\0';
0N/A tz = getZoneName(linkbuf);
0N/A if (tz != NULL) {
0N/A tz = strdup(tz);
5066N/A return tz;
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * If it's a regular file, we need to find out the same zoneinfo file
0N/A * that has been copied as /etc/localtime.
5066N/A * If initial symbolic link resolution failed, we should treat target
5066N/A * file as a regular file.
0N/A */
5066N/A if ((fd = open(DEFAULT_ZONEINFO_FILE, O_RDONLY)) == -1) {
5066N/A return NULL;
5066N/A }
5066N/A if (fstat(fd, &statbuf) == -1) {
5066N/A (void) close(fd);
5066N/A return NULL;
5066N/A }
0N/A size = (size_t) statbuf.st_size;
0N/A buf = (char *) malloc(size);
0N/A if (buf == NULL) {
5066N/A (void) close(fd);
0N/A return NULL;
0N/A }
0N/A
0N/A if (read(fd, buf, size) != (ssize_t) size) {
0N/A (void) close(fd);
0N/A free((void *) buf);
0N/A return NULL;
0N/A }
0N/A (void) close(fd);
0N/A
1628N/A tz = findZoneinfoFile(buf, size, ZONEINFO_DIR);
0N/A free((void *) buf);
0N/A return tz;
0N/A}
0N/A#else
0N/A#ifdef __solaris__
0N/A#if !defined(__sparcv9) && !defined(amd64)
0N/A
0N/A/*
0N/A * Those file* functions mimic the UNIX stream io functions. This is
0N/A * because of the limitation of the number of open files on Solaris
0N/A * (32-bit mode only) due to the System V ABI.
0N/A */
0N/A
0N/A#define BUFFER_SIZE 4096
0N/A
0N/Astatic struct iobuffer {
0N/A int magic; /* -1 to distinguish from the real FILE */
0N/A int fd; /* file descriptor */
0N/A char *buffer; /* pointer to buffer */
0N/A char *ptr; /* current read pointer */
0N/A char *endptr; /* end pointer */
0N/A};
0N/A
0N/Astatic int
0N/Afileclose(FILE *stream)
0N/A{
0N/A struct iobuffer *iop = (struct iobuffer *) stream;
0N/A
0N/A if (iop->magic != -1) {
0N/A return fclose(stream);
0N/A }
0N/A
0N/A if (iop == NULL) {
0N/A return 0;
0N/A }
0N/A close(iop->fd);
0N/A free((void *)iop->buffer);
0N/A free((void *)iop);
0N/A return 0;
0N/A}
0N/A
0N/Astatic FILE *
0N/Afileopen(const char *fname, const char *fmode)
0N/A{
0N/A FILE *fp;
0N/A int fd;
0N/A struct iobuffer *iop;
0N/A
0N/A if ((fp = fopen(fname, fmode)) != NULL) {
0N/A return fp;
0N/A }
0N/A
0N/A /*
0N/A * It assumes read open.
0N/A */
0N/A if ((fd = open(fname, O_RDONLY)) == -1) {
0N/A return NULL;
0N/A }
0N/A
0N/A /*
0N/A * Allocate struct iobuffer and its buffer
0N/A */
0N/A iop = malloc(sizeof(struct iobuffer));
0N/A if (iop == NULL) {
0N/A (void) close(fd);
0N/A errno = ENOMEM;
0N/A return NULL;
0N/A }
0N/A iop->magic = -1;
0N/A iop->fd = fd;
0N/A iop->buffer = malloc(BUFFER_SIZE);
0N/A if (iop->buffer == NULL) {
0N/A (void) close(fd);
0N/A free((void *) iop);
0N/A errno = ENOMEM;
0N/A return NULL;
0N/A }
0N/A iop->ptr = iop->buffer;
0N/A iop->endptr = iop->buffer;
0N/A return (FILE *)iop;
0N/A}
0N/A
0N/A/*
0N/A * This implementation assumes that n is large enough and the line
0N/A * separator is '\n'.
0N/A */
0N/Astatic char *
0N/Afilegets(char *s, int n, FILE *stream)
0N/A{
0N/A struct iobuffer *iop = (struct iobuffer *) stream;
0N/A char *p;
0N/A
0N/A if (iop->magic != -1) {
0N/A return fgets(s, n, stream);
0N/A }
0N/A
0N/A p = s;
0N/A for (;;) {
0N/A char c;
0N/A
0N/A if (iop->ptr == iop->endptr) {
0N/A ssize_t len;
0N/A
0N/A if ((len = read(iop->fd, (void *)iop->buffer, BUFFER_SIZE)) == -1) {
0N/A return NULL;
0N/A }
0N/A if (len == 0) {
0N/A *p = 0;
0N/A if (s == p) {
0N/A return NULL;
0N/A }
0N/A return s;
0N/A }
0N/A iop->ptr = iop->buffer;
0N/A iop->endptr = iop->buffer + len;
0N/A }
0N/A c = *iop->ptr++;
0N/A *p++ = c;
0N/A if ((p - s) == (n - 1)) {
0N/A *p = 0;
0N/A return s;
0N/A }
0N/A if (c == '\n') {
0N/A *p = 0;
0N/A return s;
0N/A }
0N/A }
0N/A /*NOTREACHED*/
0N/A}
0N/A#endif /* not __sparcv9 */
0N/A
0N/A
0N/A/*
4481N/A * Performs Solaris dependent mapping. Returns a zone ID if
4481N/A * found. Otherwise, NULL is returned. Solaris libc looks up
4481N/A * "/etc/default/init" to get the default TZ value if TZ is not defined
0N/A * as an environment variable.
0N/A */
0N/Astatic char *
0N/AgetPlatformTimeZoneID()
0N/A{
0N/A char *tz = NULL;
0N/A FILE *fp;
0N/A
0N/A /*
0N/A * Try the TZ entry in /etc/default/init.
0N/A */
4481N/A if ((fp = fileopen(SYS_INIT_FILE, "r")) != NULL) {
0N/A char line[256];
0N/A char quote = '\0';
0N/A
0N/A while (filegets(line, sizeof(line), fp) != NULL) {
0N/A char *p = line;
0N/A char *s;
0N/A char c;
0N/A
0N/A /* quick check for comment lines */
0N/A if (*p == '#') {
0N/A continue;
0N/A }
0N/A if (strncmp(p, "TZ=", 3) == 0) {
0N/A p += 3;
0N/A SKIP_SPACE(p);
0N/A c = *p;
0N/A if (c == '"' || c == '\'') {
0N/A quote = c;
0N/A p++;
0N/A }
0N/A
0N/A /*
0N/A * PSARC/2001/383: quoted string support
0N/A */
0N/A for (s = p; (c = *s) != '\0' && c != '\n'; s++) {
0N/A /* No '\\' is supported here. */
0N/A if (c == quote) {
0N/A quote = '\0';
0N/A break;
0N/A }
0N/A if (c == ' ' && quote == '\0') {
0N/A break;
0N/A }
0N/A }
0N/A if (quote != '\0') {
0N/A jio_fprintf(stderr, "ZoneInfo: unterminated time zone name in /etc/TIMEZONE\n");
0N/A }
0N/A *s = '\0';
0N/A tz = strdup(p);
0N/A break;
0N/A }
0N/A }
0N/A (void) fileclose(fp);
0N/A }
0N/A return tz;
0N/A}
0N/A
4481N/A#define TIMEZONE_FMRI "svc:/system/timezone:default"
4481N/A#define TIMEZONE_PG "timezone"
4481N/A#define LOCALTIME_PROP "localtime"
4481N/A
4481N/Astatic void
4481N/AcleanupScf(scf_handle_t *h,
4481N/A scf_snapshot_t *snap,
4481N/A scf_instance_t *inst,
4481N/A scf_propertygroup_t *pg,
4481N/A scf_property_t *prop,
4481N/A scf_value_t *val,
4481N/A char *buf) {
4481N/A if (buf != NULL) {
4481N/A free(buf);
4481N/A }
4481N/A if (snap != NULL) {
4481N/A scf_snapshot_destroy(snap);
4481N/A }
4481N/A if (val != NULL) {
4481N/A scf_value_destroy(val);
4481N/A }
4481N/A if (prop != NULL) {
4481N/A scf_property_destroy(prop);
4481N/A }
4481N/A if (pg != NULL) {
4481N/A scf_pg_destroy(pg);
4481N/A }
4481N/A if (inst != NULL) {
4481N/A scf_instance_destroy(inst);
4481N/A }
4481N/A if (h != NULL) {
4481N/A scf_handle_destroy(h);
4481N/A }
4481N/A}
4481N/A
4481N/A/*
4481N/A * Retruns a zone ID of Solaris when the TZ value is "localtime".
4481N/A * First, it tries scf. If scf fails, it looks for the same file as
4481N/A * /usr/share/lib/zoneinfo/localtime under /usr/share/lib/zoneinfo/.
4481N/A */
4481N/Astatic char *
4481N/AgetSolarisDefaultZoneID() {
4481N/A char *tz = NULL;
4481N/A struct stat statbuf;
4481N/A size_t size;
4481N/A char *buf;
4481N/A int fd;
4481N/A /* scf specific variables */
4481N/A scf_handle_t *h = NULL;
4481N/A scf_snapshot_t *snap = NULL;
4481N/A scf_instance_t *inst = NULL;
4481N/A scf_propertygroup_t *pg = NULL;
4481N/A scf_property_t *prop = NULL;
4481N/A scf_value_t *val = NULL;
4481N/A
4481N/A if ((h = scf_handle_create(SCF_VERSION)) != NULL
4481N/A && scf_handle_bind(h) == 0
4481N/A && (inst = scf_instance_create(h)) != NULL
4481N/A && (snap = scf_snapshot_create(h)) != NULL
4481N/A && (pg = scf_pg_create(h)) != NULL
4481N/A && (prop = scf_property_create(h)) != NULL
4481N/A && (val = scf_value_create(h)) != NULL
4481N/A && scf_handle_decode_fmri(h, TIMEZONE_FMRI, NULL, NULL, inst,
4481N/A NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) == 0
4481N/A && scf_instance_get_snapshot(inst, "running", snap) == 0
4481N/A && scf_instance_get_pg_composed(inst, snap, TIMEZONE_PG, pg) == 0
4481N/A && scf_pg_get_property(pg, LOCALTIME_PROP, prop) == 0
4481N/A && scf_property_get_value(prop, val) == 0) {
4481N/A ssize_t len;
4481N/A
4481N/A /* Gets the length of the zone ID string */
4481N/A len = scf_value_get_astring(val, NULL, 0);
4481N/A if (len != -1) {
4481N/A tz = malloc(++len); /* +1 for a null byte */
4481N/A if (tz != NULL && scf_value_get_astring(val, tz, len) != -1) {
4481N/A cleanupScf(h, snap, inst, pg, prop, val, NULL);
4481N/A return tz;
4481N/A }
4481N/A }
4481N/A }
4481N/A cleanupScf(h, snap, inst, pg, prop, val, tz);
4481N/A
4481N/A if (stat(DEFAULT_ZONEINFO_FILE, &statbuf) == -1) {
4481N/A return NULL;
4481N/A }
4481N/A size = (size_t) statbuf.st_size;
4481N/A buf = malloc(size);
4481N/A if (buf == NULL) {
4481N/A return NULL;
4481N/A }
4481N/A if ((fd = open(DEFAULT_ZONEINFO_FILE, O_RDONLY)) == -1) {
4481N/A free((void *) buf);
4481N/A return NULL;
4481N/A }
4481N/A
4481N/A if (read(fd, buf, size) != (ssize_t) size) {
4481N/A (void) close(fd);
4481N/A free((void *) buf);
4481N/A return NULL;
4481N/A }
4481N/A (void) close(fd);
4481N/A tz = findZoneinfoFile(buf, size, ZONEINFO_DIR);
4481N/A free((void *) buf);
4481N/A return tz;
4481N/A}
4481N/A#endif /*__solaris__*/
4481N/A#endif /*__linux__*/
0N/A
0N/A/*
0N/A * findJavaTZ_md() maps platform time zone ID to Java time zone ID
0N/A * using <java_home>/lib/tzmappings. If the TZ value is not found, it
0N/A * trys some libc implementation dependent mappings. If it still
0N/A * can't map to a Java time zone ID, it falls back to the GMT+/-hh:mm
0N/A * form. `country', which can be null, is not used for UNIX platforms.
0N/A */
0N/A/*ARGSUSED1*/
0N/Achar *
0N/AfindJavaTZ_md(const char *java_home_dir, const char *country)
0N/A{
0N/A char *tz;
0N/A char *javatz = NULL;
0N/A char *freetz = NULL;
0N/A
0N/A tz = getenv("TZ");
0N/A
4632N/A#if defined(__linux__) || defined(_ALLBSD_SOURCE)
0N/A if (tz == NULL) {
0N/A#else
0N/A#ifdef __solaris__
0N/A if (tz == NULL || *tz == '\0') {
0N/A#endif
0N/A#endif
0N/A tz = getPlatformTimeZoneID();
0N/A freetz = tz;
0N/A }
0N/A
4481N/A /*
4481N/A * Remove any preceding ':'
4481N/A */
4481N/A if (tz != NULL && *tz == ':') {
4481N/A tz++;
4481N/A }
4481N/A
4481N/A#ifdef __solaris__
5003N/A if (tz != NULL && strcmp(tz, "localtime") == 0) {
4481N/A tz = getSolarisDefaultZoneID();
4481N/A freetz = tz;
4481N/A }
4481N/A#endif
4481N/A
0N/A if (tz != NULL) {
0N/A#ifdef __linux__
0N/A /*
0N/A * Ignore "posix/" prefix.
0N/A */
0N/A if (strncmp(tz, "posix/", 6) == 0) {
0N/A tz += 6;
0N/A }
0N/A#endif
0N/A javatz = strdup(tz);
0N/A if (freetz != NULL) {
0N/A free((void *) freetz);
0N/A }
0N/A }
0N/A return javatz;
0N/A}
0N/A/**
4481N/A * Returns a GMT-offset-based zone ID. (e.g., "GMT-08:00")
0N/A */
4632N/A
4632N/A#ifdef MACOSX
4632N/A
4632N/Achar *
4632N/AgetGMTOffsetID()
4632N/A{
4632N/A time_t offset;
4632N/A char sign, buf[16];
4632N/A struct tm *local_tm;
4632N/A time_t clock;
4632N/A
4632N/A clock = time(NULL);
4632N/A tzset();
4632N/A local_tm = localtime(&clock);
4632N/A if (local_tm->tm_gmtoff >= 0) {
4632N/A offset = (time_t) local_tm->tm_gmtoff;
4632N/A sign = "+";
4632N/A } else {
4632N/A offset = (time_t) -local_tm->tm_gmtoff;
4632N/A sign = "-";
4632N/A }
4632N/A sprintf(buf, (const char *)"GMT%c%02d:%02d",
4632N/A sign, (int)(offset/3600), (int)((offset%3600)/60));
4632N/A return strdup(buf);
4632N/A}
4632N/A#else
4632N/A
0N/Achar *
0N/AgetGMTOffsetID()
0N/A{
0N/A time_t offset;
4481N/A char sign, buf[32];
4481N/A#ifdef __solaris__
4481N/A struct tm localtm;
4481N/A time_t currenttime;
0N/A
4481N/A currenttime = time(NULL);
4481N/A if (localtime_r(&currenttime, &localtm) == NULL) {
4481N/A return NULL;
4481N/A }
4481N/A
4481N/A offset = localtm.tm_isdst ? altzone : timezone;
4481N/A#else
4481N/A offset = timezone;
4481N/A#endif /*__linux__*/
4481N/A
4481N/A if (offset == 0) {
0N/A return strdup("GMT");
0N/A }
0N/A
0N/A /* Note that the time offset direction is opposite. */
4481N/A if (offset > 0) {
0N/A sign = '-';
0N/A } else {
4481N/A offset = -offset;
0N/A sign = '+';
0N/A }
0N/A sprintf(buf, (const char *)"GMT%c%02d:%02d",
0N/A sign, (int)(offset/3600), (int)((offset%3600)/60));
0N/A return strdup(buf);
0N/A}
4632N/A#endif /* MACOSX */