X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fsd-login.c;h=2489d78c603dba842113eda63d8ee663eb0100ce;hp=3ae850d80116ba4201e7ec9d4b83a5d6ae40bf69;hb=cd0ed1db9b58900959866e7b265fae2b153b68c0;hpb=74b91131ed09850ed487a2f7849147ff6f80194d diff --git a/src/sd-login.c b/src/sd-login.c index 3ae850d80..2489d78c6 100644 --- a/src/sd-login.c +++ b/src/sd-login.c @@ -22,15 +22,17 @@ #include #include #include +#include #include "util.h" #include "cgroup-util.h" #include "macro.h" #include "sd-login.h" +#include "strv.h" -_public_ int sd_pid_get_session(pid_t pid, char **session) { - int r; +static int pid_get_cgroup(pid_t pid, char **root, char **cgroup) { char *cg_process, *cg_init, *p; + int r; if (pid == 0) pid = getpid(); @@ -38,9 +40,6 @@ _public_ int sd_pid_get_session(pid_t pid, char **session) { if (pid <= 0) return -EINVAL; - if (!session) - return -EINVAL; - r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &cg_process); if (r < 0) return r; @@ -63,26 +62,57 @@ _public_ int sd_pid_get_session(pid_t pid, char **session) { free(cg_init); - if (!startswith(p, "/user/")) { - free(cg_process); - return -ENOENT; + if (cgroup) { + char* c; + + c = strdup(p); + if (!c) { + free(cg_process); + return -ENOMEM; + } + + *cgroup = c; } - p += 6; - if (startswith(p, "shared/") || streq(p, "shared")) { + if (root) { + cg_process[p-cg_process] = 0; + *root = cg_process; + } else free(cg_process); + + return 0; +} + +_public_ int sd_pid_get_session(pid_t pid, char **session) { + int r; + char *cgroup, *p; + + if (!session) + return -EINVAL; + + r = pid_get_cgroup(pid, NULL, &cgroup); + if (r < 0) + return r; + + if (!startswith(cgroup, "/user/")) { + free(cgroup); return -ENOENT; } - p = strchr(p, '/'); + p = strchr(cgroup + 6, '/'); if (!p) { - free(cg_process); + free(cgroup); return -ENOENT; } p++; + if (startswith(p, "shared/") || streq(p, "shared")) { + free(cgroup); + return -ENOENT; + } + p = strndup(p, strcspn(p, "/")); - free(cg_process); + free(cgroup); if (!p) return -ENOMEM; @@ -91,6 +121,54 @@ _public_ int sd_pid_get_session(pid_t pid, char **session) { return 0; } +_public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) { + int r; + char *root, *cgroup, *p, *cc; + struct stat st; + + if (!uid) + return -EINVAL; + + r = pid_get_cgroup(pid, &root, &cgroup); + if (r < 0) + return r; + + if (!startswith(cgroup, "/user/")) { + free(cgroup); + free(root); + return -ENOENT; + } + + p = strchr(cgroup + 6, '/'); + if (!p) { + free(cgroup); + return -ENOENT; + } + + p++; + p += strcspn(p, "/"); + *p = 0; + + r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, root, cgroup, &cc); + free(root); + free(cgroup); + + if (r < 0) + return -ENOMEM; + + r = lstat(cc, &st); + free(cc); + + if (r < 0) + return -errno; + + if (!S_ISDIR(st.st_mode)) + return -ENOTDIR; + + *uid = st.st_uid; + return 0; +} + _public_ int sd_uid_get_state(uid_t uid, char**state) { char *p, *s = NULL; int r; @@ -122,19 +200,22 @@ _public_ int sd_uid_get_state(uid_t uid, char**state) { return 0; } -static int uid_is_on_seat_internal(uid_t uid, const char *seat, const char *variable) { +_public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) { char *p, *w, *t, *state, *s = NULL; size_t l; int r; + const char *variable; if (!seat) return -EINVAL; + variable = require_active ? "ACTIVE_UID" : "UIDS"; + p = strappend("/run/systemd/seats/", seat); if (!p) return -ENOMEM; - r = parse_env_file(p, NEWLINE, "UIDS", &s, NULL); + r = parse_env_file(p, NEWLINE, variable, &s, NULL); free(p); if (r < 0) { @@ -165,12 +246,60 @@ static int uid_is_on_seat_internal(uid_t uid, const char *seat, const char *vari return 0; } -_public_ int sd_uid_is_on_seat(uid_t uid, const char *seat) { - return uid_is_on_seat_internal(uid, seat, "UIDS"); +static int uid_get_array(uid_t uid, const char *variable, char ***array) { + char *p, *s = NULL; + char **a; + int r; + + if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0) + return -ENOMEM; + + r = parse_env_file(p, NEWLINE, + variable, &s, + NULL); + free(p); + + if (r < 0) { + free(s); + + if (r == -ENOENT) { + if (array) + *array = NULL; + return 0; + } + + return r; + } + + if (!s) { + if (array) + *array = NULL; + return 0; + } + + a = strv_split(s, " "); + free(s); + + if (!a) + return -ENOMEM; + + strv_uniq(a); + r = strv_length(a); + + if (array) + *array = a; + else + strv_free(a); + + return r; } -_public_ int sd_uid_is_active_on_seat(uid_t uid, const char *seat) { - return uid_is_on_seat_internal(uid, seat, "ACTIVE_UID"); +_public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) { + return uid_get_array(uid, require_active ? "ACTIVE_SESSIONS" : "SESSIONS", sessions); +} + +_public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) { + return uid_get_array(uid, require_active ? "ACTIVE_SEATS" : "SEATS", seats); } _public_ int sd_session_is_active(const char *session) { @@ -204,7 +333,6 @@ _public_ int sd_session_is_active(const char *session) { _public_ int sd_session_get_uid(const char *session, uid_t *uid) { int r; char *p, *s = NULL; - unsigned long ul; if (!session) return -EINVAL; @@ -226,14 +354,10 @@ _public_ int sd_session_get_uid(const char *session, uid_t *uid) { if (!s) return -EIO; - r = safe_atolu(s, &ul); + r = parse_uid(s, uid); free(s); - if (r < 0) - return r; - - *uid = (uid_t) ul; - return 0; + return r; } _public_ int sd_session_get_seat(const char *session, char **seat) { @@ -291,25 +415,21 @@ _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) { if (session && !s) { free(t); - return -EIO; + return -ENOENT; } if (uid && !t) { free(s); - return -EIO; + return -ENOENT; } if (uid && t) { - unsigned long ul; - - r = safe_atolu(t, &ul); + r = parse_uid(t, uid); if (r < 0) { free(t); free(s); return r; } - - *uid = (uid_t) ul; } free(t); @@ -321,3 +441,277 @@ _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) { return 0; } + +_public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) { + char *p, *s = NULL, *t = NULL, **a = NULL; + uid_t *b = NULL; + unsigned n = 0; + int r; + + if (!seat) + return -EINVAL; + + p = strappend("/run/systemd/seats/", seat); + if (!p) + return -ENOMEM; + + r = parse_env_file(p, NEWLINE, + "SESSIONS", &s, + "ACTIVE_SESSIONS", &t, + NULL); + free(p); + + if (r < 0) { + free(s); + free(t); + return r; + } + + if (s) { + a = strv_split(s, " "); + if (!a) { + free(s); + free(t); + return -ENOMEM; + } + } + + free(s); + + if (uids && t) { + char *w, *state; + size_t l; + unsigned i = 0; + + FOREACH_WORD(w, l, t, state) + n++; + + b = new(uid_t, n); + if (!b) { + strv_free(a); + return -ENOMEM; + } + + FOREACH_WORD(w, l, t, state) { + char *k; + + k = strndup(w, l); + if (!k) { + free(t); + free(b); + return -ENOMEM; + } + + r = parse_uid(k, b + i); + free(k); + if (r < 0) + continue; + + i++; + } + } + + free(t); + + r = strv_length(a); + + if (sessions) + *sessions = a; + else + strv_free(a); + + if (uids) + *uids = b; + + if (n_uids) + *n_uids = n; + + return r; +} + +_public_ int sd_seat_can_multi_session(const char *seat) { + char *p, *s = NULL; + int r; + + if (!seat) + return -EINVAL; + + p = strappend("/run/systemd/seats/", seat); + if (!p) + return -ENOMEM; + + r = parse_env_file(p, NEWLINE, + "IS_VTCONSOLE", &s, + NULL); + free(p); + + if (r < 0) { + free(s); + return r; + } + + if (s) { + r = parse_boolean(s); + free(s); + } else + r = 0; + + return r; +} + +_public_ int sd_get_seats(char ***seats) { + return get_files_in_directory("/run/systemd/seats/", seats); +} + +_public_ int sd_get_sessions(char ***sessions) { + return get_files_in_directory("/run/systemd/sessions/", sessions); +} + +_public_ int sd_get_uids(uid_t **users) { + DIR *d; + int r = 0; + unsigned n = 0; + uid_t *l = NULL; + + d = opendir("/run/systemd/users/"); + for (;;) { + struct dirent buffer, *de; + int k; + uid_t uid; + + k = readdir_r(d, &buffer, &de); + if (k != 0) { + r = -k; + goto finish; + } + + if (!de) + break; + + dirent_ensure_type(d, de); + + if (!dirent_is_file(de)) + continue; + + k = parse_uid(de->d_name, &uid); + if (k < 0) + continue; + + if (users) { + if ((unsigned) r >= n) { + uid_t *t; + + n = MAX(16, 2*r); + t = realloc(l, sizeof(uid_t) * n); + if (!t) { + r = -ENOMEM; + goto finish; + } + + l = t; + } + + assert((unsigned) r < n); + l[r++] = uid; + } else + r++; + } + +finish: + if (d) + closedir(d); + + if (r >= 0) { + if (users) + *users = l; + } else + free(l); + + return r; +} + +static inline int MONITOR_TO_FD(sd_login_monitor *m) { + return (int) (unsigned long) m - 1; +} + +static inline sd_login_monitor* FD_TO_MONITOR(int fd) { + return (sd_login_monitor*) (unsigned long) (fd + 1); +} + +_public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) { + int fd, k; + bool good = false; + + if (!m) + return -EINVAL; + + fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC); + if (fd < 0) + return errno; + + if (!category || streq(category, "seat")) { + k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE); + if (k < 0) { + close_nointr_nofail(fd); + return -errno; + } + + good = true; + } + + if (!category || streq(category, "session")) { + k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE); + if (k < 0) { + close_nointr_nofail(fd); + return -errno; + } + + good = true; + } + + if (!category || streq(category, "uid")) { + k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE); + if (k < 0) { + close_nointr_nofail(fd); + return -errno; + } + + good = true; + } + + if (!good) { + close_nointr(fd); + return -EINVAL; + } + + *m = FD_TO_MONITOR(fd); + return 0; +} + +_public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) { + int fd; + + if (!m) + return NULL; + + fd = MONITOR_TO_FD(m); + close_nointr(fd); + + return NULL; +} + +_public_ int sd_login_monitor_flush(sd_login_monitor *m) { + + if (!m) + return -EINVAL; + + return flush_fd(MONITOR_TO_FD(m)); +} + +_public_ int sd_login_monitor_get_fd(sd_login_monitor *m) { + + if (!m) + return -EINVAL; + + return MONITOR_TO_FD(m); +}