#include <errno.h>
#include <fcntl.h>
#include <linux/kd.h>
-#include <signal.h>
-#include <string.h>
#include <sys/epoll.h>
#include <sys/inotify.h>
#include <sys/ioctl.h>
#include "dbus-manager.h"
#include "dbus-unit.h"
#include "dbus.h"
+#include "def.h"
#include "dirent-util.h"
#include "env-util.h"
#include "escape.h"
#include "fs-util.h"
#include "hashmap.h"
#include "io-util.h"
+#include "install.h"
#include "label.h"
#include "locale-setup.h"
#include "log.h"
#include "macro.h"
#include "manager.h"
#include "memory-util.h"
-#include "missing.h"
#include "mkdir.h"
#include "parse-util.h"
#include "path-lookup.h"
#include "path-util.h"
-#include "plymouth-util.h"
#include "process-util.h"
#include "ratelimit.h"
#include "rlimit-util.h"
#include "string-util.h"
#include "strv.h"
#include "strxcpyx.h"
+#include "sysctl-util.h"
#include "syslog-util.h"
#include "terminal-util.h"
#include "time-util.h"
if (m->ask_password_inotify_fd < 0)
return log_error_errno(errno, "Failed to create inotify object: %m");
- if (inotify_add_watch(m->ask_password_inotify_fd, "/run/systemd/ask-password", IN_CREATE|IN_DELETE|IN_MOVE) < 0) {
- log_error_errno(errno, "Failed to watch \"/run/systemd/ask-password\": %m");
+ r = inotify_add_watch_and_warn(m->ask_password_inotify_fd,
+ "/run/systemd/ask-password",
+ IN_CREATE|IN_DELETE|IN_MOVE);
+ if (r < 0) {
manager_close_ask_password(m);
- return -errno;
+ return r;
}
r = sd_event_add_io(m->event, &m->ask_password_event_source,
}
int manager_default_environment(Manager *m) {
+ int r;
+
assert(m);
m->transient_environment = strv_free(m->transient_environment);
* /proc/self/environ valid; it is used for tagging
* the init process inside containers. */
m->transient_environment = strv_new("PATH=" DEFAULT_PATH);
+ if (!m->transient_environment)
+ return log_oom();
/* Import locale variables LC_*= from configuration */
(void) locale_setup(&m->transient_environment);
- } else
+ } else {
+ _cleanup_free_ char *k = NULL;
+
/* The user manager passes its own environment
- * along to its children. */
+ * along to its children, except for $PATH. */
m->transient_environment = strv_copy(environ);
+ if (!m->transient_environment)
+ return log_oom();
- 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);
+ if (r < 0)
+ return log_oom();
+ TAKE_PTR(k);
+ }
sanitize_environment(m->transient_environment);
return 0;
}
+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_cache_mtime = 0;
+}
+
static int manager_setup_run_queue(Manager *m) {
int r;
}
/* Reboot immediately if the user hits C-A-D more often than 7x per 2s */
- RATELIMIT_INIT(m->ctrl_alt_del_ratelimit, 2 * USEC_PER_SEC, 7);
+ m->ctrl_alt_del_ratelimit = (RateLimit) { .interval = 2 * USEC_PER_SEC, .burst = 7 };
r = manager_default_environment(m);
if (r < 0)
if (r < 0)
return r;
+ r = prioq_ensure_allocated(&m->run_queue, compare_job_priority);
+ if (r < 0)
+ return r;
+
r = manager_setup_prefix(m);
if (r < 0)
return r;
manager_dispatch_cleanup_queue(m);
assert(!m->load_queue);
- assert(!m->run_queue);
+ assert(prioq_isempty(m->run_queue));
assert(!m->dbus_unit_queue);
assert(!m->dbus_job_queue);
assert(!m->cleanup_queue);
hashmap_free(m->watch_pids);
hashmap_free(m->watch_bus);
+ prioq_free(m->run_queue);
+
set_free(m->startup_units);
set_free(m->failed_units);
strv_free(m->client_environment);
hashmap_free(m->cgroup_unit);
- set_free_free(m->unit_path_cache);
+ manager_free_unit_name_maps(m);
free(m->switch_root);
free(m->switch_root_init);
}
}
-static void manager_build_unit_path_cache(Manager *m) {
- char **i;
- int r;
-
- assert(m);
-
- set_free_free(m->unit_path_cache);
-
- m->unit_path_cache = set_new(&path_hash_ops);
- if (!m->unit_path_cache) {
- r = -ENOMEM;
- goto fail;
- }
-
- /* This simply builds a list of files we know exist, so that
- * we don't always have to go to disk */
-
- STRV_FOREACH(i, m->lookup_paths.search_path) {
- _cleanup_closedir_ DIR *d = NULL;
- struct dirent *de;
-
- d = opendir(*i);
- if (!d) {
- if (errno != ENOENT)
- log_warning_errno(errno, "Failed to open directory %s, ignoring: %m", *i);
- continue;
- }
-
- FOREACH_DIRENT(de, d, r = -errno; goto fail) {
- char *p;
-
- p = path_join(*i, de->d_name);
- if (!p) {
- r = -ENOMEM;
- goto fail;
- }
-
- r = set_consume(m->unit_path_cache, p);
- if (r < 0)
- goto fail;
- }
- }
-
- return;
-
-fail:
- log_warning_errno(r, "Failed to build unit path cache, proceeding without: %m");
- m->unit_path_cache = set_free_free(m->unit_path_cache);
-}
-
static void manager_distribute_fds(Manager *m, FDSet *fds) {
Iterator i;
Unit *u;
manager_preset_all(m);
- r = lookup_paths_reduce(&m->lookup_paths);
- if (r < 0)
- log_warning_errno(r, "Failed to reduce unit file paths, ignoring: %m");
-
- manager_build_unit_path_cache(m);
+ lookup_paths_log(&m->lookup_paths);
{
/* This block is (optionally) done with the reloading counter bumped */
if (mode == JOB_ISOLATE && !unit->allow_isolate)
return sd_bus_error_setf(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.");
+
log_unit_debug(unit, "Trying to enqueue job %s/%s/%s", unit->id, job_type_to_string(type), job_mode_to_string(mode));
type = job_type_collapse(type, unit);
goto tr_abort;
}
+ if (mode == JOB_TRIGGERING) {
+ r = transaction_add_triggering_jobs(tr, unit);
+ if (r < 0)
+ goto tr_abort;
+ }
+
r = transaction_activate(tr, m, mode, affected_jobs, error);
if (r < 0)
goto tr_abort;
assert(source);
assert(m);
- while ((j = m->run_queue)) {
+ while ((j = prioq_peek(m->run_queue))) {
assert(j->installed);
assert(j->in_run_queue);
}
int manager_loop(Manager *m) {
+ RateLimit rl = { .interval = 1*USEC_PER_SEC, .burst = 50000 };
int r;
- RATELIMIT_DEFINE(rl, 1*USEC_PER_SEC, 50000);
-
assert(m);
assert(m->objective == MANAGER_OK); /* Ensure manager_startup() has been called */
- /* Release the path cache */
- m->unit_path_cache = set_free_free(m->unit_path_cache);
-
manager_check_finished(m);
/* There might still be some zombies hanging around from before we were exec()'ed. Let's reap them. */
(void) manager_run_environment_generators(m);
(void) manager_run_generators(m);
- r = lookup_paths_reduce(&m->lookup_paths);
- if (r < 0)
- log_warning_errno(r, "Failed to reduce unit file paths, ignoring: %m");
+ lookup_paths_log(&m->lookup_paths);
- manager_build_unit_path_cache(m);
+ /* We flushed out generated files, for which we don't watch mtime, so we should flush the old map. */
+ manager_free_unit_name_maps(m);
/* First, enumerate what we can from kernel and suchlike */
manager_enumerate_perpetual(m);
return true;
}
+void disable_printk_ratelimit(void) {
+ /* Disable kernel's printk ratelimit.
+ *
+ * Logging to /dev/kmsg is most useful during early boot and shutdown, where normal logging
+ * mechanisms are not available. The semantics of this sysctl are such that any kernel command-line
+ * setting takes precedence. */
+ int r;
+
+ r = sysctl_write("kernel/printk_devkmsg", "on");
+ if (r < 0)
+ log_debug_errno(r, "Failed to set sysctl kernel.printk_devkmsg=on: %m");
+}
+
void manager_recheck_journal(Manager *m) {
assert(m);
const char *manager_get_confirm_spawn(Manager *m) {
static int last_errno = 0;
- const char *vc = m->confirm_spawn;
struct stat st;
int r;
+ assert(m);
+
/* Here's the deal: we want to test the validity of the console but don't want
* PID1 to go through the whole console process which might block. But we also
* want to warn the user only once if something is wrong with the console so we
* reason the configured console is not ready, we fallback to the default
* console. */
- if (!vc || path_equal(vc, "/dev/console"))
- return vc;
+ if (!m->confirm_spawn || path_equal(m->confirm_spawn, "/dev/console"))
+ return m->confirm_spawn;
- r = stat(vc, &st);
- if (r < 0)
+ if (stat(m->confirm_spawn, &st) < 0) {
+ r = -errno;
goto fail;
+ }
if (!S_ISCHR(st.st_mode)) {
- errno = ENOTTY;
+ r = -ENOTTY;
goto fail;
}
last_errno = 0;
- return vc;
+ return m->confirm_spawn;
+
fail:
- if (last_errno != errno) {
- last_errno = errno;
- log_warning_errno(errno, "Failed to open %s: %m, using default console", vc);
- }
+ if (last_errno != r)
+ last_errno = log_warning_errno(r, "Failed to open %s, using default console: %m", m->confirm_spawn);
+
return "/dev/console";
}