diff options
Diffstat (limited to 'src/core/manager.c')
-rw-r--r-- | src/core/manager.c | 165 |
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); |