2017-11-18 17:09:20 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
2011-06-15 15:37:39 +02:00
|
|
|
/***
|
|
|
|
This file is part of systemd.
|
|
|
|
|
|
|
|
Copyright 2011 Lennart Poettering
|
|
|
|
***/
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
#include "sd-bus.h"
|
2015-10-26 21:16:26 +01:00
|
|
|
#include "sd-event.h"
|
|
|
|
#include "sd-messages.h"
|
2013-10-16 06:10:04 +02:00
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2014-12-10 19:00:46 +01:00
|
|
|
#include "bus-common-errors.h"
|
2015-10-26 21:16:26 +01:00
|
|
|
#include "bus-error.h"
|
|
|
|
#include "bus-util.h"
|
|
|
|
#include "clock-util.h"
|
|
|
|
#include "def.h"
|
|
|
|
#include "fileio-label.h"
|
|
|
|
#include "fs-util.h"
|
2018-04-17 07:09:13 +02:00
|
|
|
#include "hashmap.h"
|
|
|
|
#include "list.h"
|
2015-10-26 21:16:26 +01:00
|
|
|
#include "path-util.h"
|
2014-12-27 18:46:36 +01:00
|
|
|
#include "selinux-util.h"
|
2018-04-17 07:09:13 +02:00
|
|
|
#include "string-util.h"
|
2015-10-26 21:16:26 +01:00
|
|
|
#include "strv.h"
|
2018-04-17 07:09:13 +02:00
|
|
|
#include "unit-def.h"
|
|
|
|
#include "unit-name.h"
|
2015-10-27 00:42:07 +01:00
|
|
|
#include "user-util.h"
|
2015-10-26 21:16:26 +01:00
|
|
|
#include "util.h"
|
2011-06-15 15:37:39 +02:00
|
|
|
|
|
|
|
#define NULL_ADJTIME_UTC "0.0 0 0\n0\nUTC\n"
|
|
|
|
#define NULL_ADJTIME_LOCAL "0.0 0 0\n0\nLOCAL\n"
|
|
|
|
|
2018-04-17 07:09:13 +02:00
|
|
|
typedef struct UnitStatusInfo {
|
|
|
|
char *name;
|
|
|
|
char *load_state;
|
|
|
|
char *unit_file_state;
|
|
|
|
char *active_state;
|
|
|
|
|
|
|
|
LIST_FIELDS(struct UnitStatusInfo, units);
|
|
|
|
} UnitStatusInfo;
|
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
typedef struct Context {
|
2012-01-16 00:23:59 +01:00
|
|
|
char *zone;
|
|
|
|
bool local_rtc;
|
2013-10-16 06:10:04 +02:00
|
|
|
Hashmap *polkit_registry;
|
2018-04-17 07:09:13 +02:00
|
|
|
|
|
|
|
LIST_HEAD(UnitStatusInfo, units);
|
2013-10-16 06:10:04 +02:00
|
|
|
} Context;
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2018-04-17 07:09:13 +02:00
|
|
|
static void unit_status_info_clear(UnitStatusInfo *p) {
|
|
|
|
assert(p);
|
|
|
|
|
|
|
|
p->load_state = mfree(p->load_state);
|
|
|
|
p->unit_file_state = mfree(p->unit_file_state);
|
|
|
|
p->active_state = mfree(p->active_state);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void unit_status_info_free(UnitStatusInfo *p) {
|
|
|
|
assert(p);
|
|
|
|
|
|
|
|
unit_status_info_clear(p);
|
|
|
|
free(p->name);
|
|
|
|
free(p);
|
|
|
|
}
|
|
|
|
|
2014-08-06 07:57:43 +02:00
|
|
|
static void context_free(Context *c) {
|
2018-04-17 07:09:13 +02:00
|
|
|
UnitStatusInfo *p;
|
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
assert(c);
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2014-05-24 04:38:32 +02:00
|
|
|
free(c->zone);
|
2014-08-06 07:57:43 +02:00
|
|
|
bus_verify_polkit_async_registry_free(c->polkit_registry);
|
2018-04-17 07:09:13 +02:00
|
|
|
|
|
|
|
while ((p = c->units)) {
|
|
|
|
LIST_REMOVE(units, c->units, p);
|
|
|
|
unit_status_info_free(p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int context_add_ntp_service(Context *c, const char *s) {
|
|
|
|
UnitStatusInfo *u;
|
|
|
|
|
|
|
|
if (!unit_name_is_valid(s, UNIT_NAME_PLAIN))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
/* Do not add this if it is already listed */
|
|
|
|
LIST_FOREACH(units, u, c->units)
|
|
|
|
if (streq(u->name, s))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
u = new0(UnitStatusInfo, 1);
|
|
|
|
if (!u)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
u->name = strdup(s);
|
|
|
|
if (!u->name) {
|
|
|
|
free(u);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
LIST_APPEND(units, c->units, u);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int context_parse_ntp_services(Context *c) {
|
|
|
|
const char *env, *p;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(c);
|
|
|
|
|
|
|
|
env = getenv("SYSTEMD_TIMEDATED_NTP_SERVICES");
|
|
|
|
if (!env) {
|
|
|
|
r = context_add_ntp_service(c, "systemd-timesyncd.service");
|
|
|
|
if (r < 0)
|
|
|
|
log_warning_errno(r, "Failed to add NTP service \"systemd-timesyncd.service\", ignoring: %m");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (p = env;;) {
|
|
|
|
_cleanup_free_ char *word = NULL;
|
|
|
|
|
|
|
|
r = extract_first_word(&p, &word, ":", 0);
|
|
|
|
if (r == 0)
|
|
|
|
break;
|
|
|
|
if (r == -ENOMEM)
|
|
|
|
return log_oom();
|
|
|
|
if (r < 0) {
|
|
|
|
log_error("Invalid syntax, ignoring: %s", env);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = context_add_ntp_service(c, word);
|
|
|
|
if (r < 0)
|
|
|
|
log_warning_errno(r, "Failed to add NTP service \"%s\", ignoring: %m", word);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int context_ntp_service_is_active(Context *c) {
|
|
|
|
UnitStatusInfo *info;
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
assert(c);
|
|
|
|
|
|
|
|
/* Call context_update_ntp_status() to update UnitStatusInfo before calling this. */
|
|
|
|
|
|
|
|
LIST_FOREACH(units, info, c->units)
|
|
|
|
count += streq_ptr(info->active_state, "active");
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int context_ntp_service_is_enabled(Context *c) {
|
|
|
|
UnitStatusInfo *info;
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
assert(c);
|
|
|
|
|
|
|
|
/* Call context_update_ntp_status() to update UnitStatusInfo before calling this. */
|
|
|
|
|
|
|
|
LIST_FOREACH(units, info, c->units)
|
|
|
|
count += STRPTR_IN_SET(info->unit_file_state, "enabled", "enabled-runtime");
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int context_ntp_service_exists(Context *c) {
|
|
|
|
UnitStatusInfo *info;
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
assert(c);
|
|
|
|
|
|
|
|
/* Call context_update_ntp_status() to update UnitStatusInfo before calling this. */
|
|
|
|
|
|
|
|
LIST_FOREACH(units, info, c->units)
|
|
|
|
count += streq_ptr(info->load_state, "loaded");
|
|
|
|
|
|
|
|
return count;
|
2011-06-15 15:37:39 +02:00
|
|
|
}
|
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
static int context_read_data(Context *c) {
|
2012-09-14 20:02:52 +02:00
|
|
|
_cleanup_free_ char *t = NULL;
|
2013-10-16 06:10:04 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(c);
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2015-08-26 19:14:51 +02:00
|
|
|
r = get_timezone(&t);
|
|
|
|
if (r == -EINVAL)
|
|
|
|
log_warning_errno(r, "/etc/localtime should be a symbolic link to a time zone data file in /usr/share/zoneinfo/.");
|
|
|
|
else if (r < 0)
|
|
|
|
log_warning_errno(r, "Failed to get target of /etc/localtime: %m");
|
2012-08-22 08:11:26 +02:00
|
|
|
|
2017-11-24 11:33:41 +01:00
|
|
|
free_and_replace(c->zone, t);
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2016-02-26 11:25:22 +01:00
|
|
|
c->local_rtc = clock_is_localtime(NULL) > 0;
|
2011-06-15 15:37:39 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
static int context_write_data_timezone(Context *c) {
|
2012-09-14 20:02:52 +02:00
|
|
|
_cleanup_free_ char *p = NULL;
|
2013-10-16 06:10:04 +02:00
|
|
|
int r = 0;
|
|
|
|
|
|
|
|
assert(c);
|
2012-09-14 20:20:29 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
if (isempty(c->zone)) {
|
2012-09-14 20:02:52 +02:00
|
|
|
if (unlink("/etc/localtime") < 0 && errno != ENOENT)
|
2011-06-15 15:37:39 +02:00
|
|
|
r = -errno;
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
p = strappend("../usr/share/zoneinfo/", c->zone);
|
2012-07-25 23:55:59 +02:00
|
|
|
if (!p)
|
|
|
|
return log_oom();
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2012-09-14 20:02:52 +02:00
|
|
|
r = symlink_atomic(p, "/etc/localtime");
|
2011-06-15 15:37:39 +02:00
|
|
|
if (r < 0)
|
2012-09-14 20:02:52 +02:00
|
|
|
return r;
|
2011-06-15 15:37:39 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
static int context_write_data_local_rtc(Context *c) {
|
2011-06-15 15:37:39 +02:00
|
|
|
int r;
|
2013-04-18 09:11:22 +02:00
|
|
|
_cleanup_free_ char *s = NULL, *w = NULL;
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
assert(c);
|
|
|
|
|
2011-06-15 15:37:39 +02:00
|
|
|
r = read_full_file("/etc/adjtime", &s, NULL);
|
|
|
|
if (r < 0) {
|
|
|
|
if (r != -ENOENT)
|
|
|
|
return r;
|
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
if (!c->local_rtc)
|
2011-06-15 15:37:39 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
w = strdup(NULL_ADJTIME_LOCAL);
|
|
|
|
if (!w)
|
|
|
|
return -ENOMEM;
|
|
|
|
} else {
|
2016-02-26 15:54:05 +01:00
|
|
|
char *p;
|
2016-02-29 00:56:07 +01:00
|
|
|
const char *e = "\n"; /* default if there is less than 3 lines */
|
2016-02-26 15:54:05 +01:00
|
|
|
const char *prepend = "";
|
2011-06-15 15:37:39 +02:00
|
|
|
size_t a, b;
|
|
|
|
|
2016-02-26 15:54:05 +01:00
|
|
|
p = strchrnul(s, '\n');
|
2016-02-29 15:16:03 +01:00
|
|
|
if (*p == '\0')
|
2016-02-26 15:54:05 +01:00
|
|
|
/* only one line, no \n terminator */
|
|
|
|
prepend = "\n0\n";
|
2016-02-29 15:16:03 +01:00
|
|
|
else if (p[1] == '\0') {
|
2016-02-26 15:54:05 +01:00
|
|
|
/* only one line, with \n terminator */
|
|
|
|
++p;
|
|
|
|
prepend = "0\n";
|
|
|
|
} else {
|
|
|
|
p = strchr(p+1, '\n');
|
|
|
|
if (!p) {
|
|
|
|
/* only two lines, no \n terminator */
|
|
|
|
prepend = "\n";
|
|
|
|
p = s + strlen(s);
|
|
|
|
} else {
|
|
|
|
char *end;
|
|
|
|
/* third line might have a \n terminator or not */
|
|
|
|
p++;
|
|
|
|
end = strchr(p, '\n');
|
|
|
|
/* if we actually have a fourth line, use that as suffix "e", otherwise the default \n */
|
|
|
|
if (end)
|
|
|
|
e = end;
|
|
|
|
}
|
|
|
|
}
|
2011-06-15 15:37:39 +02:00
|
|
|
|
|
|
|
a = p - s;
|
|
|
|
b = strlen(e);
|
|
|
|
|
2016-02-26 15:54:05 +01:00
|
|
|
w = new(char, a + (c->local_rtc ? 5 : 3) + strlen(prepend) + b + 1);
|
2013-04-02 22:07:21 +02:00
|
|
|
if (!w)
|
2011-06-15 15:37:39 +02:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2016-02-26 15:54:05 +01:00
|
|
|
*(char*) mempcpy(stpcpy(stpcpy(mempcpy(w, s, a), prepend), c->local_rtc ? "LOCAL" : "UTC"), e, b) = 0;
|
2011-06-15 15:37:39 +02:00
|
|
|
|
|
|
|
if (streq(w, NULL_ADJTIME_UTC)) {
|
2013-04-02 22:07:21 +02:00
|
|
|
if (unlink("/etc/adjtime") < 0)
|
2011-06-15 15:37:39 +02:00
|
|
|
if (errno != ENOENT)
|
|
|
|
return -errno;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2013-10-16 06:10:04 +02:00
|
|
|
|
2016-03-02 02:35:55 +01:00
|
|
|
mac_selinux_init();
|
2013-04-02 22:07:21 +02:00
|
|
|
return write_string_file_atomic_label("/etc/adjtime", w);
|
2011-06-15 15:37:39 +02:00
|
|
|
}
|
|
|
|
|
2018-04-17 07:09:13 +02:00
|
|
|
static int context_update_ntp_status(Context *c, sd_bus *bus, sd_bus_message *m) {
|
|
|
|
static const struct bus_properties_map map[] = {
|
|
|
|
{ "LoadState", "s", NULL, offsetof(UnitStatusInfo, load_state) },
|
|
|
|
{ "ActiveState", "s", NULL, offsetof(UnitStatusInfo, active_state) },
|
|
|
|
{ "UnitFileState", "s", NULL, offsetof(UnitStatusInfo, unit_file_state) },
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
static sd_bus_message *_m = NULL;
|
|
|
|
UnitStatusInfo *u;
|
2011-08-22 01:08:10 +02:00
|
|
|
int r;
|
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
assert(c);
|
2011-08-22 01:08:10 +02:00
|
|
|
assert(bus);
|
|
|
|
|
2018-04-17 07:09:13 +02:00
|
|
|
/* Suppress multiple call of context_update_ntp_status() within single DBus transaction. */
|
|
|
|
if (m && m == _m)
|
|
|
|
return 0;
|
2012-02-15 00:05:31 +01:00
|
|
|
|
2018-04-17 07:09:13 +02:00
|
|
|
_m = m;
|
2012-02-15 00:05:31 +01:00
|
|
|
|
2018-04-17 07:09:13 +02:00
|
|
|
LIST_FOREACH(units, u, c->units) {
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
_cleanup_free_ char *path = NULL;
|
2011-08-22 01:08:10 +02:00
|
|
|
|
2018-04-17 07:09:13 +02:00
|
|
|
unit_status_info_clear(u);
|
2013-10-16 06:10:04 +02:00
|
|
|
|
2018-04-17 07:09:13 +02:00
|
|
|
path = unit_dbus_path_from_name(u->name);
|
|
|
|
if (!path)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
r = bus_map_all_properties(
|
|
|
|
bus,
|
|
|
|
"org.freedesktop.systemd1",
|
|
|
|
path,
|
|
|
|
map,
|
|
|
|
BUS_MAP_STRDUP,
|
|
|
|
&error,
|
|
|
|
NULL,
|
|
|
|
u);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
|
|
|
|
}
|
2011-08-22 01:08:10 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
return 0;
|
2011-08-22 01:08:10 +02:00
|
|
|
}
|
|
|
|
|
2018-04-17 07:09:13 +02:00
|
|
|
static int unit_start_or_stop(UnitStatusInfo *u, sd_bus *bus, sd_bus_error *error, bool start) {
|
2011-08-22 01:08:10 +02:00
|
|
|
int r;
|
|
|
|
|
2018-04-17 07:09:13 +02:00
|
|
|
assert(u);
|
2011-08-22 01:08:10 +02:00
|
|
|
assert(bus);
|
|
|
|
assert(error);
|
|
|
|
|
2018-04-17 07:09:13 +02:00
|
|
|
/* Call context_update_ntp_status() to update UnitStatusInfo before calling this. */
|
|
|
|
|
|
|
|
if (streq(u->active_state, "active") == start)
|
|
|
|
return 0;
|
|
|
|
|
2015-03-22 00:21:17 +01:00
|
|
|
r = sd_bus_call_method(
|
|
|
|
bus,
|
|
|
|
"org.freedesktop.systemd1",
|
|
|
|
"/org/freedesktop/systemd1",
|
|
|
|
"org.freedesktop.systemd1.Manager",
|
2018-04-17 07:09:13 +02:00
|
|
|
start ? "StartUnit" : "StopUnit",
|
2015-03-22 00:21:17 +01:00
|
|
|
error,
|
|
|
|
NULL,
|
|
|
|
"ss",
|
2018-04-17 07:09:13 +02:00
|
|
|
u->name,
|
2015-03-22 00:21:17 +01:00
|
|
|
"replace");
|
2018-04-17 07:09:13 +02:00
|
|
|
if (r < 0)
|
2014-07-09 14:29:20 +02:00
|
|
|
return r;
|
2011-08-22 01:08:10 +02:00
|
|
|
|
2014-07-09 14:29:20 +02:00
|
|
|
return 0;
|
2011-08-22 01:08:10 +02:00
|
|
|
}
|
|
|
|
|
2018-04-17 07:09:13 +02:00
|
|
|
static int unit_enable_or_disable(UnitStatusInfo *u, sd_bus *bus, sd_bus_error *error, bool enable) {
|
2011-08-22 01:08:10 +02:00
|
|
|
int r;
|
|
|
|
|
2018-04-17 07:09:13 +02:00
|
|
|
assert(u);
|
2011-08-22 01:08:10 +02:00
|
|
|
assert(bus);
|
|
|
|
assert(error);
|
|
|
|
|
2018-04-17 07:09:13 +02:00
|
|
|
/* Call context_update_ntp_status() to update UnitStatusInfo before calling this. */
|
|
|
|
|
|
|
|
if (streq(u->unit_file_state, "enabled") == enable)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (enable)
|
2013-10-16 06:10:04 +02:00
|
|
|
r = sd_bus_call_method(
|
|
|
|
bus,
|
2012-07-01 17:37:21 +02:00
|
|
|
"org.freedesktop.systemd1",
|
|
|
|
"/org/freedesktop/systemd1",
|
|
|
|
"org.freedesktop.systemd1.Manager",
|
2014-07-09 14:29:20 +02:00
|
|
|
"EnableUnitFiles",
|
2013-10-16 06:10:04 +02:00
|
|
|
error,
|
|
|
|
NULL,
|
2014-07-09 14:29:20 +02:00
|
|
|
"asbb", 1,
|
2018-04-17 07:09:13 +02:00
|
|
|
u->name,
|
2014-07-09 14:29:20 +02:00
|
|
|
false, true);
|
|
|
|
else
|
|
|
|
r = sd_bus_call_method(
|
|
|
|
bus,
|
|
|
|
"org.freedesktop.systemd1",
|
|
|
|
"/org/freedesktop/systemd1",
|
|
|
|
"org.freedesktop.systemd1.Manager",
|
|
|
|
"DisableUnitFiles",
|
|
|
|
error,
|
|
|
|
NULL,
|
|
|
|
"asb", 1,
|
2018-04-17 07:09:13 +02:00
|
|
|
u->name,
|
2014-07-09 14:29:20 +02:00
|
|
|
false);
|
2018-04-17 07:09:13 +02:00
|
|
|
if (r < 0)
|
2014-07-09 14:29:20 +02:00
|
|
|
return r;
|
2011-08-22 01:08:10 +02:00
|
|
|
|
2014-07-09 14:29:20 +02:00
|
|
|
r = sd_bus_call_method(
|
|
|
|
bus,
|
|
|
|
"org.freedesktop.systemd1",
|
|
|
|
"/org/freedesktop/systemd1",
|
|
|
|
"org.freedesktop.systemd1.Manager",
|
|
|
|
"Reload",
|
|
|
|
error,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
2018-04-17 07:09:13 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-07-09 14:29:20 +02:00
|
|
|
return 0;
|
2013-10-16 06:10:04 +02:00
|
|
|
}
|
2011-08-22 01:08:10 +02:00
|
|
|
|
2018-05-14 03:04:04 +02:00
|
|
|
static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_time, "t", now(CLOCK_REALTIME));
|
|
|
|
static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_ntp_sync, "b", ntp_synced());
|
|
|
|
|
2013-10-16 16:57:49 +02:00
|
|
|
static int property_get_rtc_time(
|
|
|
|
sd_bus *bus,
|
|
|
|
const char *path,
|
|
|
|
const char *interface,
|
|
|
|
const char *property,
|
|
|
|
sd_bus_message *reply,
|
2013-11-21 19:34:37 +01:00
|
|
|
void *userdata,
|
|
|
|
sd_bus_error *error) {
|
2013-10-16 16:57:49 +02:00
|
|
|
|
|
|
|
struct tm tm;
|
|
|
|
usec_t t;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
zero(tm);
|
2014-05-24 04:26:33 +02:00
|
|
|
r = clock_get_hwclock(&tm);
|
2013-10-29 19:31:41 +01:00
|
|
|
if (r == -EBUSY) {
|
2014-03-18 05:27:05 +01:00
|
|
|
log_warning("/dev/rtc is busy. Is somebody keeping it open continuously? That's not a good idea... Returning a bogus RTC timestamp.");
|
2013-10-29 19:31:41 +01:00
|
|
|
t = 0;
|
2013-12-12 03:00:57 +01:00
|
|
|
} else if (r == -ENOENT) {
|
2014-03-18 05:27:05 +01:00
|
|
|
log_debug("/dev/rtc not found.");
|
2013-12-12 03:00:57 +01:00
|
|
|
t = 0; /* no RTC found */
|
2013-11-21 19:34:37 +01:00
|
|
|
} else if (r < 0)
|
2015-04-21 18:05:44 +02:00
|
|
|
return sd_bus_error_set_errnof(error, r, "Failed to read RTC: %m");
|
2013-11-21 19:34:37 +01:00
|
|
|
else
|
2013-10-31 02:26:07 +01:00
|
|
|
t = (usec_t) timegm(&tm) * USEC_PER_SEC;
|
2013-10-16 16:57:49 +02:00
|
|
|
|
2013-11-21 19:34:37 +01:00
|
|
|
return sd_bus_message_append(reply, "t", t);
|
2013-10-16 16:57:49 +02:00
|
|
|
}
|
|
|
|
|
2018-04-17 07:09:13 +02:00
|
|
|
static int property_get_can_ntp(
|
|
|
|
sd_bus *bus,
|
|
|
|
const char *path,
|
|
|
|
const char *interface,
|
|
|
|
const char *property,
|
|
|
|
sd_bus_message *reply,
|
|
|
|
void *userdata,
|
|
|
|
sd_bus_error *error) {
|
|
|
|
|
|
|
|
Context *c = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(c);
|
|
|
|
assert(bus);
|
|
|
|
assert(property);
|
|
|
|
assert(reply);
|
|
|
|
assert(error);
|
|
|
|
|
|
|
|
r = context_update_ntp_status(c, bus, reply);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return sd_bus_message_append(reply, "b", context_ntp_service_exists(c) > 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int property_get_ntp(
|
|
|
|
sd_bus *bus,
|
|
|
|
const char *path,
|
|
|
|
const char *interface,
|
|
|
|
const char *property,
|
|
|
|
sd_bus_message *reply,
|
|
|
|
void *userdata,
|
|
|
|
sd_bus_error *error) {
|
|
|
|
|
|
|
|
Context *c = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(c);
|
|
|
|
assert(bus);
|
|
|
|
assert(property);
|
|
|
|
assert(reply);
|
|
|
|
assert(error);
|
|
|
|
|
|
|
|
r = context_update_ntp_status(c, bus, reply);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return sd_bus_message_append(reply, "b", context_ntp_service_is_active(c) > 0);
|
|
|
|
}
|
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
static int method_set_timezone(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
2013-10-16 06:10:04 +02:00
|
|
|
Context *c = userdata;
|
2018-05-09 17:59:47 +02:00
|
|
|
int interactive, r;
|
2013-10-16 06:10:04 +02:00
|
|
|
const char *z;
|
2011-08-22 01:08:10 +02:00
|
|
|
|
2013-10-18 00:48:00 +02:00
|
|
|
assert(m);
|
|
|
|
assert(c);
|
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
r = sd_bus_message_read(m, "sb", &z, &interactive);
|
|
|
|
if (r < 0)
|
2013-11-21 19:34:37 +01:00
|
|
|
return r;
|
2011-08-22 01:08:10 +02:00
|
|
|
|
2018-05-12 21:20:13 +02:00
|
|
|
if (!timezone_is_valid(z, LOG_DEBUG))
|
2013-11-21 19:34:37 +01:00
|
|
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid time zone '%s'", z);
|
2012-07-01 17:37:21 +02:00
|
|
|
|
2018-05-15 15:53:19 +02:00
|
|
|
if (streq_ptr(z, c->zone))
|
2013-11-21 01:51:16 +01:00
|
|
|
return sd_bus_reply_method_return(m, NULL);
|
2011-08-22 01:08:10 +02:00
|
|
|
|
2015-02-18 12:55:25 +01:00
|
|
|
r = bus_verify_polkit_async(
|
|
|
|
m,
|
|
|
|
CAP_SYS_TIME,
|
|
|
|
"org.freedesktop.timedate1.set-timezone",
|
2015-09-05 16:07:16 +02:00
|
|
|
NULL,
|
2015-02-18 12:55:25 +01:00
|
|
|
interactive,
|
|
|
|
UID_INVALID,
|
|
|
|
&c->polkit_registry,
|
|
|
|
error);
|
2013-10-16 06:10:04 +02:00
|
|
|
if (r < 0)
|
2013-11-21 19:34:37 +01:00
|
|
|
return r;
|
2013-10-16 06:10:04 +02:00
|
|
|
if (r == 0)
|
2013-10-16 16:57:49 +02:00
|
|
|
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
|
2013-03-04 22:35:02 +01:00
|
|
|
|
2018-05-15 15:53:19 +02:00
|
|
|
r = free_and_strdup(&c->zone, z);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
/* 1. Write new configuration file */
|
|
|
|
r = context_write_data_timezone(c);
|
|
|
|
if (r < 0) {
|
2014-11-28 13:19:16 +01:00
|
|
|
log_error_errno(r, "Failed to set time zone: %m");
|
2015-04-21 18:05:44 +02:00
|
|
|
return sd_bus_error_set_errnof(error, r, "Failed to set time zone: %m");
|
2013-10-16 06:10:04 +02:00
|
|
|
}
|
2013-03-04 22:35:02 +01:00
|
|
|
|
2018-05-29 12:36:40 +02:00
|
|
|
/* 2. Make glibc notice the new timezone */
|
|
|
|
tzset();
|
|
|
|
|
|
|
|
/* 3. Tell the kernel our timezone */
|
2018-05-29 12:39:16 +02:00
|
|
|
r = clock_set_timezone(NULL);
|
|
|
|
if (r < 0)
|
|
|
|
log_debug_errno(r, "Failed to tell kernel about timezone, ignoring: %m");
|
2013-03-04 22:35:02 +01:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
if (c->local_rtc) {
|
|
|
|
struct timespec ts;
|
|
|
|
struct tm *tm;
|
2011-08-22 01:08:10 +02:00
|
|
|
|
2018-05-29 12:36:40 +02:00
|
|
|
/* 4. Sync RTC from system clock, with the new delta */
|
2013-10-16 06:10:04 +02:00
|
|
|
assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
|
|
|
|
assert_se(tm = localtime(&ts.tv_sec));
|
2018-05-29 12:39:16 +02:00
|
|
|
|
|
|
|
r = clock_set_hwclock(tm);
|
|
|
|
if (r < 0)
|
|
|
|
log_debug_errno(r, "Failed to sync time to hardware clock, ignoring: %m");
|
2013-10-16 06:10:04 +02:00
|
|
|
}
|
2011-08-22 01:08:10 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
log_struct(LOG_INFO,
|
tree-wide: add SD_ID128_MAKE_STR, remove LOG_MESSAGE_ID
Embedding sd_id128_t's in constant strings was rather cumbersome. We had
SD_ID128_CONST_STR which returned a const char[], but it had two problems:
- it wasn't possible to statically concatanate this array with a normal string
- gcc wasn't really able to optimize this, and generated code to perform the
"conversion" at runtime.
Because of this, even our own code in coredumpctl wasn't using
SD_ID128_CONST_STR.
Add a new macro to generate a constant string: SD_ID128_MAKE_STR.
It is not as elegant as SD_ID128_CONST_STR, because it requires a repetition
of the numbers, but in practice it is more convenient to use, and allows gcc
to generate smarter code:
$ size .libs/systemd{,-logind,-journald}{.old,}
text data bss dec hex filename
1265204 149564 4808 1419576 15a938 .libs/systemd.old
1260268 149564 4808 1414640 1595f0 .libs/systemd
246805 13852 209 260866 3fb02 .libs/systemd-logind.old
240973 13852 209 255034 3e43a .libs/systemd-logind
146839 4984 34 151857 25131 .libs/systemd-journald.old
146391 4984 34 151409 24f71 .libs/systemd-journald
It is also much easier to check if a certain binary uses a certain MESSAGE_ID:
$ strings .libs/systemd.old|grep MESSAGE_ID
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
$ strings .libs/systemd|grep MESSAGE_ID
MESSAGE_ID=c7a787079b354eaaa9e77b371893cd27
MESSAGE_ID=b07a249cd024414a82dd00cd181378ff
MESSAGE_ID=641257651c1b4ec9a8624d7a40a9e1e7
MESSAGE_ID=de5b426a63be47a7b6ac3eaac82e2f6f
MESSAGE_ID=d34d037fff1847e6ae669a370e694725
MESSAGE_ID=7d4958e842da4a758f6c1cdc7b36dcc5
MESSAGE_ID=1dee0369c7fc4736b7099b38ecb46ee7
MESSAGE_ID=39f53479d3a045ac8e11786248231fbf
MESSAGE_ID=be02cf6855d2428ba40df7e9d022f03d
MESSAGE_ID=7b05ebc668384222baa8881179cfda54
MESSAGE_ID=9d1aaa27d60140bd96365438aad20286
2016-11-06 18:48:23 +01:00
|
|
|
"MESSAGE_ID=" SD_MESSAGE_TIMEZONE_CHANGE_STR,
|
2013-10-16 06:10:04 +02:00
|
|
|
"TIMEZONE=%s", c->zone,
|
2018-05-29 12:36:40 +02:00
|
|
|
"TIMEZONE_SHORTNAME=%s", tzname[daylight],
|
|
|
|
"DAYLIGHT=%i", daylight,
|
2018-06-04 12:59:22 +02:00
|
|
|
LOG_MESSAGE("Changed time zone to '%s' (%s).", c->zone, tzname[daylight]));
|
2011-08-22 01:08:10 +02:00
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
(void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "Timezone", NULL);
|
2011-08-22 01:08:10 +02:00
|
|
|
|
2013-11-21 01:51:16 +01:00
|
|
|
return sd_bus_reply_method_return(m, NULL);
|
2011-08-22 01:08:10 +02:00
|
|
|
}
|
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
static int method_set_local_rtc(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
2013-11-07 02:03:10 +01:00
|
|
|
int lrtc, fix_system, interactive;
|
2013-10-16 06:10:04 +02:00
|
|
|
Context *c = userdata;
|
|
|
|
struct timespec ts;
|
2011-06-15 15:37:39 +02:00
|
|
|
int r;
|
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
assert(m);
|
|
|
|
assert(c);
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
r = sd_bus_message_read(m, "bbb", &lrtc, &fix_system, &interactive);
|
|
|
|
if (r < 0)
|
2013-11-21 19:34:37 +01:00
|
|
|
return r;
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
if (lrtc == c->local_rtc)
|
2013-11-21 01:51:16 +01:00
|
|
|
return sd_bus_reply_method_return(m, NULL);
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2015-02-18 12:55:25 +01:00
|
|
|
r = bus_verify_polkit_async(
|
|
|
|
m,
|
|
|
|
CAP_SYS_TIME,
|
|
|
|
"org.freedesktop.timedate1.set-local-rtc",
|
2015-09-05 16:07:16 +02:00
|
|
|
NULL,
|
2015-02-18 12:55:25 +01:00
|
|
|
interactive,
|
|
|
|
UID_INVALID,
|
|
|
|
&c->polkit_registry,
|
|
|
|
error);
|
2013-10-16 06:10:04 +02:00
|
|
|
if (r < 0)
|
2013-11-21 19:34:37 +01:00
|
|
|
return r;
|
2013-10-16 06:10:04 +02:00
|
|
|
if (r == 0)
|
|
|
|
return 1;
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
c->local_rtc = lrtc;
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
/* 1. Write new configuration file */
|
|
|
|
r = context_write_data_local_rtc(c);
|
|
|
|
if (r < 0) {
|
2014-11-28 13:19:16 +01:00
|
|
|
log_error_errno(r, "Failed to set RTC to local/UTC: %m");
|
2015-04-21 18:05:44 +02:00
|
|
|
return sd_bus_error_set_errnof(error, r, "Failed to set RTC to local/UTC: %m");
|
2013-10-16 06:10:04 +02:00
|
|
|
}
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
/* 2. Tell the kernel our timezone */
|
2018-05-29 12:39:16 +02:00
|
|
|
r = clock_set_timezone(NULL);
|
|
|
|
if (r < 0)
|
|
|
|
log_debug_errno(r, "Failed to tell kernel about timezone, ignoring: %m");
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
/* 3. Synchronize clocks */
|
|
|
|
assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
if (fix_system) {
|
|
|
|
struct tm tm;
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2018-05-29 12:39:16 +02:00
|
|
|
/* Sync system clock from RTC; first, initialize the timezone fields of struct tm. */
|
2013-10-16 06:10:04 +02:00
|
|
|
if (c->local_rtc)
|
|
|
|
tm = *localtime(&ts.tv_sec);
|
|
|
|
else
|
|
|
|
tm = *gmtime(&ts.tv_sec);
|
2012-09-17 16:41:13 +02:00
|
|
|
|
2018-05-29 12:39:16 +02:00
|
|
|
/* Override the main fields of struct tm, but not the timezone fields */
|
|
|
|
r = clock_get_hwclock(&tm);
|
|
|
|
if (r < 0)
|
|
|
|
log_debug_errno(r, "Failed to get hardware clock, ignoring: %m");
|
|
|
|
else {
|
|
|
|
/* And set the system clock with this */
|
2013-10-16 06:10:04 +02:00
|
|
|
if (c->local_rtc)
|
|
|
|
ts.tv_sec = mktime(&tm);
|
|
|
|
else
|
|
|
|
ts.tv_sec = timegm(&tm);
|
2011-06-16 21:52:11 +02:00
|
|
|
|
2018-05-29 12:39:16 +02:00
|
|
|
if (clock_settime(CLOCK_REALTIME, &ts) < 0)
|
|
|
|
log_debug_errno(errno, "Failed to update system clock, ignoring: %m");
|
2011-06-15 15:37:39 +02:00
|
|
|
}
|
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
} else {
|
|
|
|
struct tm *tm;
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
/* Sync RTC from system clock */
|
|
|
|
if (c->local_rtc)
|
|
|
|
tm = localtime(&ts.tv_sec);
|
|
|
|
else
|
|
|
|
tm = gmtime(&ts.tv_sec);
|
2011-06-16 21:52:11 +02:00
|
|
|
|
2018-05-29 12:39:16 +02:00
|
|
|
r = clock_set_hwclock(tm);
|
|
|
|
if (r < 0)
|
|
|
|
log_debug_errno(r, "Failed to sync time to hardware clock, ignoring: %m");
|
2013-10-16 06:10:04 +02:00
|
|
|
}
|
2011-06-16 21:52:11 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
log_info("RTC configured to %s time.", c->local_rtc ? "local" : "UTC");
|
2011-06-16 21:52:11 +02:00
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
(void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "LocalRTC", NULL);
|
2011-06-16 21:52:11 +02:00
|
|
|
|
2013-11-21 01:51:16 +01:00
|
|
|
return sd_bus_reply_method_return(m, NULL);
|
2013-10-16 06:10:04 +02:00
|
|
|
}
|
2011-06-16 21:52:11 +02:00
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
static int method_set_time(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
2018-04-17 07:09:13 +02:00
|
|
|
sd_bus *bus = sd_bus_message_get_bus(m);
|
|
|
|
int relative, interactive, r;
|
2013-10-16 06:10:04 +02:00
|
|
|
Context *c = userdata;
|
|
|
|
int64_t utc;
|
|
|
|
struct timespec ts;
|
2015-02-16 20:47:08 +01:00
|
|
|
usec_t start;
|
2013-10-16 06:10:04 +02:00
|
|
|
struct tm* tm;
|
2011-06-16 21:52:11 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
assert(m);
|
|
|
|
assert(c);
|
2011-06-16 21:52:11 +02:00
|
|
|
|
2018-04-17 07:09:13 +02:00
|
|
|
r = context_update_ntp_status(c, bus, m);
|
|
|
|
if (r < 0)
|
|
|
|
return sd_bus_error_set_errnof(error, r, "Failed to update context: %m");
|
|
|
|
|
|
|
|
if (context_ntp_service_is_active(c) > 0)
|
2018-04-17 07:05:27 +02:00
|
|
|
return sd_bus_error_set(error, BUS_ERROR_AUTOMATIC_TIME_SYNC_ENABLED, "Automatic time synchronization is enabled");
|
2014-05-24 04:38:32 +02:00
|
|
|
|
2015-03-07 10:43:32 +01:00
|
|
|
/* this only gets used if dbus does not provide a timestamp */
|
|
|
|
start = now(CLOCK_MONOTONIC);
|
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
r = sd_bus_message_read(m, "xbb", &utc, &relative, &interactive);
|
|
|
|
if (r < 0)
|
2013-11-21 19:34:37 +01:00
|
|
|
return r;
|
2011-06-16 21:52:11 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
if (!relative && utc <= 0)
|
2018-04-17 07:05:27 +02:00
|
|
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid absolute time");
|
2011-06-16 21:52:11 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
if (relative && utc == 0)
|
2013-11-21 01:51:16 +01:00
|
|
|
return sd_bus_reply_method_return(m, NULL);
|
2011-06-16 21:52:11 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
if (relative) {
|
|
|
|
usec_t n, x;
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
n = now(CLOCK_REALTIME);
|
|
|
|
x = n + utc;
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
if ((utc > 0 && x < n) ||
|
|
|
|
(utc < 0 && x > n))
|
2018-04-17 07:05:27 +02:00
|
|
|
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Time value overflow");
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
timespec_store(&ts, x);
|
|
|
|
} else
|
|
|
|
timespec_store(&ts, (usec_t) utc);
|
2011-06-16 21:52:11 +02:00
|
|
|
|
2015-02-18 12:55:25 +01:00
|
|
|
r = bus_verify_polkit_async(
|
|
|
|
m,
|
|
|
|
CAP_SYS_TIME,
|
|
|
|
"org.freedesktop.timedate1.set-time",
|
2015-09-05 16:07:16 +02:00
|
|
|
NULL,
|
2015-02-18 12:55:25 +01:00
|
|
|
interactive,
|
|
|
|
UID_INVALID,
|
|
|
|
&c->polkit_registry,
|
|
|
|
error);
|
2013-10-16 06:10:04 +02:00
|
|
|
if (r < 0)
|
2013-11-21 19:34:37 +01:00
|
|
|
return r;
|
2013-10-16 06:10:04 +02:00
|
|
|
if (r == 0)
|
|
|
|
return 1;
|
|
|
|
|
2015-02-16 20:47:08 +01:00
|
|
|
/* adjust ts for time spent in program */
|
|
|
|
r = sd_bus_message_get_monotonic_usec(m, &start);
|
2015-03-07 10:43:32 +01:00
|
|
|
/* when sd_bus_message_get_monotonic_usec() returns -ENODATA it does not modify &start */
|
2015-02-16 20:47:08 +01:00
|
|
|
if (r < 0 && r != -ENODATA)
|
|
|
|
return r;
|
2015-03-07 10:43:32 +01:00
|
|
|
|
|
|
|
timespec_store(&ts, timespec_load(&ts) + (now(CLOCK_MONOTONIC) - start));
|
2015-02-16 20:47:08 +01:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
/* Set system clock */
|
|
|
|
if (clock_settime(CLOCK_REALTIME, &ts) < 0) {
|
2014-11-28 19:29:59 +01:00
|
|
|
log_error_errno(errno, "Failed to set local time: %m");
|
2013-11-21 19:34:37 +01:00
|
|
|
return sd_bus_error_set_errnof(error, errno, "Failed to set local time: %m");
|
2013-10-16 06:10:04 +02:00
|
|
|
}
|
2011-06-16 21:52:11 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
/* Sync down to RTC */
|
|
|
|
if (c->local_rtc)
|
|
|
|
tm = localtime(&ts.tv_sec);
|
|
|
|
else
|
|
|
|
tm = gmtime(&ts.tv_sec);
|
2018-05-29 12:39:16 +02:00
|
|
|
|
|
|
|
r = clock_set_hwclock(tm);
|
|
|
|
if (r < 0)
|
|
|
|
log_debug_errno(r, "Failed to update hardware clock, ignoring: %m");
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
log_struct(LOG_INFO,
|
tree-wide: add SD_ID128_MAKE_STR, remove LOG_MESSAGE_ID
Embedding sd_id128_t's in constant strings was rather cumbersome. We had
SD_ID128_CONST_STR which returned a const char[], but it had two problems:
- it wasn't possible to statically concatanate this array with a normal string
- gcc wasn't really able to optimize this, and generated code to perform the
"conversion" at runtime.
Because of this, even our own code in coredumpctl wasn't using
SD_ID128_CONST_STR.
Add a new macro to generate a constant string: SD_ID128_MAKE_STR.
It is not as elegant as SD_ID128_CONST_STR, because it requires a repetition
of the numbers, but in practice it is more convenient to use, and allows gcc
to generate smarter code:
$ size .libs/systemd{,-logind,-journald}{.old,}
text data bss dec hex filename
1265204 149564 4808 1419576 15a938 .libs/systemd.old
1260268 149564 4808 1414640 1595f0 .libs/systemd
246805 13852 209 260866 3fb02 .libs/systemd-logind.old
240973 13852 209 255034 3e43a .libs/systemd-logind
146839 4984 34 151857 25131 .libs/systemd-journald.old
146391 4984 34 151409 24f71 .libs/systemd-journald
It is also much easier to check if a certain binary uses a certain MESSAGE_ID:
$ strings .libs/systemd.old|grep MESSAGE_ID
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
$ strings .libs/systemd|grep MESSAGE_ID
MESSAGE_ID=c7a787079b354eaaa9e77b371893cd27
MESSAGE_ID=b07a249cd024414a82dd00cd181378ff
MESSAGE_ID=641257651c1b4ec9a8624d7a40a9e1e7
MESSAGE_ID=de5b426a63be47a7b6ac3eaac82e2f6f
MESSAGE_ID=d34d037fff1847e6ae669a370e694725
MESSAGE_ID=7d4958e842da4a758f6c1cdc7b36dcc5
MESSAGE_ID=1dee0369c7fc4736b7099b38ecb46ee7
MESSAGE_ID=39f53479d3a045ac8e11786248231fbf
MESSAGE_ID=be02cf6855d2428ba40df7e9d022f03d
MESSAGE_ID=7b05ebc668384222baa8881179cfda54
MESSAGE_ID=9d1aaa27d60140bd96365438aad20286
2016-11-06 18:48:23 +01:00
|
|
|
"MESSAGE_ID=" SD_MESSAGE_TIME_CHANGE_STR,
|
2014-04-25 13:45:15 +02:00
|
|
|
"REALTIME="USEC_FMT, timespec_load(&ts),
|
2018-06-04 12:59:22 +02:00
|
|
|
LOG_MESSAGE("Changed local time to %s", ctime(&ts.tv_sec)));
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2013-11-21 01:51:16 +01:00
|
|
|
return sd_bus_reply_method_return(m, NULL);
|
2013-10-16 06:10:04 +02:00
|
|
|
}
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
static int method_set_ntp(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
2018-04-17 07:09:13 +02:00
|
|
|
sd_bus *bus = sd_bus_message_get_bus(m);
|
2013-10-16 06:10:04 +02:00
|
|
|
Context *c = userdata;
|
2018-04-17 07:09:13 +02:00
|
|
|
UnitStatusInfo *u;
|
|
|
|
int enable, interactive, q, r;
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
assert(m);
|
2018-04-17 07:09:13 +02:00
|
|
|
assert(bus);
|
2015-04-29 18:35:10 +02:00
|
|
|
assert(c);
|
|
|
|
|
2018-04-17 07:09:13 +02:00
|
|
|
r = sd_bus_message_read(m, "bb", &enable, &interactive);
|
2013-10-16 06:10:04 +02:00
|
|
|
if (r < 0)
|
2013-11-21 19:34:37 +01:00
|
|
|
return r;
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2018-04-17 07:09:13 +02:00
|
|
|
r = context_update_ntp_status(c, bus, m);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (context_ntp_service_exists(c) <= 0)
|
|
|
|
return sd_bus_error_set(error, BUS_ERROR_NO_NTP_SUPPORT, "NTP not supported");
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2015-02-18 12:55:25 +01:00
|
|
|
r = bus_verify_polkit_async(
|
|
|
|
m,
|
|
|
|
CAP_SYS_TIME,
|
|
|
|
"org.freedesktop.timedate1.set-ntp",
|
2015-09-05 16:07:16 +02:00
|
|
|
NULL,
|
2015-02-18 12:55:25 +01:00
|
|
|
interactive,
|
|
|
|
UID_INVALID,
|
|
|
|
&c->polkit_registry,
|
|
|
|
error);
|
2013-10-16 06:10:04 +02:00
|
|
|
if (r < 0)
|
2013-11-21 19:34:37 +01:00
|
|
|
return r;
|
2013-10-16 06:10:04 +02:00
|
|
|
if (r == 0)
|
|
|
|
return 1;
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2018-04-17 07:09:13 +02:00
|
|
|
if (!enable)
|
|
|
|
LIST_FOREACH(units, u, c->units) {
|
|
|
|
if (!streq(u->load_state, "loaded"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
q = unit_enable_or_disable(u, bus, error, enable);
|
|
|
|
if (q < 0)
|
|
|
|
r = q;
|
|
|
|
|
|
|
|
q = unit_start_or_stop(u, bus, error, enable);
|
|
|
|
if (q < 0)
|
|
|
|
r = q;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (context_ntp_service_is_enabled(c) <= 0)
|
|
|
|
LIST_FOREACH(units, u, c->units) {
|
|
|
|
if (!streq(u->load_state, "loaded"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
r = unit_enable_or_disable(u, bus, error, enable);
|
|
|
|
if (r < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
r = unit_start_or_stop(u, bus, error, enable);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (context_ntp_service_is_active(c) <= 0)
|
|
|
|
LIST_FOREACH(units, u, c->units) {
|
|
|
|
if (!streq(u->load_state, "loaded") ||
|
|
|
|
!streq(u->unit_file_state, "enabled"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
r = unit_start_or_stop(u, bus, error, enable);
|
|
|
|
break;
|
|
|
|
}
|
2013-10-16 06:10:04 +02:00
|
|
|
|
|
|
|
if (r < 0)
|
2013-11-21 19:34:37 +01:00
|
|
|
return r;
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2018-04-17 07:09:13 +02:00
|
|
|
log_info("Set NTP to %sd", enable_disable(enable));
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2018-04-17 07:09:13 +02:00
|
|
|
(void) sd_bus_emit_properties_changed(bus, "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "NTP", NULL);
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2013-11-21 01:51:16 +01:00
|
|
|
return sd_bus_reply_method_return(m, NULL);
|
2011-06-15 15:37:39 +02:00
|
|
|
}
|
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
static const sd_bus_vtable timedate_vtable[] = {
|
|
|
|
SD_BUS_VTABLE_START(0),
|
|
|
|
SD_BUS_PROPERTY("Timezone", "s", NULL, offsetof(Context, zone), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
2014-05-24 04:38:32 +02:00
|
|
|
SD_BUS_PROPERTY("LocalRTC", "b", bus_property_get_bool, offsetof(Context, local_rtc), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
2018-04-17 07:09:13 +02:00
|
|
|
SD_BUS_PROPERTY("CanNTP", "b", property_get_can_ntp, 0, 0),
|
|
|
|
SD_BUS_PROPERTY("NTP", "b", property_get_ntp, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
2013-10-17 01:03:39 +02:00
|
|
|
SD_BUS_PROPERTY("NTPSynchronized", "b", property_get_ntp_sync, 0, 0),
|
|
|
|
SD_BUS_PROPERTY("TimeUSec", "t", property_get_time, 0, 0),
|
2013-10-16 16:57:49 +02:00
|
|
|
SD_BUS_PROPERTY("RTCTimeUSec", "t", property_get_rtc_time, 0, 0),
|
2013-12-10 17:41:39 +01:00
|
|
|
SD_BUS_METHOD("SetTime", "xbb", NULL, method_set_time, SD_BUS_VTABLE_UNPRIVILEGED),
|
|
|
|
SD_BUS_METHOD("SetTimezone", "sb", NULL, method_set_timezone, SD_BUS_VTABLE_UNPRIVILEGED),
|
|
|
|
SD_BUS_METHOD("SetLocalRTC", "bbb", NULL, method_set_local_rtc, SD_BUS_VTABLE_UNPRIVILEGED),
|
|
|
|
SD_BUS_METHOD("SetNTP", "bb", NULL, method_set_ntp, SD_BUS_VTABLE_UNPRIVILEGED),
|
2013-10-16 06:10:04 +02:00
|
|
|
SD_BUS_VTABLE_END,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
2011-06-15 15:37:39 +02:00
|
|
|
int r;
|
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
assert(c);
|
|
|
|
assert(event);
|
2011-06-15 15:37:39 +02:00
|
|
|
assert(_bus);
|
|
|
|
|
2013-11-11 22:00:48 +01:00
|
|
|
r = sd_bus_default_system(&bus);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to get system bus connection: %m");
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2014-05-15 01:15:30 +02:00
|
|
|
r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/timedate1", "org.freedesktop.timedate1", timedate_vtable, c);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to register object: %m");
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2017-12-18 22:10:11 +01:00
|
|
|
r = sd_bus_request_name_async(bus, NULL, "org.freedesktop.timedate1", 0, NULL, NULL);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
2017-12-18 22:10:11 +01:00
|
|
|
return log_error_errno(r, "Failed to request name: %m");
|
2011-06-27 23:15:57 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
r = sd_bus_attach_event(bus, event, 0);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to attach bus to event loop: %m");
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2018-04-05 07:26:26 +02:00
|
|
|
*_bus = TAKE_PTR(bus);
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
return 0;
|
2011-06-15 15:37:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char *argv[]) {
|
2014-05-24 04:38:32 +02:00
|
|
|
Context context = {};
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
|
|
|
|
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
2011-06-15 15:37:39 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
log_set_target(LOG_TARGET_AUTO);
|
|
|
|
log_parse_environment();
|
|
|
|
log_open();
|
|
|
|
|
2011-08-01 20:52:18 +02:00
|
|
|
umask(0022);
|
|
|
|
|
2011-06-15 15:37:39 +02:00
|
|
|
if (argc != 1) {
|
|
|
|
log_error("This program takes no arguments.");
|
|
|
|
r = -EINVAL;
|
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
2013-11-11 19:34:13 +01:00
|
|
|
r = sd_event_default(&event);
|
2011-06-15 15:37:39 +02:00
|
|
|
if (r < 0) {
|
2014-11-28 13:19:16 +01:00
|
|
|
log_error_errno(r, "Failed to allocate event loop: %m");
|
2011-06-15 15:37:39 +02:00
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
2013-12-11 18:14:52 +01:00
|
|
|
sd_event_set_watchdog(event, true);
|
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
r = connect_bus(&context, event, &bus);
|
2011-06-15 15:37:39 +02:00
|
|
|
if (r < 0)
|
|
|
|
goto finish;
|
|
|
|
|
2015-03-14 03:20:01 +01:00
|
|
|
(void) sd_bus_negotiate_timestamp(bus, true);
|
2015-02-16 20:47:08 +01:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
r = context_read_data(&context);
|
2011-08-22 01:08:10 +02:00
|
|
|
if (r < 0) {
|
2014-11-28 13:19:16 +01:00
|
|
|
log_error_errno(r, "Failed to read time zone data: %m");
|
2011-08-22 01:08:10 +02:00
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
2018-04-17 07:09:13 +02:00
|
|
|
r = context_parse_ntp_services(&context);
|
|
|
|
if (r < 0)
|
2013-10-16 06:10:04 +02:00
|
|
|
goto finish;
|
2011-09-03 03:26:58 +02:00
|
|
|
|
2013-12-19 21:14:52 +01:00
|
|
|
r = bus_event_loop_with_idle(event, bus, "org.freedesktop.timedate1", DEFAULT_EXIT_USEC, NULL, NULL);
|
2013-10-16 06:10:04 +02:00
|
|
|
if (r < 0) {
|
2014-11-28 13:19:16 +01:00
|
|
|
log_error_errno(r, "Failed to run event loop: %m");
|
2013-10-16 06:10:04 +02:00
|
|
|
goto finish;
|
2011-09-03 03:26:58 +02:00
|
|
|
}
|
2011-06-15 15:37:39 +02:00
|
|
|
|
|
|
|
finish:
|
2014-08-06 07:57:43 +02:00
|
|
|
context_free(&context);
|
2011-06-15 15:37:39 +02:00
|
|
|
|
|
|
|
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
|
|
}
|