79
80 /*
81 * Returns a path name created from the given 'dir' and 'name' under
82 * UNIX. This function allocates memory for the pathname calling
83 * malloc(). NULL is returned if malloc() fails.
84 */
85 static char *
86 getPathName(const char *dir, const char *name) {
87 char *path;
88
89 path = (char *) malloc(strlen(dir) + strlen(name) + 2);
90 if (path == NULL) {
91 return NULL;
92 }
93 return strcat(strcat(strcpy(path, dir), "/"), name);
94 }
95
96 /*
97 * Scans the specified directory and its subdirectories to find a
98 * zoneinfo file which has the same content as /etc/localtime on Linux
99 * or /usr/share/lib/zoneinfo/localtime (most likely a symbolic link)
100 * on Solaris given in 'buf'. Returns a zone ID if found, otherwise,
101 * NULL is returned.
102 */
103 static char *
104 findZoneinfoFile(char *buf, size_t size, const char *dir)
105 {
106 DIR *dirp = NULL;
107 struct stat statbuf;
108 struct dirent *dp = NULL;
109 struct dirent *entry = NULL;
110 char *pathname = NULL;
111 int fd = -1;
112 char *dbuf = NULL;
113 char *tz = NULL;
114
115 dirp = opendir(dir);
116 if (dirp == NULL) {
117 return NULL;
118 }
119
120 entry = (struct dirent *) malloc((size_t) pathconf(dir, _PC_NAME_MAX));
121 if (entry == NULL) {
209 free((void *) dbuf);
210 }
211 return tz;
212 }
213
214 #if defined(__linux__) || defined(MACOSX)
215
216 /*
217 * Performs Linux specific mapping and returns a zone ID
218 * if found. Otherwise, NULL is returned.
219 */
220 static char *
221 getPlatformTimeZoneID()
222 {
223 struct stat statbuf;
224 char *tz = NULL;
225 FILE *fp;
226 int fd;
227 char *buf;
228 size_t size;
229
230 #ifdef __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 }
250 if (tz != NULL) {
251 return tz;
252 }
253 }
254 #endif /* __linux__ */
255
256 /*
257 * Next, try /etc/localtime to find the zone ID.
258 */
259 if (lstat(DEFAULT_ZONEINFO_FILE, &statbuf) == -1) {
260 return NULL;
261 }
262
263 /*
264 * If it's a symlink, get the link name and its zone ID part. (The
265 * older versions of timeconfig created a symlink as described in
266 * the Red Hat man page. It was changed in 1999 to create a copy
267 * of a zoneinfo file. It's no longer possible to get the zone ID
268 * from /etc/localtime.)
269 */
270 if (S_ISLNK(statbuf.st_mode)) {
271 char linkbuf[PATH_MAX+1];
272 int len;
273
274 if ((len = readlink(DEFAULT_ZONEINFO_FILE, linkbuf, sizeof(linkbuf)-1)) == -1) {
275 jio_fprintf(stderr, (const char *) "can't get a symlink of %s\n",
276 DEFAULT_ZONEINFO_FILE);
277 return NULL;
278 }
279 linkbuf[len] = '\0';
280 tz = getZoneName(linkbuf);
281 if (tz != NULL) {
282 tz = strdup(tz);
283 }
284 return tz;
285 }
286
287 /*
288 * If it's a regular file, we need to find out the same zoneinfo file
289 * that has been copied as /etc/localtime.
290 */
291 size = (size_t) statbuf.st_size;
292 buf = (char *) malloc(size);
293 if (buf == NULL) {
294 return NULL;
295 }
296 if ((fd = open(DEFAULT_ZONEINFO_FILE, O_RDONLY)) == -1) {
297 free((void *) buf);
298 return NULL;
299 }
300
301 if (read(fd, buf, size) != (ssize_t) size) {
302 (void) close(fd);
303 free((void *) buf);
304 return NULL;
305 }
306 (void) close(fd);
307
308 tz = findZoneinfoFile(buf, size, ZONEINFO_DIR);
309 free((void *) buf);
310 return tz;
311 }
312 #else
313 #ifdef __solaris__
314 #if !defined(__sparcv9) && !defined(amd64)
315
316 /*
|
79
80 /*
81 * Returns a path name created from the given 'dir' and 'name' under
82 * UNIX. This function allocates memory for the pathname calling
83 * malloc(). NULL is returned if malloc() fails.
84 */
85 static char *
86 getPathName(const char *dir, const char *name) {
87 char *path;
88
89 path = (char *) malloc(strlen(dir) + strlen(name) + 2);
90 if (path == NULL) {
91 return NULL;
92 }
93 return strcat(strcat(strcpy(path, dir), "/"), name);
94 }
95
96 /*
97 * Scans the specified directory and its subdirectories to find a
98 * zoneinfo file which has the same content as /etc/localtime on Linux
99 * or /usr/share/lib/zoneinfo/localtime on Solaris given in 'buf'.
100 * If file is symbolic link, then the contents it points to are in buf.
101 * Returns a zone ID if found, otherwise, NULL is returned.
102 */
103 static char *
104 findZoneinfoFile(char *buf, size_t size, const char *dir)
105 {
106 DIR *dirp = NULL;
107 struct stat statbuf;
108 struct dirent *dp = NULL;
109 struct dirent *entry = NULL;
110 char *pathname = NULL;
111 int fd = -1;
112 char *dbuf = NULL;
113 char *tz = NULL;
114
115 dirp = opendir(dir);
116 if (dirp == NULL) {
117 return NULL;
118 }
119
120 entry = (struct dirent *) malloc((size_t) pathconf(dir, _PC_NAME_MAX));
121 if (entry == NULL) {
209 free((void *) dbuf);
210 }
211 return tz;
212 }
213
214 #if defined(__linux__) || defined(MACOSX)
215
216 /*
217 * Performs Linux specific mapping and returns a zone ID
218 * if found. Otherwise, NULL is returned.
219 */
220 static char *
221 getPlatformTimeZoneID()
222 {
223 struct stat statbuf;
224 char *tz = NULL;
225 FILE *fp;
226 int fd;
227 char *buf;
228 size_t size;
229 char linkbuf[PATH_MAX+1];
230
231 #ifdef __linux__
232 /*
233 * Try reading the /etc/timezone file for Debian distros. There's
234 * no spec of the file format available. This parsing assumes that
235 * there's one line of an Olson tzid followed by a '\n', no
236 * leading or trailing spaces, no comments.
237 */
238 if ((fp = fopen(ETC_TIMEZONE_FILE, "r")) != NULL) {
239 char line[256];
240
241 if (fgets(line, sizeof(line), fp) != NULL) {
242 char *p = strchr(line, '\n');
243 if (p != NULL) {
244 *p = '\0';
245 }
246 if (strlen(line) > 0) {
247 tz = strdup(line);
248 }
249 }
251 if (tz != NULL) {
252 return tz;
253 }
254 }
255 #endif /* __linux__ */
256
257 /*
258 * Next, try /etc/localtime to find the zone ID.
259 */
260 if (lstat(DEFAULT_ZONEINFO_FILE, &statbuf) == -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 strcpy(linkbuf, DEFAULT_ZONEINFO_FILE);
272 linkbuf[strlen(DEFAULT_ZONEINFO_FILE)] = '\0';
273 if (S_ISLNK(statbuf.st_mode)) {
274 int len;
275
276 if ((len = readlink(DEFAULT_ZONEINFO_FILE, linkbuf, sizeof(linkbuf)-1)) == -1) {
277 jio_fprintf(stderr, (const char *) "can't get a symlink of %s\n",
278 DEFAULT_ZONEINFO_FILE);
279 return NULL;
280 }
281 linkbuf[len] = '\0';
282 tz = getZoneName(linkbuf);
283 if (tz != NULL) {
284 tz = strdup(tz);
285 return tz;
286 }
287 }
288
289 /*
290 * If it's a regular file, we need to find out the same zoneinfo file
291 * that has been copied as /etc/localtime.
292 * If initial symbolic link resolution failed, we should treat target
293 * file as a regular file. Obtain new statbuf for this (using stat)
294 */
295 if (stat(linkbuf, &statbuf) == -1) {
296 return NULL;
297 }
298
299 size = (size_t) statbuf.st_size;
300 buf = (char *) malloc(size);
301 if (buf == NULL) {
302 return NULL;
303 }
304 if ((fd = open(linkbuf, O_RDONLY)) == -1) {
305 free((void *) buf);
306 return NULL;
307 }
308
309 if (read(fd, buf, size) != (ssize_t) size) {
310 (void) close(fd);
311 free((void *) buf);
312 return NULL;
313 }
314 (void) close(fd);
315
316 tz = findZoneinfoFile(buf, size, ZONEINFO_DIR);
317 free((void *) buf);
318 return tz;
319 }
320 #else
321 #ifdef __solaris__
322 #if !defined(__sparcv9) && !defined(amd64)
323
324 /*
|