#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
+#include "generator-setup.h"
#include "hashmap.h"
#include "install.h"
#include "io-util.h"
#define CGROUPS_AGENT_RCVBUF_SIZE (8*1024*1024)
/* Initial delay and the interval for printing status messages about running jobs */
-#define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC)
+#define JOBS_IN_PROGRESS_WAIT_USEC (2*USEC_PER_SEC)
+#define JOBS_IN_PROGRESS_QUIET_WAIT_USEC (25*USEC_PER_SEC)
#define JOBS_IN_PROGRESS_PERIOD_USEC (USEC_PER_SEC / 3)
#define JOBS_IN_PROGRESS_PERIOD_DIVISOR 3
static int manager_run_environment_generators(Manager *m);
static int manager_run_generators(Manager *m);
+static usec_t manager_watch_jobs_next_time(Manager *m) {
+ return usec_add(now(CLOCK_MONOTONIC),
+ show_status_on(m->show_status) ? JOBS_IN_PROGRESS_WAIT_USEC :
+ JOBS_IN_PROGRESS_QUIET_WAIT_USEC);
+}
+
static void manager_watch_jobs_in_progress(Manager *m) {
usec_t next;
int r;
if (m->jobs_in_progress_event_source)
return;
- next = now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC;
+ next = manager_watch_jobs_next_time(m);
r = sd_event_add_time(
m->event,
&m->jobs_in_progress_event_source,
}
}
-void manager_flip_auto_status(Manager *m, bool enable) {
+void manager_flip_auto_status(Manager *m, bool enable, const char *reason) {
assert(m);
if (enable) {
if (m->show_status == SHOW_STATUS_AUTO)
- manager_set_show_status(m, SHOW_STATUS_TEMPORARY);
+ manager_set_show_status(m, SHOW_STATUS_TEMPORARY, reason);
} else {
if (m->show_status == SHOW_STATUS_TEMPORARY)
- manager_set_show_status(m, SHOW_STATUS_AUTO);
+ manager_set_show_status(m, SHOW_STATUS_AUTO, reason);
}
}
assert(m);
assert(m->n_running_jobs > 0);
- manager_flip_auto_status(m, true);
+ manager_flip_auto_status(m, true, "delay");
print_nr = (m->jobs_in_progress_iteration / JOBS_IN_PROGRESS_PERIOD_DIVISOR) % m->n_running_jobs;
m->ask_password_inotify_fd, EPOLLIN,
manager_dispatch_ask_password_fd, m);
if (r < 0) {
- log_error_errno(errno, "Failed to add event source for /run/systemd/ask-password: %m");
+ log_error_errno(r, "Failed to add event source for /run/systemd/ask-password: %m");
manager_close_ask_password(m);
- return -errno;
+ return r;
}
(void) sd_event_source_set_description(m->ask_password_event_source, "manager-ask-password");
p = paths_user;
for (i = 0; i < _EXEC_DIRECTORY_TYPE_MAX; i++) {
- r = sd_path_home(p[i].type, p[i].suffix, &m->prefix[i]);
+ r = sd_path_lookup(p[i].type, p[i].suffix, &m->prefix[i]);
if (r < 0)
return r;
}
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);
return 0;
}
+static bool manager_process_barrier_fd(const char *buf, FDSet *fds) {
+ assert(buf);
+
+ /* 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.");
+ 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;
+}
+
static void manager_invoke_notify_message(
Manager *m,
Unit *u,
.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,
return 0;
}
- n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC|MSG_TRUNC);
- if (n < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
- return 0; /* Spurious wakeup, try again */
-
- /* 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");
- }
+ 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 < 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
+ * 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(n, "Failed to receive notification message: %m");
CMSG_FOREACH(cmsg, &msghdr) {
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
+ assert(!fd_array);
fd_array = (int*) CMSG_DATA(cmsg);
n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
cmsg->cmsg_type == SCM_CREDENTIALS &&
cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
+ assert(!ucred);
ucred = (struct ucred*) CMSG_DATA(cmsg);
}
}
/* Make sure it's NUL-terminated. */
buf[n] = 0;
+ /* possibly a barrier fd, let's see */
+ if (manager_process_barrier_fd(buf, fds))
+ return 0;
+
/* Increase the generation counter used for filtering out duplicate unit invocations. */
m->notifygen++;
switch (sfsi.ssi_signo - SIGRTMIN) {
case 20:
- manager_set_show_status(m, SHOW_STATUS_YES);
+ manager_set_show_status(m, SHOW_STATUS_YES, "signal");
break;
case 21:
- manager_set_show_status(m, SHOW_STATUS_NO);
+ manager_set_show_status(m, SHOW_STATUS_NO, "signal");
break;
case 22:
if (manager_dispatch_dbus_queue(m) > 0)
continue;
- /* Sleep for half the watchdog time */
- if (timestamp_is_set(m->runtime_watchdog) && MANAGER_IS_SYSTEM(m)) {
- wait_usec = m->runtime_watchdog / 2;
- if (wait_usec <= 0)
- wait_usec = 1;
- } else
+ /* Sleep for watchdog runtime wait time */
+ if (MANAGER_IS_SYSTEM(m))
+ wait_usec = watchdog_runtime_wait();
+ else
wait_usec = USEC_INFINITY;
r = sd_event_run(m->event, wait_usec);
}
int manager_open_serialization(Manager *m, FILE **_f) {
- int fd;
+ _cleanup_close_ int fd = -1;
FILE *f;
assert(_f);
if (fd < 0)
return fd;
- f = fdopen(fd, "w+");
- if (!f) {
- safe_close(fd);
+ f = take_fdopen(&fd, "w+");
+ if (!f)
return -errno;
- }
*_f = f;
return 0;
if (s < 0)
log_notice("Failed to parse show-status flag '%s', ignoring.", val);
else
- manager_set_show_status(m, s);
+ manager_set_show_status(m, s, "deserialization");
} else if ((val = startswith(l, "log-level-override="))) {
int level;
if (hashmap_size(m->jobs) > 0) {
if (m->jobs_in_progress_event_source)
/* Ignore any failure, this is only for feedback */
- (void) sd_event_source_set_time(m->jobs_in_progress_event_source, now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC);
-
+ (void) sd_event_source_set_time(m->jobs_in_progress_event_source,
+ manager_watch_jobs_next_time(m));
return;
}
- manager_flip_auto_status(m, false);
+ manager_flip_auto_status(m, false, "boot finished");
/* Notify Type=idle units that we are done now */
manager_close_idle_pipe(m);
return found;
}
-static const char *const system_env_generator_binary_paths[] = {
- "/run/systemd/system-environment-generators",
- "/etc/systemd/system-environment-generators",
- "/usr/local/lib/systemd/system-environment-generators",
- SYSTEM_ENV_GENERATOR_PATH,
- NULL
-};
-
-static const char *const user_env_generator_binary_paths[] = {
- "/run/systemd/user-environment-generators",
- "/etc/systemd/user-environment-generators",
- "/usr/local/lib/systemd/user-environment-generators",
- USER_ENV_GENERATOR_PATH,
- NULL
-};
-
static int manager_run_environment_generators(Manager *m) {
char **tmp = NULL; /* this is only used in the forked process, no cleanup here */
- const char *const *paths;
+ _cleanup_strv_free_ char **paths = NULL;
void* args[] = {
[STDOUT_GENERATE] = &tmp,
[STDOUT_COLLECT] = &tmp,
if (MANAGER_IS_TEST_RUN(m) && !(m->test_run_flags & MANAGER_TEST_RUN_ENV_GENERATORS))
return 0;
- paths = MANAGER_IS_SYSTEM(m) ? system_env_generator_binary_paths : user_env_generator_binary_paths;
+ paths = env_generator_binary_paths(MANAGER_IS_SYSTEM(m));
+ if (!paths)
+ return log_oom();
- if (!generator_path_any(paths))
+ if (!generator_path_any((const char* const*) paths))
return 0;
RUN_WITH_UMASK(0022)
- r = execute_directories(paths, DEFAULT_TIMEOUT_USEC, gather_environment,
+ r = execute_directories((const char* const*) paths, DEFAULT_TIMEOUT_USEC, gather_environment,
args, NULL, m->transient_environment, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
return r;
}
log_open();
}
-void manager_set_show_status(Manager *m, ShowStatus mode) {
+void manager_set_show_status(Manager *m, ShowStatus mode, const char *reason) {
assert(m);
- assert(IN_SET(mode, SHOW_STATUS_AUTO, SHOW_STATUS_NO, SHOW_STATUS_YES, SHOW_STATUS_TEMPORARY));
+ assert(mode >= 0 && mode < _SHOW_STATUS_MAX);
if (!MANAGER_IS_SYSTEM(m))
return;
- if (m->show_status != mode)
- log_debug("%s showing of status.",
- mode == SHOW_STATUS_NO ? "Disabling" : "Enabling");
+ 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 (IN_SET(mode, SHOW_STATUS_TEMPORARY, SHOW_STATUS_YES))
+ if (enabled)
(void) touch("/run/systemd/show-status");
else
(void) unlink("/run/systemd/show-status");
if (type != STATUS_TYPE_EMERGENCY && manager_check_ask_password(m) > 0)
return false;
- return IN_SET(m->show_status, SHOW_STATUS_TEMPORARY, SHOW_STATUS_YES);
+ if (type == STATUS_TYPE_NOTICE && m->show_status != SHOW_STATUS_NO)
+ return true;
+
+ return show_status_on(m->show_status);
}
const char *manager_get_confirm_spawn(Manager *m) {
assert(m);
+ /* Is the special shutdown target active or queued? If so, we are in shutdown state */
+ u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET);
+ if (u && unit_active_or_pending(u))
+ return MANAGER_STOPPING;
+
/* Did we ever finish booting? If not then we are still starting up */
if (!MANAGER_IS_FINISHED(m)) {
return MANAGER_STARTING;
}
- /* Is the special shutdown target active or queued? If so, we are in shutdown state */
- u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET);
- if (u && unit_active_or_pending(u))
- return MANAGER_STOPPING;
-
if (MANAGER_IS_SYSTEM(m)) {
/* Are the rescue or emergency targets active or queued? If so we are in maintenance state */
u = manager_get_unit(m, SPECIAL_RESCUE_TARGET);