之前的文章提到过把镜像的/etc/localtime 删除后挂载本地的就可以解决问题,但是最近更新了centos7的基础镜像,发现时间又少了8个小时,确认了下镜像制作没问题,但是依然出现了,百思不得其解,于是把java获取时区的代码抠出来了
#include<stdlib.h> #include<stdio.h> #include<strings.h> #include<time.h> #include<limits.h> #include<errno.h> #include<stddef.h> #include<sys/stat.h> #include<sys/types.h> #include<string.h> #include<dirent.h> #include<unistd.h> #include<fcntl.h> static const char *ETC_TIMEZONE_FILE = "/etc/timezone"; static const char *ZONEINFO_DIR = "/usr/share/zoneinfo"; static const char *DEFAULT_ZONEINFO_FILE = "/etc/localtime"; static char * getZoneName(char *str) { static const char *zidir = "zoneinfo/"; char *pos = strstr((const char *)str, zidir); if (pos == NULL) { return NULL; } return pos + strlen(zidir); } /* * Returns a path name created from the given 'dir' and 'name' under * UNIX. This function allocates memory for the pathname calling * malloc(). NULL is returned if malloc() fails. */ static char * getPathName(const char *dir, const char *name) { char *path; path = (char *) malloc(strlen(dir) + strlen(name) + 2); if (path == NULL) { return NULL; } return strcat(strcat(strcpy(path, dir), "/"), name); } static char * findZoneinfoFile(char *buf, size_t size, const char *dir) { DIR *dirp = NULL; struct stat statbuf; struct dirent *dp = NULL; struct dirent *entry = NULL; char *pathname = NULL; int fd = -1; char *dbuf = NULL; char *tz = NULL; dirp = opendir(dir); if (dirp == NULL) { return NULL; } entry = (struct dirent *) malloc((size_t) pathconf(dir, _PC_NAME_MAX)); if (entry == NULL) { (void) closedir(dirp); return NULL; } #ifdefined(__linux__) || defined(MACOSX) || (defined(__solaris__) / && (defined(_POSIX_PTHREAD_SEMANTICS) || defined(_LP64))) while (readdir_r(dirp, entry, &dp) == 0 && dp != NULL) { #else while ((dp = readdir_r(dirp, entry)) != NULL) { #endif /* * Skip '.' and '..' (and possibly other .* files) */ if (dp->d_name[0] == '.') { continue; } /* * Skip "ROC", "posixrules", and "localtime". */ if ((strcmp(dp->d_name, "ROC") == 0) || (strcmp(dp->d_name, "posixrules") == 0) #ifdef __solaris__ /* * Skip the "src" and "tab" directories on Solaris. */ || (strcmp(dp->d_name, "src") == 0) || (strcmp(dp->d_name, "tab") == 0) #endif || (strcmp(dp->d_name, "localtime") == 0)) { continue; } pathname = getPathName(dir, dp->d_name); if (pathname == NULL) { break; } if (stat(pathname, &statbuf) == -1) { break; } if (S_ISDIR(statbuf.st_mode)) { tz = findZoneinfoFile(buf, size, pathname); if (tz != NULL) { break; } // 这里失败 usr share zoneinfo asia 目录下 所有的文件都通不S_ISREG 这个函数 } else if (S_ISREG(statbuf.st_mode) && (size_t)statbuf.st_size == size) { dbuf = (char *) malloc(size); if (dbuf == NULL) { break; } if ((fd = open(pathname, O_RDONLY)) == -1) { break; } if (read(fd, dbuf, size) != (ssize_t) size) { break; } if (memcmp(buf, dbuf, size) == 0) { tz = getZoneName(pathname); if (tz != NULL) { tz = strdup(tz); } break; } free((void *) dbuf); dbuf = NULL; (void) close(fd); fd = -1; } free((void *) pathname); pathname = NULL; } if (entry != NULL) { free((void *) entry); } if (dirp != NULL) { (void) closedir(dirp); } if (pathname != NULL) { free((void *) pathname); } if (fd != -1) { (void) close(fd); } if (dbuf != NULL) { free((void *) dbuf); } return tz; } int main(){ struct stat statbuf; char *tz = NULL; FILE *fp; int fd; char *buf; size_t size; if ((fd = open(DEFAULT_ZONEINFO_FILE, O_RDONLY)) == -1) { return NULL; } if (fstat(fd, &statbuf) == -1) { (void) close(fd); return NULL; } size = (size_t) statbuf.st_size; buf = (char *) malloc(size); if (buf == NULL) { (void) close(fd); return NULL; } if (read(fd, buf, size) != (ssize_t) size) { (void) close(fd); free((void *) buf); return NULL; } (void) close(fd); tz = findZoneinfoFile(buf, size, ZONEINFO_DIR); printf("%s", tz); free((void *) buf); return 0; }
docker 仓库上centos:7的基础镜像一直在更新,虽然是都叫centos:7但是一直都在默默的更新着,处于可控性考虑,还是得自己从头做一个基础镜像,为了彻底解决java时区问题,删除镜像localtime的同时,挂载localtime和/user/share/zoneinfo