#include <unistd.h>
#include "alloc-util.h"
+#include "capsule-util.h"
#include "cgroup-util.h"
#include "constants.h"
#include "dirent-util.h"
}
/**
- * Skip user@*.service, but require it to be there.
+ * Skip user@*.service or capsule@*.service, but require either of them to be there.
*/
static const char *skip_user_manager(const char *p) {
size_t n;
p += strspn(p, "/");
n = strcspn(p, "/");
- if (n < STRLEN("user@x.service"))
+ if (n < CONST_MIN(STRLEN("user@x.service"), STRLEN("capsule@x.service")))
return NULL;
- if (memcmp(p, "user@", 5) == 0 && memcmp(p + n - 8, ".service", 8) == 0) {
- char buf[n - 5 - 8 + 1];
+ /* Any possible errors from functions called below are converted to NULL return, so our callers won't
+ * resolve user/capsule name. */
+ _cleanup_free_ char *unit_name = strndup(p, n);
+ if (!unit_name)
+ return NULL;
- memcpy(buf, p + 5, n - 5 - 8);
- buf[n - 5 - 8] = 0;
+ _cleanup_free_ char *i = NULL;
+ UnitNameFlags type = unit_name_to_instance(unit_name, &i);
- /* Note that user manager services never need unescaping,
- * since they cannot conflict with the kernel's own
- * names, hence we don't need to call cg_unescape()
- * here. */
+ if (type != UNIT_NAME_INSTANCE)
+ return NULL;
- if (parse_uid(buf, NULL) < 0)
+ /* Note that user manager services never need unescaping, since they cannot conflict with the
+ * kernel's own names, hence we don't need to call cg_unescape() here. Prudently check validity of
+ * instance names, they should be always valid as we validate them upon unit start. */
+ if (startswith(unit_name, "user@")) {
+ if (parse_uid(i, NULL) < 0)
return NULL;
p += n;
p += strspn(p, "/");
+ return p;
+ } else if (startswith(unit_name, "capsule@")) {
+ if (capsule_name_is_valid(i) <= 0)
+ return NULL;
+ p += n;
+ p += strspn(p, "/");
return p;
}
check_p_g_u_u("/user.slice/user-1000.slice/user@1000.service/server.service", 0, "server.service");
check_p_g_u_u("/user.slice/user-1000.slice/user@1000.service/foobar.slice/foobar@pie.service", 0, "foobar@pie.service");
check_p_g_u_u("/user.slice/user-1000.slice/user@.service/server.service", -ENXIO, NULL);
+ check_p_g_u_u("/capsule.slice/capsule@test.service/app.slice/run-p9-i1.service", 0, "run-p9-i1.service");
+ check_p_g_u_u("/capsule.slice/capsule@usr-joe.service/foo.slice/foo-bar.slice/run-p9-i1.service", 0, "run-p9-i1.service");
+ check_p_g_u_u("/capsule.slice/capsule@#.service/foo.slice/foo-bar.slice/run-p9-i1.service", -ENXIO, NULL);
}
static void check_p_g_s(const char *path, int code, const char *result) {
check_p_g_slice("foobar", 0, SPECIAL_ROOT_SLICE);
check_p_g_slice("foobar.slice", 0, "foobar.slice");
check_p_g_slice("foo.slice/foo-bar.slice/waldo.service", 0, "foo-bar.slice");
+ check_p_g_slice("/capsule.slice/capsule@test.service/app.slice/run-p9-i1.service", 0, "capsule.slice");
}
static void check_p_g_u_slice(const char *path, int code, const char *result) {
check_p_g_u_slice("foo.slice/foo-bar.slice/user@1000.service/waldo.service", 0, SPECIAL_ROOT_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");
+
+ check_p_g_u_slice("/capsule.slice/capsule@test.service/app.slice/run-p9-i1.service", 0, "app.slice");
+ check_p_g_u_slice("/capsule.slice/capsule@usr-joe.service/app.slice/run-p9-i1.service", 0, "app.slice");
+ check_p_g_u_slice("/capsule.slice/capsule@usr-joe.service/foo.slice/foo-bar.slice/run-p9-i1.service", 0, "foo-bar.slice");
}
TEST(get_paths, .sd_booted = true) {