2011-06-15 15:37:39 +02:00
|
|
|
/***
|
|
|
|
This file is part of systemd.
|
|
|
|
|
|
|
|
Copyright 2011 Lennart Poettering
|
|
|
|
|
|
|
|
systemd is free software; you can redistribute it and/or modify it
|
2012-04-12 00:20:58 +02:00
|
|
|
under the terms of the GNU Lesser General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2.1 of the License, or
|
2011-06-15 15:37:39 +02:00
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
systemd is distributed in the hope that it will be useful, but
|
|
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
2012-04-12 00:20:58 +02:00
|
|
|
Lesser General Public License for more details.
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2012-04-12 00:20:58 +02:00
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
2011-06-15 15:37:39 +02:00
|
|
|
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
***/
|
|
|
|
|
|
|
|
#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"
|
|
|
|
#include "path-util.h"
|
2014-12-27 18:46:36 +01:00
|
|
|
#include "selinux-util.h"
|
2015-10-26 21:16:26 +01:00
|
|
|
#include "strv.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"
|
|
|
|
|
2014-12-06 02:39:15 +01:00
|
|
|
static BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map timedated_errors[] = {
|
2015-03-13 14:08:00 +01:00
|
|
|
SD_BUS_ERROR_MAP("org.freedesktop.timedate1.NoNTPSupport", EOPNOTSUPP),
|
2014-12-06 02:39:15 +01:00
|
|
|
SD_BUS_ERROR_MAP_END
|
2014-10-31 01:32:17 +01:00
|
|
|
};
|
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
typedef struct Context {
|
2012-01-16 00:23:59 +01:00
|
|
|
char *zone;
|
|
|
|
bool local_rtc;
|
2014-05-24 04:38:32 +02:00
|
|
|
bool can_ntp;
|
|
|
|
bool use_ntp;
|
2013-10-16 06:10:04 +02:00
|
|
|
Hashmap *polkit_registry;
|
|
|
|
} Context;
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2014-08-06 07:57:43 +02:00
|
|
|
static void context_free(Context *c) {
|
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);
|
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
|
|
|
|
2015-08-26 19:14:51 +02:00
|
|
|
free(c->zone);
|
|
|
|
c->zone = t;
|
|
|
|
t = NULL;
|
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
|
|
|
}
|
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
static int context_read_ntp(Context *c, 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_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
2014-07-09 14:29:20 +02:00
|
|
|
const char *s;
|
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);
|
|
|
|
|
2014-07-09 14:29:20 +02:00
|
|
|
r = sd_bus_call_method(
|
|
|
|
bus,
|
|
|
|
"org.freedesktop.systemd1",
|
|
|
|
"/org/freedesktop/systemd1",
|
|
|
|
"org.freedesktop.systemd1.Manager",
|
|
|
|
"GetUnitFileState",
|
|
|
|
&error,
|
|
|
|
&reply,
|
|
|
|
"s",
|
|
|
|
"systemd-timesyncd.service");
|
2012-02-15 00:05:31 +01:00
|
|
|
|
2014-07-09 14:29:20 +02:00
|
|
|
if (r < 0) {
|
|
|
|
if (sd_bus_error_has_name(&error, SD_BUS_ERROR_FILE_NOT_FOUND) ||
|
|
|
|
sd_bus_error_has_name(&error, "org.freedesktop.systemd1.LoadFailed") ||
|
|
|
|
sd_bus_error_has_name(&error, "org.freedesktop.systemd1.NoSuchUnit"))
|
|
|
|
return 0;
|
2012-02-15 00:05:31 +01:00
|
|
|
|
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_message_read(reply, "s", &s);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2013-10-16 06:10:04 +02:00
|
|
|
|
2014-07-09 14:29:20 +02:00
|
|
|
c->can_ntp = true;
|
|
|
|
c->use_ntp = STR_IN_SET(s, "enabled", "enabled-runtime");
|
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
|
|
|
}
|
|
|
|
|
2015-03-22 00:21:17 +01:00
|
|
|
static int context_start_ntp(sd_bus *bus, sd_bus_error *error, bool enabled) {
|
2011-08-22 01:08:10 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
assert(error);
|
|
|
|
|
2015-03-22 00:21:17 +01:00
|
|
|
r = sd_bus_call_method(
|
|
|
|
bus,
|
|
|
|
"org.freedesktop.systemd1",
|
|
|
|
"/org/freedesktop/systemd1",
|
|
|
|
"org.freedesktop.systemd1.Manager",
|
|
|
|
enabled ? "StartUnit" : "StopUnit",
|
|
|
|
error,
|
|
|
|
NULL,
|
|
|
|
"ss",
|
|
|
|
"systemd-timesyncd.service",
|
|
|
|
"replace");
|
2014-07-09 14:29:20 +02:00
|
|
|
if (r < 0) {
|
|
|
|
if (sd_bus_error_has_name(error, SD_BUS_ERROR_FILE_NOT_FOUND) ||
|
|
|
|
sd_bus_error_has_name(error, "org.freedesktop.systemd1.LoadFailed") ||
|
2014-10-31 01:32:17 +01:00
|
|
|
sd_bus_error_has_name(error, "org.freedesktop.systemd1.NoSuchUnit"))
|
|
|
|
return sd_bus_error_set_const(error, "org.freedesktop.timedate1.NoNTPSupport", "NTP not supported.");
|
2012-07-01 17:37:21 +02:00
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2015-03-22 00:21:17 +01:00
|
|
|
static int context_enable_ntp(sd_bus *bus, sd_bus_error *error, bool enabled) {
|
2011-08-22 01:08:10 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
assert(error);
|
|
|
|
|
2015-03-22 00:21:17 +01:00
|
|
|
if (enabled)
|
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,
|
|
|
|
"systemd-timesyncd.service",
|
|
|
|
false, true);
|
|
|
|
else
|
|
|
|
r = sd_bus_call_method(
|
|
|
|
bus,
|
|
|
|
"org.freedesktop.systemd1",
|
|
|
|
"/org/freedesktop/systemd1",
|
|
|
|
"org.freedesktop.systemd1.Manager",
|
|
|
|
"DisableUnitFiles",
|
|
|
|
error,
|
|
|
|
NULL,
|
|
|
|
"asb", 1,
|
|
|
|
"systemd-timesyncd.service",
|
|
|
|
false);
|
2012-07-01 17:37:21 +02:00
|
|
|
|
2014-07-09 14:29:20 +02:00
|
|
|
if (r < 0) {
|
2014-10-31 01:32:17 +01:00
|
|
|
if (sd_bus_error_has_name(error, SD_BUS_ERROR_FILE_NOT_FOUND))
|
|
|
|
return sd_bus_error_set_const(error, "org.freedesktop.timedate1.NoNTPSupport", "NTP not supported.");
|
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);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 0;
|
2013-10-16 06:10:04 +02:00
|
|
|
}
|
2011-08-22 01:08:10 +02:00
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2013-10-17 01:03:39 +02:00
|
|
|
static int property_get_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-17 01:03:39 +02:00
|
|
|
|
2013-11-21 19:34:37 +01:00
|
|
|
return sd_bus_message_append(reply, "t", now(CLOCK_REALTIME));
|
2013-10-17 01:03:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int property_get_ntp_sync(
|
|
|
|
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-17 01:03:39 +02:00
|
|
|
|
2013-11-21 19:34:37 +01:00
|
|
|
return sd_bus_message_append(reply, "b", ntp_synced());
|
2013-10-17 01:03:39 +02:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
const char *z;
|
2013-11-07 02:03:10 +01:00
|
|
|
int interactive;
|
2013-10-16 06:10:04 +02:00
|
|
|
char *t;
|
|
|
|
int r;
|
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
|
|
|
|
2014-07-07 11:49:48 +02:00
|
|
|
if (!timezone_is_valid(z))
|
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
|
|
|
|
2013-10-16 06:10:04 +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
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
t = strdup(z);
|
|
|
|
if (!t)
|
2013-11-21 19:34:37 +01:00
|
|
|
return -ENOMEM;
|
2013-03-04 22:35:02 +01:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
free(c->zone);
|
|
|
|
c->zone = t;
|
2013-03-04 22:35:02 +01:00
|
|
|
|
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
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
/* 2. Tell the kernel our timezone */
|
2014-05-22 14:21:38 +02:00
|
|
|
clock_set_timezone(NULL);
|
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
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
/* 3. Sync RTC from system clock, with the new delta */
|
|
|
|
assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
|
|
|
|
assert_se(tm = localtime(&ts.tv_sec));
|
2014-05-24 04:26:33 +02:00
|
|
|
clock_set_hwclock(tm);
|
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,
|
2014-11-28 02:05:14 +01:00
|
|
|
LOG_MESSAGE("Changed time zone to '%s'.", c->zone),
|
2013-10-16 06:10:04 +02:00
|
|
|
NULL);
|
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 */
|
2014-05-22 14:21:38 +02:00
|
|
|
clock_set_timezone(NULL);
|
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
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
/* Sync system clock from RTC; first,
|
|
|
|
* initialize the timezone fields of
|
|
|
|
* struct tm. */
|
|
|
|
if (c->local_rtc)
|
|
|
|
tm = *localtime(&ts.tv_sec);
|
|
|
|
else
|
|
|
|
tm = *gmtime(&ts.tv_sec);
|
2012-09-17 16:41:13 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
/* Override the main fields of
|
|
|
|
* struct tm, but not the timezone
|
|
|
|
* fields */
|
2014-05-24 04:26:33 +02:00
|
|
|
if (clock_get_hwclock(&tm) >= 0) {
|
2011-06-16 21:52:11 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
/* And set the system clock
|
|
|
|
* with this */
|
|
|
|
if (c->local_rtc)
|
|
|
|
ts.tv_sec = mktime(&tm);
|
|
|
|
else
|
|
|
|
ts.tv_sec = timegm(&tm);
|
2011-06-16 21:52:11 +02:00
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
clock_settime(CLOCK_REALTIME, &ts);
|
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
|
|
|
|
2014-05-24 04:26:33 +02:00
|
|
|
clock_set_hwclock(tm);
|
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) {
|
2013-11-07 02:03:10 +01:00
|
|
|
int relative, interactive;
|
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;
|
|
|
|
int r;
|
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
|
|
|
|
2014-05-24 04:38:32 +02:00
|
|
|
if (c->use_ntp)
|
|
|
|
return sd_bus_error_setf(error, BUS_ERROR_AUTOMATIC_TIME_SYNC_ENABLED, "Automatic time synchronization is enabled");
|
|
|
|
|
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)
|
2013-11-21 19:34:37 +01:00
|
|
|
return sd_bus_error_setf(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))
|
2013-11-21 19:34:37 +01:00
|
|
|
return sd_bus_error_setf(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);
|
2014-05-24 04:26:33 +02:00
|
|
|
clock_set_hwclock(tm);
|
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),
|
2014-11-28 02:05:14 +01:00
|
|
|
LOG_MESSAGE("Changed local time to %s", ctime(&ts.tv_sec)),
|
2013-10-16 06:10:04 +02:00
|
|
|
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);
|
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) {
|
2015-03-22 00:21:17 +01:00
|
|
|
int enabled, interactive;
|
2013-10-16 06:10:04 +02:00
|
|
|
Context *c = userdata;
|
|
|
|
int r;
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
assert(m);
|
|
|
|
assert(c);
|
|
|
|
|
2015-03-22 00:21:17 +01:00
|
|
|
r = sd_bus_message_read(m, "bb", &enabled, &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
|
|
|
|
2015-03-22 00:21:17 +01:00
|
|
|
if ((bool)enabled == c->use_ntp)
|
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-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
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
r = context_enable_ntp(sd_bus_message_get_bus(m), error, enabled);
|
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
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
r = context_start_ntp(sd_bus_message_get_bus(m), error, enabled);
|
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
|
|
|
|
2015-03-22 00:21:17 +01:00
|
|
|
c->use_ntp = enabled;
|
2016-07-24 20:12:58 +02:00
|
|
|
log_info("Set NTP to %sd", enable_disable(enabled));
|
2011-06-15 15:37:39 +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", "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),
|
|
|
|
SD_BUS_PROPERTY("CanNTP", "b", bus_property_get_bool, offsetof(Context, can_ntp), 0),
|
|
|
|
SD_BUS_PROPERTY("NTP", "b", bus_property_get_bool, offsetof(Context, use_ntp), 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
|
|
|
|
2013-12-12 20:26:48 +01:00
|
|
|
r = sd_bus_request_name(bus, "org.freedesktop.timedate1", 0);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to register 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
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
*_bus = bus;
|
|
|
|
bus = NULL;
|
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;
|
|
|
|
}
|
|
|
|
|
2013-10-16 06:10:04 +02:00
|
|
|
r = context_read_ntp(&context, bus);
|
|
|
|
if (r < 0) {
|
2014-11-28 13:19:16 +01:00
|
|
|
log_error_errno(r, "Failed to determine whether NTP is enabled: %m");
|
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;
|
|
|
|
}
|