summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Gundersen <teg@jklm.no>2015-09-01 19:48:04 +0200
committerTom Gundersen <teg@jklm.no>2015-09-01 19:48:04 +0200
commitfc94c3260549c12892461be031c4b9dc122ca1ef (patch)
tree3b9bf7eccf1690daa57da5419d29554175605c20
parent332929623af07716530fb0d0a30e792b564ea486 (diff)
parentd06673212e7672da44d5147d1d393278d9b1b478 (diff)
Merge pull request #1111 from poettering/more-cgroup-fixes
More cgroup fixes
-rw-r--r--src/basic/cgroup-util.c107
-rw-r--r--src/basic/cgroup-util.h4
-rw-r--r--src/basic/set.h6
-rw-r--r--src/cgtop/cgtop.c8
-rw-r--r--src/core/cgroup.c23
-rw-r--r--src/core/cgroup.h2
-rw-r--r--src/core/main.c2
-rw-r--r--src/core/manager.c13
-rw-r--r--src/core/manager.h3
-rw-r--r--src/core/scope.c2
-rw-r--r--src/core/service.c29
-rw-r--r--src/core/unit.c75
-rw-r--r--src/libsystemd/sd-login/sd-login.c6
-rw-r--r--src/libsystemd/sd-login/test-login.c26
-rw-r--r--src/login/loginctl.c2
-rw-r--r--src/machine/machinectl.c2
-rw-r--r--src/shared/cgroup-show.c2
-rw-r--r--src/systemctl/systemctl.c2
-rw-r--r--src/test/test-cgroup.c12
19 files changed, 207 insertions, 119 deletions
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
index 6b3162a35f..98adace55a 100644
--- a/src/basic/cgroup-util.c
+++ b/src/basic/cgroup-util.c
@@ -29,7 +29,6 @@
#include <sys/types.h>
#include <ftw.h>
-#include "cgroup-util.h"
#include "set.h"
#include "macro.h"
#include "util.h"
@@ -41,6 +40,7 @@
#include "special.h"
#include "mkdir.h"
#include "login-util.h"
+#include "cgroup-util.h"
int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
_cleanup_free_ char *fs = NULL;
@@ -113,7 +113,7 @@ int cg_read_subgroup(DIR *d, char **fn) {
assert(d);
assert(fn);
- FOREACH_DIRENT(de, d, return -errno) {
+ FOREACH_DIRENT_ALL(de, d, return -errno) {
char *b;
if (de->d_type != DT_DIR)
@@ -197,7 +197,7 @@ int cg_kill(const char *controller, const char *path, int sig, bool sigcont, boo
ret = -errno;
} else {
if (sigcont && sig != SIGKILL)
- kill(pid, SIGCONT);
+ (void) kill(pid, SIGCONT);
if (ret == 0)
ret = 1;
@@ -233,7 +233,7 @@ int cg_kill(const char *controller, const char *path, int sig, bool sigcont, boo
int cg_kill_recursive(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, bool rem, Set *s) {
_cleanup_set_free_ Set *allocated_set = NULL;
_cleanup_closedir_ DIR *d = NULL;
- int r, ret = 0;
+ int r, ret;
char *fn;
assert(path);
@@ -264,7 +264,7 @@ int cg_kill_recursive(const char *controller, const char *path, int sig, bool si
return -ENOMEM;
r = cg_kill_recursive(controller, p, sig, sigcont, ignore_self, rem, s);
- if (ret >= 0 && r != 0)
+ if (r != 0 && ret >= 0)
ret = r;
}
@@ -321,6 +321,14 @@ int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char
if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
continue;
+ /* Ignore kernel threads. Since they can only
+ * exist in the root cgroup, we only check for
+ * them there. */
+ if (cfrom &&
+ (isempty(pfrom) || path_equal(pfrom, "/")) &&
+ is_kernel_thread(pid) > 0)
+ continue;
+
r = cg_attach(cto, pto, pid);
if (r < 0) {
if (ret >= 0 && r != -ESRCH)
@@ -382,12 +390,8 @@ int cg_migrate_recursive(
p = strjoin(pfrom, "/", fn, NULL);
free(fn);
- if (!p) {
- if (ret >= 0)
- return -ENOMEM;
-
- return ret;
- }
+ if (!p)
+ return -ENOMEM;
r = cg_migrate_recursive(cfrom, p, cto, pto, ignore_self, rem);
if (r != 0 && ret >= 0)
@@ -428,13 +432,15 @@ int cg_migrate_recursive_fallback(
/* This didn't work? Then let's try all prefixes of the destination */
PATH_FOREACH_PREFIX(prefix, pto) {
- r = cg_migrate_recursive(cfrom, pfrom, cto, prefix, ignore_self, rem);
- if (r >= 0)
- break;
+ int q;
+
+ q = cg_migrate_recursive(cfrom, pfrom, cto, prefix, ignore_self, rem);
+ if (q >= 0)
+ return q;
}
}
- return 0;
+ return r;
}
static const char *normalize_controller(const char *controller) {
@@ -549,7 +555,7 @@ static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct
if (ftwbuf->level < 1)
return 0;
- rmdir(path);
+ (void) rmdir(path);
return 0;
}
@@ -564,8 +570,14 @@ int cg_trim(const char *controller, const char *path, bool delete_root) {
return r;
errno = 0;
- if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) != 0)
- r = errno ? -errno : -EIO;
+ if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) != 0) {
+ if (errno == ENOENT)
+ r = 0;
+ else if (errno != 0)
+ r = -errno;
+ else
+ r = -EIO;
+ }
if (delete_root) {
if (rmdir(fs) < 0 && errno != ENOENT)
@@ -664,13 +676,15 @@ int cg_attach_fallback(const char *controller, const char *path, pid_t pid) {
* the destination */
PATH_FOREACH_PREFIX(prefix, path) {
- r = cg_attach(controller, prefix, pid);
- if (r >= 0)
- break;
+ int q;
+
+ q = cg_attach(controller, prefix, pid);
+ if (q >= 0)
+ return q;
}
}
- return 0;
+ return r;
}
int cg_set_group_access(
@@ -683,7 +697,8 @@ int cg_set_group_access(
_cleanup_free_ char *fs = NULL;
int r;
- assert(path);
+ if (mode == MODE_INVALID && uid == UID_INVALID && gid == GID_INVALID)
+ return 0;
if (mode != MODE_INVALID)
mode &= 0777;
@@ -819,7 +834,7 @@ int cg_install_release_agent(const char *controller, const char *agent) {
return r;
sc = strstrip(contents);
- if (sc[0] == 0) {
+ if (isempty(sc)) {
r = write_string_file(fs, agent, 0);
if (r < 0)
return r;
@@ -876,49 +891,46 @@ int cg_uninstall_release_agent(const char *controller) {
return 0;
}
-int cg_is_empty(const char *controller, const char *path, bool ignore_self) {
+int cg_is_empty(const char *controller, const char *path) {
_cleanup_fclose_ FILE *f = NULL;
- pid_t pid = 0, self_pid;
- bool found = false;
+ pid_t pid = 0;
int r;
assert(path);
r = cg_enumerate_processes(controller, path, &f);
+ if (r == -ENOENT)
+ return 1;
if (r < 0)
- return r == -ENOENT ? 1 : r;
-
- self_pid = getpid();
-
- while ((r = cg_read_pid(f, &pid)) > 0) {
-
- if (ignore_self && pid == self_pid)
- continue;
-
- found = true;
- break;
- }
+ return r;
+ r = cg_read_pid(f, &pid);
if (r < 0)
return r;
- return !found;
+ return r == 0;
}
-int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self) {
+int cg_is_empty_recursive(const char *controller, const char *path) {
_cleanup_closedir_ DIR *d = NULL;
char *fn;
int r;
assert(path);
- r = cg_is_empty(controller, path, ignore_self);
+ /* The root cgroup is always populated */
+ if (controller && (isempty(path) || path_equal(path, "/")))
+ return 0;
+
+ r = cg_is_empty(controller, path);
if (r <= 0)
return r;
r = cg_enumerate_subgroups(controller, path, &d);
+ if (r == -ENOENT)
+ return 1;
if (r < 0)
- return r == -ENOENT ? 1 : r;
+ return r;
while ((r = cg_read_subgroup(d, &fn)) > 0) {
_cleanup_free_ char *p = NULL;
@@ -928,7 +940,7 @@ int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_
if (!p)
return -ENOMEM;
- r = cg_is_empty_recursive(controller, p, ignore_self);
+ r = cg_is_empty_recursive(controller, p);
if (r <= 0)
return r;
}
@@ -1869,6 +1881,11 @@ int cg_kernel_controllers(Set *controllers) {
assert(controllers);
+ /* Determines the full list of kernel-known controllers. Might
+ * include controllers we don't actually support, arbitrary
+ * named hierarchies and controllers that aren't currently
+ * accessible (because not mounted). */
+
f = fopen("/proc/cgroups", "re");
if (!f) {
if (errno == ENOENT)
@@ -1889,7 +1906,7 @@ int cg_kernel_controllers(Set *controllers) {
if (feof(f))
break;
- if (ferror(f) && errno)
+ if (ferror(f) && errno != 0)
return -errno;
return -EBADMSG;
diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h
index fd72e9e5c5..1c86581eb5 100644
--- a/src/basic/cgroup-util.h
+++ b/src/basic/cgroup-util.h
@@ -93,8 +93,8 @@ int cg_set_task_access(const char *controller, const char *path, mode_t mode, ui
int cg_install_release_agent(const char *controller, const char *agent);
int cg_uninstall_release_agent(const char *controller);
-int cg_is_empty(const char *controller, const char *path, bool ignore_self);
-int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self);
+int cg_is_empty(const char *controller, const char *path);
+int cg_is_empty_recursive(const char *controller, const char *path);
int cg_get_root_path(char **path);
diff --git a/src/basic/set.h b/src/basic/set.h
index 51e40d3a6c..4554ef2d49 100644
--- a/src/basic/set.h
+++ b/src/basic/set.h
@@ -28,12 +28,14 @@ Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
#define set_new(ops) internal_set_new(ops HASHMAP_DEBUG_SRC_ARGS)
-static inline void set_free(Set *s) {
+static inline Set *set_free(Set *s) {
internal_hashmap_free(HASHMAP_BASE(s));
+ return NULL;
}
-static inline void set_free_free(Set *s) {
+static inline Set *set_free_free(Set *s) {
internal_hashmap_free_free(HASHMAP_BASE(s));
+ return NULL;
}
/* no set_free_free_free */
diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c
index 06a43d15e4..ae562ba135 100644
--- a/src/cgtop/cgtop.c
+++ b/src/cgtop/cgtop.c
@@ -560,15 +560,17 @@ static void display(Hashmap *a) {
path_columns = maxtpath;
for (j = 0; j < n; j++) {
- _cleanup_free_ char *p = NULL;
+ _cleanup_free_ char *ellipsized = NULL;
+ const char *path;
if (on_tty() && j + 5 > rows)
break;
g = array[j];
- p = ellipsize(g->path, path_columns, 33);
- printf("%-*s", path_columns, p ?: g->path);
+ path = isempty(g->path) ? "/" : g->path;
+ ellipsized = ellipsize(path, path_columns, 33);
+ printf("%-*s", path_columns, ellipsized ?: path);
if (g->n_tasks_valid)
printf(" %7u", g->n_tasks);
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index c26807ba2b..e92d2cc850 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -1005,6 +1005,7 @@ Unit* manager_get_unit_by_cgroup(Manager *m, const char *cgroup) {
Unit *manager_get_unit_by_pid(Manager *m, pid_t pid) {
_cleanup_free_ char *cgroup = NULL;
+ Unit *u;
int r;
assert(m);
@@ -1012,6 +1013,14 @@ Unit *manager_get_unit_by_pid(Manager *m, pid_t pid) {
if (pid <= 1)
return NULL;
+ u = hashmap_get(m->watch_pids1, LONG_TO_PTR(pid));
+ if (u)
+ return u;
+
+ u = hashmap_get(m->watch_pids2, LONG_TO_PTR(pid));
+ if (u)
+ return u;
+
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &cgroup);
if (r < 0)
return NULL;
@@ -1030,7 +1039,7 @@ int manager_notify_cgroup_empty(Manager *m, const char *cgroup) {
if (!u)
return 0;
- r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
+ r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path);
if (r <= 0)
return r;
@@ -1124,6 +1133,18 @@ int unit_reset_cpu_usage(Unit *u) {
return 0;
}
+bool unit_cgroup_delegate(Unit *u) {
+ CGroupContext *c;
+
+ assert(u);
+
+ c = unit_get_cgroup_context(u);
+ if (!c)
+ return false;
+
+ return c->delegate;
+}
+
static const char* const cgroup_device_policy_table[_CGROUP_DEVICE_POLICY_MAX] = {
[CGROUP_AUTO] = "auto",
[CGROUP_CLOSED] = "closed",
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
index 869ddae8c4..7b38d210fb 100644
--- a/src/core/cgroup.h
+++ b/src/core/cgroup.h
@@ -130,5 +130,7 @@ int unit_get_memory_current(Unit *u, uint64_t *ret);
int unit_get_cpu_usage(Unit *u, nsec_t *ret);
int unit_reset_cpu_usage(Unit *u);
+bool unit_cgroup_delegate(Unit *u);
+
const char* cgroup_device_policy_to_string(CGroupDevicePolicy i) _const_;
CGroupDevicePolicy cgroup_device_policy_from_string(const char *s) _pure_;
diff --git a/src/core/main.c b/src/core/main.c
index 833fd74d87..2736b272dc 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -2048,7 +2048,7 @@ finish:
* kernel; at this point, we will not listen to the
* signals anyway */
if (detect_container(NULL) <= 0)
- cg_uninstall_release_agent(SYSTEMD_CGROUP_CONTROLLER);
+ (void) cg_uninstall_release_agent(SYSTEMD_CGROUP_CONTROLLER);
execve(SYSTEMD_SHUTDOWN_BINARY_PATH, (char **) command_line, env_block);
log_error_errno(errno, "Failed to execute shutdown binary, %s: %m",
diff --git a/src/core/manager.c b/src/core/manager.c
index ede2a9910d..14f069ba97 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -573,6 +573,7 @@ int manager_new(ManagerRunningAs running_as, bool test_run, Manager **_m) {
m->ask_password_inotify_fd = -1;
m->have_ask_password = -EINVAL; /* we don't know */
+ m->first_boot = -1;
m->test_run = test_run;
@@ -2998,12 +2999,14 @@ void manager_set_first_boot(Manager *m, bool b) {
if (m->running_as != MANAGER_SYSTEM)
return;
- m->first_boot = b;
+ if (m->first_boot != (int) b) {
+ if (b)
+ (void) touch("/run/systemd/first-boot");
+ else
+ (void) unlink("/run/systemd/first-boot");
+ }
- if (m->first_boot)
- touch("/run/systemd/first-boot");
- else
- unlink("/run/systemd/first-boot");
+ m->first_boot = b;
}
void manager_status_printf(Manager *m, StatusType type, const char *status, const char *format, ...) {
diff --git a/src/core/manager.h b/src/core/manager.h
index 1e01f2bdef..3f7fa24e58 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -233,7 +233,6 @@ struct Manager {
bool dispatching_dbus_queue:1;
bool taint_usr:1;
- bool first_boot:1;
bool test_run:1;
@@ -295,6 +294,8 @@ struct Manager {
const char *unit_log_field;
const char *unit_log_format_string;
+
+ int first_boot;
};
int manager_new(ManagerRunningAs running_as, bool test_run, Manager **m);
diff --git a/src/core/scope.c b/src/core/scope.c
index c594ab5294..1e94d63561 100644
--- a/src/core/scope.c
+++ b/src/core/scope.c
@@ -396,7 +396,7 @@ static bool scope_check_gc(Unit *u) {
if (u->cgroup_path) {
int r;
- r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
+ r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path);
if (r <= 0)
return true;
}
diff --git a/src/core/service.c b/src/core/service.c
index 3c4232417d..5a0a3aa867 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -1269,7 +1269,7 @@ static int cgroup_good(Service *s) {
if (!UNIT(s)->cgroup_path)
return 0;
- r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, UNIT(s)->cgroup_path, true);
+ r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, UNIT(s)->cgroup_path);
if (r < 0)
return r;
@@ -1520,18 +1520,33 @@ fail:
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
}
+static bool service_good(Service *s) {
+ int main_pid_ok;
+ assert(s);
+
+ if (s->type == SERVICE_DBUS && !s->bus_name_good)
+ return false;
+
+ main_pid_ok = main_pid_good(s);
+ if (main_pid_ok > 0) /* It's alive */
+ return true;
+ if (main_pid_ok == 0) /* It's dead */
+ return false;
+
+ /* OK, we don't know anything about the main PID, maybe
+ * because there is none. Let's check the control group
+ * instead. */
+
+ return cgroup_good(s) != 0;
+}
+
static void service_enter_running(Service *s, ServiceResult f) {
- int main_pid_ok, cgroup_ok;
assert(s);
if (f != SERVICE_SUCCESS)
s->result = f;
- main_pid_ok = main_pid_good(s);
- cgroup_ok = cgroup_good(s);
-
- if ((main_pid_ok > 0 || (main_pid_ok < 0 && cgroup_ok != 0)) &&
- (s->bus_name_good || s->type != SERVICE_DBUS)) {
+ if (service_good(s)) {
/* If there are any queued up sd_notify()
* notifications, process them now */
diff --git a/src/core/unit.c b/src/core/unit.c
index 5f602bdf5f..34d3adcd3b 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -28,27 +28,28 @@
#include "sd-id128.h"
#include "sd-messages.h"
#include "set.h"
-#include "unit.h"
#include "macro.h"
#include "strv.h"
#include "path-util.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
#include "log.h"
-#include "unit-name.h"
-#include "dbus-unit.h"
-#include "special.h"
#include "cgroup-util.h"
#include "missing.h"
#include "mkdir.h"
#include "fileio-label.h"
-#include "bus-common-errors.h"
-#include "dbus.h"
-#include "execute.h"
-#include "dropin.h"
#include "formats-util.h"
#include "process-util.h"
+#include "virt.h"
+#include "bus-common-errors.h"
#include "bus-util.h"
+#include "dropin.h"
+#include "unit-name.h"
+#include "special.h"
+#include "unit.h"
+#include "load-fragment.h"
+#include "load-dropin.h"
+#include "dbus.h"
+#include "dbus-unit.h"
+#include "execute.h"
const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
[UNIT_SERVICE] = &service_vtable,
@@ -2016,9 +2017,9 @@ void unit_unwatch_pid(Unit *u, pid_t pid) {
assert(u);
assert(pid >= 1);
- hashmap_remove_value(u->manager->watch_pids1, LONG_TO_PTR(pid), u);
- hashmap_remove_value(u->manager->watch_pids2, LONG_TO_PTR(pid), u);
- set_remove(u->pids, LONG_TO_PTR(pid));
+ (void) hashmap_remove_value(u->manager->watch_pids1, LONG_TO_PTR(pid), u);
+ (void) hashmap_remove_value(u->manager->watch_pids2, LONG_TO_PTR(pid), u);
+ (void) set_remove(u->pids, LONG_TO_PTR(pid));
}
void unit_unwatch_all_pids(Unit *u) {
@@ -2440,6 +2441,9 @@ int unit_set_slice(Unit *u, Unit *slice) {
if (u->type == UNIT_SLICE)
return -EINVAL;
+ if (unit_active_state(u) != UNIT_INACTIVE)
+ return -EBUSY;
+
if (slice->type != UNIT_SLICE)
return -EINVAL;
@@ -3168,7 +3172,7 @@ int unit_kill_common(
if (!pid_set)
return -ENOMEM;
- q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, false, true, false, pid_set);
+ q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, false, false, false, pid_set);
if (q < 0 && q != -EAGAIN && q != -ESRCH && q != -ENOENT)
r = q;
}
@@ -3524,7 +3528,8 @@ int unit_kill_context(
pid_t control_pid,
bool main_pid_alien) {
- int sig, wait_for_exit = false, r;
+ bool wait_for_exit = false;
+ int sig, r;
assert(u);
assert(c);
@@ -3553,13 +3558,13 @@ int unit_kill_context(
_cleanup_free_ char *comm = NULL;
get_process_comm(main_pid, &comm);
- log_unit_warning_errno(u, r, "Failed to kill main process " PID_FMT " (%s): %m", main_pid, strna(comm));
+ log_unit_warning_errno(u, r, "Failed to kill main process " PID_FMT " (%s), ignoring: %m", main_pid, strna(comm));
} else {
if (!main_pid_alien)
wait_for_exit = true;
- if (c->send_sighup && k != KILL_KILL)
- kill(main_pid, SIGHUP);
+ if (c->send_sighup && k == KILL_TERMINATE)
+ (void) kill(main_pid, SIGHUP);
}
}
@@ -3570,16 +3575,17 @@ int unit_kill_context(
_cleanup_free_ char *comm = NULL;
get_process_comm(control_pid, &comm);
- log_unit_warning_errno(u, r, "Failed to kill control process " PID_FMT " (%s): %m", control_pid, strna(comm));
+ log_unit_warning_errno(u, r, "Failed to kill control process " PID_FMT " (%s), ignoring: %m", control_pid, strna(comm));
} else {
wait_for_exit = true;
- if (c->send_sighup && k != KILL_KILL)
- kill(control_pid, SIGHUP);
+ if (c->send_sighup && k == KILL_TERMINATE)
+ (void) kill(control_pid, SIGHUP);
}
}
- if ((c->kill_mode == KILL_CONTROL_GROUP || (c->kill_mode == KILL_MIXED && k == KILL_KILL)) && u->cgroup_path) {
+ if (u->cgroup_path &&
+ (c->kill_mode == KILL_CONTROL_GROUP || (c->kill_mode == KILL_MIXED && k == KILL_KILL))) {
_cleanup_set_free_ Set *pid_set = NULL;
/* Exclude the main/control pids from being killed via the cgroup */
@@ -3587,21 +3593,26 @@ int unit_kill_context(
if (!pid_set)
return -ENOMEM;
- r = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, sig, true, true, false, pid_set);
+ r = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, sig, true, k != KILL_TERMINATE, false, pid_set);
if (r < 0) {
if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
- log_unit_warning_errno(u, r, "Failed to kill control group: %m");
+ log_unit_warning_errno(u, r, "Failed to kill control group %s, ignoring: %m", u->cgroup_path);
+
} else if (r > 0) {
/* FIXME: For now, we will not wait for the
- * cgroup members to die, simply because
- * cgroup notification is unreliable. It
- * doesn't work at all in containers, and
- * outside of containers it can be confused
- * easily by leaving directories in the
- * cgroup. */
-
- /* wait_for_exit = true; */
+ * cgroup members to die if we are running in
+ * a container or if this is a delegation
+ * unit, simply because cgroup notification is
+ * unreliable in these cases. It doesn't work
+ * at all in containers, and outside of
+ * containers it can be confused easily by
+ * left-over directories in the cgroup --
+ * which however should not exist in
+ * non-delegated units. */
+
+ if (detect_container(NULL) == 0 && !unit_cgroup_delegate(u))
+ wait_for_exit = true;
if (c->send_sighup && k != KILL_KILL) {
set_free(pid_set);
diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c
index 0eadc8c747..7d6a4b78cf 100644
--- a/src/libsystemd/sd-login/sd-login.c
+++ b/src/libsystemd/sd-login/sd-login.c
@@ -237,11 +237,13 @@ _public_ int sd_uid_get_display(uid_t uid, char **session) {
return r;
r = parse_env_file(p, NEWLINE, "DISPLAY", &s, NULL);
+ if (r == -ENOENT)
+ return -ENXIO;
if (r < 0)
return r;
if (isempty(s))
- return -ENOENT;
+ return -ENXIO;
*session = s;
s = NULL;
@@ -465,7 +467,7 @@ static int session_get_string(const char *session, const char *field, char **val
return r;
if (isempty(s))
- return -ENOENT;
+ return -ENXIO;
*value = s;
s = NULL;
diff --git a/src/libsystemd/sd-login/test-login.c b/src/libsystemd/sd-login/test-login.c
index 05affa442d..ddea7ffa14 100644
--- a/src/libsystemd/sd-login/test-login.c
+++ b/src/libsystemd/sd-login/test-login.c
@@ -33,7 +33,7 @@ static void test_login(void) {
_cleanup_free_ char *pp = NULL, *qq = NULL;
int r, k;
uid_t u, u2;
- char *seat, *type, *class, *display, *remote_user, *remote_host;
+ char *seat, *type, *class, *display, *remote_user, *remote_host, *display_session;
char *session;
char *state;
char *session2;
@@ -50,6 +50,12 @@ static void test_login(void) {
assert_se(sd_pid_get_owner_uid(0, &u2) == 0);
printf("user = "UID_FMT"\n", u2);
+ display_session = NULL;
+ r = sd_uid_get_display(u2, &display_session);
+ assert_se(r >= 0 || r == -ENXIO);
+ printf("user's display session = %s\n", strna(display_session));
+ free(display_session);
+
assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == 0);
sd_peer_get_session(pair[0], &pp);
sd_peer_get_session(pair[1], &qq);
@@ -100,16 +106,22 @@ static void test_login(void) {
printf("class = %s\n", class);
free(class);
- assert_se(sd_session_get_display(session, &display) >= 0);
- printf("display = %s\n", display);
+ display = NULL;
+ r = sd_session_get_display(session, &display);
+ assert_se(r >= 0 || r == -ENXIO);
+ printf("display = %s\n", strna(display));
free(display);
- assert_se(sd_session_get_remote_user(session, &remote_user) >= 0);
- printf("remote_user = %s\n", remote_user);
+ remote_user = NULL;
+ r = sd_session_get_remote_user(session, &remote_user);
+ assert_se(r >= 0 || r == -ENXIO);
+ printf("remote_user = %s\n", strna(remote_user));
free(remote_user);
- assert_se(sd_session_get_remote_host(session, &remote_host) >= 0);
- printf("remote_host = %s\n", remote_host);
+ remote_host = NULL;
+ r = sd_session_get_remote_host(session, &remote_host);
+ assert_se(r >= 0 || r == -ENXIO);
+ printf("remote_host = %s\n", strna(remote_host));
free(remote_host);
assert_se(sd_session_get_seat(session, &seat) >= 0);
diff --git a/src/login/loginctl.c b/src/login/loginctl.c
index 5fa98e069f..a7e64071cf 100644
--- a/src/login/loginctl.c
+++ b/src/login/loginctl.c
@@ -263,7 +263,7 @@ static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit
if (isempty(cgroup))
return 0;
- if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0)
+ if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
return 0;
c = columns();
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index 8bd0ed756b..bb8c5ac64b 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -375,7 +375,7 @@ static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
if (r < 0)
return bus_log_parse_error(r);
- if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0)
+ if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
return 0;
c = columns();
diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c
index 3abccdb49a..31b4f6c684 100644
--- a/src/shared/cgroup-show.c
+++ b/src/shared/cgroup-show.c
@@ -152,7 +152,7 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
if (!k)
return -ENOMEM;
- if (!(flags & OUTPUT_SHOW_ALL) && cg_is_empty_recursive(NULL, k, false) > 0)
+ if (!(flags & OUTPUT_SHOW_ALL) && cg_is_empty_recursive(NULL, k) > 0)
continue;
if (!shown_pids) {
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 3cb5f61868..8d80aae182 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -3557,7 +3557,7 @@ static void print_status_info(
if (i->control_group &&
(i->main_pid > 0 || i->control_pid > 0 ||
- ((arg_transport != BUS_TRANSPORT_LOCAL && arg_transport != BUS_TRANSPORT_MACHINE) || cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, i->control_group, false) == 0))) {
+ ((arg_transport != BUS_TRANSPORT_LOCAL && arg_transport != BUS_TRANSPORT_MACHINE) || cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, i->control_group) == 0))) {
unsigned c;
printf(" CGroup: %s\n", i->control_group);
diff --git a/src/test/test-cgroup.c b/src/test/test-cgroup.c
index 4be69a408d..8b0302cfe6 100644
--- a/src/test/test-cgroup.c
+++ b/src/test/test-cgroup.c
@@ -56,18 +56,18 @@ int main(int argc, char*argv[]) {
assert_se(path_equal(path, "/sys/fs/cgroup/systemd/test-b/test-d"));
free(path);
- assert_se(cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, "/test-a", false) > 0);
- assert_se(cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, "/test-b", false) > 0);
- assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", false) > 0);
- assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", false) == 0);
+ assert_se(cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, "/test-a") > 0);
+ assert_se(cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, "/test-b") > 0);
+ assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a") > 0);
+ assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b") == 0);
assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", 0, false, false, false, NULL) == 0);
assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", 0, false, false, false, NULL) > 0);
assert_se(cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", SYSTEMD_CGROUP_CONTROLLER, "/test-a", false, false) > 0);
- assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", false) == 0);
- assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", false) > 0);
+ assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a") == 0);
+ assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b") > 0);
assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", 0, false, false, false, NULL) > 0);
assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", 0, false, false, false, NULL) == 0);