summaryrefslogtreecommitdiff
path: root/src/core/manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/manager.c')
-rw-r--r--src/core/manager.c165
1 files changed, 91 insertions, 74 deletions
diff --git a/src/core/manager.c b/src/core/manager.c
index b58f68fa7a..c1dce62a18 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -590,7 +590,7 @@ int manager_new(UnitFileScope scope, bool test_run, Manager **_m) {
m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1;
m->pin_cgroupfs_fd = m->notify_fd = m->cgroups_agent_fd = m->signal_fd = m->time_change_fd =
- m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->cgroup_inotify_fd =
+ m->dev_autofs_fd = m->private_listen_fd = m->cgroup_inotify_fd =
m->ask_password_inotify_fd = -1;
m->user_lookup_fds[0] = m->user_lookup_fds[1] = -1;
@@ -661,9 +661,8 @@ int manager_new(UnitFileScope scope, bool test_run, Manager **_m) {
goto fail;
}
- /* Note that we set up neither kdbus, nor the notify fd
- * here. We do that after deserialization, since they might
- * have gotten serialized across the reexec. */
+ /* Note that we do not set up the notify fd here. We do that after deserialization,
+ * since they might have gotten serialized across the reexec. */
m->taint_usr = dir_is_empty("/usr") > 0;
@@ -879,7 +878,6 @@ static int manager_connect_bus(Manager *m, bool reexecuting) {
return 0;
try_bus_connect =
- m->kdbus_fd >= 0 ||
reexecuting ||
(MANAGER_IS_USER(m) && getenv("DBUS_SESSION_BUS_ADDRESS"));
@@ -1084,7 +1082,6 @@ Manager* manager_free(Manager *m) {
safe_close(m->notify_fd);
safe_close(m->cgroups_agent_fd);
safe_close(m->time_change_fd);
- safe_close(m->kdbus_fd);
safe_close_pair(m->user_lookup_fds);
manager_close_ask_password(m);
@@ -1239,9 +1236,11 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
return r;
/* Make sure the transient directory always exists, so that it remains in the search path */
- r = mkdir_p_label(m->lookup_paths.transient, 0755);
- if (r < 0)
- return r;
+ if (!m->test_run) {
+ r = mkdir_p_label(m->lookup_paths.transient, 0755);
+ if (r < 0)
+ return r;
+ }
dual_timestamp_get(&m->generators_start_timestamp);
r = manager_run_generators(m);
@@ -1287,7 +1286,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
if (q < 0 && r == 0)
r = q;
- /* We might have deserialized the kdbus control fd, but if we didn't, then let's create the bus now. */
+ /* Let's connect to the bus now. */
(void) manager_connect_bus(m, !!serialization);
(void) bus_track_coldplug(m, &m->subscribed, false, m->deserialized_subscribed);
@@ -1660,13 +1659,12 @@ static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, ui
return 0;
}
-static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, const char *buf, size_t n, FDSet *fds) {
+static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, const char *buf, FDSet *fds) {
_cleanup_strv_free_ char **tags = NULL;
assert(m);
assert(u);
assert(buf);
- assert(n > 0);
tags = strv_split(buf, "\n\r");
if (!tags) {
@@ -1676,8 +1674,14 @@ static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, const
if (UNIT_VTABLE(u)->notify_message)
UNIT_VTABLE(u)->notify_message(u, pid, tags, fds);
- else
- log_unit_debug(u, "Got notification message for unit. Ignoring.");
+ else if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
+ _cleanup_free_ char *x = NULL, *y = NULL;
+
+ x = cescape(buf);
+ if (x)
+ y = ellipsize(x, 20, 90);
+ log_unit_debug(u, "Got notification message \"%s\", ignoring.", strnull(y));
+ }
}
static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
@@ -1703,7 +1707,6 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t
struct cmsghdr *cmsg;
struct ucred *ucred = NULL;
- bool found = false;
Unit *u1, *u2, *u3;
int r, *fd_array = NULL;
unsigned n_fds = 0;
@@ -1717,12 +1720,15 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t
return 0;
}
- n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
+ n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC|MSG_TRUNC);
if (n < 0) {
- if (errno == EAGAIN || errno == EINTR)
- return 0;
+ if (IN_SET(errno, EAGAIN, EINTR))
+ return 0; /* Spurious wakeup, try again */
- return -errno;
+ /* 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 looping around this:
+ * being woken up over and over again but being unable to actually read the message off the socket. */
+ return log_error_errno(errno, "Failed to receive notification message: %m");
}
CMSG_FOREACH(cmsg, &msghdr) {
@@ -1745,7 +1751,8 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t
r = fdset_new_array(&fds, fd_array, n_fds);
if (r < 0) {
close_many(fd_array, n_fds);
- return log_oom();
+ log_oom();
+ return 0;
}
}
@@ -1754,38 +1761,40 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t
return 0;
}
- if ((size_t) n >= sizeof(buf)) {
+ if ((size_t) n >= sizeof(buf) || (msghdr.msg_flags & MSG_TRUNC)) {
log_warning("Received notify message exceeded maximum size. Ignoring.");
return 0;
}
+ /* As extra safety check, let's make sure the string we get doesn't contain embedded NUL bytes. We permit one
+ * trailing NUL byte in the message, but don't expect it. */
+ if (n > 1 && memchr(buf, 0, n-1)) {
+ log_warning("Received notify message with embedded NUL bytes. Ignoring.");
+ return 0;
+ }
+
+ /* Make sure it's NUL-terminated. */
buf[n] = 0;
/* Notify every unit that might be interested, but try
* to avoid notifying the same one multiple times. */
u1 = manager_get_unit_by_pid_cgroup(m, ucred->pid);
- if (u1) {
- manager_invoke_notify_message(m, u1, ucred->pid, buf, n, fds);
- found = true;
- }
+ if (u1)
+ manager_invoke_notify_message(m, u1, ucred->pid, buf, fds);
u2 = hashmap_get(m->watch_pids1, PID_TO_PTR(ucred->pid));
- if (u2 && u2 != u1) {
- manager_invoke_notify_message(m, u2, ucred->pid, buf, n, fds);
- found = true;
- }
+ if (u2 && u2 != u1)
+ manager_invoke_notify_message(m, u2, ucred->pid, buf, fds);
u3 = hashmap_get(m->watch_pids2, PID_TO_PTR(ucred->pid));
- if (u3 && u3 != u2 && u3 != u1) {
- manager_invoke_notify_message(m, u3, ucred->pid, buf, n, fds);
- found = true;
- }
+ if (u3 && u3 != u2 && u3 != u1)
+ manager_invoke_notify_message(m, u3, ucred->pid, buf, fds);
- if (!found)
+ if (!u1 && !u2 && !u3)
log_warning("Cannot find unit for notify message of PID "PID_FMT".", ucred->pid);
if (fdset_size(fds) > 0)
- log_warning("Got auxiliary fds with notification message, closing all.");
+ log_warning("Got extra auxiliary fds with notification message, closing them.");
return 0;
}
@@ -1890,6 +1899,35 @@ static int manager_start_target(Manager *m, const char *name, JobMode mode) {
return r;
}
+static void manager_handle_ctrl_alt_del(Manager *m) {
+ /* If the user presses C-A-D more than
+ * 7 times within 2s, we reboot/shutdown immediately,
+ * unless it was disabled in system.conf */
+
+ if (ratelimit_test(&m->ctrl_alt_del_ratelimit) || m->cad_burst_action == CAD_BURST_ACTION_IGNORE)
+ manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE_IRREVERSIBLY);
+ else {
+ switch (m->cad_burst_action) {
+
+ case CAD_BURST_ACTION_REBOOT:
+ m->exit_code = MANAGER_REBOOT;
+ break;
+
+ case CAD_BURST_ACTION_POWEROFF:
+ m->exit_code = MANAGER_POWEROFF;
+ break;
+
+ default:
+ assert_not_reached("Unknown action.");
+ }
+
+ log_notice("Ctrl-Alt-Del was pressed more than 7 times within 2s, performing immediate %s.",
+ cad_burst_action_to_string(m->cad_burst_action));
+ status_printf(NULL, true, false, "Ctrl-Alt-Del was pressed more than 7 times within 2s, performing immediate %s.",
+ cad_burst_action_to_string(m->cad_burst_action));
+ }
+}
+
static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
Manager *m = userdata;
ssize_t n;
@@ -1908,14 +1946,17 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
for (;;) {
n = read(m->signal_fd, &sfsi, sizeof(sfsi));
if (n != sizeof(sfsi)) {
+ if (n >= 0) {
+ log_warning("Truncated read from signal fd (%zu bytes)!", n);
+ return 0;
+ }
- if (n >= 0)
- return -EIO;
-
- if (errno == EINTR || errno == EAGAIN)
+ if (IN_SET(errno, EINTR, EAGAIN))
break;
- return -errno;
+ /* We return an error here, which will kill this handler,
+ * to avoid a busy loop on read error. */
+ return log_error_errno(errno, "Reading from signal fd failed: %m");
}
log_received_signal(sfsi.ssi_signo == SIGCHLD ||
@@ -1941,19 +1982,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
case SIGINT:
if (MANAGER_IS_SYSTEM(m)) {
-
- /* If the user presses C-A-D more than
- * 7 times within 2s, we reboot
- * immediately. */
-
- if (ratelimit_test(&m->ctrl_alt_del_ratelimit))
- manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE_IRREVERSIBLY);
- else {
- log_notice("Ctrl-Alt-Del was pressed more than 7 times within 2s, rebooting immediately.");
- status_printf(NULL, true, false, "Ctrl-Alt-Del was pressed more than 7 times within 2s, rebooting immediately.");
- m->exit_code = MANAGER_REBOOT;
- }
-
+ manager_handle_ctrl_alt_del(m);
break;
}
@@ -2481,16 +2510,6 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
fprintf(f, "user-lookup=%i %i\n", copy0, copy1);
}
- if (m->kdbus_fd >= 0) {
- int copy;
-
- copy = fdset_put_dup(fds, m->kdbus_fd);
- if (copy < 0)
- return copy;
-
- fprintf(f, "kdbus-fd=%i\n", copy);
- }
-
bus_track_serialize(m->subscribed, f, "subscribed");
r = dynamic_user_serialize(m, f, fds);
@@ -2678,16 +2697,6 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
m->user_lookup_fds[1] = fdset_remove(fds, fd1);
}
- } else if (startswith(l, "kdbus-fd=")) {
- int fd;
-
- if (safe_atoi(l + 9, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_debug("Failed to parse kdbus fd: %s", l + 9);
- else {
- safe_close(m->kdbus_fd);
- m->kdbus_fd = fdset_remove(fds, fd);
- }
-
} else if (startswith(l, "dynamic-user="))
dynamic_user_deserialize_one(m, l + 13, fds);
else if (startswith(l, "destroy-ipc-uid="))
@@ -2699,7 +2708,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
if (strv_extend(&m->deserialized_subscribed, l+11) < 0)
log_oom();
- } else
+ } else if (!startswith(l, "kdbus-fd=")) /* ignore this one */
log_debug("Unknown serialization item '%s'", l);
}
@@ -3560,3 +3569,11 @@ static const char *const manager_state_table[_MANAGER_STATE_MAX] = {
};
DEFINE_STRING_TABLE_LOOKUP(manager_state, ManagerState);
+
+static const char *const cad_burst_action_table[_CAD_BURST_ACTION_MAX] = {
+ [CAD_BURST_ACTION_IGNORE] = "ignore",
+ [CAD_BURST_ACTION_REBOOT] = "reboot-force",
+ [CAD_BURST_ACTION_POWEROFF] = "poweroff-force",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(cad_burst_action, CADBurstAction);