timedate: assorted improvements
- Make writing/reading of /etc/timezone dependendent of HAVE_SYSV_COMPAT - Introduce symlink_atomic() after all, and use it - Use relative symlink for /etc/localtime
This commit is contained in:
parent
608da9e9b5
commit
424a19f8a2
4
TODO
4
TODO
|
@ -53,6 +53,10 @@ Bugfixes:
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
|
|
||||||
|
* hw watchdog: optionally try to use the preset watchdog timeout instead of always overriding it
|
||||||
|
|
||||||
|
* after deserializing sockets in socket.c we should reapply sockopts and things
|
||||||
|
|
||||||
* journald: warn if we drop messages we forward to the syslog socket
|
* journald: warn if we drop messages we forward to the syslog socket
|
||||||
|
|
||||||
* does vasprintf advance the struct vaargs? http://pastie.org/pastes/4712773/text
|
* does vasprintf advance the struct vaargs? http://pastie.org/pastes/4712773/text
|
||||||
|
|
|
@ -264,12 +264,12 @@ char *path_kill_slashes(char *path) {
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool path_startswith(const char *path, const char *prefix) {
|
char* path_startswith(const char *path, const char *prefix) {
|
||||||
assert(path);
|
assert(path);
|
||||||
assert(prefix);
|
assert(prefix);
|
||||||
|
|
||||||
if ((path[0] == '/') != (prefix[0] == '/'))
|
if ((path[0] == '/') != (prefix[0] == '/'))
|
||||||
return false;
|
return NULL;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
size_t a, b;
|
size_t a, b;
|
||||||
|
@ -278,19 +278,19 @@ bool path_startswith(const char *path, const char *prefix) {
|
||||||
prefix += strspn(prefix, "/");
|
prefix += strspn(prefix, "/");
|
||||||
|
|
||||||
if (*prefix == 0)
|
if (*prefix == 0)
|
||||||
return true;
|
return (char*) path;
|
||||||
|
|
||||||
if (*path == 0)
|
if (*path == 0)
|
||||||
return false;
|
return NULL;
|
||||||
|
|
||||||
a = strcspn(path, "/");
|
a = strcspn(path, "/");
|
||||||
b = strcspn(prefix, "/");
|
b = strcspn(prefix, "/");
|
||||||
|
|
||||||
if (a != b)
|
if (a != b)
|
||||||
return false;
|
return NULL;
|
||||||
|
|
||||||
if (memcmp(path, prefix, a) != 0)
|
if (memcmp(path, prefix, a) != 0)
|
||||||
return false;
|
return NULL;
|
||||||
|
|
||||||
path += a;
|
path += a;
|
||||||
prefix += b;
|
prefix += b;
|
||||||
|
|
|
@ -32,7 +32,7 @@ bool path_is_absolute(const char *p);
|
||||||
char *path_make_absolute(const char *p, const char *prefix);
|
char *path_make_absolute(const char *p, const char *prefix);
|
||||||
char *path_make_absolute_cwd(const char *p);
|
char *path_make_absolute_cwd(const char *p);
|
||||||
char *path_kill_slashes(char *path);
|
char *path_kill_slashes(char *path);
|
||||||
bool path_startswith(const char *path, const char *prefix);
|
char *path_startswith(const char *path, const char *prefix);
|
||||||
bool path_equal(const char *a, const char *b);
|
bool path_equal(const char *a, const char *b);
|
||||||
|
|
||||||
char **path_strv_make_absolute_cwd(char **l);
|
char **path_strv_make_absolute_cwd(char **l);
|
||||||
|
|
|
@ -4644,49 +4644,9 @@ int copy_file(const char *from, const char *to) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int symlink_or_copy(const char *from, const char *to) {
|
int symlink_atomic(const char *from, const char *to) {
|
||||||
char *pf = NULL, *pt = NULL;
|
char *x;
|
||||||
struct stat a, b;
|
_cleanup_free_ char *t;
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(from);
|
|
||||||
assert(to);
|
|
||||||
|
|
||||||
if (path_get_parent(from, &pf) < 0 ||
|
|
||||||
path_get_parent(to, &pt) < 0) {
|
|
||||||
r = -ENOMEM;
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stat(pf, &a) < 0 ||
|
|
||||||
stat(pt, &b) < 0) {
|
|
||||||
r = -errno;
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a.st_dev != b.st_dev) {
|
|
||||||
free(pf);
|
|
||||||
free(pt);
|
|
||||||
|
|
||||||
return copy_file(from, to);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (symlink(from, to) < 0) {
|
|
||||||
r = -errno;
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = 0;
|
|
||||||
|
|
||||||
finish:
|
|
||||||
free(pf);
|
|
||||||
free(pt);
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
int symlink_or_copy_atomic(const char *from, const char *to) {
|
|
||||||
char *t, *x;
|
|
||||||
const char *fn;
|
const char *fn;
|
||||||
size_t k;
|
size_t k;
|
||||||
unsigned long long ull;
|
unsigned long long ull;
|
||||||
|
@ -4714,22 +4674,16 @@ int symlink_or_copy_atomic(const char *from, const char *to) {
|
||||||
|
|
||||||
*x = 0;
|
*x = 0;
|
||||||
|
|
||||||
r = symlink_or_copy(from, t);
|
if (symlink(from, t) < 0)
|
||||||
if (r < 0) {
|
return -errno;
|
||||||
unlink(t);
|
|
||||||
free(t);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rename(t, to) < 0) {
|
if (rename(t, to) < 0) {
|
||||||
r = -errno;
|
r = -errno;
|
||||||
unlink(t);
|
unlink(t);
|
||||||
free(t);
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(t);
|
return 0;
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool display_is_local(const char *display) {
|
bool display_is_local(const char *display) {
|
||||||
|
|
|
@ -430,8 +430,8 @@ int terminal_vhangup(const char *name);
|
||||||
int vt_disallocate(const char *name);
|
int vt_disallocate(const char *name);
|
||||||
|
|
||||||
int copy_file(const char *from, const char *to);
|
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);
|
int fchmod_umask(int fd, mode_t mode);
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "def.h"
|
#include "def.h"
|
||||||
#include "hwclock.h"
|
#include "hwclock.h"
|
||||||
#include "conf-files.h"
|
#include "conf-files.h"
|
||||||
|
#include "path-util.h"
|
||||||
|
|
||||||
#define NULL_ADJTIME_UTC "0.0 0 0\n0\nUTC\n"
|
#define NULL_ADJTIME_UTC "0.0 0 0\n0\nUTC\n"
|
||||||
#define NULL_ADJTIME_LOCAL "0.0 0 0\n0\nLOCAL\n"
|
#define NULL_ADJTIME_LOCAL "0.0 0 0\n0\nLOCAL\n"
|
||||||
|
@ -76,9 +77,6 @@
|
||||||
BUS_GENERIC_INTERFACES_LIST \
|
BUS_GENERIC_INTERFACES_LIST \
|
||||||
"org.freedesktop.timedate1\0"
|
"org.freedesktop.timedate1\0"
|
||||||
|
|
||||||
/* Must start and end with '/' */
|
|
||||||
#define ZONEINFO_PATH "/usr/share/zoneinfo/"
|
|
||||||
|
|
||||||
const char timedate_interface[] _introspect_("timedate1") = INTERFACE;
|
const char timedate_interface[] _introspect_("timedate1") = INTERFACE;
|
||||||
|
|
||||||
typedef struct TZ {
|
typedef struct TZ {
|
||||||
|
@ -132,7 +130,7 @@ static bool valid_timezone(const char *name) {
|
||||||
if (slash)
|
if (slash)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
t = strappend(ZONEINFO_PATH, name);
|
t = strappend("/usr/share/zoneinfo/", name);
|
||||||
if (!t)
|
if (!t)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -148,56 +146,29 @@ static bool valid_timezone(const char *name) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void verify_timezone(void) {
|
|
||||||
char *p, *a = NULL, *b = NULL;
|
|
||||||
size_t l, q;
|
|
||||||
int j, k;
|
|
||||||
|
|
||||||
if (!tz.zone)
|
|
||||||
return;
|
|
||||||
|
|
||||||
p = strappend(ZONEINFO_PATH, tz.zone);
|
|
||||||
if (!p) {
|
|
||||||
log_oom();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
tz.zone = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(a);
|
|
||||||
free(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int read_data(void) {
|
static int read_data(void) {
|
||||||
int r;
|
int r;
|
||||||
char *t = NULL;
|
_cleanup_free_ char *t = NULL;
|
||||||
|
|
||||||
free_data();
|
free_data();
|
||||||
|
|
||||||
r = readlink_malloc("/etc/localtime", &t);
|
r = readlink_malloc("/etc/localtime", &t);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
if (r == -EINVAL)
|
if (r == -EINVAL)
|
||||||
log_warning("/etc/localtime should be a symbolic link to a timezone data file in " ZONEINFO_PATH);
|
log_warning("/etc/localtime should be a symbolic link to a timezone data file in /usr/share/zoneinfo/.");
|
||||||
else
|
else
|
||||||
log_warning("Failed to get target of %s: %s", "/etc/localtime", strerror(-r));
|
log_warning("Failed to get target of /etc/localtime: %s", strerror(-r));
|
||||||
} else {
|
} else {
|
||||||
/* we only support the trivial relative link of (/etc/)..$ABSOLUTE */
|
const char *e;
|
||||||
int rel_link_offset = startswith(t, "..") ? strlen("..") : 0;
|
|
||||||
|
|
||||||
if (!startswith(t + rel_link_offset, ZONEINFO_PATH))
|
e = path_startswith(t, "/usr/share/zoneinfo/");
|
||||||
log_warning("/etc/localtime should be a symbolic link to a timezone data file in " ZONEINFO_PATH);
|
if (!e)
|
||||||
|
e = path_startswith(t, "../usr/share/zoneinfo/");
|
||||||
|
|
||||||
|
if (!e)
|
||||||
|
log_warning("/etc/localtime should be a symbolic link to a timezone data file in /usr/share/zoneinfo/.");
|
||||||
else {
|
else {
|
||||||
tz.zone = strdup(t + rel_link_offset + strlen(ZONEINFO_PATH));
|
tz.zone = strdup(e);
|
||||||
free(t);
|
|
||||||
if (!tz.zone)
|
if (!tz.zone)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
|
@ -205,8 +176,7 @@ static int read_data(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(t);
|
#ifdef HAVE_SYSV_COMPAT
|
||||||
|
|
||||||
r = read_one_line_file("/etc/timezone", &tz.zone);
|
r = read_one_line_file("/etc/timezone", &tz.zone);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
if (r != -ENOENT)
|
if (r != -ENOENT)
|
||||||
|
@ -221,6 +191,7 @@ static int read_data(void) {
|
||||||
log_warning("Failed to read /etc/sysconfig/clock: %s", strerror(-r));
|
log_warning("Failed to read /etc/sysconfig/clock: %s", strerror(-r));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
have_timezone:
|
have_timezone:
|
||||||
if (isempty(tz.zone)) {
|
if (isempty(tz.zone)) {
|
||||||
|
@ -228,8 +199,6 @@ have_timezone:
|
||||||
tz.zone = NULL;
|
tz.zone = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
verify_timezone();
|
|
||||||
|
|
||||||
tz.local_rtc = hwclock_is_localtime() > 0;
|
tz.local_rtc = hwclock_is_localtime() > 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -237,34 +206,36 @@ have_timezone:
|
||||||
|
|
||||||
static int write_data_timezone(void) {
|
static int write_data_timezone(void) {
|
||||||
int r = 0;
|
int r = 0;
|
||||||
char *p;
|
_cleanup_free_ char *p = NULL;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if (!tz.zone) {
|
if (!tz.zone) {
|
||||||
if (unlink("/etc/timezone") < 0 && errno != ENOENT)
|
|
||||||
r = -errno;
|
|
||||||
|
|
||||||
if (unlink("/etc/localtime") < 0 && errno != ENOENT)
|
if (unlink("/etc/localtime") < 0 && errno != ENOENT)
|
||||||
r = -errno;
|
r = -errno;
|
||||||
|
|
||||||
|
#ifdef HAVE_SYSV_COMPAT
|
||||||
|
if (unlink("/etc/timezone") < 0 && errno != ENOENT)
|
||||||
|
r = -errno;
|
||||||
|
#endif
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
p = strappend(ZONEINFO_PATH, tz.zone);
|
p = strappend("../usr/share/zoneinfo/", tz.zone);
|
||||||
if (!p)
|
if (!p)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
r = symlink(p, "/etc/localtime");
|
r = symlink_atomic(p, "/etc/localtime");
|
||||||
free(p);
|
|
||||||
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return -errno;
|
return r;
|
||||||
|
|
||||||
|
#ifdef HAVE_SYSV_COMPAT
|
||||||
if (stat("/etc/timezone", &st) == 0 && S_ISREG(st.st_mode)) {
|
if (stat("/etc/timezone", &st) == 0 && S_ISREG(st.st_mode)) {
|
||||||
r = write_one_line_file_atomic("/etc/timezone", tz.zone);
|
r = write_one_line_file_atomic("/etc/timezone", tz.zone);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue