#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
+#include <sys/timerfd.h>
#ifdef HAVE_AUDIT
#include <libaudit.h>
#include "watchdog.h"
#include "cgroup-util.h"
#include "path-util.h"
+#include "audit-fd.h"
+#include "efivars.h"
+#include "env-util.h"
/* As soon as 16 units are in our GC queue, make sure to run a gc sweep */
#define GC_QUEUE_ENTRIES_MAX 16
/* As soon as 5s passed since a unit was added to our GC queue, make sure to run a gc sweep */
#define GC_QUEUE_USEC_MAX (10*USEC_PER_SEC)
+/* Initial delay and the interval for printing status messages about running jobs */
+#define JOBS_IN_PROGRESS_WAIT_SEC 5
+#define JOBS_IN_PROGRESS_PERIOD_SEC 1
+#define JOBS_IN_PROGRESS_PERIOD_DIVISOR 3
+
/* Where clients shall send notification messages to */
#define NOTIFY_SOCKET "@/org/freedesktop/systemd1/notify"
+#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
+
static int manager_setup_notify(Manager *m) {
union {
struct sockaddr sa;
ev.events = EPOLLIN;
ev.data.ptr = &m->notify_watch;
- if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->notify_watch.fd, &ev) < 0)
+ if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->notify_watch.fd, &ev) < 0) {
+ log_error("Failed to add notification socket fd to epoll: %m");
return -errno;
+ }
sa.un.sun_path[0] = '@';
m->notify_socket = strdup(sa.un.sun_path);
if (!m->notify_socket)
- return -ENOMEM;
+ return log_oom();
log_debug("Using notification socket %s", m->notify_socket);
return 0;
}
+static int manager_jobs_in_progress_mod_timer(Manager *m) {
+ struct itimerspec its;
+
+ if (m->jobs_in_progress_watch.type != WATCH_JOBS_IN_PROGRESS)
+ return 0;
+
+ zero(its);
+
+ its.it_value.tv_sec = JOBS_IN_PROGRESS_WAIT_SEC;
+ its.it_interval.tv_sec = JOBS_IN_PROGRESS_PERIOD_SEC;
+
+ if (timerfd_settime(m->jobs_in_progress_watch.fd, 0, &its, NULL) < 0)
+ return -errno;
+
+ return 0;
+}
+
+static int manager_watch_jobs_in_progress(Manager *m) {
+ struct epoll_event ev;
+ int r;
+
+ assert(m);
+
+ if (m->jobs_in_progress_watch.type != WATCH_INVALID)
+ return 0;
+
+ m->jobs_in_progress_watch.type = WATCH_JOBS_IN_PROGRESS;
+ m->jobs_in_progress_watch.fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC);
+ if (m->jobs_in_progress_watch.fd < 0) {
+ log_error("Failed to create timerfd: %m");
+ r = -errno;
+ goto err;
+ }
+
+ r = manager_jobs_in_progress_mod_timer(m);
+ if (r < 0) {
+ log_error("Failed to set up timer for jobs progress watch: %s", strerror(-r));
+ goto err;
+ }
+
+ zero(ev);
+ ev.events = EPOLLIN;
+ ev.data.ptr = &m->jobs_in_progress_watch;
+
+ if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->jobs_in_progress_watch.fd, &ev) < 0) {
+ log_error("Failed to add jobs progress timer fd to epoll: %m");
+ r = -errno;
+ goto err;
+ }
+
+ log_debug("Set up jobs progress timerfd.");
+
+ return 0;
+
+err:
+ if (m->jobs_in_progress_watch.fd >= 0)
+ close_nointr_nofail(m->jobs_in_progress_watch.fd);
+ watch_init(&m->jobs_in_progress_watch);
+ return r;
+}
+
+static void manager_unwatch_jobs_in_progress(Manager *m) {
+ if (m->jobs_in_progress_watch.type != WATCH_JOBS_IN_PROGRESS)
+ return;
+
+ assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, m->jobs_in_progress_watch.fd, NULL) >= 0);
+ close_nointr_nofail(m->jobs_in_progress_watch.fd);
+ watch_init(&m->jobs_in_progress_watch);
+ m->jobs_in_progress_iteration = 0;
+
+ log_debug("Closed jobs progress timerfd.");
+}
+
+#define CYLON_BUFFER_EXTRA (2*strlen(ANSI_RED_ON) + strlen(ANSI_HIGHLIGHT_RED_ON) + 2*strlen(ANSI_HIGHLIGHT_OFF))
+static void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned pos) {
+ char *p = buffer;
+
+ assert(buflen >= CYLON_BUFFER_EXTRA + width + 1);
+ assert(pos <= width+1); /* 0 or width+1 mean that the center light is behind the corner */
+
+ if (pos > 1) {
+ if (pos > 2)
+ p = mempset(p, ' ', pos-2);
+ p = stpcpy(p, ANSI_RED_ON);
+ *p++ = '*';
+ }
+
+ if (pos > 0 && pos <= width) {
+ p = stpcpy(p, ANSI_HIGHLIGHT_RED_ON);
+ *p++ = '*';
+ }
+
+ p = stpcpy(p, ANSI_HIGHLIGHT_OFF);
+
+ if (pos < width) {
+ p = stpcpy(p, ANSI_RED_ON);
+ *p++ = '*';
+ if (pos < width-1)
+ p = mempset(p, ' ', width-1-pos);
+ p = stpcpy(p, ANSI_HIGHLIGHT_OFF);
+ }
+}
+
+static void manager_print_jobs_in_progress(Manager *m) {
+ Iterator i;
+ Job *j;
+ char *job_of_n = NULL;
+ unsigned counter = 0, print_nr;
+ char cylon[6 + CYLON_BUFFER_EXTRA + 1];
+ unsigned cylon_pos;
+
+ print_nr = (m->jobs_in_progress_iteration / JOBS_IN_PROGRESS_PERIOD_DIVISOR) % m->n_running_jobs;
+
+ HASHMAP_FOREACH(j, m->jobs, i)
+ if (j->state == JOB_RUNNING && counter++ == print_nr)
+ break;
+
+ /* m->n_running_jobs must be consistent with the contents of m->jobs,
+ * so the above loop must have succeeded in finding j. */
+ assert(counter == print_nr + 1);
+
+ cylon_pos = m->jobs_in_progress_iteration % 14;
+ if (cylon_pos >= 8)
+ cylon_pos = 14 - cylon_pos;
+ draw_cylon(cylon, sizeof(cylon), 6, cylon_pos);
+
+ if (m->n_running_jobs > 1)
+ if (asprintf(&job_of_n, "(%u of %u) ", counter, m->n_running_jobs) < 0)
+ job_of_n = NULL;
+
+ manager_status_printf(m, true, cylon, "%sA %s job is running for %s",
+ strempty(job_of_n), job_type_to_string(j->type), unit_description(j->unit));
+ free(job_of_n);
+
+ m->jobs_in_progress_iteration++;
+}
+
+static int manager_setup_time_change(Manager *m) {
+ struct epoll_event ev;
+ struct itimerspec its;
+
+ assert(m);
+ assert(m->time_change_watch.type == WATCH_INVALID);
+
+ /* Uses TFD_TIMER_CANCEL_ON_SET to get notifications whenever
+ * CLOCK_REALTIME makes a jump relative to CLOCK_MONOTONIC */
+
+ m->time_change_watch.type = WATCH_TIME_CHANGE;
+ m->time_change_watch.fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
+ if (m->time_change_watch.fd < 0) {
+ log_error("Failed to create timerfd: %m");
+ return -errno;
+ }
+
+ zero(its);
+
+ /* We only care for the cancellation event, hence we set the
+ * timeout to the latest possible value. */
+ assert_cc(sizeof(time_t) == sizeof(TIME_T_MAX));
+ its.it_value.tv_sec = TIME_T_MAX;
+
+ if (timerfd_settime(m->time_change_watch.fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) {
+ log_debug("Failed to set up TFD_TIMER_CANCEL_ON_SET, ignoring: %m");
+ close_nointr_nofail(m->time_change_watch.fd);
+ watch_init(&m->time_change_watch);
+ return 0;
+ }
+
+ zero(ev);
+ ev.events = EPOLLIN;
+ ev.data.ptr = &m->time_change_watch;
+
+ if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->time_change_watch.fd, &ev) < 0) {
+ log_error("Failed to add timer change fd to epoll: %m");
+ return -errno;
+ }
+
+ log_debug("Set up TFD_TIMER_CANCEL_ON_SET timerfd.");
+
+ return 0;
+}
+
static int enable_special_signals(Manager *m) {
int fd;
SIGRTMIN+21, /* systemd: disable status messages */
SIGRTMIN+22, /* systemd: set log level to LOG_DEBUG */
SIGRTMIN+23, /* systemd: set log level to LOG_INFO */
+ SIGRTMIN+24, /* systemd: Immediate exit (--user only) */
SIGRTMIN+26, /* systemd: set log target to journal-or-kmsg */
SIGRTMIN+27, /* systemd: set log target to console */
SIGRTMIN+28, /* systemd: set log target to kmsg */
assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
m->signal_watch.type = WATCH_SIGNAL;
- if ((m->signal_watch.fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0)
+ m->signal_watch.fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
+ if (m->signal_watch.fd < 0)
return -errno;
zero(ev);
if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->signal_watch.fd, &ev) < 0)
return -errno;
- if (m->running_as == MANAGER_SYSTEM)
+ if (m->running_as == SYSTEMD_SYSTEM)
return enable_special_signals(m);
return 0;
* the initrd interface:
* http://www.freedesktop.org/wiki/Software/systemd/InitrdInterface */
strv_remove_prefix(m->environment, "RD_");
+
+ /* Drop invalid entries */
+ strv_env_clean(m->environment);
}
-int manager_new(ManagerRunningAs running_as, Manager **_m) {
+int manager_new(SystemdRunningAs running_as, Manager **_m) {
Manager *m;
int r = -ENOMEM;
assert(_m);
assert(running_as >= 0);
- assert(running_as < _MANAGER_RUNNING_AS_MAX);
+ assert(running_as < _SYSTEMD_RUNNING_AS_MAX);
m = new0(Manager, 1);
if (!m)
return -ENOMEM;
dual_timestamp_get(&m->userspace_timestamp);
+ dual_timestamp_from_monotonic(&m->kernel_timestamp, 0);
+#ifdef ENABLE_EFI
+ efi_get_boot_timestamps(&m->userspace_timestamp, &m->firmware_timestamp, &m->loader_timestamp);
+#endif
m->running_as = running_as;
m->name_data_slot = m->conn_data_slot = m->subscribed_data_slot = -1;
m->pin_cgroupfs_fd = -1;
m->idle_pipe[0] = m->idle_pipe[1] = -1;
-#ifdef HAVE_AUDIT
- m->audit_fd = -1;
-#endif
+ watch_init(&m->signal_watch);
+ watch_init(&m->mount_watch);
+ watch_init(&m->swap_watch);
+ watch_init(&m->udev_watch);
+ watch_init(&m->time_change_watch);
+ watch_init(&m->jobs_in_progress_watch);
- m->signal_watch.fd = m->mount_watch.fd = m->udev_watch.fd = m->epoll_fd = m->dev_autofs_fd = m->swap_watch.fd = -1;
+ m->epoll_fd = m->dev_autofs_fd = -1;
m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
m->environment = strv_copy(environ);
manager_strip_environment(m);
- if (running_as == MANAGER_SYSTEM) {
+ if (running_as == SYSTEMD_SYSTEM) {
m->default_controllers = strv_new("cpu", NULL);
if (!m->default_controllers)
goto fail;
if (!(m->watch_bus = hashmap_new(string_hash_func, string_compare_func)))
goto fail;
- if ((m->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0)
+ m->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+ if (m->epoll_fd < 0)
goto fail;
- if ((r = manager_setup_signals(m)) < 0)
+ r = manager_setup_signals(m);
+ if (r < 0)
goto fail;
- if ((r = manager_setup_cgroup(m)) < 0)
+ r = manager_setup_cgroup(m);
+ if (r < 0)
goto fail;
- if ((r = manager_setup_notify(m)) < 0)
+ r = manager_setup_notify(m);
+ if (r < 0)
goto fail;
- /* Try to connect to the busses, if possible. */
- if ((r = bus_init(m, running_as != MANAGER_SYSTEM)) < 0)
+ r = manager_setup_time_change(m);
+ if (r < 0)
goto fail;
-#ifdef HAVE_AUDIT
- if ((m->audit_fd = audit_open()) < 0 &&
- /* If the kernel lacks netlink or audit support,
- * don't worry about it. */
- errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT)
- log_error("Failed to connect to audit log: %m");
-#endif
+ /* Try to connect to the busses, if possible. */
+ r = bus_init(m, running_as != SYSTEMD_SYSTEM);
+ if (r < 0)
+ goto fail;
m->taint_usr = dir_is_empty("/usr") > 0;
if (u->gc_marker == gc_marker + GC_OFFSET_BAD ||
u->gc_marker == gc_marker + GC_OFFSET_UNSURE) {
- log_debug("Collecting %s", u->id);
+ log_debug_unit(u->id, "Collecting %s", u->id);
u->gc_marker = gc_marker + GC_OFFSET_BAD;
unit_add_to_cleanup_queue(u);
}
assert(hashmap_isempty(m->jobs));
assert(hashmap_isempty(m->units));
+
+ m->n_on_console = 0;
+ m->n_running_jobs = 0;
}
void manager_free(Manager *m) {
close_nointr_nofail(m->signal_watch.fd);
if (m->notify_watch.fd >= 0)
close_nointr_nofail(m->notify_watch.fd);
-
-#ifdef HAVE_AUDIT
- if (m->audit_fd >= 0)
- audit_close(m->audit_fd);
-#endif
+ if (m->time_change_watch.fd >= 0)
+ close_nointr_nofail(m->time_change_watch.fd);
+ if (m->jobs_in_progress_watch.fd >= 0)
+ close_nointr_nofail(m->jobs_in_progress_watch.fd);
free(m->notify_socket);
static void manager_build_unit_path_cache(Manager *m) {
char **i;
- DIR *d = NULL;
+ DIR _cleanup_free_ *d = NULL;
int r;
assert(m);
set_free_free(m->unit_path_cache);
- if (!(m->unit_path_cache = set_new(string_hash_func, string_compare_func))) {
+ m->unit_path_cache = set_new(string_hash_func, string_compare_func);
+ if (!m->unit_path_cache) {
log_error("Failed to allocate unit path cache.");
return;
}
STRV_FOREACH(i, m->lookup_paths.unit_path) {
struct dirent *de;
- if (!(d = opendir(*i))) {
- log_error("Failed to open directory: %m");
+ d = opendir(*i);
+ if (!d) {
+ if (errno != ENOENT)
+ log_error("Failed to open directory %s: %m", *i);
continue;
}
goto fail;
}
- if ((r = set_put(m->unit_path_cache, p)) < 0) {
+ r = set_put(m->unit_path_cache, p);
+ if (r < 0) {
free(p);
goto fail;
}
set_free_free(m->unit_path_cache);
m->unit_path_cache = NULL;
-
- if (d)
- closedir(d);
}
int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
r = q;
}
+ /* Any fds left? Find some unit which wants them. This is
+ * useful to allow container managers to pass some file
+ * descriptors to us pre-initialized. This enables
+ * socket-based activation of entire containers. */
+ if (fdset_size(fds) > 0) {
+ q = manager_distribute_fds(m, fds);
+ if (q < 0)
+ r = q;
+ }
+
/* Third, fire things up! */
q = manager_coldplug(m);
if (q < 0)
return -EPERM;
}
- log_debug("Trying to enqueue job %s/%s/%s", unit->id, job_type_to_string(type), job_mode_to_string(mode));
+ log_debug_unit(unit->id,
+ "Trying to enqueue job %s/%s/%s", unit->id,
+ job_type_to_string(type), job_mode_to_string(mode));
job_type_collapse(&type, unit);
- tr = transaction_new();
+ tr = transaction_new(mode == JOB_REPLACE_IRREVERSIBLY);
if (!tr)
return -ENOMEM;
if (r < 0)
goto tr_abort;
- log_debug("Enqueued job %s/%s as %u", unit->id, job_type_to_string(type), (unsigned) tr->anchor_job->id);
+ log_debug_unit(unit->id,
+ "Enqueued job %s/%s as %u", unit->id,
+ job_type_to_string(type), (unsigned) tr->anchor_job->id);
if (_ret)
*_ret = tr->anchor_job;
}
m->dispatching_run_queue = false;
+
+ if (m->n_running_jobs > 0)
+ manager_watch_jobs_in_progress(m);
+
return n;
}
msghdr.msg_control = &control;
msghdr.msg_controllen = sizeof(control);
- if ((n = recvmsg(m->notify_watch.fd, &msghdr, MSG_DONTWAIT)) <= 0) {
+ n = recvmsg(m->notify_watch.fd, &msghdr, MSG_DONTWAIT);
+ if (n <= 0) {
if (n >= 0)
return -EIO;
ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
- if (!(u = hashmap_get(m->watch_pids, LONG_TO_PTR(ucred->pid))))
- if (!(u = cgroup_unit_by_pid(m, ucred->pid))) {
+ u = hashmap_get(m->watch_pids, LONG_TO_PTR(ucred->pid));
+ if (!u) {
+ u = cgroup_unit_by_pid(m, ucred->pid);
+ if (!u) {
log_warning("Cannot find unit for notify message of PID %lu.", (unsigned long) ucred->pid);
continue;
}
+ }
assert((size_t) n < sizeof(buf));
buf[n] = 0;
- if (!(tags = strv_split(buf, "\n\r")))
- return -ENOMEM;
+ tags = strv_split(buf, "\n\r");
+ if (!tags)
+ return log_oom();
- log_debug("Got notification message for unit %s", u->id);
+ log_debug_unit(u->id, "Got notification message for unit %s", u->id);
if (UNIT_VTABLE(u)->notify_message)
UNIT_VTABLE(u)->notify_message(u, ucred->pid, tags);
break;
if (si.si_code == CLD_EXITED || si.si_code == CLD_KILLED || si.si_code == CLD_DUMPED) {
- char *name = NULL;
+ char _cleanup_free_ *name = NULL;
get_process_comm(si.si_pid, &name);
log_debug("Got SIGCHLD for process %lu (%s)", (unsigned long) si.si_pid, strna(name));
- free(name);
}
/* Let's flush any message the dying child might still
* have queued for us. This ensures that the process
* still exists in /proc so that we can figure out
* which cgroup and hence unit it belongs to. */
- if ((r = manager_process_notify_fd(m)) < 0)
+ r = manager_process_notify_fd(m);
+ if (r < 0)
return r;
/* And now figure out the unit this belongs to */
- if (!(u = hashmap_get(m->watch_pids, LONG_TO_PTR(si.si_pid))))
+ u = hashmap_get(m->watch_pids, LONG_TO_PTR(si.si_pid));
+ if (!u)
u = cgroup_unit_by_pid(m, si.si_pid);
/* And now, we actually reap the zombie. */
if (!u)
continue;
- log_debug("Child %lu belongs to %s", (long unsigned) si.si_pid, u->id);
+ log_debug_unit(u->id,
+ "Child %lu belongs to %s", (long unsigned) si.si_pid, u->id);
hashmap_remove(m->watch_pids, LONG_TO_PTR(si.si_pid));
UNIT_VTABLE(u)->sigchld_event(u, si.si_pid, si.si_code, si.si_status);
dbus_error_init(&error);
- log_debug("Activating special unit %s", name);
+ log_debug_unit(name, "Activating special unit %s", name);
- if ((r = manager_add_job_by_name(m, JOB_START, name, mode, true, &error, NULL)) < 0)
- log_error("Failed to enqueue %s job: %s", name, bus_error(&error, r));
+ r = manager_add_job_by_name(m, JOB_START, name, mode, true, &error, NULL);
+ if (r < 0)
+ log_error_unit(name,
+ "Failed to enqueue %s job: %s", name, bus_error(&error, r));
dbus_error_free(&error);
assert(m);
for (;;) {
- if ((n = read(m->signal_watch.fd, &sfsi, sizeof(sfsi))) != sizeof(sfsi)) {
+ n = read(m->signal_watch.fd, &sfsi, sizeof(sfsi));
+ if (n != sizeof(sfsi)) {
if (n >= 0)
return -EIO;
break;
case SIGTERM:
- if (m->running_as == MANAGER_SYSTEM) {
+ if (m->running_as == SYSTEMD_SYSTEM) {
/* This is for compatibility with the
* original sysvinit */
m->exit_code = MANAGER_REEXECUTE;
/* Fall through */
case SIGINT:
- if (m->running_as == MANAGER_SYSTEM) {
+ if (m->running_as == SYSTEMD_SYSTEM) {
manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE);
break;
}
break;
case SIGWINCH:
- if (m->running_as == MANAGER_SYSTEM)
+ if (m->running_as == SYSTEMD_SYSTEM)
manager_start_target(m, SPECIAL_KBREQUEST_TARGET, JOB_REPLACE);
/* This is a nop on non-init */
break;
case SIGPWR:
- if (m->running_as == MANAGER_SYSTEM)
+ if (m->running_as == SYSTEMD_SYSTEM)
manager_start_target(m, SPECIAL_SIGPWR_TARGET, JOB_REPLACE);
/* This is a nop on non-init */
log_notice("Setting log level to info.");
break;
+ case 24:
+ if (m->running_as == SYSTEMD_USER) {
+ m->exit_code = MANAGER_EXIT;
+ return 0;
+ }
+
+ /* This is a nop on init */
+ break;
+
case 26:
log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
log_notice("Setting log target to journal-or-kmsg.");
ssize_t k;
/* Some timer event, to be dispatched to the units */
- if ((k = read(w->fd, &v, sizeof(v))) != sizeof(v)) {
+ k = read(w->fd, &v, sizeof(v));
+ if (k != sizeof(v)) {
if (k < 0 && (errno == EINTR || errno == EAGAIN))
break;
+ log_error("Failed to read timer event counter: %s", k < 0 ? strerror(-k) : "Short read");
return k < 0 ? -errno : -EIO;
}
bus_timeout_event(m, w, ev->events);
break;
+ case WATCH_TIME_CHANGE: {
+ Unit *u;
+ Iterator i;
+
+ log_struct(LOG_INFO,
+ MESSAGE_ID(SD_MESSAGE_TIME_CHANGE),
+ "MESSAGE=Time has been changed",
+ NULL);
+
+ /* Restart the watch */
+ epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, m->time_change_watch.fd,
+ NULL);
+ close_nointr_nofail(m->time_change_watch.fd);
+ watch_init(&m->time_change_watch);
+ manager_setup_time_change(m);
+
+ HASHMAP_FOREACH(u, m->units, i) {
+ if (UNIT_VTABLE(u)->time_change)
+ UNIT_VTABLE(u)->time_change(u);
+ }
+
+ break;
+ }
+
+ case WATCH_JOBS_IN_PROGRESS: {
+ uint64_t v;
+
+ /* not interested in the data */
+ read(w->fd, &v, sizeof(v));
+
+ manager_print_jobs_in_progress(m);
+ break;
+ }
+
default:
log_error("event type=%i", w->type);
assert_not_reached("Unknown epoll event type.");
int n;
int wait_msec = -1;
- if (m->runtime_watchdog > 0 && m->running_as == MANAGER_SYSTEM)
+ if (m->runtime_watchdog > 0 && m->running_as == SYSTEMD_SYSTEM)
watchdog_ping();
if (!ratelimit_test(&rl)) {
continue;
/* Sleep for half the watchdog time */
- if (m->runtime_watchdog > 0 && m->running_as == MANAGER_SYSTEM) {
+ if (m->runtime_watchdog > 0 && m->running_as == SYSTEMD_SYSTEM) {
wait_msec = (int) (m->runtime_watchdog / 2 / USEC_PER_MSEC);
if (wait_msec <= 0)
wait_msec = 1;
if (!startswith(s, "/org/freedesktop/systemd1/job/"))
return -EINVAL;
- if ((r = safe_atou(s + 30, &id)) < 0)
+ r = safe_atou(s + 30, &id);
+ if (r < 0)
return r;
- if (!(j = manager_get_job(m, id)))
+ j = manager_get_job(m, id);
+ if (!j)
return -ENOENT;
*_j = j;
#ifdef HAVE_AUDIT
char *p;
+ int audit_fd;
- if (m->audit_fd < 0)
+ audit_fd = get_audit_fd();
+ if (audit_fd < 0)
return;
/* Don't generate audit events if the service was already
if (m->n_reloading > 0)
return;
- if (m->running_as != MANAGER_SYSTEM)
+ if (m->running_as != SYSTEMD_SYSTEM)
return;
if (u->type != UNIT_SERVICE)
return;
- if (!(p = unit_name_to_prefix_and_instance(u->id))) {
- log_error("Failed to allocate unit name for audit message: %s", strerror(ENOMEM));
+ p = unit_name_to_prefix_and_instance(u->id);
+ if (!p) {
+ log_error_unit(u->id,
+ "Failed to allocate unit name for audit message: %s", strerror(ENOMEM));
return;
}
- if (audit_log_user_comm_message(m->audit_fd, type, "", p, NULL, NULL, NULL, success) < 0) {
+ if (audit_log_user_comm_message(audit_fd, type, "", p, NULL, NULL, NULL, success) < 0) {
if (errno == EPERM) {
/* We aren't allowed to send audit messages?
* Then let's not retry again. */
- audit_close(m->audit_fd);
- m->audit_fd = -1;
+ close_audit_fd();
} else
log_warning("Failed to send audit message: %m");
}
if (m->n_reloading > 0)
return;
- if (m->running_as != MANAGER_SYSTEM)
+ if (m->running_as != SYSTEMD_SYSTEM)
return;
if (u->type != UNIT_SERVICE &&
assert(_f);
- if (m->running_as == MANAGER_SYSTEM)
+ if (m->running_as == SYSTEMD_SYSTEM)
asprintf(&path, "/run/systemd/dump-%lu-XXXXXX", (unsigned long) getpid());
else
asprintf(&path, "/tmp/systemd-dump-%lu-XXXXXX", (unsigned long) getpid());
log_debug("Serializing state to %s", path);
free(path);
- if (!(f = fdopen(fd, "w+")))
+ f = fdopen(fd, "w+");
+ if (!f)
return -errno;
*_f = f;
Iterator i;
Unit *u;
const char *t;
+ char **e;
int r;
assert(m);
dual_timestamp_serialize(f, "finish-timestamp", &m->finish_timestamp);
}
+ STRV_FOREACH(e, m->environment) {
+ _cleanup_free_ char *ce;
+
+ ce = cescape(*e);
+ if (ce)
+ fprintf(f, "env=%s\n", *e);
+ }
+
fputc('\n', f);
HASHMAP_FOREACH_KEY(u, t, m->units, i) {
dual_timestamp_deserialize(l+20, &m->userspace_timestamp);
else if (startswith(l, "finish-timestamp="))
dual_timestamp_deserialize(l+17, &m->finish_timestamp);
- else
+ else if (startswith(l, "env=")) {
+ _cleanup_free_ char *uce = NULL;
+ char **e;
+
+ uce = cunescape(l+4);
+ if (!uce) {
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ e = strv_env_set(m->environment, uce);
+ if (!e) {
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ strv_free(m->environment);
+ m->environment = e;
+ } else
log_debug("Unknown serialization item '%s'", l);
}
char_array_0(name);
- if ((r = manager_load_unit(m, strstrip(name), NULL, NULL, &u)) < 0)
+ r = manager_load_unit(m, strstrip(name), NULL, NULL, &u);
+ if (r < 0)
goto finish;
- if ((r = unit_deserialize(u, f, fds)) < 0)
+ r = unit_deserialize(u, f, fds);
+ if (r < 0)
goto finish;
}
return r;
}
+int manager_distribute_fds(Manager *m, FDSet *fds) {
+ Unit *u;
+ Iterator i;
+ int r;
+
+ assert(m);
+
+ HASHMAP_FOREACH(u, m->units, i) {
+
+ if (fdset_size(fds) <= 0)
+ break;
+
+ if (UNIT_VTABLE(u)->distribute_fds) {
+ r = UNIT_VTABLE(u)->distribute_fds(u, fds);
+ if (r < 0)
+ return r;
+ }
+ }
+
+ return 0;
+}
+
int manager_reload(Manager *m) {
int r, q;
FILE *f;
return r;
}
-bool manager_is_booting_or_shutting_down(Manager *m) {
+static bool manager_is_booting_or_shutting_down(Manager *m) {
Unit *u;
assert(m);
return false;
}
+bool manager_is_reloading_or_reexecuting(Manager *m) {
+ assert(m);
+
+ return m->n_reloading != 0;
+}
+
void manager_reset_failed(Manager *m) {
Unit *u;
Iterator i;
assert(name);
/* Returns true if the unit is inactive or going down */
- if (!(u = manager_get_unit(m, name)))
+ u = manager_get_unit(m, name);
+ if (!u)
return true;
return unit_pending_inactive(u);
assert(m);
- if (hashmap_size(m->jobs) > 0)
+ if (m->n_running_jobs == 0)
+ manager_unwatch_jobs_in_progress(m);
+
+ if (hashmap_size(m->jobs) > 0) {
+ manager_jobs_in_progress_mod_timer(m);
return;
+ }
/* Notify Type=idle units that we are done now */
close_pipe(m->idle_pipe);
dual_timestamp_get(&m->finish_timestamp);
- if (m->running_as == MANAGER_SYSTEM && detect_container(NULL) <= 0) {
+ if (m->running_as == SYSTEMD_SYSTEM && detect_container(NULL) <= 0) {
/* Note that m->kernel_usec.monotonic is always at 0,
* and m->firmware_usec.monotonic and
if (!log_on_console())
log_struct(LOG_INFO,
- "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(SD_MESSAGE_STARTUP_FINISHED),
+ MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
"KERNEL_USEC=%llu", (unsigned long long) kernel_usec,
"INITRD_USEC=%llu", (unsigned long long) initrd_usec,
"USERSPACE_USEC=%llu", (unsigned long long) userspace_usec,
if (!log_on_console())
log_struct(LOG_INFO,
- "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(SD_MESSAGE_STARTUP_FINISHED),
+ MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
"KERNEL_USEC=%llu", (unsigned long long) kernel_usec,
"USERSPACE_USEC=%llu", (unsigned long long) userspace_usec,
"MESSAGE=Startup finished in %s (kernel) + %s (userspace) = %s.",
if (!log_on_console())
log_struct(LOG_INFO,
- "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(SD_MESSAGE_STARTUP_FINISHED),
+ MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
"USERSPACE_USEC=%llu", (unsigned long long) userspace_usec,
"MESSAGE=Startup finished in %s.",
format_timespan(sum, sizeof(sum), total_usec),
if (*generator)
return 0;
- if (m->running_as == MANAGER_SYSTEM && getpid() == 1) {
+ if (m->running_as == SYSTEMD_SYSTEM && getpid() == 1) {
p = strappend("/run/systemd/", name);
if (!p)
r = mkdir_p_label(p, 0755);
if (r < 0) {
- log_error("Failed to create generator directory: %s", strerror(-r));
+ log_error("Failed to create generator directory %s: %s",
+ p, strerror(-r));
free(p);
return r;
}
return log_oom();
if (!mkdtemp(p)) {
+ log_error("Failed to create generator directory %s: %m",
+ p);
free(p);
- log_error("Failed to create generator directory: %m");
return -errno;
}
}
assert(m);
- generator_path = m->running_as == MANAGER_SYSTEM ? SYSTEM_GENERATOR_PATH : USER_GENERATOR_PATH;
+ generator_path = m->running_as == SYSTEMD_SYSTEM ? SYSTEM_GENERATOR_PATH : USER_GENERATOR_PATH;
d = opendir(generator_path);
if (!d) {
if (errno == ENOENT)
return;
- log_error("Failed to enumerate generator directory: %m");
+ log_error("Failed to enumerate generator directory %s: %m",
+ generator_path);
return;
}
assert(m);
- if (m->running_as != MANAGER_SYSTEM)
+ if (m->running_as != SYSTEMD_SYSTEM)
return;
u = manager_get_unit(m, SPECIAL_JOURNALD_SOCKET);
void manager_set_show_status(Manager *m, bool b) {
assert(m);
- if (m->running_as != MANAGER_SYSTEM)
+ if (m->running_as != SYSTEMD_SYSTEM)
return;
m->show_status = b;
unlink("/run/systemd/show-status");
}
-bool manager_get_show_status(Manager *m) {
+static bool manager_get_show_status(Manager *m) {
assert(m);
- if (m->running_as != MANAGER_SYSTEM)
+ if (m->running_as != SYSTEMD_SYSTEM)
return false;
if (m->show_status)
return plymouth_running();
}
-static const char* const manager_running_as_table[_MANAGER_RUNNING_AS_MAX] = {
- [MANAGER_SYSTEM] = "system",
- [MANAGER_USER] = "user"
-};
+void manager_status_printf(Manager *m, bool ephemeral, const char *status, const char *format, ...) {
+ va_list ap;
+
+ if (!manager_get_show_status(m))
+ return;
-DEFINE_STRING_TABLE_LOOKUP(manager_running_as, ManagerRunningAs);
+ /* XXX We should totally drop the check for ephemeral here
+ * and thus effectively make 'Type=idle' pointless. */
+ if (ephemeral && m->n_on_console > 0)
+ return;
+
+ if (!manager_is_booting_or_shutting_down(m))
+ return;
+
+ va_start(ap, format);
+ status_vprintf(status, true, ephemeral, format, ap);
+ va_end(ap);
+}
+
+void watch_init(Watch *w) {
+ assert(w);
+
+ w->type = WATCH_INVALID;
+ w->fd = -1;
+}