summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
cdefbd6)
/etc/localtime -> /usr/share/zoneinfo/...
or
/etc/localtime -> ../usr/share/zoneinfo/...
(note, ../usr is not the same if /etc is a symlink, as this isn't
using canonicalize_file_name())
keep other method for now, consider dropping later.
Supporting relative links here are problematic as timezones in
/usr/share/zoneinfo are often themselves symlinks (and symlinks to
symlinks), so this implamentation only supports absolute symlinks
"/usr/share/zoneinfo/" and relative symlinks starting with
"../usr/share/zoneinfo/"
>From TODO (kay sievers):
* kill /etc/timezone handling entirely? What does it provide?
- /etc/localtime carries the same information already:
$ ls -l /etc/localtime; cat /etc/timezone
lrwxrwxrwx 1 root root 33 Jul 27 09:55 /etc/localtime -> /usr/share/zoneinfo/Europe/Berlin
Europe/Berlin
- systemd enforces /usr to be available at bootup, so we can
enforce the use of the symlink
BUS_GENERIC_INTERFACES_LIST \
"org.freedesktop.timedate1\0"
BUS_GENERIC_INTERFACES_LIST \
"org.freedesktop.timedate1\0"
+/* Must start and end with '/' */
+#define ZONEINFO_PATH "/usr/share/zoneinfo/"
+
const char timedate_interface[] _introspect_("timedate1") = INTERFACE;
typedef struct TZ {
const char timedate_interface[] _introspect_("timedate1") = INTERFACE;
typedef struct TZ {
- t = strappend("/usr/share/zoneinfo/", name);
+ t = strappend(ZONEINFO_PATH, name);
- p = strappend("/usr/share/zoneinfo/", tz.zone);
+ p = strappend(ZONEINFO_PATH, tz.zone);
if (!p) {
log_oom();
return;
}
if (!p) {
log_oom();
return;
}
- j = read_full_file("/etc/localtime", &a, &l);
k = read_full_file(p, &b, &q);
k = read_full_file(p, &b, &q);
+ j = read_full_file("/etc/localtime", &a, &l);
+
if (j < 0 || k < 0 || l != q || memcmp(a, b, l)) {
log_warning("/etc/localtime and /etc/timezone out of sync.");
free(tz.zone);
if (j < 0 || k < 0 || l != q || memcmp(a, b, l)) {
log_warning("/etc/localtime and /etc/timezone out of sync.");
free(tz.zone);
static int read_data(void) {
int r;
static int read_data(void) {
int r;
+ r = readlink_malloc("/etc/localtime", &t);
+ if (r < 0) {
+ if (r == -EINVAL)
+ log_warning("/etc/localtime should be a symbolic link to a timezone data file in " ZONEINFO_PATH);
+ else
+ log_warning("Failed to get target of %s: %s", "/etc/localtime", strerror(-r));
+ } else {
+ /* we only support the trivial relative link of (/etc/)..$ABSOLUTE */
+ int rel_link_offset = startswith(t, "..") ? strlen("..") : 0;
+
+ if (!startswith(t + rel_link_offset, ZONEINFO_PATH))
+ log_warning("/etc/localtime should be a symbolic link to a timezone data file in " ZONEINFO_PATH);
+ else {
+ tz.zone = strdup(t + rel_link_offset + strlen(ZONEINFO_PATH));
+ free(t);
+ if (!tz.zone)
+ return log_oom();
+
+ goto have_timezone;
+ }
+ }
+
+ free(t);
+
r = read_one_line_file("/etc/timezone", &tz.zone);
if (r < 0) {
if (r != -ENOENT)
r = read_one_line_file("/etc/timezone", &tz.zone);
if (r < 0) {
if (r != -ENOENT)
if (isempty(tz.zone)) {
free(tz.zone);
tz.zone = NULL;
if (isempty(tz.zone)) {
free(tz.zone);
tz.zone = NULL;
static int write_data_timezone(void) {
int r = 0;
char *p;
static int write_data_timezone(void) {
int r = 0;
char *p;
if (!tz.zone) {
if (unlink("/etc/timezone") < 0 && errno != ENOENT)
if (!tz.zone) {
if (unlink("/etc/timezone") < 0 && errno != ENOENT)
- p = strappend("/usr/share/zoneinfo/", tz.zone);
+ p = strappend(ZONEINFO_PATH, tz.zone);
if (!p)
return log_oom();
if (!p)
return log_oom();
- r = symlink_or_copy_atomic(p, "/etc/localtime");
+ r = symlink(p, "/etc/localtime");
- r = write_one_line_file_atomic("/etc/timezone", tz.zone);
- if (r < 0)
- return r;
+ if (stat("/etc/timezone", &st) == 0 && S_ISREG(st.st_mode)) {
+ r = write_one_line_file_atomic("/etc/timezone", tz.zone);
+ if (r < 0)
+ return r;
+ }