< prev index next >

src/java.base/unix/native/libjava/TimeZone_md.c

Print this page
rev 52679 : 8214077: test java/io/File/SetLastModified.java fails on ARM32
Summary: replace uses of stat with stat64 in java.base
Reviewed-by: duke
Contributed-by: nick.gasson@arm.com

Jira: ENTLLT-1484
Change-Id: I7eb190fdc1f60db7cc13327eb2e9fe233063ffd1


  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(__solaris__) || defined(__sparcv9) || defined(amd64)
  54 #define fileopen        fopen
  55 #define filegets        fgets
  56 #define fileclose       fclose
  57 #endif
  58 








  59 #if defined(__linux__) || defined(_ALLBSD_SOURCE)
  60 static const char *ETC_TIMEZONE_FILE = "/etc/timezone";
  61 static const char *ZONEINFO_DIR = "/usr/share/zoneinfo";
  62 static const char *DEFAULT_ZONEINFO_FILE = "/etc/localtime";
  63 #else
  64 static const char *SYS_INIT_FILE = "/etc/default/init";
  65 static const char *ZONEINFO_DIR = "/usr/share/lib/zoneinfo";
  66 static const char *DEFAULT_ZONEINFO_FILE = "/usr/share/lib/zoneinfo/localtime";
  67 #endif /* defined(__linux__) || defined(_ALLBSD_SOURCE) */
  68 
  69 #if defined(_AIX)
  70 static const char *ETC_ENVIRONMENT_FILE = "/etc/environment";
  71 #endif
  72 
  73 #if defined(__linux__) || defined(MACOSX) || defined(__solaris__)
  74 
  75 /*
  76  * Returns a pointer to the zone ID portion of the given zoneinfo file
  77  * name, or NULL if the given string doesn't contain "zoneinfo/".
  78  */


  98     char *path;
  99 
 100     path = (char *) malloc(strlen(dir) + strlen(name) + 2);
 101     if (path == NULL) {
 102         return NULL;
 103     }
 104     return strcat(strcat(strcpy(path, dir), "/"), name);
 105 }
 106 
 107 /*
 108  * Scans the specified directory and its subdirectories to find a
 109  * zoneinfo file which has the same content as /etc/localtime on Linux
 110  * or /usr/share/lib/zoneinfo/localtime on Solaris given in 'buf'.
 111  * If file is symbolic link, then the contents it points to are in buf.
 112  * Returns a zone ID if found, otherwise, NULL is returned.
 113  */
 114 static char *
 115 findZoneinfoFile(char *buf, size_t size, const char *dir)
 116 {
 117     DIR *dirp = NULL;
 118     struct stat statbuf;
 119     struct dirent *dp = NULL;
 120     char *pathname = NULL;
 121     int fd = -1;
 122     char *dbuf = NULL;
 123     char *tz = NULL;
 124     int res;
 125 
 126     dirp = opendir(dir);
 127     if (dirp == NULL) {
 128         return NULL;
 129     }
 130 
 131     while ((dp = readdir(dirp)) != NULL) {
 132         /*
 133          * Skip '.' and '..' (and possibly other .* files)
 134          */
 135         if (dp->d_name[0] == '.') {
 136             continue;
 137         }
 138 
 139         /*
 140          * Skip "ROC", "posixrules", and "localtime".
 141          */
 142         if ((strcmp(dp->d_name, "ROC") == 0)
 143             || (strcmp(dp->d_name, "posixrules") == 0)
 144 #if defined(__solaris__)
 145             /*
 146              * Skip the "src" and "tab" directories on Solaris.
 147              */
 148             || (strcmp(dp->d_name, "src") == 0)
 149             || (strcmp(dp->d_name, "tab") == 0)
 150 #endif
 151             || (strcmp(dp->d_name, "localtime") == 0)) {
 152             continue;
 153         }
 154 
 155         pathname = getPathName(dir, dp->d_name);
 156         if (pathname == NULL) {
 157             break;
 158         }
 159         RESTARTABLE(stat(pathname, &statbuf), res);
 160         if (res == -1) {
 161             break;
 162         }
 163 
 164         if (S_ISDIR(statbuf.st_mode)) {
 165             tz = findZoneinfoFile(buf, size, pathname);
 166             if (tz != NULL) {
 167                 break;
 168             }
 169         } else if (S_ISREG(statbuf.st_mode) && (size_t)statbuf.st_size == size) {
 170             dbuf = (char *) malloc(size);
 171             if (dbuf == NULL) {
 172                 break;
 173             }
 174             RESTARTABLE(open(pathname, O_RDONLY), fd);
 175             if (fd == -1) {
 176                 break;
 177             }
 178             RESTARTABLE(read(fd, dbuf, size), res);
 179             if (res != (ssize_t) size) {


 202         free((void *) pathname);
 203     }
 204     if (fd != -1) {
 205         (void) close(fd);
 206     }
 207     if (dbuf != NULL) {
 208         free((void *) dbuf);
 209     }
 210     return tz;
 211 }
 212 
 213 #if defined(__linux__) || defined(MACOSX)
 214 
 215 /*
 216  * Performs Linux specific mapping and returns a zone ID
 217  * if found. Otherwise, NULL is returned.
 218  */
 219 static char *
 220 getPlatformTimeZoneID()
 221 {
 222     struct stat statbuf;
 223     char *tz = NULL;
 224     FILE *fp;
 225     int fd;
 226     char *buf;
 227     size_t size;
 228     int res;
 229 
 230 #if defined(__linux__)
 231     /*
 232      * Try reading the /etc/timezone file for Debian distros. There's
 233      * no spec of the file format available. This parsing assumes that
 234      * there's one line of an Olson tzid followed by a '\n', no
 235      * leading or trailing spaces, no comments.
 236      */
 237     if ((fp = fopen(ETC_TIMEZONE_FILE, "r")) != NULL) {
 238         char line[256];
 239 
 240         if (fgets(line, sizeof(line), fp) != NULL) {
 241             char *p = strchr(line, '\n');
 242             if (p != NULL) {
 243                 *p = '\0';
 244             }
 245             if (strlen(line) > 0) {
 246                 tz = strdup(line);
 247             }
 248         }
 249         (void) fclose(fp);
 250         if (tz != NULL) {
 251             return tz;
 252         }
 253     }
 254 #endif /* defined(__linux__) */
 255 
 256     /*
 257      * Next, try /etc/localtime to find the zone ID.
 258      */
 259     RESTARTABLE(lstat(DEFAULT_ZONEINFO_FILE, &statbuf), res);
 260     if (res == -1) {
 261         return NULL;
 262     }
 263 
 264     /*
 265      * If it's a symlink, get the link name and its zone ID part. (The
 266      * older versions of timeconfig created a symlink as described in
 267      * the Red Hat man page. It was changed in 1999 to create a copy
 268      * of a zoneinfo file. It's no longer possible to get the zone ID
 269      * from /etc/localtime.)
 270      */
 271     if (S_ISLNK(statbuf.st_mode)) {
 272         char linkbuf[PATH_MAX+1];
 273         int len;
 274 
 275         if ((len = readlink(DEFAULT_ZONEINFO_FILE, linkbuf, sizeof(linkbuf)-1)) == -1) {
 276             jio_fprintf(stderr, (const char *) "can't get a symlink of %s\n",
 277                         DEFAULT_ZONEINFO_FILE);
 278             return NULL;
 279         }
 280         linkbuf[len] = '\0';
 281         tz = getZoneName(linkbuf);
 282         if (tz != NULL) {
 283             tz = strdup(tz);
 284             return tz;
 285         }
 286     }
 287 
 288     /*
 289      * If it's a regular file, we need to find out the same zoneinfo file
 290      * that has been copied as /etc/localtime.
 291      * If initial symbolic link resolution failed, we should treat target
 292      * file as a regular file.
 293      */
 294     RESTARTABLE(open(DEFAULT_ZONEINFO_FILE, O_RDONLY), fd);
 295     if (fd == -1) {
 296         return NULL;
 297     }
 298 
 299     RESTARTABLE(fstat(fd, &statbuf), res);
 300     if (res == -1) {
 301         (void) close(fd);
 302         return NULL;
 303     }
 304     size = (size_t) statbuf.st_size;
 305     buf = (char *) malloc(size);
 306     if (buf == NULL) {
 307         (void) close(fd);
 308         return NULL;
 309     }
 310 
 311     RESTARTABLE(read(fd, buf, size), res);
 312     if (res != (ssize_t) size) {
 313         (void) close(fd);
 314         free((void *) buf);
 315         return NULL;
 316     }
 317     (void) close(fd);
 318 
 319     tz = findZoneinfoFile(buf, size, ZONEINFO_DIR);


 540     }
 541     if (pg != NULL) {
 542         scf_pg_destroy(pg);
 543     }
 544     if (inst != NULL) {
 545         scf_instance_destroy(inst);
 546     }
 547     if (h != NULL) {
 548         scf_handle_destroy(h);
 549     }
 550 }
 551 
 552 /*
 553  * Returns a zone ID of Solaris when the TZ value is "localtime".
 554  * First, it tries scf. If scf fails, it looks for the same file as
 555  * /usr/share/lib/zoneinfo/localtime under /usr/share/lib/zoneinfo/.
 556  */
 557 static char *
 558 getSolarisDefaultZoneID() {
 559     char *tz = NULL;
 560     struct stat statbuf;
 561     size_t size;
 562     char *buf;
 563     int fd;
 564     int res;
 565     /* scf specific variables */
 566     scf_handle_t *h = NULL;
 567     scf_snapshot_t *snap = NULL;
 568     scf_instance_t *inst = NULL;
 569     scf_propertygroup_t *pg = NULL;
 570     scf_property_t *prop = NULL;
 571     scf_value_t *val = NULL;
 572 
 573     if ((h = scf_handle_create(SCF_VERSION)) != NULL
 574         && scf_handle_bind(h) == 0
 575         && (inst = scf_instance_create(h)) != NULL
 576         && (snap = scf_snapshot_create(h)) != NULL
 577         && (pg = scf_pg_create(h)) != NULL
 578         && (prop = scf_property_create(h)) != NULL
 579         && (val = scf_value_create(h)) != NULL
 580         && scf_handle_decode_fmri(h, TIMEZONE_FMRI, NULL, NULL, inst,
 581                                   NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) == 0
 582         && scf_instance_get_snapshot(inst, "running", snap) == 0
 583         && scf_instance_get_pg_composed(inst, snap, TIMEZONE_PG, pg) == 0
 584         && scf_pg_get_property(pg, LOCALTIME_PROP, prop) == 0
 585         && scf_property_get_value(prop, val) == 0) {
 586         ssize_t len;
 587 
 588         /* Gets the length of the zone ID string */
 589         len = scf_value_get_astring(val, NULL, 0);
 590         if (len != -1) {
 591             tz = malloc(++len); /* +1 for a null byte */
 592             if (tz != NULL && scf_value_get_astring(val, tz, len) != -1) {
 593                 cleanupScf(h, snap, inst, pg, prop, val, NULL);
 594                 return tz;
 595             }
 596         }
 597     }
 598     cleanupScf(h, snap, inst, pg, prop, val, tz);
 599 
 600     RESTARTABLE(stat(DEFAULT_ZONEINFO_FILE, &statbuf), res);
 601     if (res == -1) {
 602         return NULL;
 603     }
 604     size = (size_t) statbuf.st_size;
 605     buf = malloc(size);
 606     if (buf == NULL) {
 607         return NULL;
 608     }
 609     RESTARTABLE(open(DEFAULT_ZONEINFO_FILE, O_RDONLY), fd);
 610     if (fd == -1) {
 611         free((void *) buf);
 612         return NULL;
 613     }
 614 
 615     RESTARTABLE(read(fd, buf, size), res);
 616     if (res != (ssize_t) size) {
 617         (void) close(fd);
 618         free((void *) buf);
 619         return NULL;
 620     }




  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(__solaris__) || defined(__sparcv9) || defined(amd64)
  54 #define fileopen        fopen
  55 #define filegets        fgets
  56 #define fileclose       fclose
  57 #endif
  58 
  59 #if defined(_ALLBSD_SOURCE)
  60   #ifndef MACOSX
  61     #define stat64 stat
  62     #define lstat64 lstat
  63     #define fstat64 fstat
  64   #endif
  65 #endif
  66 
  67 #if defined(__linux__) || defined(_ALLBSD_SOURCE)
  68 static const char *ETC_TIMEZONE_FILE = "/etc/timezone";
  69 static const char *ZONEINFO_DIR = "/usr/share/zoneinfo";
  70 static const char *DEFAULT_ZONEINFO_FILE = "/etc/localtime";
  71 #else
  72 static const char *SYS_INIT_FILE = "/etc/default/init";
  73 static const char *ZONEINFO_DIR = "/usr/share/lib/zoneinfo";
  74 static const char *DEFAULT_ZONEINFO_FILE = "/usr/share/lib/zoneinfo/localtime";
  75 #endif /* defined(__linux__) || defined(_ALLBSD_SOURCE) */
  76 
  77 #if defined(_AIX)
  78 static const char *ETC_ENVIRONMENT_FILE = "/etc/environment";
  79 #endif
  80 
  81 #if defined(__linux__) || defined(MACOSX) || defined(__solaris__)
  82 
  83 /*
  84  * Returns a pointer to the zone ID portion of the given zoneinfo file
  85  * name, or NULL if the given string doesn't contain "zoneinfo/".
  86  */


 106     char *path;
 107 
 108     path = (char *) malloc(strlen(dir) + strlen(name) + 2);
 109     if (path == NULL) {
 110         return NULL;
 111     }
 112     return strcat(strcat(strcpy(path, dir), "/"), name);
 113 }
 114 
 115 /*
 116  * Scans the specified directory and its subdirectories to find a
 117  * zoneinfo file which has the same content as /etc/localtime on Linux
 118  * or /usr/share/lib/zoneinfo/localtime on Solaris given in 'buf'.
 119  * If file is symbolic link, then the contents it points to are in buf.
 120  * Returns a zone ID if found, otherwise, NULL is returned.
 121  */
 122 static char *
 123 findZoneinfoFile(char *buf, size_t size, const char *dir)
 124 {
 125     DIR *dirp = NULL;
 126     struct stat64 statbuf;
 127     struct dirent *dp = NULL;
 128     char *pathname = NULL;
 129     int fd = -1;
 130     char *dbuf = NULL;
 131     char *tz = NULL;
 132     int res;
 133 
 134     dirp = opendir(dir);
 135     if (dirp == NULL) {
 136         return NULL;
 137     }
 138 
 139     while ((dp = readdir(dirp)) != NULL) {
 140         /*
 141          * Skip '.' and '..' (and possibly other .* files)
 142          */
 143         if (dp->d_name[0] == '.') {
 144             continue;
 145         }
 146 
 147         /*
 148          * Skip "ROC", "posixrules", and "localtime".
 149          */
 150         if ((strcmp(dp->d_name, "ROC") == 0)
 151             || (strcmp(dp->d_name, "posixrules") == 0)
 152 #if defined(__solaris__)
 153             /*
 154              * Skip the "src" and "tab" directories on Solaris.
 155              */
 156             || (strcmp(dp->d_name, "src") == 0)
 157             || (strcmp(dp->d_name, "tab") == 0)
 158 #endif
 159             || (strcmp(dp->d_name, "localtime") == 0)) {
 160             continue;
 161         }
 162 
 163         pathname = getPathName(dir, dp->d_name);
 164         if (pathname == NULL) {
 165             break;
 166         }
 167         RESTARTABLE(stat64(pathname, &statbuf), res);
 168         if (res == -1) {
 169             break;
 170         }
 171 
 172         if (S_ISDIR(statbuf.st_mode)) {
 173             tz = findZoneinfoFile(buf, size, pathname);
 174             if (tz != NULL) {
 175                 break;
 176             }
 177         } else if (S_ISREG(statbuf.st_mode) && (size_t)statbuf.st_size == size) {
 178             dbuf = (char *) malloc(size);
 179             if (dbuf == NULL) {
 180                 break;
 181             }
 182             RESTARTABLE(open(pathname, O_RDONLY), fd);
 183             if (fd == -1) {
 184                 break;
 185             }
 186             RESTARTABLE(read(fd, dbuf, size), res);
 187             if (res != (ssize_t) size) {


 210         free((void *) pathname);
 211     }
 212     if (fd != -1) {
 213         (void) close(fd);
 214     }
 215     if (dbuf != NULL) {
 216         free((void *) dbuf);
 217     }
 218     return tz;
 219 }
 220 
 221 #if defined(__linux__) || defined(MACOSX)
 222 
 223 /*
 224  * Performs Linux specific mapping and returns a zone ID
 225  * if found. Otherwise, NULL is returned.
 226  */
 227 static char *
 228 getPlatformTimeZoneID()
 229 {
 230     struct stat64 statbuf;
 231     char *tz = NULL;
 232     FILE *fp;
 233     int fd;
 234     char *buf;
 235     size_t size;
 236     int res;
 237 
 238 #if defined(__linux__)
 239     /*
 240      * Try reading the /etc/timezone file for Debian distros. There's
 241      * no spec of the file format available. This parsing assumes that
 242      * there's one line of an Olson tzid followed by a '\n', no
 243      * leading or trailing spaces, no comments.
 244      */
 245     if ((fp = fopen(ETC_TIMEZONE_FILE, "r")) != NULL) {
 246         char line[256];
 247 
 248         if (fgets(line, sizeof(line), fp) != NULL) {
 249             char *p = strchr(line, '\n');
 250             if (p != NULL) {
 251                 *p = '\0';
 252             }
 253             if (strlen(line) > 0) {
 254                 tz = strdup(line);
 255             }
 256         }
 257         (void) fclose(fp);
 258         if (tz != NULL) {
 259             return tz;
 260         }
 261     }
 262 #endif /* defined(__linux__) */
 263 
 264     /*
 265      * Next, try /etc/localtime to find the zone ID.
 266      */
 267     RESTARTABLE(lstat64(DEFAULT_ZONEINFO_FILE, &statbuf), res);
 268     if (res == -1) {
 269         return NULL;
 270     }
 271 
 272     /*
 273      * If it's a symlink, get the link name and its zone ID part. (The
 274      * older versions of timeconfig created a symlink as described in
 275      * the Red Hat man page. It was changed in 1999 to create a copy
 276      * of a zoneinfo file. It's no longer possible to get the zone ID
 277      * from /etc/localtime.)
 278      */
 279     if (S_ISLNK(statbuf.st_mode)) {
 280         char linkbuf[PATH_MAX+1];
 281         int len;
 282 
 283         if ((len = readlink(DEFAULT_ZONEINFO_FILE, linkbuf, sizeof(linkbuf)-1)) == -1) {
 284             jio_fprintf(stderr, (const char *) "can't get a symlink of %s\n",
 285                         DEFAULT_ZONEINFO_FILE);
 286             return NULL;
 287         }
 288         linkbuf[len] = '\0';
 289         tz = getZoneName(linkbuf);
 290         if (tz != NULL) {
 291             tz = strdup(tz);
 292             return tz;
 293         }
 294     }
 295 
 296     /*
 297      * If it's a regular file, we need to find out the same zoneinfo file
 298      * that has been copied as /etc/localtime.
 299      * If initial symbolic link resolution failed, we should treat target
 300      * file as a regular file.
 301      */
 302     RESTARTABLE(open(DEFAULT_ZONEINFO_FILE, O_RDONLY), fd);
 303     if (fd == -1) {
 304         return NULL;
 305     }
 306 
 307     RESTARTABLE(fstat64(fd, &statbuf), res);
 308     if (res == -1) {
 309         (void) close(fd);
 310         return NULL;
 311     }
 312     size = (size_t) statbuf.st_size;
 313     buf = (char *) malloc(size);
 314     if (buf == NULL) {
 315         (void) close(fd);
 316         return NULL;
 317     }
 318 
 319     RESTARTABLE(read(fd, buf, size), res);
 320     if (res != (ssize_t) size) {
 321         (void) close(fd);
 322         free((void *) buf);
 323         return NULL;
 324     }
 325     (void) close(fd);
 326 
 327     tz = findZoneinfoFile(buf, size, ZONEINFO_DIR);


 548     }
 549     if (pg != NULL) {
 550         scf_pg_destroy(pg);
 551     }
 552     if (inst != NULL) {
 553         scf_instance_destroy(inst);
 554     }
 555     if (h != NULL) {
 556         scf_handle_destroy(h);
 557     }
 558 }
 559 
 560 /*
 561  * Returns a zone ID of Solaris when the TZ value is "localtime".
 562  * First, it tries scf. If scf fails, it looks for the same file as
 563  * /usr/share/lib/zoneinfo/localtime under /usr/share/lib/zoneinfo/.
 564  */
 565 static char *
 566 getSolarisDefaultZoneID() {
 567     char *tz = NULL;
 568     struct stat64 statbuf;
 569     size_t size;
 570     char *buf;
 571     int fd;
 572     int res;
 573     /* scf specific variables */
 574     scf_handle_t *h = NULL;
 575     scf_snapshot_t *snap = NULL;
 576     scf_instance_t *inst = NULL;
 577     scf_propertygroup_t *pg = NULL;
 578     scf_property_t *prop = NULL;
 579     scf_value_t *val = NULL;
 580 
 581     if ((h = scf_handle_create(SCF_VERSION)) != NULL
 582         && scf_handle_bind(h) == 0
 583         && (inst = scf_instance_create(h)) != NULL
 584         && (snap = scf_snapshot_create(h)) != NULL
 585         && (pg = scf_pg_create(h)) != NULL
 586         && (prop = scf_property_create(h)) != NULL
 587         && (val = scf_value_create(h)) != NULL
 588         && scf_handle_decode_fmri(h, TIMEZONE_FMRI, NULL, NULL, inst,
 589                                   NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) == 0
 590         && scf_instance_get_snapshot(inst, "running", snap) == 0
 591         && scf_instance_get_pg_composed(inst, snap, TIMEZONE_PG, pg) == 0
 592         && scf_pg_get_property(pg, LOCALTIME_PROP, prop) == 0
 593         && scf_property_get_value(prop, val) == 0) {
 594         ssize_t len;
 595 
 596         /* Gets the length of the zone ID string */
 597         len = scf_value_get_astring(val, NULL, 0);
 598         if (len != -1) {
 599             tz = malloc(++len); /* +1 for a null byte */
 600             if (tz != NULL && scf_value_get_astring(val, tz, len) != -1) {
 601                 cleanupScf(h, snap, inst, pg, prop, val, NULL);
 602                 return tz;
 603             }
 604         }
 605     }
 606     cleanupScf(h, snap, inst, pg, prop, val, tz);
 607 
 608     RESTARTABLE(stat64(DEFAULT_ZONEINFO_FILE, &statbuf), res);
 609     if (res == -1) {
 610         return NULL;
 611     }
 612     size = (size_t) statbuf.st_size;
 613     buf = malloc(size);
 614     if (buf == NULL) {
 615         return NULL;
 616     }
 617     RESTARTABLE(open(DEFAULT_ZONEINFO_FILE, O_RDONLY), fd);
 618     if (fd == -1) {
 619         free((void *) buf);
 620         return NULL;
 621     }
 622 
 623     RESTARTABLE(read(fd, buf, size), res);
 624     if (res != (ssize_t) size) {
 625         (void) close(fd);
 626         free((void *) buf);
 627         return NULL;
 628     }


< prev index next >