#include "util.h"
#include "mkdir.h"
#include "ratelimit.h"
-#include "cgroup.h"
#include "mount-setup.h"
#include "unit-name.h"
#include "dbus-unit.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)
union {
struct sockaddr sa;
struct sockaddr_un un;
- } sa;
- struct epoll_event ev;
+ } sa = {
+ .sa.sa_family = AF_UNIX,
+ };
+ struct epoll_event ev = {
+ .events = EPOLLIN,
+ .data.ptr = &m->notify_watch,
+ };
int one = 1, r;
- assert(m);
-
m->notify_watch.type = WATCH_NOTIFY;
m->notify_watch.fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (m->notify_watch.fd < 0) {
return -errno;
}
- zero(sa);
- sa.sa.sa_family = AF_UNIX;
-
if (getpid() != 1 || detect_container(NULL) > 0)
snprintf(sa.un.sun_path, sizeof(sa.un.sun_path), NOTIFY_SOCKET "/%llu", random_ull());
else
return -errno;
}
- zero(ev);
- ev.events = EPOLLIN;
- ev.data.ptr = &m->notify_watch;
-
r = epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->notify_watch.fd, &ev);
if (r < 0) {
log_error("Failed to add notification socket fd to epoll: %m");
}
static int manager_jobs_in_progress_mod_timer(Manager *m) {
- struct itimerspec its;
+ struct itimerspec its = {
+ .it_value.tv_sec = JOBS_IN_PROGRESS_WAIT_SEC,
+ .it_interval.tv_sec = JOBS_IN_PROGRESS_PERIOD_SEC,
+ };
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;
}
static int manager_watch_jobs_in_progress(Manager *m) {
- struct epoll_event ev;
+ struct epoll_event ev = {
+ .events = EPOLLIN,
+ .data.ptr = &m->jobs_in_progress_watch,
+ };
int r;
- assert(m);
-
if (m->jobs_in_progress_watch.type != WATCH_INVALID)
return 0;
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;
}
static int manager_setup_time_change(Manager *m) {
- struct epoll_event ev;
- struct itimerspec its;
+ struct epoll_event ev = {
+ .events = EPOLLIN,
+ .data.ptr = &m->time_change_watch,
+ };
+
+ /* We only care for the cancellation event, hence we set the
+ * timeout to the latest possible value. */
+ struct itimerspec its = {
+ .it_value.tv_sec = TIME_T_MAX,
+ };
+ assert_cc(sizeof(time_t) == sizeof(TIME_T_MAX));
- assert(m);
assert(m->time_change_watch.type == WATCH_INVALID);
/* Uses TFD_TIMER_CANCEL_ON_SET to get notifications whenever
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);
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;
static int manager_setup_signals(Manager *m) {
sigset_t mask;
- struct epoll_event ev;
- struct sigaction sa;
+ struct epoll_event ev = {
+ .events = EPOLLIN,
+ .data.ptr = &m->signal_watch,
+ };
+ struct sigaction sa = {
+ .sa_handler = SIG_DFL,
+ .sa_flags = SA_NOCLDSTOP|SA_RESTART,
+ };
assert(m);
/* We are not interested in SIGSTOP and friends. */
- zero(sa);
- sa.sa_handler = SIG_DFL;
- sa.sa_flags = SA_NOCLDSTOP|SA_RESTART;
assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
assert_se(sigemptyset(&mask) == 0);
if (m->signal_watch.fd < 0)
return -errno;
- zero(ev);
- ev.events = EPOLLIN;
- ev.data.ptr = &m->signal_watch;
-
if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->signal_watch.fd, &ev) < 0)
return -errno;
strv_env_clean(m->environment);
}
-int manager_new(SystemdRunningAs running_as, Manager **_m) {
+int manager_new(SystemdRunningAs running_as, bool reexecuting, Manager **_m) {
Manager *m;
int r = -ENOMEM;
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);
+ if (detect_container(NULL) <= 0)
+ efi_get_boot_timestamps(&m->userspace_timestamp, &m->firmware_timestamp, &m->loader_timestamp);
#endif
m->running_as = running_as;
manager_strip_environment(m);
- if (running_as == SYSTEMD_SYSTEM) {
- m->default_controllers = strv_new("cpu", NULL);
- if (!m->default_controllers)
- goto fail;
- }
-
if (!(m->units = hashmap_new(string_hash_func, string_compare_func)))
goto fail;
if (!(m->watch_pids = hashmap_new(trivial_hash_func, trivial_compare_func)))
goto fail;
- if (!(m->cgroup_bondings = hashmap_new(string_hash_func, string_compare_func)))
+ m->cgroup_unit = hashmap_new(string_hash_func, string_compare_func);
+ if (!m->cgroup_unit)
goto fail;
- if (!(m->watch_bus = hashmap_new(string_hash_func, string_compare_func)))
+ m->watch_bus = hashmap_new(string_hash_func, string_compare_func);
+ if (!m->watch_bus)
goto fail;
m->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
goto fail;
/* Try to connect to the busses, if possible. */
- r = bus_init(m, running_as != SYSTEMD_SYSTEM);
- if (r < 0)
- goto fail;
+ if ((running_as == SYSTEMD_USER && getenv("DBUS_SESSION_BUS_ADDRESS")) ||
+ running_as == SYSTEMD_SYSTEM) {
+ r = bus_init(m, reexecuting || running_as != SYSTEMD_SYSTEM);
+ if (r < 0)
+ goto fail;
+ } else
+ log_debug("Skipping DBus session bus connection attempt - no DBUS_SESSION_BUS_ADDRESS set...");
m->taint_usr = dir_is_empty("/usr") > 0;
assert(m);
- if ((m->n_in_gc_queue < GC_QUEUE_ENTRIES_MAX) &&
- (m->gc_queue_timestamp <= 0 ||
- (m->gc_queue_timestamp + GC_QUEUE_USEC_MAX) > now(CLOCK_MONOTONIC)))
- return 0;
-
- log_debug("Running GC...");
+ /* log_debug("Running GC..."); */
m->gc_marker += _GC_OFFSET_MAX;
if (m->gc_marker + _GC_OFFSET_MAX <= _GC_OFFSET_MAX)
}
m->n_in_gc_queue = 0;
- m->gc_queue_timestamp = 0;
return n;
}
lookup_paths_free(&m->lookup_paths);
strv_free(m->environment);
- strv_free(m->default_controllers);
-
- hashmap_free(m->cgroup_bondings);
+ hashmap_free(m->cgroup_unit);
set_free_free(m->unit_path_cache);
close_pipe(m->idle_pipe);
static void manager_build_unit_path_cache(Manager *m) {
char **i;
- DIR _cleanup_free_ *d = NULL;
+ _cleanup_free_ DIR *d = NULL;
int r;
assert(m);
goto fail;
}
- r = set_put(m->unit_path_cache, p);
- if (r < 0) {
- free(p);
+ r = set_consume(m->unit_path_cache, p);
+ if (r < 0)
goto fail;
- }
}
closedir(d);
assert(m);
+ dual_timestamp_get(&m->generators_start_timestamp);
manager_run_generators(m);
+ dual_timestamp_get(&m->generators_finish_timestamp);
r = lookup_paths_init(
&m->lookup_paths, m->running_as, true,
m->n_reloading ++;
/* First, enumerate what we can from all config files */
+ dual_timestamp_get(&m->unitsload_start_timestamp);
r = manager_enumerate(m);
+ dual_timestamp_get(&m->unitsload_finish_timestamp);
/* Second, deserialize if there is something to deserialize */
if (serialization) {
if (serialization) {
assert(m->n_reloading > 0);
m->n_reloading --;
+
+ /* Let's wait for the UnitNew/JobNew messages being
+ * sent, before we notify that the reload is
+ * finished */
+ m->send_reloading_done = true;
}
return r;
return n;
}
-int manager_load_unit_prepare(Manager *m, const char *name, const char *path, DBusError *e, Unit **_ret) {
+int manager_load_unit_prepare(
+ Manager *m,
+ const char *name,
+ const char *path,
+ DBusError *e,
+ Unit **_ret) {
+
Unit *ret;
UnitType t;
int r;
}
}
- if ((r = unit_add_name(ret, name)) < 0) {
+ r = unit_add_name(ret, name);
+ if (r < 0) {
unit_free(ret);
return r;
}
return 0;
}
-int manager_load_unit(Manager *m, const char *name, const char *path, DBusError *e, Unit **_ret) {
+int manager_load_unit(
+ Manager *m,
+ const char *name,
+ const char *path,
+ DBusError *e,
+ Unit **_ret) {
+
int r;
assert(m);
}
m->dispatching_dbus_queue = false;
+
+ if (m->send_reloading_done) {
+ m->send_reloading_done = false;
+
+ bus_broadcast_reloading(m, false);
+ }
+
return n;
}
for (;;) {
char buf[4096];
- struct msghdr msghdr;
- struct iovec iovec;
- struct ucred *ucred;
+ struct iovec iovec = {
+ .iov_base = buf,
+ .iov_len = sizeof(buf)-1,
+ };
+
union {
struct cmsghdr cmsghdr;
uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
- } control;
+ } control = {};
+
+ struct msghdr msghdr = {
+ .msg_iov = &iovec,
+ .msg_iovlen = 1,
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
+ };
+ struct ucred *ucred;
Unit *u;
- char _cleanup_strv_free_ **tags = NULL;
-
- zero(iovec);
- iovec.iov_base = buf;
- iovec.iov_len = sizeof(buf)-1;
-
- zero(control);
- zero(msghdr);
- msghdr.msg_iov = &iovec;
- msghdr.msg_iovlen = 1;
- msghdr.msg_control = &control;
- msghdr.msg_controllen = sizeof(control);
+ _cleanup_strv_free_ char **tags = NULL;
n = recvmsg(m->notify_watch.fd, &msghdr, MSG_DONTWAIT);
if (n <= 0) {
- if (n >= 0)
+ if (n == 0)
return -EIO;
if (errno == EAGAIN || errno == EINTR)
u = hashmap_get(m->watch_pids, LONG_TO_PTR(ucred->pid));
if (!u) {
- u = cgroup_unit_by_pid(m, ucred->pid);
+ u = manager_get_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(m);
for (;;) {
- siginfo_t si;
+ siginfo_t si = {};
Unit *u;
int r;
- zero(si);
-
/* First we call waitd() for a PID and do not reap the
* zombie. That way we can still access /proc/$PID for
* it while it is a zombie. */
break;
if (si.si_code == CLD_EXITED || si.si_code == CLD_KILLED || si.si_code == CLD_DUMPED) {
- char _cleanup_free_ *name = NULL;
+ _cleanup_free_ char *name = NULL;
get_process_comm(si.si_pid, &name);
log_debug("Got SIGCHLD for process %lu (%s)", (unsigned long) si.si_pid, strna(name));
/* And now figure out the unit this belongs to */
u = hashmap_get(m->watch_pids, LONG_TO_PTR(si.si_pid));
if (!u)
- u = cgroup_unit_by_pid(m, si.si_pid);
+ u = manager_get_unit_by_pid(m, si.si_pid);
/* And now, we actually reap the zombie. */
if (waitid(P_PID, si.si_pid, &si, WEXITED) < 0) {
case SIGINT:
if (m->running_as == SYSTEMD_SYSTEM) {
- manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE);
+ manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE_IRREVERSIBLY);
break;
}
if (manager_dispatch_load_queue(m) > 0)
continue;
- if (manager_dispatch_run_queue(m) > 0)
+ if (manager_dispatch_gc_queue(m) > 0)
continue;
- if (bus_dispatch(m) > 0)
+ if (manager_dispatch_cleanup_queue(m) > 0)
continue;
- if (manager_dispatch_cleanup_queue(m) > 0)
+ if (manager_dispatch_cgroup_queue(m) > 0)
continue;
- if (manager_dispatch_gc_queue(m) > 0)
+ if (manager_dispatch_run_queue(m) > 0)
+ continue;
+
+ if (bus_dispatch(m) > 0)
continue;
if (manager_dispatch_dbus_queue(m) > 0)
}
int manager_load_unit_from_dbus_path(Manager *m, const char *s, DBusError *e, Unit **_u) {
- char *n;
+ _cleanup_free_ char *n = NULL;
Unit *u;
int r;
assert(s);
assert(_u);
- if (!startswith(s, "/org/freedesktop/systemd1/unit/"))
- return -EINVAL;
-
- n = bus_path_unescape(s+31);
- if (!n)
- return -ENOMEM;
+ r = unit_name_from_dbus_path(s, &n);
+ if (r < 0)
+ return r;
r = manager_load_unit(m, n, NULL, e, &u);
- free(n);
-
if (r < 0)
return r;
int manager_open_serialization(Manager *m, FILE **_f) {
char *path = NULL;
- mode_t saved_umask;
int fd;
FILE *f;
if (!path)
return -ENOMEM;
- saved_umask = umask(0077);
- fd = mkostemp(path, O_RDWR|O_CLOEXEC);
- umask(saved_umask);
+ RUN_WITH_UMASK(0077) {
+ fd = mkostemp(path, O_RDWR|O_CLOEXEC);
+ }
if (fd < 0) {
free(path);
return 0;
}
-int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool serialize_jobs) {
+int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
Iterator i;
Unit *u;
const char *t;
dual_timestamp_serialize(f, "finish-timestamp", &m->finish_timestamp);
}
- STRV_FOREACH(e, m->environment) {
- _cleanup_free_ char *ce;
+ if (!switching_root) {
+ STRV_FOREACH(e, m->environment) {
+ _cleanup_free_ char *ce;
- ce = cescape(*e);
- if (ce)
- fprintf(f, "env=%s\n", *e);
+ ce = cescape(*e);
+ if (ce)
+ fprintf(f, "env=%s\n", *e);
+ }
}
+ bus_serialize(m, f);
+
fputc('\n', f);
HASHMAP_FOREACH_KEY(u, t, m->units, i) {
fputs(u->id, f);
fputc('\n', f);
- if ((r = unit_serialize(u, f, fds, serialize_jobs)) < 0) {
+ r = unit_serialize(u, f, fds, !switching_root);
+ if (r < 0) {
m->n_reloading --;
return r;
}
strv_free(m->environment);
m->environment = e;
- } else
+ } else if (bus_deserialize_item(m, l) == 0)
log_debug("Unknown serialization item '%s'", l);
}
return r;
m->n_reloading ++;
+ bus_broadcast_reloading(m, true);
fds = fdset_new();
if (!fds) {
goto finish;
}
- r = manager_serialize(m, f, fds, true);
+ r = manager_serialize(m, f, fds, false);
if (r < 0) {
m->n_reloading --;
goto finish;
assert(m->n_reloading > 0);
m->n_reloading--;
+ m->send_reloading_done = true;
+
finish:
if (f)
fclose(f);
unit_reset_failed(u);
}
-bool manager_unit_pending_inactive(Manager *m, const char *name) {
+bool manager_unit_inactive_or_pending(Manager *m, const char *name) {
Unit *u;
assert(m);
if (!u)
return true;
- return unit_pending_inactive(u);
+ return unit_inactive_or_pending(u);
}
void manager_check_finished(Manager *m) {
DIR *d = NULL;
const char *generator_path;
const char *argv[5];
- mode_t u;
int r;
assert(m);
argv[3] = m->generator_unit_path_late;
argv[4] = NULL;
- u = umask(0022);
- execute_directory(generator_path, d, (char**) argv);
- umask(u);
+ RUN_WITH_UMASK(0022) {
+ execute_directory(generator_path, d, (char**) argv);
+ }
trim_generator_dir(m, &m->generator_unit_path);
trim_generator_dir(m, &m->generator_unit_path_early);
remove_generator_dir(m, &m->generator_unit_path_late);
}
-int manager_set_default_controllers(Manager *m, char **controllers) {
- char **l;
+int manager_set_default_environment(Manager *m, char **environment) {
+ char **e = NULL;
assert(m);
-
- l = strv_copy(controllers);
- if (!l)
+ e = strv_env_merge(2, m->environment, environment);
+ if (!e)
return -ENOMEM;
-
- strv_free(m->default_controllers);
- m->default_controllers = l;
-
- cg_shorten_controllers(m->default_controllers);
-
+ strv_free(m->environment);
+ m->environment = e;
return 0;
}