along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/inotify.h>
#include <sys/epoll.h>
-#include <sys/poll.h>
#include <sys/reboot.h>
#include <sys/ioctl.h>
#include <linux/kd.h>
-#include <termios.h>
#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <dirent.h>
#include <sys/timerfd.h>
#endif
#include "sd-daemon.h"
-#include "sd-id128.h"
#include "sd-messages.h"
#include "manager.h"
#include "mkdir.h"
#include "ratelimit.h"
#include "locale-setup.h"
-#include "mount-setup.h"
#include "unit-name.h"
#include "missing.h"
#include "path-lookup.h"
#include "exit-status.h"
#include "virt.h"
#include "watchdog.h"
-#include "cgroup-util.h"
#include "path-util.h"
#include "audit-fd.h"
#include "boot-timestamps.h"
static int manager_run_generators(Manager *m);
static void manager_undo_generators(Manager *m);
-static int manager_watch_jobs_in_progress(Manager *m) {
+static void manager_watch_jobs_in_progress(Manager *m) {
usec_t next;
assert(m);
if (m->jobs_in_progress_event_source)
- return 0;
+ return;
next = now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC;
- return sd_event_add_time(
+ (void) sd_event_add_time(
m->event,
&m->jobs_in_progress_event_source,
CLOCK_MONOTONIC,
int q;
if (unit_vtable[c]->supported && !unit_vtable[c]->supported(m)) {
- log_info("Unit type .%s is not supported on this system.", unit_type_to_string(c));
+ log_debug("Unit type .%s is not supported on this system.", unit_type_to_string(c));
continue;
}
Unit *u;
char *k;
- assert(m);
+ /*
+ * Some unit types tend to spawn jobs or check other units' state
+ * during coldplug. This is wrong because it is undefined whether the
+ * units in question have been already coldplugged (i. e. their state
+ * restored). This way, we can easily re-start an already started unit
+ * or otherwise make a wrong decision based on the unit's state.
+ *
+ * Solve this by providing a way for coldplug functions to defer
+ * such actions until after all units have been coldplugged.
+ *
+ * We store Unit* -> int(*)(Unit*).
+ *
+ * https://bugs.freedesktop.org/show_bug.cgi?id=88401
+ */
+ _cleanup_hashmap_free_ Hashmap *deferred_work = NULL;
+ int(*proc)(Unit*);
+
+ assert(m);
+
+ deferred_work = hashmap_new(&trivial_hash_ops);
+ if (!deferred_work)
+ return -ENOMEM;
/* Then, let's set up their initial state. */
HASHMAP_FOREACH_KEY(u, k, m->units, i) {
if (u->id != k)
continue;
- q = unit_coldplug(u);
+ q = unit_coldplug(u, deferred_work);
+ if (q < 0)
+ r = q;
+ }
+
+ /* After coldplugging and setting up initial state of the units,
+ * let's perform operations which spawn jobs or query units' state. */
+ HASHMAP_FOREACH_KEY(proc, u, deferred_work, i) {
+ int q;
+
+ q = proc(u);
if (q < 0)
r = q;
}
case SIGINT:
if (m->running_as == SYSTEMD_SYSTEM) {
- /* If the user presses C-A-D too more
- * than 7 times within 2s, we reboot
+ /* If the user presses C-A-D more than
+ * 7 times within 2s, we reboot
* immediately. */
if (ratelimit_test(&m->ctrl_alt_del_ratelimit))
return;
}
- msg = strappenda("unit=", p);
-
+ msg = strjoina("unit=", p);
if (audit_log_user_comm_message(audit_fd, type, msg, "systemd", NULL, NULL, NULL, success) < 0) {
if (errno == EPERM)
/* We aren't allowed to send audit messages?
if (hashmap_size(m->jobs) > 0) {
if (m->jobs_in_progress_event_source)
- sd_event_source_set_time(m->jobs_in_progress_event_source, now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC);
+ /* 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);
return;
}
getenv("XDG_RUNTIME_DIR");
}
+void manager_update_failed_units(Manager *m, Unit *u, bool failed) {
+ unsigned size;
+
+ assert(m);
+ assert(u->manager == m);
+
+ size = set_size(m->failed_units);
+
+ if (failed) {
+ if (set_put(m->failed_units, u) < 0)
+ log_oom();
+ } else
+ set_remove(m->failed_units, u);
+
+ if (set_size(m->failed_units) != size)
+ bus_manager_send_change_signal(m);
+}
+
ManagerState manager_state(Manager *m) {
Unit *u;