diff --git a/drop-timezone.patch b/drop-timezone.patch new file mode 100644 index 0000000..0229807 --- /dev/null +++ b/drop-timezone.patch @@ -0,0 +1,48 @@ +Index: systemd-44/src/timedate/timedated.c +=================================================================== +--- systemd-44.orig/src/timedate/timedated.c ++++ systemd-44/src/timedate/timedated.c +@@ -203,24 +203,18 @@ static int read_data(void) { + + free(t); + +- r = read_one_line_file("/etc/timezone", &tz.zone); +- if (r < 0) { +- if (r != -ENOENT) +- log_warning("Failed to read /etc/timezone: %s", strerror(-r)); +- + #if defined(TARGET_FEDORA) || defined(TARGET_SUSE) +- r = parse_env_file("/etc/sysconfig/clock", NEWLINE, ++ r = parse_env_file("/etc/sysconfig/clock", NEWLINE, + #ifdef TARGET_FEDORA +- "ZONE", &tz.zone, ++ "ZONE", &tz.zone, + #else /* TARGET_SUSE */ +- "TIMEZONE", &tz.zone, ++ "TIMEZONE", &tz.zone, + #endif +- NULL); ++ NULL); + +- if (r < 0 && r != -ENOENT) +- log_warning("Failed to read /etc/sysconfig/clock: %s", strerror(-r)); ++ if (r < 0 && r != -ENOENT) ++ log_warning("Failed to read /etc/sysconfig/clock: %s", strerror(-r)); + #endif +- } + + have_timezone: + if (isempty(tz.zone)) { +@@ -263,12 +257,6 @@ static int write_data_timezone(void) { + if (r < 0) + return -errno; + +- 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; + } + diff --git a/fix-enable-disable-boot-initscript.patch b/fix-enable-disable-boot-initscript.patch new file mode 100644 index 0000000..1f4fe5c --- /dev/null +++ b/fix-enable-disable-boot-initscript.patch @@ -0,0 +1,44 @@ +From f9d333f8d202fd853f2553ee6c3196b041ccfba5 Mon Sep 17 00:00:00 2001 +From: Frederic Crozat +Date: Thu, 23 Aug 2012 11:08:25 +0200 +Subject: [PATCH] fix support for boot prefixed initscript (bnc#746506) + +--- + src/systemctl.c | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/src/systemctl.c b/src/systemctl.c +index e94e024..1a98599 100644 +--- a/src/systemctl.c ++++ b/src/systemctl.c +@@ -3669,7 +3669,27 @@ static int enable_sysv_units(char **args) { + + if (!found_sysv) { + free(p); ++#if defined(TARGET_SUSE) ++ p = NULL; ++ if (!isempty(arg_root)) ++ asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/boot.%s", arg_root, name); ++ else ++ asprintf(&p, SYSTEM_SYSVINIT_PATH "/boot.%s", name); ++ if (!p) { ++ log_error("No memory"); ++ r = -ENOMEM; ++ goto finish; ++ } ++ p[strlen(p) - sizeof(".service") + 1] = 0; ++ found_sysv = access(p, F_OK) >= 0; ++ ++ if (!found_sysv) { ++ free(p); ++ continue; ++ } ++#else + continue; ++#endif + } + + /* Mark this entry, so that we don't try enabling it as native unit */ +-- +1.7.10.4 + diff --git a/journalctl-pager-improvement.patch b/journalctl-pager-improvement.patch new file mode 100644 index 0000000..81be11e --- /dev/null +++ b/journalctl-pager-improvement.patch @@ -0,0 +1,448 @@ +From 1682c4bf5b993b956b0367aedc9f0638055540f4 Mon Sep 17 00:00:00 2001 +From: Eelco Dolstra +Date: Thu, 19 Jul 2012 21:12:16 +0000 +Subject: [PATCH 1/3] journalctl: fix assertion failure in ellipsize_mem() + +When showing the journal through "journalctl --no-pager", if the +prefix of the log message (i.e. the date and syslog identifier) is +less than 3 characters shorter than the width of the terminal, you +get: + +Assertion 'new_length >= 3' failed at src/shared/util.c:3859, function ellipsize_mem(). Aborting. + +because there is not enough space for the "...". This patch add the +necessary check. +--- + src/logs-show.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/logs-show.c b/src/logs-show.c +index eb9a902..72367f2 100644 +--- a/src/logs-show.c ++++ b/src/logs-show.c +@@ -230,7 +230,7 @@ static int output_short(sd_journal *j, unsigned line, unsigned n_columns, bool s + printf(": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len)); + } else if (message_len + n < n_columns) + printf(": %.*s\n", (int) message_len, message); +- else if (n < n_columns) { ++ else if (n < n_columns && n_columns - n - 2 >= 3) { + char *e; + + e = ellipsize_mem(message, message_len, n_columns - n - 2, 90); +-- +1.7.10.4 + + +From ee385756e10862a8bcc0e5c7a3776135af84c750 Mon Sep 17 00:00:00 2001 +From: Zbigniew Jedrzejewski-Szmek +Date: Fri, 20 Jul 2012 09:06:26 +0200 +Subject: [PATCH 2/3] journalctl: fix ellipsization with PAGER=cat + +There are other reasons for not opening the pager then the --no-pager +or --follow options (described below). If the pager is not used, +messages must be ellipsized. + +On Fri, Jul 20, 2012 at 05:42:44AM +0000, Shawn Landen wrote: +> "Pager to use when --no-pager is not given; overrides $PAGER. +> Setting this to an empty string or the value cat is equivalent to passing --no-pager." + +Conflicts: + src/journal/journalctl.c +--- + src/journal/journalctl.c | 5 +---- + src/pager.c | 17 ++++++++++------- + src/pager.h | 4 +++- + 3 files changed, 14 insertions(+), 12 deletions(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index f90b2dd..3a3b043 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -259,10 +259,7 @@ int main(int argc, char *argv[]) { + goto finish; + } + +- if (!arg_no_pager && !arg_follow) { +- columns(); +- pager_open(); +- } ++ have_pager = !arg_no_pager && !arg_follow && pager_open(); + + if (arg_output == OUTPUT_JSON) { + fputc('[', stdout); +diff --git a/src/pager.c b/src/pager.c +index 3fc8182..8065841 100644 +--- a/src/pager.c ++++ b/src/pager.c +@@ -44,20 +44,20 @@ _noreturn_ static void pager_fallback(void) { + _exit(EXIT_SUCCESS); + } + +-void pager_open(void) { ++bool pager_open(void) { + int fd[2]; + const char *pager; + pid_t parent_pid; + + if (pager_pid > 0) +- return; ++ return false; + + if ((pager = getenv("SYSTEMD_PAGER")) || (pager = getenv("PAGER"))) + if (!*pager || streq(pager, "cat")) +- return; ++ return false; + + if (isatty(STDOUT_FILENO) <= 0) +- return; ++ return false; + + /* Determine and cache number of columns before we spawn the + * pager so that we get the value from the actual tty */ +@@ -65,7 +65,7 @@ void pager_open(void) { + + if (pipe(fd) < 0) { + log_error("Failed to create pager pipe: %m"); +- return; ++ return false; + } + + parent_pid = getpid(); +@@ -74,7 +74,7 @@ void pager_open(void) { + if (pager_pid < 0) { + log_error("Failed to fork pager: %m"); + close_pipe(fd); +- return; ++ return false; + } + + /* In the child start the pager */ +@@ -115,10 +115,13 @@ void pager_open(void) { + } + + /* Return in the parent */ +- if (dup2(fd[1], STDOUT_FILENO) < 0) ++ if (dup2(fd[1], STDOUT_FILENO) < 0) { + log_error("Failed to duplicate pager pipe: %m"); ++ return false; ++ } + + close_pipe(fd); ++ return true; + } + + void pager_close(void) { +diff --git a/src/pager.h b/src/pager.h +index b5b4998..bd1a983 100644 +--- a/src/pager.h ++++ b/src/pager.h +@@ -22,7 +22,9 @@ + along with systemd; If not, see . + ***/ + +-void pager_open(void); ++#include ++ ++bool pager_open(void); + void pager_close(void); + + #endif +-- +1.7.10.4 + + +From ae88e07aec6280e90582703f7950468604182a4b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 17 Jul 2012 07:35:08 +0200 +Subject: [PATCH 3/3] journalctl: do not ellipsize when using pager +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If a pager is used, ellipsization is redundant — the pager does +that better by hiding the part that cannot be shown. Pager's advantage +is that the user can press → to view the hidden part of a message, +and then ← to return. + +cherry-picked from 92a1fd9e95954a557d6fe27b56f5ef1b89fc2f5e and 25277cd7fbd77e4c8b20572570aa77c7da9abcc2 +--- + src/journal/journalctl.c | 7 ++++- + src/logs-show.c | 66 ++++++++++++++++++++++++++++------------------ + src/logs-show.h | 14 +++++++--- + src/systemctl.c | 8 +++++- + 4 files changed, 64 insertions(+), 31 deletions(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 3a3b043..197af71 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -198,6 +198,7 @@ int main(int argc, char *argv[]) { + sd_journal *j = NULL; + unsigned line = 0; + bool need_seek = false; ++ bool have_pager; + + log_parse_environment(); + log_open(); +@@ -268,6 +269,10 @@ int main(int argc, char *argv[]) { + + for (;;) { + for (;;) { ++ int flags = ++ arg_show_all * OUTPUT_SHOW_ALL | ++ have_pager * OUTPUT_FULL_WIDTH; ++ + if (need_seek) { + r = sd_journal_next(j); + if (r < 0) { +@@ -281,7 +286,7 @@ int main(int argc, char *argv[]) { + + line ++; + +- r = output_journal(j, arg_output, line, 0, arg_show_all); ++ r = output_journal(j, arg_output, line, 0, flags); + if (r < 0) + goto finish; + +diff --git a/src/logs-show.c b/src/logs-show.c +index 72367f2..06ba569 100644 +--- a/src/logs-show.c ++++ b/src/logs-show.c +@@ -86,7 +86,8 @@ static bool shall_print(bool show_all, char *p, size_t l) { + return true; + } + +-static int output_short(sd_journal *j, unsigned line, unsigned n_columns, bool show_all, bool monotonic_mode) { ++static int output_short(sd_journal *j, unsigned line, unsigned n_columns, ++ OutputFlags flags) { + int r; + const void *data; + size_t length; +@@ -150,7 +151,7 @@ static int output_short(sd_journal *j, unsigned line, unsigned n_columns, bool s + goto finish; + } + +- if (monotonic_mode) { ++ if (flags & OUTPUT_MONOTONIC_MODE) { + uint64_t t; + sd_id128_t boot_id; + +@@ -202,33 +203,39 @@ static int output_short(sd_journal *j, unsigned line, unsigned n_columns, bool s + n += strlen(buf); + } + +- if (hostname && shall_print(show_all, hostname, hostname_len)) { ++ if (hostname && shall_print(flags & OUTPUT_SHOW_ALL, ++ hostname, hostname_len)) { + printf(" %.*s", (int) hostname_len, hostname); + n += hostname_len + 1; + } + +- if (identifier && shall_print(show_all, identifier, identifier_len)) { ++ if (identifier && shall_print(flags & OUTPUT_SHOW_ALL, ++ identifier, identifier_len)) { + printf(" %.*s", (int) identifier_len, identifier); + n += identifier_len + 1; +- } else if (comm && shall_print(show_all, comm, comm_len)) { ++ } else if (comm && shall_print(flags & OUTPUT_SHOW_ALL, ++ comm, comm_len)) { + printf(" %.*s", (int) comm_len, comm); + n += comm_len + 1; +- } ++ } else ++ putchar(' '); + +- if (pid && shall_print(show_all, pid, pid_len)) { ++ if (pid && shall_print(flags & OUTPUT_SHOW_ALL, pid, pid_len)) { + printf("[%.*s]", (int) pid_len, pid); + n += pid_len + 2; +- } else if (fake_pid && shall_print(show_all, fake_pid, fake_pid_len)) { ++ } else if (fake_pid && shall_print(flags & OUTPUT_SHOW_ALL, ++ fake_pid, fake_pid_len)) { + printf("[%.*s]", (int) fake_pid_len, fake_pid); + n += fake_pid_len + 2; + } + +- if (show_all) ++ if (flags & OUTPUT_SHOW_ALL) + printf(": %.*s\n", (int) message_len, message); + else if (contains_unprintable(message, message_len)) { + char bytes[FORMAT_BYTES_MAX]; + printf(": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len)); +- } else if (message_len + n < n_columns) ++ } else if ((flags & OUTPUT_FULL_WIDTH) || ++ (message_len + n + 1 < n_columns)) + printf(": %.*s\n", (int) message_len, message); + else if (n < n_columns && n_columns - n - 2 >= 3) { + char *e; +@@ -259,15 +266,18 @@ finish: + return r; + } + +-static int output_short_realtime(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) { +- return output_short(j, line, n_columns, show_all, false); ++static int output_short_realtime(sd_journal *j, unsigned line, ++ unsigned n_columns, OutputFlags flags) { ++ return output_short(j, line, n_columns, flags & ~OUTPUT_MONOTONIC_MODE); + } + +-static int output_short_monotonic(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) { +- return output_short(j, line, n_columns, show_all, true); ++static int output_short_monotonic(sd_journal *j, unsigned line, ++ unsigned n_columns, OutputFlags flags) { ++ return output_short(j, line, n_columns, flags | OUTPUT_MONOTONIC_MODE); + } + +-static int output_verbose(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) { ++static int output_verbose(sd_journal *j, unsigned line, ++ unsigned n_columns, OutputFlags flags) { + const void *data; + size_t length; + char *cursor; +@@ -296,7 +306,7 @@ static int output_verbose(sd_journal *j, unsigned line, unsigned n_columns, bool + free(cursor); + + SD_JOURNAL_FOREACH_DATA(j, data, length) { +- if (!show_all && (length > PRINT_THRESHOLD || ++ if (!(flags & OUTPUT_SHOW_ALL) && (length > PRINT_THRESHOLD || + contains_unprintable(data, length))) { + const char *c; + char bytes[FORMAT_BYTES_MAX]; +@@ -318,7 +328,8 @@ static int output_verbose(sd_journal *j, unsigned line, unsigned n_columns, bool + return 0; + } + +-static int output_export(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) { ++static int output_export(sd_journal *j, unsigned line, ++ unsigned n_columns, OutputFlags flags) { + sd_id128_t boot_id; + char sid[33]; + int r; +@@ -424,7 +435,8 @@ static void json_escape(const char* p, size_t l) { + } + } + +-static int output_json(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) { ++static int output_json(sd_journal *j, unsigned line, ++ unsigned n_columns, OutputFlags flags) { + uint64_t realtime, monotonic; + char *cursor; + const void *data; +@@ -491,7 +503,8 @@ static int output_json(sd_journal *j, unsigned line, unsigned n_columns, bool sh + return 0; + } + +-static int output_cat(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) { ++static int output_cat(sd_journal *j, unsigned line, ++ unsigned n_columns, OutputFlags flags) { + const void *data; + size_t l; + int r; +@@ -512,7 +525,8 @@ static int output_cat(sd_journal *j, unsigned line, unsigned n_columns, bool sho + return 0; + } + +-static int (*output_funcs[_OUTPUT_MODE_MAX])(sd_journal*j, unsigned line, unsigned n_columns, bool show_all) = { ++static int (*output_funcs[_OUTPUT_MODE_MAX])(sd_journal*j, unsigned line, ++ unsigned n_columns, OutputFlags flags) = { + [OUTPUT_SHORT] = output_short_realtime, + [OUTPUT_SHORT_MONOTONIC] = output_short_monotonic, + [OUTPUT_VERBOSE] = output_verbose, +@@ -521,14 +535,15 @@ static int (*output_funcs[_OUTPUT_MODE_MAX])(sd_journal*j, unsigned line, unsign + [OUTPUT_CAT] = output_cat + }; + +-int output_journal(sd_journal *j, OutputMode mode, unsigned line, unsigned n_columns, bool show_all) { ++int output_journal(sd_journal *j, OutputMode mode, unsigned line, ++ unsigned n_columns, OutputFlags flags) { + assert(mode >= 0); + assert(mode < _OUTPUT_MODE_MAX); + + if (n_columns <= 0) + n_columns = columns(); + +- return output_funcs[mode](j, line, n_columns, show_all); ++ return output_funcs[mode](j, line, n_columns, flags); + } + + int show_journal_by_unit( +@@ -537,8 +552,7 @@ int show_journal_by_unit( + unsigned n_columns, + usec_t not_before, + unsigned how_many, +- bool show_all, +- bool follow) { ++ OutputFlags flags) { + + char *m = NULL; + sd_journal *j = NULL; +@@ -621,12 +635,12 @@ int show_journal_by_unit( + + line ++; + +- r = output_journal(j, mode, line, n_columns, show_all); ++ r = output_journal(j, mode, line, n_columns, flags); + if (r < 0) + goto finish; + } + +- if (!follow) ++ if (!(flags & OUTPUT_FOLLOW)) + break; + + r = fd_wait_for_event(fd, POLLIN, (usec_t) -1); +diff --git a/src/logs-show.h b/src/logs-show.h +index db9c7e3..e8c6b03 100644 +--- a/src/logs-show.h ++++ b/src/logs-show.h +@@ -39,7 +39,16 @@ typedef enum OutputMode { + _OUTPUT_MODE_INVALID = -1 + } OutputMode; + +-int output_journal(sd_journal *j, OutputMode mode, unsigned line, unsigned n_columns, bool show_all); ++typedef enum OutputFlags { ++ OUTPUT_SHOW_ALL = 1 << 0, ++ OUTPUT_MONOTONIC_MODE = 1 << 1, ++ OUTPUT_FOLLOW = 1 << 2, ++ OUTPUT_WARN_CUTOFF = 1 << 3, ++ OUTPUT_FULL_WIDTH = 1 << 4, ++} OutputFlags; ++ ++int output_journal(sd_journal *j, OutputMode mode, unsigned line, ++ unsigned n_columns, OutputFlags flags); + + int show_journal_by_unit( + const char *unit, +@@ -47,8 +56,7 @@ int show_journal_by_unit( + unsigned n_columns, + usec_t not_before, + unsigned how_many, +- bool show_all, +- bool follow); ++ OutputFlags flags); + + const char* output_mode_to_string(OutputMode m); + OutputMode output_mode_from_string(const char *s); +diff --git a/src/systemctl.c b/src/systemctl.c +index f51085f..e94e024 100644 +--- a/src/systemctl.c ++++ b/src/systemctl.c +@@ -2374,8 +2374,14 @@ static void print_status_info(UnitStatusInfo *i) { + } + + if (i->id && arg_transport != TRANSPORT_SSH) { ++ int flags = ++ arg_lines * OUTPUT_SHOW_ALL | ++ arg_follow * OUTPUT_FOLLOW; ++ + printf("\n"); +- show_journal_by_unit(i->id, arg_output, 0, i->inactive_exit_timestamp_monotonic, arg_lines, arg_all, arg_follow); ++ show_journal_by_unit(i->id, arg_output, 0, ++ i->inactive_exit_timestamp_monotonic, ++ arg_lines, flags); + } + + if (i->need_daemon_reload) +-- +1.7.10.4 + diff --git a/support-suse-clock-sysconfig.patch b/support-suse-clock-sysconfig.patch new file mode 100644 index 0000000..de3992a --- /dev/null +++ b/support-suse-clock-sysconfig.patch @@ -0,0 +1,32 @@ +From 64ddc0bfa995041196fd0b9c61756d64578f925c Mon Sep 17 00:00:00 2001 +From: Frederic Crozat +Date: Tue, 14 Aug 2012 14:26:16 +0200 +Subject: [PATCH] timedate: add support for openSUSE version of + /etc/sysconfig/clock + +--- + src/timedate/timedated.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c +index 6a7d980..fbebc1d 100644 +--- a/src/timedate/timedated.c ++++ b/src/timedate/timedated.c +@@ -180,9 +180,13 @@ static int read_data(void) { + if (r != -ENOENT) + log_warning("Failed to read /etc/timezone: %s", strerror(-r)); + +-#ifdef TARGET_FEDORA ++#if defined(TARGET_FEDORA) || defined(TARGET_SUSE) + r = parse_env_file("/etc/sysconfig/clock", NEWLINE, ++#ifdef TARGET_FEDORA + "ZONE", &tz.zone, ++#else /* TARGET_SUSE */ ++ "TIMEZONE", &tz.zone, ++#endif + NULL); + + if (r < 0 && r != -ENOENT) +-- +1.7.10.4 + diff --git a/systemd.changes b/systemd.changes index 4cff8ff..7b07e1c 100644 --- a/systemd.changes +++ b/systemd.changes @@ -1,3 +1,17 @@ +------------------------------------------------------------------- +Thu Aug 23 11:11:25 CEST 2012 - fcrozat@suse.com + +- Add use_localtime.patch: use /etc/localtime instead of + /etc/timezone (bnc#773491) +- Add support-suse-clock-sysconfig.patch: read SUSE + /etc/sysconfig/clock file. +- Add drop-timezone.patch: drop support for /etc/timezone, never + supported on openSUSE. +- Add journalctl-pager-improvement.patch: better handle output when + using pager. +- Add fix-enable-disable-boot-initscript.patch: support boot.* + initscripts for systemctl enable /disable (bnc#746506). + ------------------------------------------------------------------- Mon Jul 30 11:37:17 UTC 2012 - fcrozat@suse.com diff --git a/systemd.spec b/systemd.spec index f593331..90324d8 100644 --- a/systemd.spec +++ b/systemd.spec @@ -81,6 +81,9 @@ Patch36: sysctl-modules.patch Patch38: dm-lvm-after-local-fs-pre-target.patch Patch41: 0001-add-sparse-support-to-detect-endianness-bug.patch Patch53: fastboot-forcefsck.patch +Patch56: support-suse-clock-sysconfig.patch +Patch57: drop-timezone.patch +Patch59: fix-enable-disable-boot-initscript.patch # Upstream First - Policy: # Never add any patches to this package without the upstream commit id @@ -99,6 +102,8 @@ Patch50: change-terminal.patch Patch51: fix-tty-startup.patch Patch52: fix-write-user-state-file.patch Patch54: fix-analyze-exception.patch +Patch55: use_localtime.patch +Patch58: journalctl-pager-improvement.patch %description Systemd is a system and service manager, compatible with SysV and LSB @@ -179,6 +184,11 @@ at boot. %patch52 -p1 %patch53 -p1 %patch54 -p1 +%patch55 -p1 +%patch56 -p1 +%patch57 -p1 +%patch58 -p1 +%patch59 -p1 #needed by patch49 rm man/systemd.conf.5 diff --git a/use_localtime.patch b/use_localtime.patch new file mode 100644 index 0000000..f078561 --- /dev/null +++ b/use_localtime.patch @@ -0,0 +1,397 @@ +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; + }