c->mask |= SD_BUS_CREDS_TID;
}
- if (mask & SD_BUS_CREDS_PPID && item->pids.ppid > 0) {
- c->ppid = (pid_t) item->pids.ppid;
- c->mask |= SD_BUS_CREDS_PPID;
+ if (mask & SD_BUS_CREDS_PPID) {
+ if (item->pids.ppid > 0) {
+ c->ppid = (pid_t) item->pids.ppid;
+ c->mask |= SD_BUS_CREDS_PPID;
+ } else if (item->pids.pid == 1) {
+ /* The structure doesn't
+ * really distuingish the case
+ * where a process has no
+ * parent and where we don't
+ * know it because it could
+ * not be translated due to
+ * namespaces. However, we
+ * know that PID 1 has no
+ * parent process, hence let's
+ * patch that in, manually. */
+ c->ppid = 0;
+ c->mask |= SD_BUS_CREDS_PPID;
+ }
}
break;
break;
case KDBUS_ITEM_AUDIT:
- if (mask & SD_BUS_CREDS_AUDIT_SESSION_ID && (uint32_t) item->audit.sessionid != (uint32_t) -1) {
+ if (mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
c->audit_session_id = (uint32_t) item->audit.sessionid;
c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
}
- if (mask & SD_BUS_CREDS_AUDIT_LOGIN_UID && (uid_t) item->audit.loginuid != UID_INVALID) {
+ if (mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
c->audit_login_uid = (uid_t) item->audit.loginuid;
c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
}
if (!(c->mask & SD_BUS_CREDS_PPID))
return -ENODATA;
+ /* PID 1 has no parent process. Let's distuingish the case of
+ * not knowing and not having a parent process by the returned
+ * error code. */
+ if (c->ppid == 0)
+ return -ENXIO;
+
*ppid = c->ppid;
return 0;
}
if (!(c->mask & SD_BUS_CREDS_EXE))
return -ENODATA;
- assert(c->exe);
+ if (!c->exe)
+ return -ENXIO;
+
*ret = c->exe;
return 0;
}
if (!(c->mask & SD_BUS_CREDS_CMDLINE))
return -ENODATA;
- assert_return(c->cmdline, -ESRCH);
- assert(c->cmdline);
+ if (!c->cmdline)
+ return -ENXIO;
if (!c->cmdline_array) {
c->cmdline_array = strv_parse_nulstr(c->cmdline, c->cmdline_size);
if (!(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID))
return -ENODATA;
+ if (c->audit_session_id == AUDIT_SESSION_INVALID)
+ return -ENXIO;
+
*sessionid = c->audit_session_id;
return 0;
}
if (!(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID))
return -ENODATA;
+ if (c->audit_login_uid == UID_INVALID)
+ return -ENXIO;
+
*uid = c->audit_login_uid;
return 0;
}
if (!(c->mask & SD_BUS_CREDS_TTY))
return -ENODATA;
+ if (!c->tty)
+ return -ENXIO;
+
*ret = c->tty;
return 0;
}
if (r < 0)
return r;
- c->mask |= SD_BUS_CREDS_PPID;
- }
+ } else
+ c->ppid = 0;
+
+ c->mask |= SD_BUS_CREDS_PPID;
continue;
}
}
if (missing & SD_BUS_CREDS_EXE) {
r = get_process_exe(pid, &c->exe);
- if (r < 0) {
+ if (r == -ESRCH) {
+ /* Unfortunately we cannot really distuingish
+ * the case here where the process does not
+ * exist, and /proc/$PID/exe being unreadable
+ * because $PID is a kernel thread. Hence,
+ * assume it is a kernel thread, and rely on
+ * that this case is caught with a later
+ * call. */
+ c->exe = NULL;
+ c->mask |= SD_BUS_CREDS_EXE;
+ } else if (r < 0) {
if (r != -EPERM && r != -EACCES)
return r;
} else
p = procfs_file_alloca(pid, "cmdline");
r = read_full_file(p, &c->cmdline, &c->cmdline_size);
+ if (r == -ENOENT)
+ return -ESRCH;
if (r < 0) {
- if (r == -ENOENT)
- return -ESRCH;
if (r != -EPERM && r != -EACCES)
return r;
} else {
if (c->cmdline_size == 0) {
free(c->cmdline);
c->cmdline = NULL;
- } else
- c->mask |= SD_BUS_CREDS_CMDLINE;
+ }
+
+ c->mask |= SD_BUS_CREDS_CMDLINE;
}
}
return -ENOMEM;
r = read_one_line_file(p, &c->tid_comm);
+ if (r == -ENOENT)
+ return -ESRCH;
if (r < 0) {
- if (r == -ENOENT)
- return -ESRCH;
if (r != -EPERM && r != -EACCES)
return r;
} else
if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
r = audit_session_from_pid(pid, &c->audit_session_id);
- if (r < 0) {
- if (r != -EOPNOTSUPP && r != -ENXIO && r != -ENOENT && r != -EPERM && r != -EACCES)
+ if (r == -ENXIO) {
+ /* ENXIO means: no audit session id assigned */
+ c->audit_session_id = AUDIT_SESSION_INVALID;
+ c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
+ } else if (r < 0) {
+ if (r != -EOPNOTSUPP && r != -ENOENT && r != -EPERM && r != -EACCES)
return r;
} else
c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
- if (r < 0) {
- if (r != -EOPNOTSUPP && r != -ENXIO && r != -ENOENT && r != -EPERM && r != -EACCES)
+ if (r == -ENXIO) {
+ /* ENXIO means: no audit login uid assigned */
+ c->audit_login_uid = UID_INVALID;
+ c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
+ } else if (r < 0) {
+ if (r != -EOPNOTSUPP && r != -ENOENT && r != -EPERM && r != -EACCES)
return r;
} else
c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
if (missing & SD_BUS_CREDS_TTY) {
r = get_ctty(pid, NULL, &c->tty);
- if (r < 0) {
+ if (r == -ENXIO) {
+ /* ENXIO means: process has no controlling TTY */
+ c->tty = NULL;
+ c->mask |= SD_BUS_CREDS_TTY;
+ } else if (r < 0) {
if (r != -EPERM && r != -EACCES && r != -ENOENT)
return r;
} else
c->mask |= SD_BUS_CREDS_TTY;
}
+ /* In case only the exe path was to be read we cannot
+ * distuingish the case where the exe path was unreadable
+ * because the process was a kernel thread, or when the
+ * process didn't exist at all. Hence, let's do a final check,
+ * to be sure. */
+ if (!pid_is_alive(pid))
+ return -ESRCH;
+
+ if (tid > 0 && tid != pid && !pid_is_unwaited(tid))
+ return -ESRCH;
+
c->augmented = missing & c->mask;
return 0;
}
if (c->mask & mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
- n->supplementary_gids = newdup(gid_t, c->supplementary_gids, c->n_supplementary_gids);
- if (!n->supplementary_gids)
- return -ENOMEM;
- n->n_supplementary_gids = c->n_supplementary_gids;
+ if (c->supplementary_gids) {
+ n->supplementary_gids = newdup(gid_t, c->supplementary_gids, c->n_supplementary_gids);
+ if (!n->supplementary_gids)
+ return -ENOMEM;
+ n->n_supplementary_gids = c->n_supplementary_gids;
+ } else {
+ n->supplementary_gids = NULL;
+ n->n_supplementary_gids = 0;
+ }
+
n->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
}
if (c->mask & mask & SD_BUS_CREDS_COMM) {
+ assert(c->comm);
+
n->comm = strdup(c->comm);
if (!n->comm)
return -ENOMEM;
}
if (c->mask & mask & SD_BUS_CREDS_TID_COMM) {
+ assert(c->tid_comm);
+
n->tid_comm = strdup(c->tid_comm);
if (!n->tid_comm)
return -ENOMEM;
}
if (c->mask & mask & SD_BUS_CREDS_EXE) {
- n->exe = strdup(c->exe);
- if (!n->exe)
- return -ENOMEM;
+ if (c->exe) {
+ n->exe = strdup(c->exe);
+ if (!n->exe)
+ return -ENOMEM;
+ } else
+ n->exe = NULL;
n->mask |= SD_BUS_CREDS_EXE;
}
if (c->mask & mask & SD_BUS_CREDS_CMDLINE) {
- n->cmdline = memdup(c->cmdline, c->cmdline_size);
- if (!n->cmdline)
- return -ENOMEM;
+ if (c->cmdline) {
+ n->cmdline = memdup(c->cmdline, c->cmdline_size);
+ if (!n->cmdline)
+ return -ENOMEM;
+
+ n->cmdline_size = c->cmdline_size;
+ } else {
+ n->cmdline = NULL;
+ n->cmdline_size = 0;
+ }
- n->cmdline_size = c->cmdline_size;
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)) {
+ assert(c->cgroup);
+
n->cgroup = strdup(c->cgroup);
if (!n->cgroup)
return -ENOMEM;
}
if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
+ assert(c->capability);
+
n->capability = memdup(c->capability, DIV_ROUND_UP(cap_last_cap(), 32U) * 4 * 4);
if (!n->capability)
return -ENOMEM;
}
if (c->mask & mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
+ assert(c->label);
+
n->label = strdup(c->label);
if (!n->label)
return -ENOMEM;
}
if (c->mask & mask & SD_BUS_CREDS_UNIQUE_NAME) {
+ assert(c->unique_name);
+
n->unique_name = strdup(c->unique_name);
if (!n->unique_name)
return -ENOMEM;
}
if (c->mask & mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
- n->well_known_names = strv_copy(c->well_known_names);
- if (!n->well_known_names)
- return -ENOMEM;
+ if (strv_isempty(c->well_known_names))
+ n->well_known_names = NULL;
+ else {
+ n->well_known_names = strv_copy(c->well_known_names);
+ if (!n->well_known_names)
+ return -ENOMEM;
+ }
n->well_known_names_driver = c->well_known_names_driver;
n->well_known_names_local = c->well_known_names_local;
n->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
}
if (c->mask & mask & SD_BUS_CREDS_DESCRIPTION) {
+ assert(c->description);
n->description = strdup(c->description);
if (!n->description)
return -ENOMEM;
}
int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) {
- bool audit_sessionid_is_set = false, audit_loginuid_is_set = false;
- const char *u = NULL, *uu = NULL, *s = NULL, *sl = NULL;
uid_t owner, audit_loginuid;
uint32_t audit_sessionid;
char **cmdline = NULL, **well_known = NULL;
- const char *prefix, *color, *suffix;
- int r;
+ const char *prefix, *color, *suffix, *s;
+ int r, q, v, w;
assert(c);
fprintf(f, "%sPID=%s"PID_FMT"%s", prefix, color, c->pid, suffix);
if (c->mask & SD_BUS_CREDS_TID)
fprintf(f, "%sTID=%s"PID_FMT"%s", prefix, color, c->tid, suffix);
- if (c->mask & SD_BUS_CREDS_PPID)
- fprintf(f, "%sPPID=%s"PID_FMT"%s", prefix, color, c->ppid, suffix);
+ if (c->mask & SD_BUS_CREDS_PPID) {
+ if (c->ppid == 0)
+ fprintf(f, "%sPPID=%sn/a%s", prefix, color, suffix);
+ else
+ fprintf(f, "%sPPID=%s"PID_FMT"%s", prefix, color, c->ppid, suffix);
+ }
if (c->mask & SD_BUS_CREDS_TTY)
fprintf(f, "%sTTY=%s%s%s", prefix, color, strna(c->tty), suffix);
if (c->mask & SD_BUS_CREDS_TID_COMM)
fprintf(f, "%sTIDComm=%s%s%s", prefix, color, c->tid_comm, suffix);
if (c->mask & SD_BUS_CREDS_EXE)
- fprintf(f, "%sExe=%s%s%s", prefix, color, c->exe, suffix);
+ fprintf(f, "%sExe=%s%s%s", prefix, color, strna(c->exe), suffix);
if (terse && (c->mask & (SD_BUS_CREDS_EXE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM)))
fputs("\n", f);
- if (sd_bus_creds_get_cmdline(c, &cmdline) >= 0) {
+ r = sd_bus_creds_get_cmdline(c, &cmdline);
+ if (r >= 0) {
char **i;
fprintf(f, "%sCommandLine=%s", prefix, color);
}
fprintf(f, "%s", suffix);
- }
+ } else if (r != -ENODATA)
+ fprintf(f, "%sCommandLine=%sn/a%s", prefix, color, suffix);
if (c->mask & SD_BUS_CREDS_SELINUX_CONTEXT)
fprintf(f, "%sLabel=%s%s%s", prefix, color, c->label, suffix);
if (c->mask & SD_BUS_CREDS_CGROUP)
fprintf(f, "%sCGroup=%s%s%s", prefix, color, c->cgroup, suffix);
- (void) sd_bus_creds_get_unit(c, &u);
- if (u)
- fprintf(f, "%sUnit=%s%s%s", prefix, color, u, suffix);
- (void) sd_bus_creds_get_user_unit(c, &uu);
- if (uu)
- fprintf(f, "%sUserUnit=%s%s%s", prefix, color, uu, suffix);
- (void) sd_bus_creds_get_slice(c, &sl);
- if (sl)
- fprintf(f, "%sSlice=%s%s%s", prefix, color, sl, suffix);
- (void) sd_bus_creds_get_session(c, &s);
- if (s)
- fprintf(f, "%sSession=%s%s%s", prefix, color, s, suffix);
-
- if (terse && ((c->mask & SD_BUS_CREDS_CGROUP) || u || uu || sl || s))
+ s = NULL;
+ r = sd_bus_creds_get_unit(c, &s);
+ 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);
+ if (w != -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))
fputs("\n", f);
- if (sd_bus_creds_get_audit_login_uid(c, &audit_loginuid) >= 0) {
- audit_loginuid_is_set = true;
+ r = sd_bus_creds_get_audit_login_uid(c, &audit_loginuid);
+ if (r >= 0)
fprintf(f, "%sAuditLoginUID=%s"UID_FMT"%s", prefix, color, audit_loginuid, suffix);
- }
- if (sd_bus_creds_get_audit_session_id(c, &audit_sessionid) >= 0) {
- audit_sessionid_is_set = true;
+ else if (r != -ENODATA)
+ fprintf(f, "%sAuditLoginUID=%sn/a%s", prefix, color, suffix);
+ q = sd_bus_creds_get_audit_session_id(c, &audit_sessionid);
+ if (q >= 0)
fprintf(f, "%sAuditSessionID=%s%"PRIu32"%s", prefix, color, audit_sessionid, suffix);
- }
+ else if (q != -ENODATA)
+ fprintf(f, "%sAuditSessionID=%sn/a%s", prefix, color, suffix);
- if (terse && (audit_loginuid_is_set || audit_sessionid_is_set))
+ if (terse && (r != -ENODATA || q != -ENODATA))
fputs("\n", f);
if (c->mask & SD_BUS_CREDS_UNIQUE_NAME)
if (d->pids.ppid > 0) {
m->creds.ppid = (pid_t) d->pids.ppid;
m->creds.mask |= SD_BUS_CREDS_PPID & bus->creds_mask;
+ } else if (d->pids.pid == 1) {
+ m->creds.ppid = 0;
+ m->creds.mask |= SD_BUS_CREDS_PPID & bus->creds_mask;
}
break;
break;
case KDBUS_ITEM_AUDIT:
- if ((uint32_t) d->audit.sessionid != (uint32_t) -1) {
- m->creds.audit_session_id = (uint32_t) d->audit.sessionid;
- m->creds.mask |= SD_BUS_CREDS_AUDIT_SESSION_ID & bus->creds_mask;
- }
+ m->creds.audit_session_id = (uint32_t) d->audit.sessionid;
+ m->creds.mask |= SD_BUS_CREDS_AUDIT_SESSION_ID & bus->creds_mask;
- if ((uid_t) d->audit.loginuid != UID_INVALID) {
- m->creds.audit_login_uid = (uid_t) d->audit.loginuid;
- m->creds.mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID & bus->creds_mask;
- }
+ m->creds.audit_login_uid = (uid_t) d->audit.loginuid;
+ m->creds.mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID & bus->creds_mask;
break;
case KDBUS_ITEM_CAPS:
if (r < 0)
return r;
- if (u == (uint32_t) -1 || u <= 0)
+ if (u == AUDIT_SESSION_INVALID || u <= 0)
return -ENXIO;
*id = u;
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "sd-bus.h"
-#include "job.h"
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/types.h>
-extern const sd_bus_vtable bus_job_vtable[];
+#define AUDIT_SESSION_INVALID ((uint32_t) -1)
-int bus_job_method_cancel(sd_bus_message *message, void *job, sd_bus_error *error);
+int audit_session_from_pid(pid_t pid, uint32_t *id);
+int audit_loginuid_from_pid(pid_t pid, uid_t *uid);
-void bus_job_send_change_signal(Job *j);
-void bus_job_send_removed_signal(Job *j);
+bool use_audit(void);
#include "util.h"
#include "formats-util.h"
#include "path-util.h"
+#include "unit-name.h"
#include "fileio.h"
#include "special.h"
#include "mkdir.h"
assert(controller);
if (streq(controller, SYSTEMD_CGROUP_CONTROLLER))
- return "elogind";
+ return "systemd";
else if (startswith(controller, "name="))
return controller + 5;
else
}
int cg_get_root_path(char **path) {
+ char *p, *e;
+ int r;
+
assert(path);
- return cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 1, path);
+ r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 1, &p);
+ if (r < 0)
+ return r;
+
+ e = endswith(p, "/" SPECIAL_SYSTEM_SLICE);
+ if (e)
+ *e = 0;
+
+ *path = p;
+ return 0;
}
int cg_shift_path(const char *cgroup, const char *root, const char **shifted) {
return 0;
}
-int cg_path_get_session(const char *path, char **session) {
- const char *e, *n, *s;
+int cg_path_decode_unit(const char *cgroup, char **unit){
+ char *e, *c, *s;
+
+ assert(cgroup);
+ assert(unit);
+
+ e = strchrnul(cgroup, '/');
+ c = strndupa(cgroup, e - cgroup);
+ c = cg_unescape(c);
+
+ if (!unit_name_is_valid(c, TEMPLATE_INVALID))
+ return -ENXIO;
+
+ s = strdup(c);
+ if (!s)
+ return -ENOMEM;
+
+ *unit = s;
+ return 0;
+}
+
+static const char *skip_slices(const char *p) {
+ /* Skips over all slice assignments */
+
+ for (;;) {
+ size_t n;
+
+ p += strspn(p, "/");
+
+ n = strcspn(p, "/");
+ if (n <= 6 || memcmp(p + n - 6, ".slice", 6) != 0)
+ return p;
+
+ p += n;
+ }
+}
+
+int cg_path_get_unit(const char *path, char **unit) {
+ const char *e;
+
+ assert(path);
+ assert(unit);
+
+ e = skip_slices(path);
+
+ return cg_path_decode_unit(e, unit);
+}
+
+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;
+
+ assert(p);
+
+ p += strspn(p, "/");
+
+ n = strcspn(p, "/");
+ if (n < strlen("session-x.scope") || memcmp(p, "session-", 8) != 0 || memcmp(p + n - 6, ".scope", 6) != 0)
+ return NULL;
+
+ p += n;
+ p += strspn(p, "/");
+
+ return p;
+}
+
+/**
+ * Skip user@*.service, but require it to be there.
+ */
+static const char *skip_user_manager(const char *p) {
+ size_t n;
+
+ assert(p);
+
+ p += strspn(p, "/");
+
+ n = strcspn(p, "/");
+ if (n < strlen("user@x.service") || memcmp(p, "user@", 5) != 0 || memcmp(p + n - 8, ".service", 8) != 0)
+ return NULL;
+
+ p += n;
+ p += strspn(p, "/");
+
+ return p;
+}
+
+int cg_path_get_user_unit(const char *path, char **unit) {
+ const char *e, *t;
+
+ assert(path);
+ assert(unit);
+
+ /* 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 session scope or user manager... */
+ t = skip_session(e);
+ if (!t)
+ t = skip_user_manager(e);
+ if (!t)
+ return -ENXIO;
+
+ /* ... and skip more slices if there are any */
+ e = skip_slices(t);
+
+ return cg_path_decode_unit(e, unit);
+}
+
+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);
+}
- /* Elogind uses a flat hierarchy, just "/SESSION". The only
- wrinkle is that SESSION might be escaped. */
+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);
+}
+
+int cg_path_get_session(const char *path, char **session) {
+ const char *e, *n, *x, *y;
+ char *s;
assert(path);
- assert(path[0] == '/');
- e = path + 1;
+ /* Skip slices, if there are any */
+ e = skip_slices(path);
+
n = strchrnul(e, '/');
if (e == n)
- return -ENOENT;
+ return -ENXIO;
s = strndupa(e, n - e);
s = cg_unescape(s);
- if (!s[0])
- return -ENOENT;
+ x = startswith(s, "session-");
+ if (!x)
+ return -ENXIO;
+ y = endswith(x, ".scope");
+ if (!y || x == y)
+ return -ENXIO;
if (session) {
char *r;
- r = strdup(s);
+ r = strndup(x, y - x);
if (!r)
return -ENOMEM;
return cg_path_get_session(cgroup, session);
}
+int cg_path_get_owner_uid(const char *path, uid_t *uid) {
+ _cleanup_free_ char *slice = NULL;
+ const char *start, *end;
+ char *s;
+ uid_t u;
+ int r;
+
+ assert(path);
+
+ r = cg_path_get_slice(path, &slice);
+ if (r < 0)
+ return r;
+
+ start = startswith(slice, "user-");
+ if (!start)
+ return -ENXIO;
+ end = endswith(slice, ".slice");
+ if (!end)
+ return -ENXIO;
+
+ s = strndupa(start, end - start);
+ if (!s)
+ return -ENXIO;
+
+ if (parse_uid(s, &u) < 0)
+ return -ENXIO;
+
+ if (uid)
+ *uid = u;
+
+ return 0;
+}
+
+int cg_pid_get_owner_uid(pid_t pid, uid_t *uid) {
+ _cleanup_free_ char *cgroup = NULL;
+ int r;
+
+ r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
+ if (r < 0)
+ return r;
+
+ return cg_path_get_owner_uid(cgroup, uid);
+}
+
+int cg_path_get_slice(const char *p, char **slice) {
+ const char *e = NULL;
+ size_t m = 0;
+
+ assert(p);
+ assert(slice);
+
+ for (;;) {
+ size_t n;
+
+ p += strspn(p, "/");
+
+ n = strcspn(p, "/");
+ if (n <= 6 || memcmp(p + n - 6, ".slice", 6) != 0) {
+ char *s;
+
+ if (!e)
+ return -ENXIO;
+
+ s = strndup(e, m);
+ if (!s)
+ return -ENOMEM;
+
+ *slice = s;
+ return 0;
+ }
+
+ e = p;
+ m = n;
+
+ p += n;
+ }
+}
+
+int cg_pid_get_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_slice(cgroup, slice);
+}
+
char *cg_escape(const char *p) {
bool need_prefix = false;
return true;
}
+int cg_slice_to_path(const char *unit, char **ret) {
+ _cleanup_free_ char *p = NULL, *s = NULL, *e = NULL;
+ const char *dash;
+
+ assert(unit);
+ assert(ret);
+
+ if (!unit_name_is_valid(unit, TEMPLATE_INVALID))
+ return -EINVAL;
+
+ if (!endswith(unit, ".slice"))
+ return -EINVAL;
+
+ p = unit_name_to_prefix(unit);
+ if (!p)
+ return -ENOMEM;
+
+ dash = strchr(p, '-');
+ while (dash) {
+ _cleanup_free_ char *escaped = NULL;
+ char n[dash - p + sizeof(".slice")];
+
+ strcpy(stpncpy(n, p, dash - p), ".slice");
+
+ if (!unit_name_is_valid(n, TEMPLATE_INVALID))
+ return -EINVAL;
+
+ escaped = cg_escape(n);
+ if (!escaped)
+ return -ENOMEM;
+
+ if (!strextend(&s, escaped, "/", NULL))
+ return -ENOMEM;
+
+ dash = strchr(dash+1, '-');
+ }
+
+ e = cg_escape(unit);
+ if (!e)
+ return -ENOMEM;
+
+ if (!strextend(&s, e, NULL))
+ return -ENOMEM;
+
+ *ret = s;
+ s = NULL;
+
+ return 0;
+}
+
int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value) {
_cleanup_free_ char *p = NULL;
int r;
return -EIO;
if (major(ttynr) == 0 && minor(ttynr) == 0)
- return -ENOENT;
+ return -ENXIO;
if (d)
*d = (dev_t) ttynr;
if (stat("/proc/1/comm", &st) == 0) {
assert_se(get_process_comm(1, &a) >= 0);
log_info("pid1 comm: '%s'", a);
- } else {
+ } else
log_warning("/proc/1/comm does not exist.");
- }
assert_se(get_process_cmdline(1, 0, true, &c) >= 0);
log_info("pid1 cmdline: '%s'", c);
log_info("self strlen(environ): '%zu'", strlen(env));
if (!detect_container(NULL))
- assert_se(get_ctty_devnr(1, &h) == -ENOENT);
+ assert_se(get_ctty_devnr(1, &h) == -ENXIO);
getenv_for_pid(1, "PATH", &i);
log_info("pid1 $PATH: '%s'", strna(i));