/* SPDX-License-Identifier: LGPL-2.1+ */
#include <errno.h>
-#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
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, "masked", "masked-runtime", "disabled", "bad");
-
- return count;
-}
-
static int context_ntp_service_exists(Context *c) {
UnitStatusInfo *info;
int count = 0;
static int context_write_data_timezone(Context *c) {
_cleanup_free_ char *p = NULL;
+ const char *source;
assert(c);
- if (isempty(c->zone)) {
- if (unlink("/etc/localtime") < 0 && errno != ENOENT)
- return -errno;
- return 0;
- }
+ /* No timezone is very similar to UTC. Hence in either of these cases link the UTC file in. Except if
+ * it isn't installed, in which case we remove the symlink altogether. Since glibc defaults to an
+ * internal version of UTC in that case behaviour is mostly equivalent. We still prefer creating the
+ * symlink though, since things are more self explanatory then. */
- p = path_join("../usr/share/zoneinfo", c->zone);
- if (!p)
- return log_oom();
+ if (isempty(c->zone) || streq(c->zone, "UTC")) {
+
+ if (access("/usr/share/zoneinfo/UTC", F_OK) < 0) {
+
+ if (unlink("/etc/localtime") < 0 && errno != ENOENT)
+ return -errno;
+
+ return 0;
+ }
+
+ source = "../usr/share/zoneinfo/UTC";
+ } else {
+ p = path_join("../usr/share/zoneinfo", c->zone);
+ if (!p)
+ return -ENOMEM;
- return symlink_atomic(p, "/etc/localtime");
+ source = p;
+ }
+
+ return symlink_atomic(source, "/etc/localtime");
}
static int context_write_data_local_rtc(Context *c) {
return r;
if (!timezone_is_valid(z, LOG_DEBUG))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid time zone '%s'", z);
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid or not installed time zone '%s'", z);
if (streq_ptr(z, c->zone))
return sd_bus_reply_method_return(m, NULL);
return r;
}
- if (!enable)
+ 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;
- }
+ bool enable_this_one = !selected;
- 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);
+ r = unit_enable_or_disable(u, bus, error, enable_this_one);
if (r < 0)
- continue;
+ /* If enablement failed, don't start this unit. */
+ enable_this_one = false;
- r = unit_start_or_stop(u, bus, error, enable);
- selected = u;
- break;
+ r = unit_start_or_stop(u, bus, error, enable_this_one);
+ if (r < 0)
+ log_unit_warning_errno(u, r, "Failed to %s %sd NTP unit, ignoring: %m",
+ enable_this_one ? "start" : "stop",
+ enable_disable(enable_this_one));
+ if (enable_this_one)
+ selected = u;
}
-
else
LIST_FOREACH(units, u, c->units) {
- if (!streq(u->load_state, "loaded") ||
- !streq(u->unit_file_state, "enabled"))
+ if (!streq(u->load_state, "loaded"))
continue;
- r = unit_start_or_stop(u, bus, error, enable);
- selected = u;
- break;
+ q = unit_enable_or_disable(u, bus, error, false);
+ if (q < 0)
+ r = q;
+
+ q = unit_start_or_stop(u, bus, error, false);
+ if (q < 0)
+ r = q;
}
if (r < 0)