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 }
|