#include "io-util.h"
#include "label.h"
#include "locale-setup.h"
+#include "load-fragment.h"
#include "log.h"
#include "macro.h"
#include "manager.h"
static int manager_dispatch_timezone_change(sd_event_source *source, const struct inotify_event *event, void *userdata);
static int manager_run_environment_generators(Manager *m);
static int manager_run_generators(Manager *m);
+static void manager_vacuum(Manager *m);
static usec_t manager_watch_jobs_next_time(Manager *m) {
return usec_add(now(CLOCK_MONOTONIC),
}
}
-void manager_flip_auto_status(Manager *m, bool enable, const char *reason) {
+static void manager_flip_auto_status(Manager *m, bool enable, const char *reason) {
assert(m);
if (enable) {
/* Let's remove some environment variables that we need ourselves to communicate with our clients */
strv_env_unset_many(
l,
+ "CACHE_DIRECTORY",
+ "CONFIGURATION_DIRECTORY",
"EXIT_CODE",
"EXIT_STATUS",
"INVOCATION_ID",
"LISTEN_FDNAMES",
"LISTEN_FDS",
"LISTEN_PID",
+ "LOGS_DIRECTORY",
"MAINPID",
"MANAGERPID",
"NOTIFY_SOCKET",
"PIDFILE",
"REMOTE_ADDR",
"REMOTE_PORT",
+ "RUNTIME_DIRECTORY",
"SERVICE_RESULT",
+ "STATE_DIRECTORY",
"WATCHDOG_PID",
"WATCHDOG_USEC",
NULL);
[EXEC_DIRECTORY_CONFIGURATION] = { SD_PATH_USER_CONFIGURATION, NULL },
};
- const struct table_entry *p;
- ExecDirectoryType i;
- int r;
-
assert(m);
- if (MANAGER_IS_SYSTEM(m))
- p = paths_system;
- else
- p = paths_user;
+ const struct table_entry *p = MANAGER_IS_SYSTEM(m) ? paths_system : paths_user;
+ int r;
- for (i = 0; i < _EXEC_DIRECTORY_TYPE_MAX; i++) {
+ for (ExecDirectoryType i = 0; i < _EXEC_DIRECTORY_TYPE_MAX; i++) {
r = sd_path_lookup(p[i].type, p[i].suffix, &m->prefix[i]);
if (r < 0)
return r;
static void manager_free_unit_name_maps(Manager *m) {
m->unit_id_map = hashmap_free(m->unit_id_map);
m->unit_name_map = hashmap_free(m->unit_name_map);
- m->unit_path_cache = set_free_free(m->unit_path_cache);
+ m->unit_path_cache = set_free(m->unit_path_cache);
m->unit_cache_mtime = 0;
}
.original_log_level = -1,
.original_log_target = _LOG_TARGET_INVALID,
+ .watchdog_overridden[WATCHDOG_RUNTIME] = USEC_INFINITY,
+ .watchdog_overridden[WATCHDOG_REBOOT] = USEC_INFINITY,
+ .watchdog_overridden[WATCHDOG_KEXEC] = USEC_INFINITY,
+
+ .show_status_overridden = _SHOW_STATUS_INVALID,
+
.notify_fd = -1,
.cgroups_agent_fd = -1,
.signal_fd = -1,
if (r < 0)
return r;
- r = hashmap_ensure_allocated(&m->jobs, NULL);
- if (r < 0)
- return r;
-
r = hashmap_ensure_allocated(&m->cgroup_unit, &path_hash_ops);
if (r < 0)
return r;
}
Manager* manager_free(Manager *m) {
- ExecDirectoryType dt;
- UnitType c;
-
if (!m)
return NULL;
manager_clear_jobs_and_units(m);
- for (c = 0; c < _UNIT_TYPE_MAX; c++)
+ for (UnitType c = 0; c < _UNIT_TYPE_MAX; c++)
if (unit_vtable[c]->shutdown)
unit_vtable[c]->shutdown(m);
hashmap_free(m->uid_refs);
hashmap_free(m->gid_refs);
- for (dt = 0; dt < _EXEC_DIRECTORY_TYPE_MAX; dt++)
+ for (ExecDirectoryType dt = 0; dt < _EXEC_DIRECTORY_TYPE_MAX; dt++)
m->prefix[dt] = mfree(m->prefix[dt]);
return mfree(m);
}
static void manager_enumerate_perpetual(Manager *m) {
- UnitType c;
-
assert(m);
if (m->test_run_flags == MANAGER_TEST_RUN_MINIMAL)
return;
/* Let's ask every type to load all units from disk/kernel that it might know */
- for (c = 0; c < _UNIT_TYPE_MAX; c++) {
+ for (UnitType c = 0; c < _UNIT_TYPE_MAX; c++) {
if (!unit_type_supported(c)) {
log_debug("Unit type .%s is not supported on this system.", unit_type_to_string(c));
continue;
}
static void manager_enumerate(Manager *m) {
- UnitType c;
-
assert(m);
if (m->test_run_flags == MANAGER_TEST_RUN_MINIMAL)
return;
/* Let's ask every type to load all units from disk/kernel that it might know */
- for (c = 0; c < _UNIT_TYPE_MAX; c++) {
+ for (UnitType c = 0; c < _UNIT_TYPE_MAX; c++) {
if (!unit_type_supported(c)) {
log_debug("Unit type .%s is not supported on this system.", unit_type_to_string(c));
continue;
log_info("Populated /etc with preset unit settings.");
}
-static void manager_vacuum(Manager *m) {
- assert(m);
-
- /* Release any dynamic users no longer referenced */
- dynamic_user_vacuum(m, true);
-
- /* Release any references to UIDs/GIDs no longer referenced, and destroy any IPC owned by them */
- manager_vacuum_uid_refs(m);
- manager_vacuum_gid_refs(m);
-
- /* Release any runtimes no longer referenced */
- exec_runtime_vacuum(m);
-}
-
static void manager_ready(Manager *m) {
assert(m);
return n;
}
+bool manager_unit_file_maybe_loadable_from_cache(Unit *u) {
+ assert(u);
+
+ if (u->load_state != UNIT_NOT_FOUND)
+ return false;
+
+ if (u->manager->unit_cache_mtime == 0)
+ return false;
+
+ if (u->manager->unit_cache_mtime > u->fragment_loadtime)
+ return true;
+
+ return !lookup_paths_mtime_good(&u->manager->lookup_paths, u->manager->unit_cache_mtime);
+}
+
int manager_load_unit_prepare(
Manager *m,
const char *name,
int r;
assert(m);
- assert(name || path);
assert(_ret);
/* This will prepare the unit for loading, but not actually
if (path && !is_path(path))
return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not absolute.", path);
- if (!name)
+ if (!name) {
+ /* 'name' and 'path' must not both be null. Check here 'path' using assert_se() to
+ * workaround a bug in gcc that generates a -Wnonnull warning when calling basename(),
+ * but this cannot be possible in any code path (See #6119). */
+ assert_se(path);
name = basename(path);
+ }
t = unit_name_to_type(name);
ret = manager_get_unit(m, name);
if (ret) {
- *_ret = ret;
- return 1;
+ /* The time-based cache allows to start new units without daemon-reload,
+ * but if they are already referenced (because of dependencies or ordering)
+ * then we have to force a load of the fragment. As an optimization, check
+ * first if anything in the usual paths was modified since the last time
+ * the cache was loaded. Also check if the last time an attempt to load the
+ * unit was made was before the most recent cache refresh, so that we know
+ * we need to try again - even if the cache is current, it might have been
+ * updated in a different context before we had a chance to retry loading
+ * this particular unit. */
+ if (manager_unit_file_maybe_loadable_from_cache(ret))
+ ret->load_state = UNIT_STUB;
+ else {
+ *_ret = ret;
+ return 1;
+ }
+ } else {
+ ret = cleanup_ret = unit_new(m, unit_vtable[t]->object_size);
+ if (!ret)
+ return -ENOMEM;
}
- ret = cleanup_ret = unit_new(m, unit_vtable[t]->object_size);
- if (!ret)
- return -ENOMEM;
-
if (path) {
- ret->fragment_path = strdup(path);
- if (!ret->fragment_path)
- return -ENOMEM;
+ r = free_and_strdup(&ret->fragment_path, path);
+ if (r < 0)
+ return r;
}
r = unit_add_name(ret, name);
return 0;
}
-static bool manager_process_barrier_fd(const char *buf, FDSet *fds) {
- assert(buf);
+static bool manager_process_barrier_fd(char * const *tags, FDSet *fds) {
/* nothing else must be sent when using BARRIER=1 */
- if (STR_IN_SET(buf, "BARRIER=1", "BARRIER=1\n")) {
- if (fdset_size(fds) != 1)
- log_warning("Got incorrect number of fds with BARRIER=1, closing them.");
+ if (strv_contains(tags, "BARRIER=1")) {
+ if (strv_length(tags) == 1) {
+ if (fdset_size(fds) != 1)
+ log_warning("Got incorrect number of fds with BARRIER=1, closing them.");
+ } else
+ log_warning("Extra notification messages sent with BARRIER=1, ignoring everything.");
+
+ /* Drop the message if BARRIER=1 was found */
return true;
- } else if (startswith(buf, "BARRIER=1\n") || strstr(buf, "\nBARRIER=1\n") || endswith(buf, "\nBARRIER=1"))
- log_warning("Extra notification messages sent with BARRIER=1, ignoring everything.");
+ }
return false;
}
Manager *m,
Unit *u,
const struct ucred *ucred,
- const char *buf,
+ char * const *tags,
FDSet *fds) {
assert(m);
assert(u);
assert(ucred);
- assert(buf);
+ assert(tags);
if (u->notifygen == m->notifygen) /* Already invoked on this same unit in this same iteration? */
return;
u->notifygen = m->notifygen;
- if (UNIT_VTABLE(u)->notify_message) {
- _cleanup_strv_free_ char **tags = NULL;
-
- tags = strv_split(buf, NEWLINE);
- if (!tags) {
- log_oom();
- return;
- }
-
+ if (UNIT_VTABLE(u)->notify_message)
UNIT_VTABLE(u)->notify_message(u, ucred, tags, fds);
- } else if (DEBUG_LOGGING) {
- _cleanup_free_ char *x = NULL, *y = NULL;
+ else if (DEBUG_LOGGING) {
+ _cleanup_free_ char *buf = NULL, *x = NULL, *y = NULL;
- x = ellipsize(buf, 20, 90);
+ buf = strv_join(tags, ", ");
+ if (buf)
+ x = ellipsize(buf, 20, 90);
if (x)
y = cescape(x);
.iov_base = buf,
.iov_len = sizeof(buf)-1,
};
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
- CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)];
- } control = {};
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred)) +
+ CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)) control;
struct msghdr msghdr = {
.msg_iov = &iovec,
.msg_iovlen = 1,
struct cmsghdr *cmsg;
struct ucred *ucred = NULL;
_cleanup_free_ Unit **array_copy = NULL;
+ _cleanup_strv_free_ char **tags = NULL;
Unit *u1, *u2, **array;
int r, *fd_array = NULL;
size_t n_fds = 0;
return 0;
}
- /* Make sure it's NUL-terminated. */
+ /* Make sure it's NUL-terminated, then parse it to obtain the tags list */
buf[n] = 0;
+ tags = strv_split_newlines(buf);
+ if (!tags) {
+ log_oom();
+ return 0;
+ }
/* possibly a barrier fd, let's see */
- if (manager_process_barrier_fd(buf, fds))
+ if (manager_process_barrier_fd(tags, fds))
return 0;
/* Increase the generation counter used for filtering out duplicate unit invocations. */
/* And now invoke the per-unit callbacks. Note that manager_invoke_notify_message() will handle duplicate units
* make sure we only invoke each unit's handler once. */
if (u1) {
- manager_invoke_notify_message(m, u1, ucred, buf, fds);
+ manager_invoke_notify_message(m, u1, ucred, tags, fds);
found = true;
}
if (u2) {
- manager_invoke_notify_message(m, u2, ucred, buf, fds);
+ manager_invoke_notify_message(m, u2, ucred, tags, fds);
found = true;
}
if (array_copy)
for (size_t i = 0; array_copy[i]; i++) {
- manager_invoke_notify_message(m, array_copy[i], ucred, buf, fds);
+ manager_invoke_notify_message(m, array_copy[i], ucred, tags, fds);
found = true;
}
switch (sfsi.ssi_signo - SIGRTMIN) {
case 20:
- manager_set_show_status(m, SHOW_STATUS_YES, "signal");
+ manager_override_show_status(m, SHOW_STATUS_YES, "signal");
break;
case 21:
- manager_set_show_status(m, SHOW_STATUS_NO, "signal");
+ manager_override_show_status(m, SHOW_STATUS_NO, "signal");
break;
case 22:
static int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t usec, void *userdata) {
Manager *m = userdata;
int r;
- uint64_t next;
assert(m);
assert(source);
manager_print_jobs_in_progress(m);
- next = now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_PERIOD_USEC;
- r = sd_event_source_set_time(source, next);
+ r = sd_event_source_set_time_relative(source, JOBS_IN_PROGRESS_PERIOD_USEC);
if (r < 0)
return r;
return log_error_errno(r, "Failed to enable SIGCHLD event source: %m");
while (m->objective == MANAGER_OK) {
- usec_t wait_usec;
+ usec_t wait_usec, watchdog_usec;
- if (timestamp_is_set(m->runtime_watchdog) && MANAGER_IS_SYSTEM(m))
+ watchdog_usec = manager_get_watchdog(m, WATCHDOG_RUNTIME);
+ if (timestamp_is_set(watchdog_usec))
watchdog_ping();
if (!ratelimit_below(&rl)) {
continue;
/* Sleep for watchdog runtime wait time */
- if (MANAGER_IS_SYSTEM(m))
+ if (timestamp_is_set(watchdog_usec))
wait_usec = watchdog_runtime_wait();
else
wait_usec = USEC_INFINITY;
MANAGER_TIMESTAMP_UNITS_LOAD_START, MANAGER_TIMESTAMP_UNITS_LOAD_FINISH);
}
+#define DESTROY_IPC_FLAG (UINT32_C(1) << 31)
+
+static void manager_serialize_uid_refs_internal(
+ Manager *m,
+ FILE *f,
+ Hashmap **uid_refs,
+ const char *field_name) {
+
+ Iterator i;
+ void *p, *k;
+
+ assert(m);
+ assert(f);
+ assert(uid_refs);
+ assert(field_name);
+
+ /* Serialize the UID reference table. Or actually, just the IPC destruction flag of it, as
+ * the actual counter of it is better rebuild after a reload/reexec. */
+
+ HASHMAP_FOREACH_KEY(p, k, *uid_refs, i) {
+ uint32_t c;
+ uid_t uid;
+
+ uid = PTR_TO_UID(k);
+ c = PTR_TO_UINT32(p);
+
+ if (!(c & DESTROY_IPC_FLAG))
+ continue;
+
+ (void) serialize_item_format(f, field_name, UID_FMT, uid);
+ }
+}
+
+static void manager_serialize_uid_refs(Manager *m, FILE *f) {
+ manager_serialize_uid_refs_internal(m, f, &m->uid_refs, "destroy-ipc-uid");
+}
+
+static void manager_serialize_gid_refs(Manager *m, FILE *f) {
+ manager_serialize_uid_refs_internal(m, f, &m->gid_refs, "destroy-ipc-gid");
+}
+
int manager_serialize(
Manager *m,
FILE *f,
/* After switching root, udevd has not been started yet. So, enumeration results should not be emitted. */
(void) serialize_bool(f, "honor-device-enumeration", !switching_root);
- t = show_status_to_string(m->show_status);
- if (t)
- (void) serialize_item(f, "show-status", t);
+ if (m->show_status_overridden != _SHOW_STATUS_INVALID)
+ (void) serialize_item(f, "show-status-overridden",
+ show_status_to_string(m->show_status_overridden));
if (m->log_level_overridden)
(void) serialize_item_format(f, "log-level-override", "%i", log_get_max_level());
if (m->log_target_overridden)
(void) serialize_item(f, "log-target-override", log_target_to_string(log_get_target()));
+ (void) serialize_usec(f, "runtime-watchdog-overridden", m->watchdog_overridden[WATCHDOG_RUNTIME]);
+ (void) serialize_usec(f, "reboot-watchdog-overridden", m->watchdog_overridden[WATCHDOG_REBOOT]);
+ (void) serialize_usec(f, "kexec-watchdog-overridden", m->watchdog_overridden[WATCHDOG_KEXEC]);
+
for (q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) {
_cleanup_free_ char *joined = NULL;
return 0;
}
+usec_t manager_get_watchdog(Manager *m, WatchdogType t) {
+ assert(m);
+
+ if (MANAGER_IS_USER(m))
+ return USEC_INFINITY;
+
+ if (timestamp_is_set(m->watchdog_overridden[t]))
+ return m->watchdog_overridden[t];
+
+ return m->watchdog[t];
+}
+
+void manager_set_watchdog(Manager *m, WatchdogType t, usec_t timeout) {
+ int r = 0;
+
+ assert(m);
+
+ if (MANAGER_IS_USER(m))
+ return;
+
+ if (m->watchdog[t] == timeout)
+ return;
+
+ if (t == WATCHDOG_RUNTIME)
+ if (!timestamp_is_set(m->watchdog_overridden[WATCHDOG_RUNTIME])) {
+ if (timestamp_is_set(timeout))
+ r = watchdog_set_timeout(&timeout);
+ else
+ watchdog_close(true);
+ }
+
+ if (r >= 0)
+ m->watchdog[t] = timeout;
+}
+
+int manager_override_watchdog(Manager *m, WatchdogType t, usec_t timeout) {
+ int r = 0;
+
+ assert(m);
+
+ if (MANAGER_IS_USER(m))
+ return 0;
+
+ if (m->watchdog_overridden[t] == timeout)
+ return 0;
+
+ if (t == WATCHDOG_RUNTIME) {
+ usec_t *p;
+
+ p = timestamp_is_set(timeout) ? &timeout : &m->watchdog[t];
+ if (timestamp_is_set(*p))
+ r = watchdog_set_timeout(p);
+ else
+ watchdog_close(true);
+ }
+
+ if (r >= 0)
+ m->watchdog_overridden[t] = timeout;
+
+ return 0;
+}
+
+static void manager_deserialize_uid_refs_one_internal(
+ Manager *m,
+ Hashmap** uid_refs,
+ const char *value) {
+
+ uid_t uid;
+ uint32_t c;
+ int r;
+
+ assert(m);
+ assert(uid_refs);
+ assert(value);
+
+ r = parse_uid(value, &uid);
+ if (r < 0 || uid == 0) {
+ log_debug("Unable to parse UID reference serialization: " UID_FMT, uid);
+ return;
+ }
+
+ r = hashmap_ensure_allocated(uid_refs, &trivial_hash_ops);
+ if (r < 0) {
+ log_oom();
+ return;
+ }
+
+ c = PTR_TO_UINT32(hashmap_get(*uid_refs, UID_TO_PTR(uid)));
+ if (c & DESTROY_IPC_FLAG)
+ return;
+
+ c |= DESTROY_IPC_FLAG;
+
+ r = hashmap_replace(*uid_refs, UID_TO_PTR(uid), UINT32_TO_PTR(c));
+ if (r < 0) {
+ log_debug_errno(r, "Failed to add UID reference entry: %m");
+ return;
+ }
+}
+
+static void manager_deserialize_uid_refs_one(Manager *m, const char *value) {
+ manager_deserialize_uid_refs_one_internal(m, &m->uid_refs, value);
+}
+
+static void manager_deserialize_gid_refs_one(Manager *m, const char *value) {
+ manager_deserialize_uid_refs_one_internal(m, &m->gid_refs, value);
+}
+
int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
int r = 0;
else
m->honor_device_enumeration = b;
- } else if ((val = startswith(l, "show-status="))) {
+ } else if ((val = startswith(l, "show-status-overridden="))) {
ShowStatus s;
s = show_status_from_string(val);
if (s < 0)
- log_notice("Failed to parse show-status flag '%s', ignoring.", val);
+ log_notice("Failed to parse show-status-overridden flag '%s', ignoring.", val);
else
- manager_set_show_status(m, s, "deserialization");
+ manager_override_show_status(m, s, "deserialize");
} else if ((val = startswith(l, "log-level-override="))) {
int level;
else
manager_override_log_target(m, target);
+ } else if ((val = startswith(l, "runtime-watchdog-overridden="))) {
+ usec_t t;
+
+ if (deserialize_usec(val, &t) < 0)
+ log_notice("Failed to parse runtime-watchdog-overridden value '%s', ignoring.", val);
+ else
+ manager_override_watchdog(m, WATCHDOG_RUNTIME, t);
+
+ } else if ((val = startswith(l, "reboot-watchdog-overridden="))) {
+ usec_t t;
+
+ if (deserialize_usec(val, &t) < 0)
+ log_notice("Failed to parse reboot-watchdog-overridden value '%s', ignoring.", val);
+ else
+ manager_override_watchdog(m, WATCHDOG_REBOOT, t);
+
+ } else if ((val = startswith(l, "kexec-watchdog-overridden="))) {
+ usec_t t;
+
+ if (deserialize_usec(val, &t) < 0)
+ log_notice("Failed to parse kexec-watchdog-overridden value '%s', ignoring.", val);
+ else
+ manager_override_watchdog(m, WATCHDOG_KEXEC, t);
+
} else if (startswith(l, "env=")) {
r = deserialize_environment(l + 4, &m->client_environment);
if (r < 0)
else if ((val = startswith(l, "destroy-ipc-gid=")))
manager_deserialize_gid_refs_one(m, val);
else if ((val = startswith(l, "exec-runtime=")))
- exec_runtime_deserialize_one(m, val, fds);
+ (void) exec_runtime_deserialize_one(m, val, fds);
else if ((val = startswith(l, "subscribed="))) {
if (strv_extend(&m->deserialized_subscribed, val) < 0)
return;
}
+ /* The jobs hashmap tends to grow a lot during boot, and then it's not reused until shutdown. Let's
+ kill the hashmap if it is relatively large. */
+ if (hashmap_buckets(m->jobs) > hashmap_size(m->units) / 10)
+ m->jobs = hashmap_free(m->jobs);
+
manager_flip_auto_status(m, false, "boot finished");
/* Notify Type=idle units that we are done now */
log_open();
}
+static ShowStatus manager_get_show_status(Manager *m) {
+ assert(m);
+
+ if (MANAGER_IS_USER(m))
+ return _SHOW_STATUS_INVALID;
+
+ if (m->show_status_overridden != _SHOW_STATUS_INVALID)
+ return m->show_status_overridden;
+
+ return m->show_status;
+}
+
+bool manager_get_show_status_on(Manager *m) {
+ assert(m);
+
+ return show_status_on(manager_get_show_status(m));
+}
+
+static void set_show_status_marker(bool b) {
+ if (b)
+ (void) touch("/run/systemd/show-status");
+ else
+ (void) unlink("/run/systemd/show-status");
+}
+
void manager_set_show_status(Manager *m, ShowStatus mode, const char *reason) {
assert(m);
+ assert(reason);
assert(mode >= 0 && mode < _SHOW_STATUS_MAX);
- if (!MANAGER_IS_SYSTEM(m))
+ if (MANAGER_IS_USER(m))
return;
if (mode == m->show_status)
return;
- bool enabled = IN_SET(mode, SHOW_STATUS_TEMPORARY, SHOW_STATUS_YES);
- log_debug("%s (%s) showing of status (%s).",
- enabled ? "Enabling" : "Disabling",
- strna(show_status_to_string(mode)),
- reason);
- m->show_status = mode;
+ if (m->show_status_overridden == _SHOW_STATUS_INVALID) {
+ bool enabled;
- if (enabled)
- (void) touch("/run/systemd/show-status");
- else
- (void) unlink("/run/systemd/show-status");
+ enabled = show_status_on(mode);
+ log_debug("%s (%s) showing of status (%s).",
+ enabled ? "Enabling" : "Disabling",
+ strna(show_status_to_string(mode)),
+ reason);
+
+ set_show_status_marker(enabled);
+ }
+
+ m->show_status = mode;
}
-static bool manager_get_show_status(Manager *m, StatusType type) {
+void manager_override_show_status(Manager *m, ShowStatus mode, const char *reason) {
assert(m);
+ assert(mode < _SHOW_STATUS_MAX);
- if (!MANAGER_IS_SYSTEM(m))
- return false;
+ if (MANAGER_IS_USER(m))
+ return;
- if (m->no_console_output)
- return false;
+ if (mode == m->show_status_overridden)
+ return;
- if (!IN_SET(manager_state(m), MANAGER_INITIALIZING, MANAGER_STARTING, MANAGER_STOPPING))
- return false;
+ m->show_status_overridden = mode;
- /* If we cannot find out the status properly, just proceed. */
- if (type != STATUS_TYPE_EMERGENCY && manager_check_ask_password(m) > 0)
- return false;
+ if (mode == _SHOW_STATUS_INVALID)
+ mode = m->show_status;
- if (type == STATUS_TYPE_NOTICE && m->show_status != SHOW_STATUS_NO)
- return true;
+ log_debug("%s (%s) showing of status (%s).",
+ m->show_status_overridden != _SHOW_STATUS_INVALID ? "Overriding" : "Restoring",
+ strna(show_status_to_string(mode)),
+ reason);
- return show_status_on(m->show_status);
+ set_show_status_marker(show_status_on(mode));
}
const char *manager_get_confirm_spawn(Manager *m) {
return access("/run/systemd/confirm_spawn_disabled", F_OK) >= 0;
}
+static bool manager_should_show_status(Manager *m, StatusType type) {
+ assert(m);
+
+ if (!MANAGER_IS_SYSTEM(m))
+ return false;
+
+ if (m->no_console_output)
+ return false;
+
+ if (!IN_SET(manager_state(m), MANAGER_INITIALIZING, MANAGER_STARTING, MANAGER_STOPPING))
+ return false;
+
+ /* If we cannot find out the status properly, just proceed. */
+ if (type != STATUS_TYPE_EMERGENCY && manager_check_ask_password(m) > 0)
+ return false;
+
+ if (type == STATUS_TYPE_NOTICE && m->show_status != SHOW_STATUS_NO)
+ return true;
+
+ return manager_get_show_status_on(m);
+}
+
void manager_status_printf(Manager *m, StatusType type, const char *status, const char *format, ...) {
va_list ap;
/* If m is NULL, assume we're after shutdown and let the messages through. */
- if (m && !manager_get_show_status(m, type))
+ if (m && !manager_should_show_status(m, type))
return;
/* XXX We should totally drop the check for ephemeral here
size = set_size(m->failed_units);
if (failed) {
- r = set_ensure_allocated(&m->failed_units, NULL);
+ r = set_ensure_put(&m->failed_units, NULL, u);
if (r < 0)
return log_oom();
-
- if (set_put(m->failed_units, u) < 0)
- return log_oom();
} else
(void) set_remove(m->failed_units, u);
return MANAGER_RUNNING;
}
-#define DESTROY_IPC_FLAG (UINT32_C(1) << 31)
-
static void manager_unref_uid_internal(
Manager *m,
Hashmap **uid_refs,
}
}
-void manager_vacuum_uid_refs(Manager *m) {
+static void manager_vacuum_uid_refs(Manager *m) {
manager_vacuum_uid_refs_internal(m, &m->uid_refs, clean_ipc_by_uid);
}
-void manager_vacuum_gid_refs(Manager *m) {
+static void manager_vacuum_gid_refs(Manager *m) {
manager_vacuum_uid_refs_internal(m, &m->gid_refs, clean_ipc_by_gid);
}
-static void manager_serialize_uid_refs_internal(
- Manager *m,
- FILE *f,
- Hashmap **uid_refs,
- const char *field_name) {
-
- Iterator i;
- void *p, *k;
-
- assert(m);
- assert(f);
- assert(uid_refs);
- assert(field_name);
-
- /* Serialize the UID reference table. Or actually, just the IPC destruction flag of it, as the actual counter
- * of it is better rebuild after a reload/reexec. */
-
- HASHMAP_FOREACH_KEY(p, k, *uid_refs, i) {
- uint32_t c;
- uid_t uid;
-
- uid = PTR_TO_UID(k);
- c = PTR_TO_UINT32(p);
-
- if (!(c & DESTROY_IPC_FLAG))
- continue;
-
- (void) serialize_item_format(f, field_name, UID_FMT, uid);
- }
-}
-
-void manager_serialize_uid_refs(Manager *m, FILE *f) {
- manager_serialize_uid_refs_internal(m, f, &m->uid_refs, "destroy-ipc-uid");
-}
-
-void manager_serialize_gid_refs(Manager *m, FILE *f) {
- manager_serialize_uid_refs_internal(m, f, &m->gid_refs, "destroy-ipc-gid");
-}
-
-static void manager_deserialize_uid_refs_one_internal(
- Manager *m,
- Hashmap** uid_refs,
- const char *value) {
-
- uid_t uid;
- uint32_t c;
- int r;
-
+static void manager_vacuum(Manager *m) {
assert(m);
- assert(uid_refs);
- assert(value);
-
- r = parse_uid(value, &uid);
- if (r < 0 || uid == 0) {
- log_debug("Unable to parse UID reference serialization: " UID_FMT, uid);
- return;
- }
-
- r = hashmap_ensure_allocated(uid_refs, &trivial_hash_ops);
- if (r < 0) {
- log_oom();
- return;
- }
-
- c = PTR_TO_UINT32(hashmap_get(*uid_refs, UID_TO_PTR(uid)));
- if (c & DESTROY_IPC_FLAG)
- return;
- c |= DESTROY_IPC_FLAG;
-
- r = hashmap_replace(*uid_refs, UID_TO_PTR(uid), UINT32_TO_PTR(c));
- if (r < 0) {
- log_debug_errno(r, "Failed to add UID reference entry: %m");
- return;
- }
-}
+ /* Release any dynamic users no longer referenced */
+ dynamic_user_vacuum(m, true);
-void manager_deserialize_uid_refs_one(Manager *m, const char *value) {
- manager_deserialize_uid_refs_one_internal(m, &m->uid_refs, value);
-}
+ /* Release any references to UIDs/GIDs no longer referenced, and destroy any IPC owned by them */
+ manager_vacuum_uid_refs(m);
+ manager_vacuum_gid_refs(m);
-void manager_deserialize_gid_refs_one(Manager *m, const char *value) {
- manager_deserialize_uid_refs_one_internal(m, &m->gid_refs, value);
+ /* Release any runtimes no longer referenced */
+ exec_runtime_vacuum(m);
}
int manager_dispatch_user_lookup_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {