From 329ac4bc5429cd86c4ac76b13e7e2784f3982760 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 30 Apr 2015 11:58:06 +0200 Subject: [PATCH] sd-bus,sd-login: add api for querying the slice within the the user systemd instance of a process units are organized in slice trees, not only for the system instance, but also for user systemd instances, expose this properly. --- src/libsystemd/libsystemd.sym.m4 | 11 ++++- src/libsystemd/sd-bus/bus-creds.c | 36 ++++++++++++-- src/libsystemd/sd-bus/bus-creds.h | 1 + src/libsystemd/sd-bus/bus-dump.c | 18 ++++--- src/libsystemd/sd-login/sd-login.c | 22 +++++++++ src/shared/cgroup-util.c | 76 +++++++++++++++++++----------- src/shared/cgroup-util.h | 2 + src/systemd/sd-bus.h | 36 +++++++------- src/systemd/sd-login.h | 25 ++++++---- src/test/test-cgroup-util.c | 25 ++++++++++ 10 files changed, 186 insertions(+), 66 deletions(-) diff --git a/src/libsystemd/libsystemd.sym.m4 b/src/libsystemd/libsystemd.sym.m4 index 098b6a0c7f..8c28d72056 100644 --- a/src/libsystemd/libsystemd.sym.m4 +++ b/src/libsystemd/libsystemd.sym.m4 @@ -163,6 +163,12 @@ global: sd_pid_notify_with_fds; } LIBSYSTEMD_217; +LIBSYSTEMD_220 { +global: + sd_pid_get_user_slice; + sd_peer_get_user_slice; +} LIBSYSTEMD_219; + m4_ifdef(`ENABLE_KDBUS', LIBSYSTEMD_FUTURE { global: @@ -334,8 +340,9 @@ global: sd_bus_creds_get_cmdline; sd_bus_creds_get_cgroup; sd_bus_creds_get_unit; - sd_bus_creds_get_user_unit; sd_bus_creds_get_slice; + sd_bus_creds_get_user_unit; + sd_bus_creds_get_user_slice; sd_bus_creds_get_session; sd_bus_creds_get_owner_uid; sd_bus_creds_has_effective_cap; @@ -459,5 +466,5 @@ global: /* sd-path */ sd_path_home; sd_path_search; -} LIBSYSTEMD_217; +} LIBSYSTEMD_220; ) diff --git a/src/libsystemd/sd-bus/bus-creds.c b/src/libsystemd/sd-bus/bus-creds.c index ed9bf5293b..fed66823c7 100644 --- a/src/libsystemd/sd-bus/bus-creds.c +++ b/src/libsystemd/sd-bus/bus-creds.c @@ -53,6 +53,7 @@ void bus_creds_done(sd_bus_creds *c) { free(c->unit); free(c->user_unit); free(c->slice); + free(c->user_slice); free(c->unescaped_description); free(c->supplementary_gids); free(c->tty); @@ -466,6 +467,33 @@ _public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) { return 0; } +_public_ int sd_bus_creds_get_user_slice(sd_bus_creds *c, const char **ret) { + int r; + + assert_return(c, -EINVAL); + assert_return(ret, -EINVAL); + + if (!(c->mask & SD_BUS_CREDS_USER_SLICE)) + return -ENODATA; + + assert(c->cgroup); + + if (!c->user_slice) { + const char *shifted; + + r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted); + if (r < 0) + return r; + + r = cg_path_get_user_slice(shifted, (char**) &c->user_slice); + if (r < 0) + return r; + } + + *ret = c->user_slice; + return 0; +} + _public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) { int r; @@ -1013,7 +1041,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { c->mask |= SD_BUS_CREDS_TID_COMM; } - if (missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID)) { + if (missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_USER_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID)) { if (!c->cgroup) { r = cg_pid_get_path(NULL, pid, &c->cgroup); @@ -1030,7 +1058,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { } if (c->cgroup) - c->mask |= missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID); + c->mask |= missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_USER_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID); } if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) { @@ -1224,7 +1252,7 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) n->mask |= SD_BUS_CREDS_CMDLINE; } - if (c->mask & mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_OWNER_UID)) { + if (c->mask & mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_USER_SLICE|SD_BUS_CREDS_OWNER_UID)) { assert(c->cgroup); n->cgroup = strdup(c->cgroup); @@ -1235,7 +1263,7 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) if (!n->cgroup_root) return -ENOMEM; - n->mask |= mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_OWNER_UID); + n->mask |= mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_USER_SLICE|SD_BUS_CREDS_OWNER_UID); } if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) { diff --git a/src/libsystemd/sd-bus/bus-creds.h b/src/libsystemd/sd-bus/bus-creds.h index 42f76b8971..209d216123 100644 --- a/src/libsystemd/sd-bus/bus-creds.h +++ b/src/libsystemd/sd-bus/bus-creds.h @@ -61,6 +61,7 @@ struct sd_bus_creds { char *unit; char *user_unit; char *slice; + char *user_slice; char *tty; diff --git a/src/libsystemd/sd-bus/bus-dump.c b/src/libsystemd/sd-bus/bus-dump.c index 47a5c6b3a8..9db86adb7f 100644 --- a/src/libsystemd/sd-bus/bus-dump.c +++ b/src/libsystemd/sd-bus/bus-dump.c @@ -335,7 +335,7 @@ int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) { uint32_t audit_sessionid; char **cmdline = NULL, **well_known = NULL; const char *prefix, *color, *suffix, *s; - int r, q, v, w; + int r, q, v, w, z; assert(c); @@ -447,19 +447,23 @@ int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) { if (r != -ENODATA) fprintf(f, "%sUnit=%s%s%s", prefix, color, strna(s), suffix); s = NULL; - q = sd_bus_creds_get_user_unit(c, &s); - if (q != -ENODATA) - fprintf(f, "%sUserUnit=%s%s%s", prefix, color, strna(s), suffix); - s = NULL; v = sd_bus_creds_get_slice(c, &s); if (v != -ENODATA) fprintf(f, "%sSlice=%s%s%s", prefix, color, strna(s), suffix); s = NULL; - w = sd_bus_creds_get_session(c, &s); + q = sd_bus_creds_get_user_unit(c, &s); + if (q != -ENODATA) + fprintf(f, "%sUserUnit=%s%s%s", prefix, color, strna(s), suffix); + s = NULL; + w = sd_bus_creds_get_user_slice(c, &s); if (w != -ENODATA) + fprintf(f, "%sUserSlice=%s%s%s", prefix, color, strna(s), suffix); + s = NULL; + z = sd_bus_creds_get_session(c, &s); + if (z != -ENODATA) fprintf(f, "%sSession=%s%s%s", prefix, color, strna(s), suffix); - if (terse && ((c->mask & SD_BUS_CREDS_CGROUP) || r != -ENODATA || q != -ENODATA || v != -ENODATA || w != -ENODATA)) + if (terse && ((c->mask & SD_BUS_CREDS_CGROUP) || r != -ENODATA || q != -ENODATA || v != -ENODATA || w != -ENODATA || z != -ENODATA)) fputs("\n", f); r = sd_bus_creds_get_audit_login_uid(c, &audit_loginuid); diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c index 7b8f0636e5..ed8aa0952a 100644 --- a/src/libsystemd/sd-login/sd-login.c +++ b/src/libsystemd/sd-login/sd-login.c @@ -74,6 +74,14 @@ _public_ int sd_pid_get_slice(pid_t pid, char **slice) { return cg_pid_get_slice(pid, slice); } +_public_ int sd_pid_get_user_slice(pid_t pid, char **slice) { + + assert_return(pid >= 0, -EINVAL); + assert_return(slice, -EINVAL); + + return cg_pid_get_user_slice(pid, slice); +} + _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) { assert_return(pid >= 0, -EINVAL); @@ -166,6 +174,20 @@ _public_ int sd_peer_get_slice(int fd, char **slice) { return cg_pid_get_slice(ucred.pid, slice); } +_public_ int sd_peer_get_user_slice(int fd, char **slice) { + struct ucred ucred; + int r; + + assert_return(fd >= 0, -EINVAL); + assert_return(slice, -EINVAL); + + r = getpeercred(fd, &ucred); + if (r < 0) + return r; + + return cg_pid_get_user_slice(ucred.pid, slice); +} + static int file_of_uid(uid_t uid, char **p) { assert(p); diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c index 67e6f70e8e..dbf7942024 100644 --- a/src/shared/cgroup-util.c +++ b/src/shared/cgroup-util.c @@ -1317,45 +1317,37 @@ static const char *skip_user_manager(const char *p) { return NULL; } -int cg_path_get_user_unit(const char *path, char **ret) { +static const char *skip_user_prefix(const char *path) { const char *e, *t; - char *unit; - int r; assert(path); - assert(ret); - - /* We always have to parse the path from the beginning as unit - * cgroups might have arbitrary child cgroups and we shouldn't get - * confused by those */ /* Skip slices, if there are any */ e = skip_slices(path); - /* Skip the user manager... */ + /* Skip the user manager, if it's in the path now... */ t = skip_user_manager(e); + if (t) + return t; - /* Alternatively skip the user session... */ - if (!t) - t = skip_session(e); + /* Alternatively skip the user session if it is in the path... */ + return skip_session(e); +} + +int cg_path_get_user_unit(const char *path, char **ret) { + const char *t; + + assert(path); + assert(ret); + + t = skip_user_prefix(path); if (!t) return -ENXIO; - /* ... and skip more slices if there are any */ - e = skip_slices(t); - - r = cg_path_decode_unit(e, &unit); - if (r < 0) - return r; - - /* We skipped over the slices, don't accept any now */ - if (endswith(unit, ".slice")) { - free(unit); - return -ENXIO; - } - - *ret = unit; - return 0; + /* And from here on it looks pretty much the same as for a + * system unit, hence let's use the same parser from here + * on. */ + return cg_path_get_unit(t, ret); } int cg_pid_get_user_unit(pid_t pid, char **unit) { @@ -1487,6 +1479,9 @@ int cg_path_get_slice(const char *p, char **slice) { assert(p); assert(slice); + /* Finds the right-most slice unit from the beginning, but + * stops before we come to the first non-slice unit. */ + for (;;) { size_t n; @@ -1527,6 +1522,33 @@ int cg_pid_get_slice(pid_t pid, char **slice) { return cg_path_get_slice(cgroup, slice); } +int cg_path_get_user_slice(const char *p, char **slice) { + const char *t; + assert(p); + assert(slice); + + t = skip_user_prefix(p); + if (!t) + return -ENXIO; + + /* And now it looks pretty much the same as for a system + * slice, so let's just use the same parser from here on. */ + return cg_path_get_slice(t, slice); +} + +int cg_pid_get_user_slice(pid_t pid, char **slice) { + _cleanup_free_ char *cgroup = NULL; + int r; + + assert(slice); + + r = cg_pid_get_path_shifted(pid, NULL, &cgroup); + if (r < 0) + return r; + + return cg_path_get_user_slice(cgroup, slice); +} + char *cg_escape(const char *p) { bool need_prefix = false; diff --git a/src/shared/cgroup-util.h b/src/shared/cgroup-util.h index 96a3d3bafa..cbf7201370 100644 --- a/src/shared/cgroup-util.h +++ b/src/shared/cgroup-util.h @@ -104,6 +104,7 @@ int cg_path_get_unit(const char *path, char **unit); int cg_path_get_user_unit(const char *path, char **unit); int cg_path_get_machine_name(const char *path, char **machine); int cg_path_get_slice(const char *path, char **slice); +int cg_path_get_user_slice(const char *path, char **slice); int cg_shift_path(const char *cgroup, const char *cached_root, const char **shifted); int cg_pid_get_path_shifted(pid_t pid, const char *cached_root, char **cgroup); @@ -114,6 +115,7 @@ int cg_pid_get_unit(pid_t pid, char **unit); int cg_pid_get_user_unit(pid_t pid, char **unit); int cg_pid_get_machine_name(pid_t pid, char **machine); int cg_pid_get_slice(pid_t pid, char **slice); +int cg_pid_get_user_slice(pid_t pid, char **slice); int cg_path_decode_unit(const char *cgroup, char **unit); diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h index 19f01a6284..9dadae9e59 100644 --- a/src/systemd/sd-bus.h +++ b/src/systemd/sd-bus.h @@ -73,23 +73,24 @@ enum { SD_BUS_CREDS_CMDLINE = 1ULL << 15, SD_BUS_CREDS_CGROUP = 1ULL << 16, SD_BUS_CREDS_UNIT = 1ULL << 17, - SD_BUS_CREDS_USER_UNIT = 1ULL << 18, - SD_BUS_CREDS_SLICE = 1ULL << 19, - SD_BUS_CREDS_SESSION = 1ULL << 20, - SD_BUS_CREDS_OWNER_UID = 1ULL << 21, - SD_BUS_CREDS_EFFECTIVE_CAPS = 1ULL << 22, - SD_BUS_CREDS_PERMITTED_CAPS = 1ULL << 23, - SD_BUS_CREDS_INHERITABLE_CAPS = 1ULL << 24, - SD_BUS_CREDS_BOUNDING_CAPS = 1ULL << 25, - SD_BUS_CREDS_SELINUX_CONTEXT = 1ULL << 26, - SD_BUS_CREDS_AUDIT_SESSION_ID = 1ULL << 27, - SD_BUS_CREDS_AUDIT_LOGIN_UID = 1ULL << 28, - SD_BUS_CREDS_TTY = 1ULL << 29, - SD_BUS_CREDS_UNIQUE_NAME = 1ULL << 30, - SD_BUS_CREDS_WELL_KNOWN_NAMES = 1ULL << 31, - SD_BUS_CREDS_DESCRIPTION = 1ULL << 32, + SD_BUS_CREDS_SLICE = 1ULL << 18, + SD_BUS_CREDS_USER_UNIT = 1ULL << 19, + SD_BUS_CREDS_USER_SLICE = 1ULL << 20, + SD_BUS_CREDS_SESSION = 1ULL << 21, + SD_BUS_CREDS_OWNER_UID = 1ULL << 22, + SD_BUS_CREDS_EFFECTIVE_CAPS = 1ULL << 23, + SD_BUS_CREDS_PERMITTED_CAPS = 1ULL << 24, + SD_BUS_CREDS_INHERITABLE_CAPS = 1ULL << 25, + SD_BUS_CREDS_BOUNDING_CAPS = 1ULL << 26, + SD_BUS_CREDS_SELINUX_CONTEXT = 1ULL << 27, + SD_BUS_CREDS_AUDIT_SESSION_ID = 1ULL << 28, + SD_BUS_CREDS_AUDIT_LOGIN_UID = 1ULL << 29, + SD_BUS_CREDS_TTY = 1ULL << 30, + SD_BUS_CREDS_UNIQUE_NAME = 1ULL << 31, + SD_BUS_CREDS_WELL_KNOWN_NAMES = 1ULL << 32, + SD_BUS_CREDS_DESCRIPTION = 1ULL << 33, SD_BUS_CREDS_AUGMENT = 1ULL << 63, /* special flag, if on sd-bus will augment creds struct, in a potentially race-full way. */ - _SD_BUS_CREDS_ALL = (1ULL << 33) -1, + _SD_BUS_CREDS_ALL = (1ULL << 34) -1, }; enum { @@ -351,8 +352,9 @@ int sd_bus_creds_get_exe(sd_bus_creds *c, const char **exe); int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline); int sd_bus_creds_get_cgroup(sd_bus_creds *c, const char **cgroup); int sd_bus_creds_get_unit(sd_bus_creds *c, const char **unit); -int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **unit); int sd_bus_creds_get_slice(sd_bus_creds *c, const char **slice); +int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **unit); +int sd_bus_creds_get_user_slice(sd_bus_creds *c, const char **slice); int sd_bus_creds_get_session(sd_bus_creds *c, const char **session); int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid); int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability); diff --git a/src/systemd/sd-login.h b/src/systemd/sd-login.h index 24c8595064..9260396d5d 100644 --- a/src/systemd/sd-login.h +++ b/src/systemd/sd-login.h @@ -62,22 +62,25 @@ int sd_pid_get_session(pid_t pid, char **session); * return an error for system processes. */ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid); -/* Get systemd unit (i.e. service) name from PID, for system +/* Get systemd non-slice unit (i.e. service) name from PID, for system * services. This will return an error for non-service processes. */ int sd_pid_get_unit(pid_t pid, char **unit); -/* Get systemd unit (i.e. service) name from PID, for user +/* Get systemd non-slice unit (i.e. service) name from PID, for user * services. This will return an error for non-user-service * processes. */ int sd_pid_get_user_unit(pid_t pid, char **unit); +/* Get slice name from PID. */ +int sd_pid_get_slice(pid_t pid, char **slice); + +/* Get user slice name from PID. */ +int sd_pid_get_user_slice(pid_t pid, char **slice); + /* Get machine name from PID, for processes assigned to a VM or * container. This will return an error for non-machine processes. */ int sd_pid_get_machine_name(pid_t pid, char **machine); -/* Get slice name from PID. */ -int sd_pid_get_slice(pid_t pid, char **slice); - /* Similar to sd_pid_get_session(), but retrieves data about peer of * connected AF_UNIX socket */ int sd_peer_get_session(int fd, char **session); @@ -94,14 +97,18 @@ int sd_peer_get_unit(int fd, char **unit); * connected AF_UNIX socket */ int sd_peer_get_user_unit(int fd, char **unit); -/* Similar to sd_pid_get_machine_name(), but retrieves data about peer - * of connected AF_UNIX socket */ -int sd_peer_get_machine_name(int fd, char **machine); - /* Similar to sd_pid_get_slice(), but retrieves data about peer of * connected AF_UNIX socket */ int sd_peer_get_slice(int fd, char **slice); +/* Similar to sd_pid_get_user_slice(), but retrieves data about peer of + * connected AF_UNIX socket */ +int sd_peer_get_user_slice(int fd, char **slice); + +/* Similar to sd_pid_get_machine_name(), but retrieves data about peer + * of connected AF_UNIX socket */ +int sd_peer_get_machine_name(int fd, char **machine); + /* Get state from UID. Possible states: offline, lingering, online, active, closing */ int sd_uid_get_state(uid_t uid, char **state); diff --git a/src/test/test-cgroup-util.c b/src/test/test-cgroup-util.c index 759ca4498b..79c11e297e 100644 --- a/src/test/test-cgroup-util.c +++ b/src/test/test-cgroup-util.c @@ -142,6 +142,30 @@ static void test_path_get_slice(void) { check_p_g_slice("foo.slice/foo-bar.slice/waldo.service", 0, "foo-bar.slice"); } +static void check_p_g_u_slice(const char *path, int code, const char *result) { + _cleanup_free_ char *s = NULL; + + assert_se(cg_path_get_user_slice(path, &s) == code); + assert_se(streq_ptr(s, result)); +} + +static void test_path_get_user_slice(void) { + check_p_g_u_slice("/user.slice", -ENXIO, NULL); + check_p_g_u_slice("/foobar", -ENXIO, NULL); + check_p_g_u_slice("/user.slice/user-waldo.slice", -ENXIO, NULL); + check_p_g_u_slice("", -ENXIO, NULL); + check_p_g_u_slice("foobar", -ENXIO, NULL); + check_p_g_u_slice("foobar.slice", -ENXIO, NULL); + check_p_g_u_slice("foo.slice/foo-bar.slice/waldo.service", -ENXIO, NULL); + + check_p_g_u_slice("foo.slice/foo-bar.slice/user@1000.service", 0, "-.slice"); + check_p_g_u_slice("foo.slice/foo-bar.slice/user@1000.service/", 0, "-.slice"); + check_p_g_u_slice("foo.slice/foo-bar.slice/user@1000.service///", 0, "-.slice"); + check_p_g_u_slice("foo.slice/foo-bar.slice/user@1000.service/waldo.service", 0, "-.slice"); + check_p_g_u_slice("foo.slice/foo-bar.slice/user@1000.service/piep.slice/foo.service", 0, "piep.slice"); + check_p_g_u_slice("/foo.slice//foo-bar.slice/user@1000.service/piep.slice//piep-pap.slice//foo.service", 0, "piep-pap.slice"); +} + static void test_get_paths(void) { _cleanup_free_ char *a = NULL; @@ -273,6 +297,7 @@ int main(void) { test_path_get_session(); test_path_get_owner_uid(); test_path_get_slice(); + test_path_get_user_slice(); TEST_REQ_RUNNING_SYSTEMD(test_get_paths()); test_proc(); TEST_REQ_RUNNING_SYSTEMD(test_escape());