#include "clean-ipc.h"
#include "clock-util.h"
#include "core-varlink.h"
+#include "creds-util.h"
#include "dbus-job.h"
#include "dbus-manager.h"
#include "dbus-unit.h"
#include "install.h"
#include "io-util.h"
#include "label.h"
-#include "locale-setup.h"
#include "load-fragment.h"
+#include "locale-setup.h"
#include "log.h"
#include "macro.h"
#include "manager.h"
#include "transaction.h"
#include "umask-util.h"
#include "unit-name.h"
+#include "unit-serialize.h"
#include "user-util.h"
#include "virt.h"
#include "watchdog.h"
SIGCHLD, /* Child died */
SIGTERM, /* Reexecute daemon */
SIGHUP, /* Reload configuration */
- SIGUSR1, /* systemd/upstart: reconnect to D-Bus */
+ SIGUSR1, /* systemd: reconnect to D-Bus */
SIGUSR2, /* systemd: dump status */
SIGINT, /* Kernel sends us this on control-alt-del */
SIGWINCH, /* Kernel sends us this on kbrequest (alt-arrowup) */
/* Import locale variables LC_*= from configuration */
(void) locale_setup(&m->transient_environment);
} else {
- _cleanup_free_ char *k = NULL;
-
- /* The user manager passes its own environment
- * along to its children, except for $PATH. */
+ /* The user manager passes its own environment along to its children, except for $PATH. */
m->transient_environment = strv_copy(environ);
if (!m->transient_environment)
return log_oom();
- k = strdup("PATH=" DEFAULT_USER_PATH);
- if (!k)
- return log_oom();
-
- r = strv_env_replace(&m->transient_environment, k);
+ r = strv_env_replace_strdup(&m->transient_environment, "PATH=" DEFAULT_USER_PATH);
if (r < 0)
return log_oom();
- TAKE_PTR(k);
}
sanitize_environment(m->transient_environment);
if (r < 0)
return r;
- e = secure_getenv("CREDENTIALS_DIRECTORY");
- if (e) {
+ r = get_credentials_dir(&e);
+ if (r >= 0) {
m->received_credentials = strdup(e);
if (!m->received_credentials)
return -ENOMEM;
is_bad = false;
}
- if (u->refs_by_target) {
- const UnitRef *ref;
-
- LIST_FOREACH(refs_by_target, ref, u->refs_by_target) {
- unit_gc_sweep(ref->source, gc_marker);
+ const UnitRef *ref;
+ LIST_FOREACH(refs_by_target, ref, u->refs_by_target) {
+ unit_gc_sweep(ref->source, gc_marker);
- if (ref->source->gc_marker == gc_marker + GC_OFFSET_GOOD)
- goto good;
+ if (ref->source->gc_marker == gc_marker + GC_OFFSET_GOOD)
+ goto good;
- if (ref->source->gc_marker != gc_marker + GC_OFFSET_BAD)
- is_bad = false;
- }
+ if (ref->source->gc_marker != gc_marker + GC_OFFSET_BAD)
+ is_bad = false;
}
if (is_bad)
assert(mode < _JOB_MODE_MAX);
if (mode == JOB_ISOLATE && type != JOB_START)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Isolate is only valid for start.");
+ return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Isolate is only valid for start.");
if (mode == JOB_ISOLATE && !unit->allow_isolate)
- return sd_bus_error_setf(error, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
+ return sd_bus_error_set(error, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
if (mode == JOB_TRIGGERING && type != JOB_STOP)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "--job-mode=triggering is only valid for stop.");
+ return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "--job-mode=triggering is only valid for stop.");
log_unit_debug(unit, "Trying to enqueue job %s/%s/%s", unit->id, job_type_to_string(type), job_mode_to_string(mode));
/* When we are reloading, let's not wait with generating signals, since we need to exit the manager as quickly
* as we can. There's no point in throttling generation of signals in that case. */
if (MANAGER_IS_RELOADING(m) || m->send_reloading_done || m->pending_reload_message)
- budget = (unsigned) -1; /* infinite budget in this case */
+ budget = UINT_MAX; /* infinite budget in this case */
else {
/* Anything to do at all? */
if (!m->dbus_unit_queue && !m->dbus_job_queue)
bus_unit_send_change_signal(u);
n++;
- if (budget != (unsigned) -1)
+ if (budget != UINT_MAX)
budget--;
}
bus_job_send_change_signal(j);
n++;
- if (budget != (unsigned) -1)
+ if (budget != UINT_MAX)
budget--;
}
n = recvmsg_safe(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC|MSG_TRUNC);
if (IN_SET(n, -EAGAIN, -EINTR))
return 0; /* Spurious wakeup, try again */
+ if (n == -EXFULL) {
+ log_warning("Got message with truncated control data (too many fds sent?), ignoring.");
+ return 0;
+ }
if (n < 0)
/* If this is any other, real error, then let's stop processing this socket. This of course
* means we won't take notification messages anymore, but that's still better than busy
usec_t wait_usec, watchdog_usec;
watchdog_usec = manager_get_watchdog(m, WATCHDOG_RUNTIME);
- if (timestamp_is_set(watchdog_usec))
+ if (m->runtime_watchdog_running)
(void) watchdog_ping();
+ else if (timestamp_is_set(watchdog_usec))
+ manager_retry_runtime_watchdog(m);
if (!ratelimit_below(&rl)) {
/* Yay, something is going seriously wrong, pause a little */
#define DESTROY_IPC_FLAG (UINT32_C(1) << 31)
static void manager_serialize_uid_refs_internal(
- Manager *m,
FILE *f,
- Hashmap **uid_refs,
+ Hashmap *uid_refs,
const char *field_name) {
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) {
+ HASHMAP_FOREACH_KEY(p, k, uid_refs) {
uint32_t c;
uid_t uid;
}
static void manager_serialize_uid_refs(Manager *m, FILE *f) {
- manager_serialize_uid_refs_internal(m, f, &m->uid_refs, "destroy-ipc-uid");
+ manager_serialize_uid_refs_internal(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");
+ manager_serialize_uid_refs_internal(f, m->gid_refs, "destroy-ipc-gid");
}
int manager_serialize(
if (t == WATCHDOG_RUNTIME)
if (!timestamp_is_set(m->watchdog_overridden[WATCHDOG_RUNTIME])) {
- if (timestamp_is_set(timeout))
+ if (timestamp_is_set(timeout)) {
r = watchdog_set_timeout(&timeout);
- else
+
+ if (r >= 0)
+ m->runtime_watchdog_running = true;
+ } else {
watchdog_close(true);
+ m->runtime_watchdog_running = false;
+ }
}
- if (r >= 0)
- m->watchdog[t] = timeout;
+ m->watchdog[t] = timeout;
}
int manager_override_watchdog(Manager *m, WatchdogType t, usec_t timeout) {
usec_t *p;
p = timestamp_is_set(timeout) ? &timeout : &m->watchdog[t];
- if (timestamp_is_set(*p))
+ if (timestamp_is_set(*p)) {
r = watchdog_set_timeout(p);
- else
+
+ if (r >= 0)
+ m->runtime_watchdog_running = true;
+ } else {
watchdog_close(true);
+ m->runtime_watchdog_running = false;
+ }
}
- if (r >= 0)
- m->watchdog_overridden[t] = timeout;
+ m->watchdog_overridden[t] = timeout;
return 0;
}
+void manager_retry_runtime_watchdog(Manager *m) {
+ int r = 0;
+
+ assert(m);
+
+ if (timestamp_is_set(m->watchdog_overridden[WATCHDOG_RUNTIME]))
+ r = watchdog_set_timeout(&m->watchdog_overridden[WATCHDOG_RUNTIME]);
+ else
+ r = watchdog_set_timeout(&m->watchdog[WATCHDOG_RUNTIME]);
+
+ if (r >= 0)
+ m->runtime_watchdog_running = true;
+}
+
static void manager_deserialize_uid_refs_one_internal(
- Manager *m,
Hashmap** uid_refs,
const char *value) {
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);
+ log_debug("Unable to parse UID/GID reference serialization: " UID_FMT, uid);
return;
}
- r = hashmap_ensure_allocated(uid_refs, &trivial_hash_ops);
- if (r < 0) {
+ if (hashmap_ensure_allocated(uid_refs, &trivial_hash_ops) < 0) {
log_oom();
return;
}
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");
+ log_debug_errno(r, "Failed to add UID/GID 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);
+ manager_deserialize_uid_refs_one_internal(&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);
+ manager_deserialize_uid_refs_one_internal(&m->gid_refs, value);
}
int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
/* Clean up runtime objects no longer referenced */
manager_vacuum(m);
+ /* Clean up deserialized tracked clients */
+ m->deserialized_subscribed = strv_free(m->deserialized_subscribed);
+
/* Consider the reload process complete now. */
assert(m->n_reloading > 0);
m->n_reloading--;
RUN_WITH_UMASK(0022)
r = execute_directories((const char* const*) paths, DEFAULT_TIMEOUT_USEC, gather_environment,
- args, NULL, m->transient_environment, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
+ args, NULL, m->transient_environment,
+ EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS | EXEC_DIR_SET_SYSTEMD_EXEC_PID);
return r;
}
RUN_WITH_UMASK(0022)
(void) execute_directories((const char* const*) paths, DEFAULT_TIMEOUT_USEC, NULL, NULL,
- (char**) argv, m->transient_environment, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
+ (char**) argv, m->transient_environment,
+ EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS | EXEC_DIR_SET_SYSTEMD_EXEC_PID);
r = 0;
}
static void manager_unref_uid_internal(
- Manager *m,
- Hashmap **uid_refs,
+ Hashmap *uid_refs,
uid_t uid,
bool destroy_now,
int (*_clean_ipc)(uid_t uid)) {
uint32_t c, n;
- assert(m);
- assert(uid_refs);
assert(uid_is_valid(uid));
assert(_clean_ipc);
if (uid == 0) /* We don't keep track of root, and will never destroy it */
return;
- c = PTR_TO_UINT32(hashmap_get(*uid_refs, UID_TO_PTR(uid)));
+ c = PTR_TO_UINT32(hashmap_get(uid_refs, UID_TO_PTR(uid)));
n = c & ~DESTROY_IPC_FLAG;
assert(n > 0);
n--;
if (destroy_now && n == 0) {
- hashmap_remove(*uid_refs, UID_TO_PTR(uid));
+ hashmap_remove(uid_refs, UID_TO_PTR(uid));
if (c & DESTROY_IPC_FLAG) {
log_debug("%s " UID_FMT " is no longer referenced, cleaning up its IPC.",
}
} else {
c = n | (c & DESTROY_IPC_FLAG);
- assert_se(hashmap_update(*uid_refs, UID_TO_PTR(uid), UINT32_TO_PTR(c)) >= 0);
+ assert_se(hashmap_update(uid_refs, UID_TO_PTR(uid), UINT32_TO_PTR(c)) >= 0);
}
}
void manager_unref_uid(Manager *m, uid_t uid, bool destroy_now) {
- manager_unref_uid_internal(m, &m->uid_refs, uid, destroy_now, clean_ipc_by_uid);
+ manager_unref_uid_internal(m->uid_refs, uid, destroy_now, clean_ipc_by_uid);
}
void manager_unref_gid(Manager *m, gid_t gid, bool destroy_now) {
- manager_unref_uid_internal(m, &m->gid_refs, (uid_t) gid, destroy_now, clean_ipc_by_gid);
+ manager_unref_uid_internal(m->gid_refs, (uid_t) gid, destroy_now, clean_ipc_by_gid);
}
static int manager_ref_uid_internal(
- Manager *m,
Hashmap **uid_refs,
uid_t uid,
bool clean_ipc) {
uint32_t c, n;
int r;
- assert(m);
assert(uid_refs);
assert(uid_is_valid(uid));
}
int manager_ref_uid(Manager *m, uid_t uid, bool clean_ipc) {
- return manager_ref_uid_internal(m, &m->uid_refs, uid, clean_ipc);
+ return manager_ref_uid_internal(&m->uid_refs, uid, clean_ipc);
}
int manager_ref_gid(Manager *m, gid_t gid, bool clean_ipc) {
- return manager_ref_uid_internal(m, &m->gid_refs, (uid_t) gid, clean_ipc);
+ return manager_ref_uid_internal(&m->gid_refs, (uid_t) gid, clean_ipc);
}
static void manager_vacuum_uid_refs_internal(
- Manager *m,
- Hashmap **uid_refs,
+ Hashmap *uid_refs,
int (*_clean_ipc)(uid_t uid)) {
void *p, *k;
- assert(m);
- assert(uid_refs);
assert(_clean_ipc);
- HASHMAP_FOREACH_KEY(p, k, *uid_refs) {
+ HASHMAP_FOREACH_KEY(p, k, uid_refs) {
uint32_t c, n;
uid_t uid;
(void) _clean_ipc(uid);
}
- assert_se(hashmap_remove(*uid_refs, k) == p);
+ assert_se(hashmap_remove(uid_refs, k) == p);
}
}
static void manager_vacuum_uid_refs(Manager *m) {
- manager_vacuum_uid_refs_internal(m, &m->uid_refs, clean_ipc_by_uid);
+ manager_vacuum_uid_refs_internal(m->uid_refs, clean_ipc_by_uid);
}
static void manager_vacuum_gid_refs(Manager *m) {
- manager_vacuum_uid_refs_internal(m, &m->gid_refs, clean_ipc_by_gid);
+ manager_vacuum_uid_refs_internal(m->gid_refs, clean_ipc_by_gid);
}
static void manager_vacuum(Manager *m) {
buf = new(char, sizeof("split-usr:"
"cgroups-missing:"
+ "cgrousv1:"
"local-hwclock:"
"var-run-bad:"
"overflowuid-not-65534:"
if (access("/proc/cgroups", F_OK) < 0)
e = stpcpy(e, "cgroups-missing:");
+ if (cg_all_unified() == 0)
+ e = stpcpy(e, "cgroupsv1:");
+
if (clock_is_localtime(NULL) > 0)
e = stpcpy(e, "local-hwclock:");