-int cg_path_decode_unit(const char *cgroup, char **unit){
- char *c, *s;
- size_t n;
-
- assert(cgroup);
- assert(unit);
-
- n = strcspn(cgroup, "/");
- if (n < 3)
- return -ENXIO;
-
- c = strndupa(cgroup, n);
- c = cg_unescape(c);
-
- if (!unit_name_is_valid(c, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
- return -ENXIO;
-
- s = strdup(c);
- if (!s)
- return -ENOMEM;
-
- *unit = s;
- return 0;
-}
-
-static bool valid_slice_name(const char *p, size_t n) {
-
- if (!p)
- return false;
-
- if (n < strlen("x.slice"))
- return false;
-
- if (memcmp(p + n - 6, ".slice", 6) == 0) {
- char buf[n+1], *c;
-
- memcpy(buf, p, n);
- buf[n] = 0;
-
- c = cg_unescape(buf);
-
- return unit_name_is_valid(c, UNIT_NAME_PLAIN);
- }
-
- return false;
-}
-
-static const char *skip_slices(const char *p) {
- assert(p);
-
- /* Skips over all slice assignments */
-
- for (;;) {
- size_t n;
-
- p += strspn(p, "/");
-
- n = strcspn(p, "/");
- if (!valid_slice_name(p, n))
- return p;
-
- p += n;
- }
-}
-
-int cg_path_get_unit(const char *path, char **ret) {
- const char *e;
- char *unit;
- int r;
-
- assert(path);
- assert(ret);
-
- e = skip_slices(path);
-
- 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;
-}
-
-int cg_pid_get_unit(pid_t pid, char **unit) {
- _cleanup_free_ char *cgroup = NULL;
- int r;
-
- assert(unit);
-
- r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
- if (r < 0)
- return r;
-
- return cg_path_get_unit(cgroup, unit);
-}
-
-/**
- * Skip session-*.scope, but require it to be there.
- */
-static const char *skip_session(const char *p) {
- size_t n;
-
- if (isempty(p))
- return NULL;
-
- p += strspn(p, "/");
-
- n = strcspn(p, "/");
- if (n < strlen("session-x.scope"))
- return NULL;
-
- if (memcmp(p, "session-", 8) == 0 && memcmp(p + n - 6, ".scope", 6) == 0) {
- char buf[n - 8 - 6 + 1];
-
- memcpy(buf, p + 8, n - 8 - 6);
- buf[n - 8 - 6] = 0;
-
- /* Note that session scopes never need unescaping,
- * since they cannot conflict with the kernel's own
- * names, hence we don't need to call cg_unescape()
- * here. */
-
- if (!session_id_valid(buf))
- return false;
-
- p += n;
- p += strspn(p, "/");
- return p;
- }
-
- return NULL;
-}
-
-/**
- * Skip user@*.service, but require it to be there.
- */
-static const char *skip_user_manager(const char *p) {
- size_t n;
-
- if (isempty(p))
- return NULL;
-
- p += strspn(p, "/");
-
- n = strcspn(p, "/");
- if (n < strlen("user@x.service"))
- return NULL;
-
- if (memcmp(p, "user@", 5) == 0 && memcmp(p + n - 8, ".service", 8) == 0) {
- char buf[n - 5 - 8 + 1];
-
- memcpy(buf, p + 5, n - 5 - 8);
- buf[n - 5 - 8] = 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. */
-
- if (parse_uid(buf, NULL) < 0)
- return NULL;
-
- p += n;
- p += strspn(p, "/");
-
- return p;
- }
-
- return NULL;
-}
-
-static const char *skip_user_prefix(const char *path) {
- const char *e, *t;
-
- assert(path);
-
- /* Skip slices, if there are any */
- e = skip_slices(path);
-
- /* 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 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 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) {
- _cleanup_free_ char *cgroup = NULL;
- int r;
-
- assert(unit);
-
- r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
- if (r < 0)
- return r;
-
- return cg_path_get_user_unit(cgroup, unit);
-}
-
-int cg_path_get_machine_name(const char *path, char **machine) {
- _cleanup_free_ char *u = NULL, *sl = NULL;
- int r;
-
- r = cg_path_get_unit(path, &u);
- if (r < 0)
- return r;
-
- sl = strjoin("/run/systemd/machines/unit:", u, NULL);
- if (!sl)
- return -ENOMEM;
-
- return readlink_malloc(sl, machine);
-}
-
-int cg_pid_get_machine_name(pid_t pid, char **machine) {
- _cleanup_free_ char *cgroup = NULL;
- int r;
-
- assert(machine);
-
- r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
- if (r < 0)
- return r;
-
- return cg_path_get_machine_name(cgroup, machine);
-}
-