src/solaris/native/java/util/TimeZone_md.c
Print this page
@@ -51,10 +51,11 @@
#if defined(__linux__) || defined(_ALLBSD_SOURCE)
static const char *ETC_TIMEZONE_FILE = "/etc/timezone";
+static const char *ETC_SYSCONFIG_CLOCK_FILE = "/etc/sysconfig/clock";
static const char *ZONEINFO_DIR = "/usr/share/zoneinfo";
static const char *DEFAULT_ZONEINFO_FILE = "/etc/localtime";
#else
static const char *SYS_INIT_FILE = "/etc/default/init";
static const char *ZONEINFO_DIR = "/usr/share/lib/zoneinfo";
@@ -92,10 +93,99 @@
}
return strcat(strcat(strcpy(path, dir), "/"), name);
}
/*
+ * Reads the entire contents of a file. The return value is negative if
+ * an error occurs.
+ */
+static int
+readEntireFile(const char *file_name, char **contents) {
+ FILE *file = fopen(file_name, "re");
+ if (!file) {
+ return -ENOENT;
+ }
+
+ char *p = NULL;
+
+ size_t allocated_size = 0;
+ size_t total_read = 0;
+ size_t bytes_read = -1;
+
+ for (;;) {
+ size_t room = allocated_size - total_read;
+ if (room == 0) {
+ allocated_size += 256;
+ char *temp_p = realloc(p, allocated_size);
+ if (temp_p == NULL) {
+ return -ENOMEM;
+ }
+ p = temp_p;
+ room = allocated_size - total_read;
+ }
+
+ bytes_read = fread(p+total_read, 1, room, file);
+
+ if (bytes_read < room) {
+ if (ferror(file) != 0) {
+ goto fail;
+ }
+ break;
+ }
+
+ total_read += bytes_read;
+ }
+ p[allocated_size-1] = '\0';
+
+ fclose(file);
+ *contents = p;
+ return 0;
+
+fail:
+ fclose(file);
+ return -1;
+}
+
+/*
+ * Reads the value of ZONE variable from the given clock file.
+ */
+static char*
+readTimeZoneFromSysconfigClock(const char* path) {
+
+ /*
+ * the file is a shell-script like file with key/value pairs
+ * that looks like this:
+ * KEY="VALUE"
+ */
+
+ char *contents = NULL;
+ int r = readEntireFile(path, &contents);
+ if (r < 0) {
+ return NULL;
+ }
+
+ char *start = NULL;
+ start = strstr(contents, "ZONE=\"");
+ if (start == NULL) {
+ goto fail;
+ }
+ start = start + strlen("ZONE=\"");
+ char *end;
+ end = strchr(start, '"');
+ if (end == NULL) {
+ goto fail;
+ }
+ char *tz_name = strndup(start, (end-start));
+ free(contents);
+ return tz_name;
+
+fail:
+ free(contents);
+ return NULL;
+}
+
+/*
* Scans the specified directory and its subdirectories to find a
* zoneinfo file which has the same content as /etc/localtime on Linux
* or /usr/share/lib/zoneinfo/localtime on Solaris given in 'buf'.
* If file is symbolic link, then the contents it points to are in buf.
* Returns a zone ID if found, otherwise, NULL is returned.
@@ -249,10 +339,18 @@
(void) fclose(fp);
if (tz != NULL) {
return tz;
}
}
+
+ /*
+ * Try reading the /etc/sysconfig/clock file for Red Hat-like distros.
+ */
+ if ((tz = readTimeZoneFromSysconfigClock(ETC_SYSCONFIG_CLOCK_FILE)) != NULL) {
+ return tz;
+ }
+
#endif /* __linux__ */
/*
* Next, try /etc/localtime to find the zone ID.
*/