[systemd-devel] [PATCH 2/2] timedated: gather timezone from /etc/localtime sym target
Shawn Landen
shawnlandden at gmail.com
Thu Aug 9 16:16:40 PDT 2012
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"
---
src/timedate/timedated.c | 56 ++++++++++++++++++++++++++++++++++++++--------
1 file changed, 47 insertions(+), 9 deletions(-)
diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c
index 09fd808..b21d930 100644
--- a/src/timedate/timedated.c
+++ b/src/timedate/timedated.c
@@ -24,6 +24,7 @@
#include <errno.h>
#include <string.h>
#include <unistd.h>
+#include <sys/stat.h>
#include "util.h"
#include "strv.h"
@@ -74,6 +75,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 {
@@ -151,13 +155,16 @@ static void verify_timezone(void) {
if (!tz.zone)
return;
- p = strappend("/usr/share/zoneinfo/", tz.zone);
- if (!p) {
- log_oom();
+ j = read_full_file("/etc/localtime", &a, &l);
+
+ /* allow /etc/localtime to not exist */
+ if (j == -ENOENT)
return;
- }
- j = read_full_file("/etc/localtime", &a, &l);
+ p = strappend("/usr/share/zoneinfo/", tz.zone);
+ if (!p)
+ return (void)log_oom();
+
k = read_full_file(p, &b, &q);
free(p);
@@ -174,9 +181,36 @@ static void verify_timezone(void) {
static int read_data(void) {
int r;
+ char *t;
+ /* we only support the trivial relative link of ..$ABSOLUTE */
+ bool relative_link = false;
free_data();
+ r = readlink_malloc("/etc/localtime", &t);
+ if (r < 0) {
+ if (errno == EINVAL)
+ log_warning("/etc/localtime should be a symbolic link to a timezone data file in %s", ZONEINFO_PATH);
+ else
+ log_warning("Failed to get target of %s: %m", "/etc/localtime");
+ } else if (!startswith(t, ZONEINFO_PATH) && !(startswith(t, "..") && startswith(t + strlen(".."), ZONEINFO_PATH)))
+ log_warning("/etc/localtime should be a symbolic link to a timezone data file in %s", ZONEINFO_PATH);
+ else {
+ if (startswith(t, ".."))
+ relative_link = true;
+
+ tz.zone = strdup(t + (relative_link ? strlen("..") : 0) + strlen(ZONEINFO_PATH));
+ if (!tz.zone) {
+ free(t);
+ return log_oom();
+ }
+
+ free(t);
+ goto have_timezone;
+ }
+
+ free(t);
+
r = read_one_line_file("/etc/timezone", &tz.zone);
if (r < 0) {
if (r != -ENOENT)
@@ -192,6 +226,7 @@ static int read_data(void) {
#endif
}
+have_timezone:
if (isempty(tz.zone)) {
free(tz.zone);
tz.zone = NULL;
@@ -207,6 +242,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)
@@ -222,15 +258,17 @@ static int write_data_timezone(void) {
if (!p)
return log_oom();
- r = symlink_or_copy_atomic(p, "/etc/localtime");
+ r = symlink_atomic(p, "/etc/localtime");
free(p);
if (r < 0)
return r;
- 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;
}
--
1.7.10.4
More information about the systemd-devel
mailing list