X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flogin%2Flogind-seat.c;h=b8f18c47a33bc715327e39369730a756c9430593;hp=feebcf4558febcb23e44ccaf0b07f88f1ba0b832;hb=49e6fdbf14b35d8840c3b263fd15259624b07818;hpb=dfd552707d43087a1e0079cdae9f5290e14b78e9 diff --git a/src/login/logind-seat.c b/src/login/logind-seat.c index feebcf455..b8f18c47a 100644 --- a/src/login/logind-seat.c +++ b/src/login/logind-seat.c @@ -27,8 +27,8 @@ #include #include -#include "systemd/sd-id128.h" -#include "systemd/sd-messages.h" +#include "sd-id128.h" +#include "sd-messages.h" #include "logind-seat.h" #include "logind-acl.h" #include "util.h" @@ -51,7 +51,7 @@ Seat *seat_new(Manager *m, const char *id) { return NULL; } - s->id = path_get_file_name(s->state_file); + s->id = basename(s->state_file); s->manager = m; if (hashmap_put(m->seats, s->id, s) < 0) { @@ -67,7 +67,7 @@ void seat_free(Seat *s) { assert(s); if (s->in_gc_queue) - LIST_REMOVE(Seat, gc_queue, s->manager->seat_gc_queue, s); + LIST_REMOVE(gc_queue, s->manager->seat_gc_queue, s); while (s->sessions) session_free(s->sessions); @@ -79,14 +79,15 @@ void seat_free(Seat *s) { hashmap_remove(s->manager->seats, s->id); + free(s->positions); free(s->state_file); free(s); } int seat_save(Seat *s) { + _cleanup_free_ char *temp_path = NULL; + _cleanup_fclose_ FILE *f = NULL; int r; - FILE *f; - char *temp_path; assert(s); @@ -151,9 +152,6 @@ int seat_save(Seat *s) { unlink(temp_path); } - fclose(f); - free(temp_path); - finish: if (r < 0) log_error("Failed to save seat data for %s: %s", s->id, strerror(-r)); @@ -169,24 +167,20 @@ int seat_load(Seat *s) { return 0; } -static int vt_allocate(int vtnr) { - int fd, r; - char *p; +static int vt_allocate(unsigned int vtnr) { + _cleanup_free_ char *p = NULL; + _cleanup_close_ int fd = -1; assert(vtnr >= 1); - if (asprintf(&p, "/dev/tty%i", vtnr) < 0) + if (asprintf(&p, "/dev/tty%u", vtnr) < 0) return -ENOMEM; fd = open_terminal(p, O_RDWR|O_NOCTTY|O_CLOEXEC); - free(p); - - r = fd < 0 ? -errno : 0; + if (fd < 0) + return -errno; - if (fd >= 0) - close_nointr_nofail(fd); - - return r; + return 0; } int seat_preallocate_vts(Seat *s) { @@ -248,18 +242,18 @@ int seat_set_active(Seat *s, Session *session) { if (old_active) { session_device_pause_all(old_active); - session_send_changed(old_active, "Active\0"); + session_send_changed(old_active, "Active", NULL); } seat_apply_acls(s, old_active); if (session && session->started) { - session_send_changed(session, "Active\0"); + session_send_changed(session, "Active", NULL); session_device_resume_all(session); } if (!session || session->started) - seat_send_changed(s, "ActiveSession\0"); + seat_send_changed(s, "ActiveSession", NULL); seat_save(s); @@ -277,7 +271,61 @@ int seat_set_active(Seat *s, Session *session) { return 0; } -int seat_active_vt_changed(Seat *s, int vtnr) { +int seat_switch_to(Seat *s, unsigned int num) { + /* Public session positions skip 0 (there is only F1-F12). Maybe it + * will get reassigned in the future, so return error for now. */ + if (!num) + return -EINVAL; + + if (num >= s->position_count || !s->positions[num]) + return -EINVAL; + + return session_activate(s->positions[num]); +} + +int seat_switch_to_next(Seat *s) { + unsigned int start, i; + + if (!s->position_count) + return -EINVAL; + + start = 1; + if (s->active && s->active->pos > 0) + start = s->active->pos; + + for (i = start + 1; i < s->position_count; ++i) + if (s->positions[i]) + return session_activate(s->positions[i]); + + for (i = 1; i < start; ++i) + if (s->positions[i]) + return session_activate(s->positions[i]); + + return -EINVAL; +} + +int seat_switch_to_previous(Seat *s) { + unsigned int start, i; + + if (!s->position_count) + return -EINVAL; + + start = 1; + if (s->active && s->active->pos > 0) + start = s->active->pos; + + for (i = start - 1; i > 0; --i) + if (s->positions[i]) + return session_activate(s->positions[i]); + + for (i = s->position_count - 1; i > start; --i) + if (s->positions[i]) + return session_activate(s->positions[i]); + + return -EINVAL; +} + +int seat_active_vt_changed(Seat *s, unsigned int vtnr) { Session *i, *new_active = NULL; int r; @@ -287,7 +335,7 @@ int seat_active_vt_changed(Seat *s, int vtnr) { if (!seat_has_vts(s)) return -EINVAL; - log_debug("VT changed to %i", vtnr); + log_debug("VT changed to %u", vtnr); LIST_FOREACH(sessions_by_seat, i, s->sessions) if (i->vtnr == vtnr) { @@ -304,7 +352,8 @@ int seat_active_vt_changed(Seat *s, int vtnr) { int seat_read_active_vt(Seat *s) { char t[64]; ssize_t k; - int r, vtnr; + unsigned int vtnr; + int r; assert(s); @@ -327,13 +376,13 @@ int seat_read_active_vt(Seat *s) { return -EIO; } - r = safe_atoi(t+3, &vtnr); + r = safe_atou(t+3, &vtnr); if (r < 0) { log_error("Failed to parse VT number %s", t+3); return r; } - if (vtnr <= 0) { + if (!vtnr) { log_error("VT number invalid: %s", t+3); return -EIO; } @@ -409,19 +458,63 @@ int seat_stop_sessions(Seat *s) { return r; } +void seat_evict_position(Seat *s, Session *session) { + unsigned int pos = session->pos; + + session->pos = 0; + + if (!pos) + return; + + if (pos < s->position_count && s->positions[pos] == session) + s->positions[pos] = NULL; +} + +void seat_claim_position(Seat *s, Session *session, unsigned int pos) { + /* with VTs, the position is always the same as the VTnr */ + if (seat_has_vts(s)) + pos = session->vtnr; + + if (!GREEDY_REALLOC0(s->positions, s->position_count, pos + 1)) + return; + + seat_evict_position(s, session); + + session->pos = pos; + if (pos > 0 && !s->positions[pos]) + s->positions[pos] = session; +} + +static void seat_assign_position(Seat *s, Session *session) { + unsigned int pos; + + if (session->pos > 0) + return; + + for (pos = 1; pos < s->position_count; ++pos) + if (!s->positions[pos]) + break; + + seat_claim_position(s, session, pos); +} + int seat_attach_session(Seat *s, Session *session) { assert(s); assert(session); assert(!session->seat); + if (!seat_has_vts(s) != !session->vtnr) + return -EINVAL; + session->seat = s; - LIST_PREPEND(Session, sessions_by_seat, s->sessions, session); + LIST_PREPEND(sessions_by_seat, s->sessions, session); + seat_assign_position(s, session); - seat_send_changed(s, "Sessions\0"); + seat_send_changed(s, "Sessions", NULL); /* On seats with VTs, the VT logic defines which session is active. On - * seats without VTs, we automatically activate the first session. */ - if (!seat_has_vts(s) && !s->active) + * seats without VTs, we automatically activate new sessions. */ + if (!seat_has_vts(s)) seat_set_active(s, session); return 0; @@ -515,14 +608,14 @@ int seat_get_idle_hint(Seat *s, dual_timestamp *t) { return idle_hint; } -int seat_check_gc(Seat *s, bool drop_not_started) { +bool seat_check_gc(Seat *s, bool drop_not_started) { assert(s); if (drop_not_started && !s->started) - return 0; + return false; if (seat_is_seat0(s)) - return 1; + return true; return seat_has_master_device(s); } @@ -533,7 +626,7 @@ void seat_add_to_gc_queue(Seat *s) { if (s->in_gc_queue) return; - LIST_PREPEND(Seat, gc_queue, s->manager->seat_gc_queue, s); + LIST_PREPEND(gc_queue, s->manager->seat_gc_queue, s); s->in_gc_queue = true; }