X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flogin%2Fsd-login.c;h=c9a2e8a07fbb883e007f553d77779f92d726e880;hb=6a70535669f9016056c1ad8bcb21e1fd14c2141a;hp=8893b1de80cfa4449850a9a08b7e424c6d334d2e;hpb=94fb446e55babb713fb24850455627acf30d999b;p=elogind.git diff --git a/src/login/sd-login.c b/src/login/sd-login.c index 8893b1de8..c9a2e8a07 100644 --- a/src/login/sd-login.c +++ b/src/login/sd-login.c @@ -6,16 +6,16 @@ Copyright 2011 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ @@ -23,185 +23,69 @@ #include #include #include +#include #include "util.h" #include "cgroup-util.h" #include "macro.h" -#include "sd-login.h" #include "strv.h" - -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(); - - if (pid <= 0) - return -EINVAL; - - r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &cg_process); - if (r < 0) - return r; - - r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &cg_init); - if (r < 0) { - free(cg_process); - return r; - } - - if (endswith(cg_init, "/system")) - cg_init[strlen(cg_init)-7] = 0; - else if (streq(cg_init, "/")) - cg_init[0] = 0; - - if (startswith(cg_process, cg_init)) - p = cg_process + strlen(cg_init); - else - p = cg_process; - - free(cg_init); - - if (cgroup) { - char* c; - - c = strdup(p); - if (!c) { - free(cg_process); - return -ENOMEM; - } - - *cgroup = c; - } - - if (root) { - cg_process[p-cg_process] = 0; - *root = cg_process; - } else - free(cg_process); - - return 0; -} +#include "fileio.h" +#include "login-shared.h" +#include "sd-login.h" _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; + assert_return(pid >= 0, -EINVAL); + assert_return(session, -EINVAL); - if (!startswith(cgroup, "/user/")) { - free(cgroup); - return -ENOENT; - } - - p = strchr(cgroup + 6, '/'); - if (!p) { - free(cgroup); - return -ENOENT; - } - - p++; - if (startswith(p, "shared/") || streq(p, "shared")) { - free(cgroup); - return -ENOENT; - } - - p = strndup(p, strcspn(p, "/")); - free(cgroup); - - if (!p) - return -ENOMEM; - - *session = p; - return 0; + return cg_pid_get_session(pid, session); } _public_ int sd_pid_get_unit(pid_t pid, char **unit) { - int r; - char *cgroup, *p; - - if (!unit) - return -EINVAL; - - r = pid_get_cgroup(pid, NULL, &cgroup); - if (r < 0) - return r; - - if (!startswith(cgroup, "/system/")) { - free(cgroup); - return -ENOENT; - } - p = cgroup + 8; - p = strndup(p, strcspn(p, "/")); - free(cgroup); + assert_return(pid >= 0, -EINVAL); + assert_return(unit, -EINVAL); - if (!p) - return -ENOMEM; - - *unit = p; - return 0; + return cg_pid_get_unit(pid, unit); } -_public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) { - int r; - char *root, *cgroup, *p, *cc; - struct stat st; +_public_ int sd_pid_get_user_unit(pid_t pid, char **unit) { - if (!uid) - return -EINVAL; + assert_return(pid >= 0, -EINVAL); + assert_return(unit, -EINVAL); - r = pid_get_cgroup(pid, &root, &cgroup); - if (r < 0) - return r; + return cg_pid_get_user_unit(pid, unit); +} - if (!startswith(cgroup, "/user/")) { - free(cgroup); - free(root); - return -ENOENT; - } +_public_ int sd_pid_get_machine_name(pid_t pid, char **name) { - p = strchr(cgroup + 6, '/'); - if (!p) { - free(cgroup); - return -ENOENT; - } + assert_return(pid >= 0, -EINVAL); + assert_return(name, -EINVAL); - p++; - p += strcspn(p, "/"); - *p = 0; + return cg_pid_get_machine_name(pid, name); +} - r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, root, cgroup, &cc); - free(root); - free(cgroup); +_public_ int sd_pid_get_slice(pid_t pid, char **slice) { - if (r < 0) - return -ENOMEM; + assert_return(pid >= 0, -EINVAL); + assert_return(slice, -EINVAL); - r = lstat(cc, &st); - free(cc); + return cg_pid_get_slice(pid, slice); +} - if (r < 0) - return -errno; +_public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) { - if (!S_ISDIR(st.st_mode)) - return -ENOTDIR; + assert_return(pid >= 0, -EINVAL); + assert_return(uid, -EINVAL); - *uid = st.st_uid; - return 0; + return cg_pid_get_owner_uid(pid, uid); } _public_ int sd_uid_get_state(uid_t uid, char**state) { char *p, *s = NULL; int r; - if (!state) - return -EINVAL; + assert_return(state, -EINVAL); if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0) return -ENOMEM; @@ -228,13 +112,13 @@ _public_ int sd_uid_get_state(uid_t uid, char**state) { } _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) { - char *p, *w, *t, *state, *s = NULL; + char *w, *state; + _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL; size_t l; int r; const char *variable; - if (!seat) - return -EINVAL; + assert_return(seat, -EINVAL); variable = require_active ? "ACTIVE_UID" : "UIDS"; @@ -243,38 +127,26 @@ _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) return -ENOMEM; r = parse_env_file(p, NEWLINE, variable, &s, NULL); - free(p); - if (r < 0) { - free(s); + if (r < 0) return r; - } if (!s) return -EIO; - if (asprintf(&t, "%lu", (unsigned long) uid) < 0) { - free(s); + if (asprintf(&t, "%lu", (unsigned long) uid) < 0) return -ENOMEM; - } FOREACH_WORD(w, l, s, state) { - if (strncmp(t, w, l) == 0) { - free(s); - free(t); - + if (strneq(t, w, l)) return 1; - } } - free(s); - free(t); - return 0; } static int uid_get_array(uid_t uid, const char *variable, char ***array) { - char *p, *s = NULL; + _cleanup_free_ char *p = NULL, *s = NULL; char **a; int r; @@ -284,11 +156,7 @@ static int uid_get_array(uid_t uid, const char *variable, char ***array) { r = parse_env_file(p, NEWLINE, variable, &s, NULL); - free(p); - if (r < 0) { - free(s); - if (r == -ENOENT) { if (array) *array = NULL; @@ -305,7 +173,6 @@ static int uid_get_array(uid_t uid, const char *variable, char ***array) { } a = strv_split(s, " "); - free(s); if (!a) return -ENOMEM; @@ -322,189 +189,269 @@ static int uid_get_array(uid_t uid, const char *variable, char ***array) { } _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); + return uid_get_array( + uid, + require_active == 0 ? "ONLINE_SESSIONS" : + require_active > 0 ? "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); + return uid_get_array( + uid, + require_active == 0 ? "ONLINE_SEATS" : + require_active > 0 ? "ACTIVE_SEATS" : + "SEATS", + seats); } -_public_ int sd_session_is_active(const char *session) { +static int file_of_session(const char *session, char **_p) { + char *p; int r; - char *p, *s = NULL; - if (!session) - return -EINVAL; + assert(_p); + + if (session) { + if (!session_id_valid(session)) + return -EINVAL; + + p = strappend("/run/systemd/sessions/", session); + } else { + _cleanup_free_ char *buf = NULL; + + r = sd_pid_get_session(0, &buf); + if (r < 0) + return r; + + p = strappend("/run/systemd/sessions/", buf); + } - p = strappend("/run/systemd/sessions/", session); if (!p) return -ENOMEM; - r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL); - free(p); + *_p = p; + return 0; +} - if (r < 0) { - free(s); +_public_ int sd_session_is_active(const char *session) { + int r; + _cleanup_free_ char *p = NULL, *s = NULL; + + r = file_of_session(session, &p); + if (r < 0) + return r; + + r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL); + if (r < 0) return r; - } if (!s) return -EIO; r = parse_boolean(s); - free(s); return r; } +_public_ int sd_session_get_state(const char *session, char **state) { + _cleanup_free_ char *p = NULL, *s = NULL; + int r; + + assert_return(state, -EINVAL); + + r = file_of_session(session, &p); + if (r < 0) + return r; + + r = parse_env_file(p, NEWLINE, "STATE", &s, NULL); + + if (r < 0) + return r; + else if (!s) + return -EIO; + + *state = s; + s = NULL; + + return 0; +} + _public_ int sd_session_get_uid(const char *session, uid_t *uid) { int r; - char *p, *s = NULL; + _cleanup_free_ char *p = NULL, *s = NULL; - if (!session) - return -EINVAL; - if (!uid) - return -EINVAL; + assert_return(uid, -EINVAL); - p = strappend("/run/systemd/sessions/", session); - if (!p) - return -ENOMEM; + r = file_of_session(session, &p); + if (r < 0) + return r; r = parse_env_file(p, NEWLINE, "UID", &s, NULL); - free(p); - if (r < 0) { - free(s); + if (r < 0) return r; - } if (!s) return -EIO; r = parse_uid(s, uid); - free(s); return r; } -_public_ int sd_session_get_seat(const char *session, char **seat) { - char *p, *s = NULL; +static int session_get_string(const char *session, const char *field, char **value) { + _cleanup_free_ char *p = NULL, *s = NULL; int r; - if (!session) - return -EINVAL; - if (!seat) - return -EINVAL; + assert_return(value, -EINVAL); - p = strappend("/run/systemd/sessions/", session); - if (!p) - return -ENOMEM; + r = file_of_session(session, &p); + if (r < 0) + return r; - r = parse_env_file(p, NEWLINE, "SEAT", &s, NULL); - free(p); + r = parse_env_file(p, NEWLINE, field, &s, NULL); - if (r < 0) { - free(s); + if (r < 0) return r; - } if (isempty(s)) return -ENOENT; - *seat = s; + *value = s; + s = NULL; return 0; } -_public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) { - char *p, *s = NULL, *t = NULL; +_public_ int sd_session_get_seat(const char *session, char **seat) { + return session_get_string(session, "SEAT", seat); +} + +_public_ int sd_session_get_tty(const char *session, char **tty) { + return session_get_string(session, "TTY", tty); +} + +_public_ int sd_session_get_vt(const char *session, unsigned *vtnr) { + _cleanup_free_ char *vtnr_string = NULL; + unsigned u; int r; - if (!seat) - return -EINVAL; - if (!session && !uid) - return -EINVAL; + r = session_get_string(session, "VTNR", &vtnr_string); + if (r < 0) + return r; + + r = safe_atou(vtnr_string, &u); + if (r < 0) + return r; + + *vtnr = u; + return 0; +} + +_public_ int sd_session_get_service(const char *session, char **service) { + return session_get_string(session, "SERVICE", service); +} + +_public_ int sd_session_get_type(const char *session, char **type) { + return session_get_string(session, "TYPE", type); +} + +_public_ int sd_session_get_class(const char *session, char **class) { + return session_get_string(session, "CLASS", class); +} + +_public_ int sd_session_get_display(const char *session, char **display) { + return session_get_string(session, "DISPLAY", display); +} + +static int file_of_seat(const char *seat, char **_p) { + char *p; + int r; + + assert(_p); + + if (seat) + p = strappend("/run/systemd/seats/", seat); + else { + _cleanup_free_ char *buf = NULL; + + r = sd_session_get_seat(NULL, &buf); + if (r < 0) + return r; + + p = strappend("/run/systemd/seats/", buf); + } - p = strappend("/run/systemd/seats/", seat); if (!p) return -ENOMEM; + *_p = p; + p = NULL; + return 0; +} + +_public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) { + _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL; + int r; + + assert_return(session || uid, -EINVAL); + + r = file_of_seat(seat, &p); + if (r < 0) + return r; + r = parse_env_file(p, NEWLINE, "ACTIVE", &s, "ACTIVE_UID", &t, NULL); - free(p); - - if (r < 0) { - free(s); - free(t); + if (r < 0) return r; - } - if (session && !s) { - free(t); + if (session && !s) return -ENOENT; - } - if (uid && !t) { - free(s); + if (uid && !t) return -ENOENT; - } if (uid && t) { r = parse_uid(t, uid); - if (r < 0) { - free(t); - free(s); + if (r < 0) return r; - } } - free(t); - - if (session && s) + if (session && s) { *session = s; - else - free(s); + s = NULL; + } 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; + _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL; + _cleanup_strv_free_ char **a = NULL; + _cleanup_free_ uid_t *b = NULL; unsigned n = 0; int r; - if (!seat) - return -EINVAL; - - p = strappend("/run/systemd/seats/", seat); - if (!p) - return -ENOMEM; + r = file_of_seat(seat, &p); + if (r < 0) + return r; r = parse_env_file(p, NEWLINE, "SESSIONS", &s, "ACTIVE_SESSIONS", &t, NULL); - free(p); - if (r < 0) { - free(s); - free(t); + if (r < 0) return r; - } if (s) { a = strv_split(s, " "); - if (!a) { - free(s); - free(t); + if (!a) return -ENOMEM; - } } - free(s); - if (uids && t) { char *w, *state; size_t l; @@ -512,30 +459,22 @@ _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **ui FOREACH_WORD(w, l, t, state) n++; - if (n == 0) - b = NULL; - else { + if (n > 0) { unsigned i = 0; b = new(uid_t, n); - if (!b) { - strv_free(a); + if (!b) return -ENOMEM; - } FOREACH_WORD(w, l, t, state) { - char *k; + _cleanup_free_ char *k = NULL; k = strndup(w, l); - if (!k) { - free(t); - free(b); - strv_free(a); + if (!k) return -ENOMEM; - } r = parse_uid(k, b + i); - free(k); + if (r < 0) continue; @@ -544,17 +483,17 @@ _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **ui } } - free(t); - r = strv_length(a); - if (sessions) + if (sessions) { *sessions = a; - else - strv_free(a); + a = NULL; + } - if (uids) + if (uids) { *uids = b; + b = NULL; + } if (n_uids) *n_uids = n; @@ -562,36 +501,40 @@ _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **ui return r; } -_public_ int sd_seat_can_multi_session(const char *seat) { - char *p, *s = NULL; +static int seat_get_can(const char *seat, const char *variable) { + _cleanup_free_ char *p = NULL, *s = NULL; int r; - if (!seat) - return -EINVAL; - - p = strappend("/run/systemd/seats/", seat); - if (!p) - return -ENOMEM; + r = file_of_seat(seat, &p); + if (r < 0) + return r; r = parse_env_file(p, NEWLINE, - "CAN_MULTI_SESSION", &s, + variable, &s, NULL); - free(p); - - if (r < 0) { - free(s); + if (r < 0) return r; - } - if (s) { + if (s) r = parse_boolean(s); - free(s); - } else + else r = 0; return r; } +_public_ int sd_seat_can_multi_session(const char *seat) { + return seat_get_can(seat, "CAN_MULTI_SESSION"); +} + +_public_ int sd_seat_can_tty(const char *seat) { + return seat_get_can(seat, "CAN_TTY"); +} + +_public_ int sd_seat_can_graphical(const char *seat) { + return seat_get_can(seat, "CAN_GRAPHICAL"); +} + _public_ int sd_get_seats(char ***seats) { return get_files_in_directory("/run/systemd/seats/", seats); } @@ -601,25 +544,24 @@ _public_ int sd_get_sessions(char ***sessions) { } _public_ int sd_get_uids(uid_t **users) { - DIR *d; + _cleanup_closedir_ DIR *d; int r = 0; unsigned n = 0; - uid_t *l = NULL; + _cleanup_free_ uid_t *l = NULL; d = opendir("/run/systemd/users/"); if (!d) return -errno; for (;;) { - struct dirent buffer, *de; + struct dirent *de; + union dirent_storage buf; int k; uid_t uid; - k = readdir_r(d, &buffer, &de); - if (k != 0) { - r = -k; - goto finish; - } + k = readdir_r(d, &buf.de, &de); + if (k != 0) + return -k; if (!de) break; @@ -639,10 +581,8 @@ _public_ int sd_get_uids(uid_t **users) { n = MAX(16, 2*r); t = realloc(l, sizeof(uid_t) * n); - if (!t) { - r = -ENOMEM; - goto finish; - } + if (!t) + return -ENOMEM; l = t; } @@ -653,19 +593,18 @@ _public_ int sd_get_uids(uid_t **users) { r++; } -finish: - if (d) - closedir(d); - - if (r >= 0) { - if (users) - *users = l; - } else - free(l); + if (users) { + *users = l; + l = NULL; + } return r; } +_public_ int sd_get_machine_names(char ***machines) { + return get_files_in_directory("/run/systemd/machines/", machines); +} + static inline int MONITOR_TO_FD(sd_login_monitor *m) { return (int) (unsigned long) m - 1; } @@ -678,12 +617,11 @@ _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) { int fd, k; bool good = false; - if (!m) - return -EINVAL; + assert_return(m, -EINVAL); fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC); if (fd < 0) - return errno; + return -errno; if (!category || streq(category, "seat")) { k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE); @@ -715,6 +653,16 @@ _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) { good = true; } + if (!category || streq(category, "machine")) { + k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE); + if (k < 0) { + close_nointr_nofail(fd); + return -errno; + } + + good = true; + } + if (!good) { close_nointr(fd); return -EINVAL; @@ -727,8 +675,7 @@ _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) { _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) { int fd; - if (!m) - return NULL; + assert_return(m, NULL); fd = MONITOR_TO_FD(m); close_nointr(fd); @@ -738,16 +685,37 @@ _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) { _public_ int sd_login_monitor_flush(sd_login_monitor *m) { - if (!m) - return -EINVAL; + assert_return(m, -EINVAL); return flush_fd(MONITOR_TO_FD(m)); } _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) { - if (!m) - return -EINVAL; + assert_return(m, -EINVAL); return MONITOR_TO_FD(m); } + +_public_ int sd_login_monitor_get_events(sd_login_monitor *m) { + + assert_return(m, -EINVAL); + + /* For now we will only return POLLIN here, since we don't + * need anything else ever for inotify. However, let's have + * this API to keep our options open should we later on need + * it. */ + return POLLIN; +} + +_public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) { + + assert_return(m, -EINVAL); + assert_return(timeout_usec, -EINVAL); + + /* For now we will only return (uint64_t) -1, since we don't + * need any timeout. However, let's have this API to keep our + * options open should we later on need it. */ + *timeout_usec = (uint64_t) -1; + return 0; +}