unlike symlink_or_copy_atomic(), this function creates a symlink even if the
oldname and newname (from and to) are on differn't devices. (stat.st_dev)
---
src/shared/util.c | 19 +++++++++++++++++--
src/shared/util.h | 1 +
2 files changed, 18 insertions(+), 2 deletions(-)
Index: systemd-44/src/util.c
===================================================================
--- systemd-44.orig/src/util.c
+++ systemd-44/src/util.c
@@ -5352,7 +5352,7 @@ finish:
return r;
}
-int symlink_or_copy_atomic(const char *from, const char *to) {
+static int symlink_atomic_raw(const char *from, const char *to, bool allow_copy) {
char *t, *x;
const char *fn;
size_t k;
@@ -5381,7 +5381,14 @@ int symlink_or_copy_atomic(const char *f
*x = 0;
- r = symlink_or_copy(from, t);
+ if (allow_copy)
+ r = symlink_or_copy(from, t);
+ else {
+ r = symlink(from, t);
+ if (r < 0)
+ r = -errno;
+ }
+
if (r < 0) {
unlink(t);
free(t);
@@ -5482,6 +5489,14 @@ int audit_loginuid_from_pid(pid_t pid, u
return 0;
}
+int symlink_or_copy_atomic(const char *from, const char *to) {
+ return symlink_atomic_raw(from, to, true);
+}
+
+int symlink_atomic(const char *from, const char *to) {
+ return symlink_atomic_raw(from, to, false);
+}
+
bool display_is_local(const char *display) {
assert(display);
Index: systemd-44/src/util.h
===================================================================
--- systemd-44.orig/src/util.h
+++ systemd-44/src/util.h
@@ -448,6 +448,7 @@ int vt_disallocate(const char *name);
int copy_file(const char *from, const char *to);
int symlink_or_copy(const char *from, const char *to);
int symlink_or_copy_atomic(const char *from, const char *to);
+int symlink_atomic(const char *from, const char *to);
int fchmod_umask(int fd, mode_t mode);
Index: systemd-44/Makefile.am
===================================================================
--- systemd-44.orig/Makefile.am
+++ systemd-44/Makefile.am
@@ -690,7 +690,7 @@ MANPAGES = \
man/systemd.conf.5 \
man/tmpfiles.d.5 \
man/hostname.5 \
- man/timezone.5 \
+ man/localtime.5 \
man/machine-id.5 \
man/locale.conf.5 \
man/os-release.5 \
Index: systemd-44/man/timezone.xml
===================================================================
--- systemd-44.orig/man/timezone.xml
+++ /dev/null
@@ -1,90 +0,0 @@
-
-
-
-
-
-
-
-
- /etc/timezone
- systemd
-
-
-
- Developer
- Lennart
- Poettering
- lennart@poettering.net
-
-
-
-
-
- timezone
- 5
-
-
-
- timezone
- Local time zone configuration file
-
-
-
- /etc/timezone
-
-
-
- Description
-
- The /etc/timezone file
- configures the system-wide time zone of the local
- system that is used by applications for presentation
- to the user. It should contain a single
- newline-terminated line consisting of a time zone
- identifier such as
- Europe/Berlin. The file
- /etc/localtime corresponds with
- /etc/timezone and contains the
- binary time zone data for the time zone. These files
- should always be changed simultaneously and kept in
- sync.
-
- The time zone may be overridden for individual
- programs by using the TZ environment variable. See
- environ7.
-
-
-
- History
-
- The simple configuration file format of
- /etc/timezone originates from
- Debian GNU/Linux.
-
-
-
- See Also
-
- systemd1
-
-
-
-
Index: systemd-44/man/localtime.xml
===================================================================
--- /dev/null
+++ systemd-44/man/localtime.xml
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+ /etc/localtime
+ systemd
+
+
+
+ Developer
+ Lennart
+ Poettering
+ lennart@poettering.net
+
+
+ Developer
+ Shawn
+ Landden
+ shawnlandden@gmail.com
+
+
+
+
+
+ localtime
+ 5
+
+
+
+ localtime
+ Local time zone configuration file
+
+
+
+ /etc/localtime -> /usr/share/zoneinfo/…
+
+
+
+ Description
+
+ The /etc/localtime file
+ configures the system-wide time zone of the local
+ system that is used by applications for presentation
+ to the user. It should be an absolute symbolic link
+ with a destination of /usr/share/zoneinfo/,
+ fallowed by a time zone identifier such as
+ Europe/Berlin or Etc/UTC.
+ The resulting link should point to the corresponding binary
+ tzfile5
+ time zone data for the configured time zone.
+
+ As the time zone identifier is extracted from the name of
+ the target of /etc/localtime this file may
+ not be a normal file or hardlink.
+
+ The time zone may be overridden for individual
+ programs by using the TZ environment variable. See
+ environ7.
+
+
+
+ See Also
+
+ tzset3
+ localtime3
+ systemd1
+
+
+
+
Index: systemd-44/src/timedate/timedated.c
===================================================================
--- systemd-44.orig/src/timedate/timedated.c
+++ systemd-44/src/timedate/timedated.c
@@ -72,6 +72,9 @@
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 {
@@ -125,7 +128,7 @@ static bool valid_timezone(const char *n
if (slash)
return false;
- t = strappend("/usr/share/zoneinfo/", name);
+ t = strappend(ZONEINFO_PATH, name);
if (!t)
return false;
@@ -149,17 +152,17 @@ static void verify_timezone(void) {
if (!tz.zone)
return;
- p = strappend("/usr/share/zoneinfo/", tz.zone);
+ p = strappend(ZONEINFO_PATH, tz.zone);
if (!p) {
log_error("Out of memory");
return;
}
- j = read_full_file("/etc/localtime", &a, &l);
k = read_full_file(p, &b, &q);
-
free(p);
+ 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);
@@ -172,9 +175,36 @@ static void verify_timezone(void) {
static int read_data(void) {
int r;
+ char *t = NULL;
free_data();
+ 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) {
+ log_error("Out of memory");
+ return -ENOMEM;
+ }
+
+ goto have_timezone;
+ }
+ }
+
+ free(t);
+
r = read_one_line_file("/etc/timezone", &tz.zone);
if (r < 0) {
if (r != -ENOENT)
@@ -190,6 +220,7 @@ static int read_data(void) {
#endif
}
+have_timezone:
if (isempty(tz.zone)) {
free(tz.zone);
tz.zone = NULL;
@@ -205,6 +236,7 @@ static int read_data(void) {
static int write_data_timezone(void) {
int r = 0;
char *p;
+ struct stat st;
if (!tz.zone) {
if (unlink("/etc/timezone") < 0 && errno != ENOENT)
@@ -216,21 +248,24 @@ static int write_data_timezone(void) {
return r;
}
- p = strappend("/usr/share/zoneinfo/", tz.zone);
+ p = strappend(ZONEINFO_PATH, tz.zone);
if (!p) {
log_error("Out of memory");
return -ENOMEM;
}
- r = symlink_or_copy_atomic(p, "/etc/localtime");
+ r = symlink_atomic(p, "/etc/localtime");
+
free(p);
if (r < 0)
- return r;
+ return -errno;
- 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;
+ }
return 0;
}