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.
      */