core: on switching root do not emit device state change based on enumeration results
return manager_load_unit(m, name, NULL, error, ret_unit);
}
-static int method_get_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int reply_unit_path(Unit *u, sd_bus_message *message, sd_bus_error *error) {
_cleanup_free_ char *path = NULL;
+ int r;
+
+ assert(u);
+ assert(message);
+
+ r = mac_selinux_unit_access_check(u, message, "status", error);
+ if (r < 0)
+ return r;
+
+ path = unit_dbus_path(u);
+ if (!path)
+ return log_oom();
+
+ return sd_bus_reply_method_return(message, "o", path);
+}
+
+static int method_get_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
const char *name;
Unit *u;
if (r < 0)
return r;
- r = mac_selinux_unit_access_check(u, message, "status", error);
- if (r < 0)
- return r;
-
- path = unit_dbus_path(u);
- if (!path)
- return -ENOMEM;
-
- return sd_bus_reply_method_return(message, "o", path);
+ return reply_unit_path(u, message, error);
}
static int method_get_unit_by_pid(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_free_ char *path = NULL;
Manager *m = userdata;
pid_t pid;
Unit *u;
if (!u)
return sd_bus_error_setf(error, BUS_ERROR_NO_UNIT_FOR_PID, "PID "PID_FMT" does not belong to any loaded unit.", pid);
- r = mac_selinux_unit_access_check(u, message, "status", error);
- if (r < 0)
- return r;
-
- path = unit_dbus_path(u);
- if (!path)
- return -ENOMEM;
-
- return sd_bus_reply_method_return(message, "o", path);
+ return reply_unit_path(u, message, error);
}
static int method_get_unit_by_invocation_id(sd_bus_message *message, void *userdata, sd_bus_error *error) {
}
static int method_get_unit_by_control_group(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_free_ char *path = NULL;
Manager *m = userdata;
const char *cgroup;
Unit *u;
if (!u)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Control group '%s' is not valid or not managed by this instance", cgroup);
- r = mac_selinux_unit_access_check(u, message, "status", error);
- if (r < 0)
- return r;
-
- path = unit_dbus_path(u);
- if (!path)
- return -ENOMEM;
-
- return sd_bus_reply_method_return(message, "o", path);
+ return reply_unit_path(u, message, error);
}
static int method_load_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_free_ char *path = NULL;
Manager *m = userdata;
const char *name;
Unit *u;
if (r < 0)
return r;
- r = mac_selinux_unit_access_check(u, message, "status", error);
- if (r < 0)
- return r;
-
- path = unit_dbus_path(u);
- if (!path)
- return -ENOMEM;
-
- return sd_bus_reply_method_return(message, "o", path);
+ return reply_unit_path(u, message, error);
}
static int method_start_unit_generic(sd_bus_message *message, Manager *m, JobType job_type, bool reload_if_possible, sd_bus_error *error) {
return method_start_unit_generic(message, userdata, JOB_TRY_RESTART, true, error);
}
+static int method_enqueue_unit_job(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+ const char *name;
+ Unit *u;
+ int r;
+
+ assert(message);
+ assert(m);
+
+ r = sd_bus_message_read(message, "s", &name);
+ if (r < 0)
+ return r;
+
+ r = manager_load_unit(m, name, NULL, error, &u);
+ if (r < 0)
+ return r;
+
+ return bus_unit_method_enqueue_job(message, u, error);
+}
+
static int method_start_unit_replace(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
const char *old_name;
return r;
/* Finally, start it */
- return bus_unit_queue_job(message, u, JOB_START, mode, false, error);
+ return bus_unit_queue_job(message, u, JOB_START, mode, 0, error);
}
static int method_get_job(sd_bus_message *message, void *userdata, sd_bus_error *error) {
}
static int method_switch_root(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- char *ri = NULL, *rt = NULL;
+ _cleanup_free_ char *ri = NULL, *rt = NULL;
const char *root, *init;
Manager *m = userdata;
struct statvfs svfs;
if (!isempty(init)) {
ri = strdup(init);
- if (!ri) {
- free(rt);
+ if (!ri)
return -ENOMEM;
- }
}
- free(m->switch_root);
- m->switch_root = rt;
-
- free(m->switch_root_init);
- m->switch_root_init = ri;
+ free_and_replace(m->switch_root, rt);
+ free_and_replace(m->switch_root_init, ri);
m->objective = MANAGER_SWITCH_ROOT;
SD_BUS_METHOD("TryRestartUnit", "ss", "o", method_try_restart_unit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ReloadOrRestartUnit", "ss", "o", method_reload_or_restart_unit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ReloadOrTryRestartUnit", "ss", "o", method_reload_or_try_restart_unit, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("EnqueueUnitJob", "sss", "uososa(uosos)", method_enqueue_unit_job, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("KillUnit", "ssi", NULL, method_kill_unit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ResetFailedUnit", "s", NULL, method_reset_failed_unit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetUnitProperties", "sba(sv)", NULL, method_set_unit_properties, SD_BUS_VTABLE_UNPRIVILEGED),
if (strv_contains(d->wants_property, *i)) /* Was this unit already listed before? */
continue;
- r = manager_add_job_by_name(u->manager, JOB_START, *i, JOB_FAIL, &error, NULL);
+ r = manager_add_job_by_name(u->manager, JOB_START, *i, JOB_FAIL, NULL, &error, NULL);
if (r < 0)
log_unit_warning_errno(u, r, "Failed to enqueue SYSTEMD_WANTS= job, ignoring: %s", bus_error_message(&error, r));
}
}
static void device_update_found_one(Device *d, DeviceFound found, DeviceFound mask) {
+ Manager *m;
+
assert(d);
- if (MANAGER_IS_RUNNING(UNIT(d)->manager)) {
+ m = UNIT(d)->manager;
+
+ if (MANAGER_IS_RUNNING(m) && (m->honor_device_enumeration || MANAGER_IS_USER(m))) {
DeviceFound n, previous;
/* When we are already running, then apply the new mask right-away, and trigger state changes
*ret_shutdown_verb = NULL;
/* Steal the switch root parameters */
- *ret_switch_root_dir = m->switch_root;
- *ret_switch_root_init = m->switch_root_init;
- m->switch_root = m->switch_root_init = NULL;
+ *ret_switch_root_dir = TAKE_PTR(m->switch_root);
+ *ret_switch_root_init = TAKE_PTR(m->switch_root_init);
return 0;
assert(target->load_state == UNIT_LOADED);
- r = manager_add_job(m, JOB_START, target, JOB_ISOLATE, &error, &default_unit_job);
+ r = manager_add_job(m, JOB_START, target, JOB_ISOLATE, NULL, &error, &default_unit_job);
if (r == -EPERM) {
log_debug_errno(r, "Default target could not be isolated, starting instead: %s", bus_error_message(&error, r));
sd_bus_error_free(&error);
- r = manager_add_job(m, JOB_START, target, JOB_REPLACE, &error, &default_unit_job);
+ r = manager_add_job(m, JOB_START, target, JOB_REPLACE, NULL, &error, &default_unit_job);
if (r < 0) {
*ret_error_message = "Failed to start default target";
return log_emergency_errno(r, "Failed to start default target: %s", bus_error_message(&error, r));
(void) prctl(PR_SET_NAME, systemd);
/* Save the original command line */
- saved_argv = argv;
- saved_argc = argc;
+ save_argc_argv(argc, argv);
/* Make sure that if the user says "syslog" we actually log to the journal. */
log_set_upgrade_syslog_to_journal(true);
m->ask_password_inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
if (m->ask_password_inotify_fd < 0)
- return log_error_errno(errno, "inotify_init1() failed: %m");
+ 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 add watch on /run/systemd/ask-password: %m");
+ log_error_errno(errno, "Failed to watch \"/run/systemd/ask-password\": %m");
manager_close_ask_password(m);
return -errno;
}
}
/* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */
- r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, &error, NULL);
+ r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, NULL, &error, NULL);
if (r < 0)
log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %s", bus_error_message(&error, r));
}
/* Let's finally catch up with any changes that took place while we were reloading/reexecing */
manager_catchup(m);
+
+ m->honor_device_enumeration = true;
}
static Manager* manager_reloading_start(Manager *m) {
return 0;
}
-int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_error *e, Job **_ret) {
- int r;
+int manager_add_job(
+ Manager *m,
+ JobType type,
+ Unit *unit,
+ JobMode mode,
+ Set *affected_jobs,
+ sd_bus_error *error,
+ Job **ret) {
+
Transaction *tr;
+ int r;
assert(m);
assert(type < _JOB_TYPE_MAX);
assert(mode < _JOB_MODE_MAX);
if (mode == JOB_ISOLATE && type != JOB_START)
- return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Isolate is only valid for start.");
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Isolate is only valid for start.");
if (mode == JOB_ISOLATE && !unit->allow_isolate)
- return sd_bus_error_setf(e, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
+ return sd_bus_error_setf(error, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
log_unit_debug(unit, "Trying to enqueue job %s/%s/%s", unit->id, job_type_to_string(type), job_mode_to_string(mode));
r = transaction_add_job_and_dependencies(tr, type, unit, NULL, true, false,
IN_SET(mode, JOB_IGNORE_DEPENDENCIES, JOB_IGNORE_REQUIREMENTS),
- mode == JOB_IGNORE_DEPENDENCIES, e);
+ mode == JOB_IGNORE_DEPENDENCIES, error);
if (r < 0)
goto tr_abort;
goto tr_abort;
}
- r = transaction_activate(tr, m, mode, e);
+ r = transaction_activate(tr, m, mode, affected_jobs, error);
if (r < 0)
goto tr_abort;
"Enqueued job %s/%s as %u", unit->id,
job_type_to_string(type), (unsigned) tr->anchor_job->id);
- if (_ret)
- *_ret = tr->anchor_job;
+ if (ret)
+ *ret = tr->anchor_job;
transaction_free(tr);
return 0;
return r;
}
-int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, sd_bus_error *e, Job **ret) {
+int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, Set *affected_jobs, sd_bus_error *e, Job **ret) {
Unit *unit = NULL; /* just to appease gcc, initialization is not really necessary */
int r;
return r;
assert(unit);
- return manager_add_job(m, type, unit, mode, e, ret);
+ return manager_add_job(m, type, unit, mode, affected_jobs, e, ret);
}
-int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Job **ret) {
+int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Set *affected_jobs, Job **ret) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
assert(name);
assert(mode < _JOB_MODE_MAX);
- r = manager_add_job_by_name(m, type, name, mode, &error, ret);
+ r = manager_add_job_by_name(m, type, name, mode, affected_jobs, &error, ret);
if (r < 0)
return log_warning_errno(r, "Failed to enqueue %s job for %s: %s", job_mode_to_string(mode), name, bus_error_message(&error, r));
/* Failure in adding individual dependencies is ignored, so this always succeeds. */
transaction_add_propagate_reload_jobs(tr, unit, tr->anchor_job, mode == JOB_IGNORE_DEPENDENCIES, e);
- r = transaction_activate(tr, m, mode, e);
+ r = transaction_activate(tr, m, mode, NULL, e);
if (r < 0)
goto tr_abort;
job_finish_and_invalidate(j, JOB_CANCELED, false, false);
}
+void manager_unwatch_pid(Manager *m, pid_t pid) {
+ assert(m);
+
+ /* First let's drop the unit keyed as "pid". */
+ (void) hashmap_remove(m->watch_pids, PID_TO_PTR(pid));
+
+ /* Then, let's also drop the array keyed by -pid. */
+ free(hashmap_remove(m->watch_pids, PID_TO_PTR(-pid)));
+}
+
static int manager_dispatch_run_queue(sd_event_source *source, void *userdata) {
Manager *m = userdata;
Job *j;
log_debug("Activating special unit %s", name);
- r = manager_add_job_by_name(m, JOB_START, name, mode, &error, NULL);
+ r = manager_add_job_by_name(m, JOB_START, name, mode, NULL, &error, NULL);
if (r < 0)
log_error("Failed to enqueue %s job: %s", name, bus_error_message(&error, r));
}
}
if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
- if (!IN_SET(errno, EPIPE, EAGAIN, ENOENT, ECONNREFUSED, ECONNRESET, ECONNABORTED))
+ if (!IN_SET(errno, EAGAIN, ENOENT) && !ERRNO_IS_DISCONNECT(errno))
log_error_errno(errno, "connect() failed: %m");
return;
}
errno = 0;
if (write(fd, message, n + 1) != n + 1)
- if (!IN_SET(errno, EPIPE, EAGAIN, ENOENT, ECONNREFUSED, ECONNRESET, ECONNABORTED))
+ if (!IN_SET(errno, EAGAIN, ENOENT) && !ERRNO_IS_DISCONNECT(errno))
log_error_errno(errno, "Failed to write Plymouth message: %m");
}
(void) serialize_bool(f, "taint-logged", m->taint_logged);
(void) serialize_bool(f, "service-watchdogs", m->service_watchdogs);
+ /* After switching root, udevd has not been started yet. So, enumeration results should not be emitted. */
+ (void) serialize_bool(f, "honor-device-enumeration", !switching_root);
+
t = show_status_to_string(m->show_status);
if (t)
(void) serialize_item(f, "show-status", t);
else
m->service_watchdogs = b;
+ } else if ((val = startswith(l, "honor-device-enumeration="))) {
+ int b;
+
+ b = parse_boolean(val);
+ if (b < 0)
+ log_notice("Failed to parse honor-device-enumeration flag '%s', ignoring.", val);
+ else
+ m->honor_device_enumeration = b;
+
} else if ((val = startswith(l, "show-status="))) {
ShowStatus s;
assert(m->n_reloading > 0);
m->n_reloading--;
+ /* On manager reloading, device tag data should exists, thus, we should honor the results of device
+ * enumeration. The flag should be always set correctly by the serialized data, but it may fail. So,
+ * let's always set the flag here for safety. */
+ m->honor_device_enumeration = true;
+
manager_ready(m);
m->send_reloading_done = true;
return found;
}
-static const char* system_env_generator_binary_paths[] = {
+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",
NULL
};
-static const char* user_env_generator_binary_paths[] = {
+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",
static int manager_run_environment_generators(Manager *m) {
char **tmp = NULL; /* this is only used in the forked process, no cleanup here */
- const char **paths;
+ const char *const *paths;
void* args[] = {
[STDOUT_GENERATE] = &tmp,
[STDOUT_COLLECT] = &tmp,
* multiple times on the same unit. */
unsigned sigchldgen;
unsigned notifygen;
+
+ bool honor_device_enumeration;
};
#define MANAGER_IS_SYSTEM(m) ((m)->unit_file_scope == UNIT_FILE_SYSTEM)
int manager_load_startable_unit_or_warn(Manager *m, const char *name, const char *path, Unit **ret);
int manager_load_unit_from_dbus_path(Manager *m, const char *s, sd_bus_error *e, Unit **_u);
-int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_error *e, Job **_ret);
-int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, sd_bus_error *e, Job **_ret);
-int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Job **ret);
+int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, Set *affected_jobs, sd_bus_error *e, Job **_ret);
+int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, Set *affected_jobs, sd_bus_error *e, Job **_ret);
+int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Set *affected_jobs, Job **ret);
int manager_propagate_reload(Manager *m, Unit *unit, JobMode mode, sd_bus_error *e);
void manager_dump_units(Manager *s, FILE *f, const char *prefix);
void manager_clear_jobs(Manager *m);
+void manager_unwatch_pid(Manager *m, pid_t pid);
+
unsigned manager_dispatch_load_queue(Manager *m);
int manager_default_environment(Manager *m);