X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flogind-seat.c;h=3cf3958c8d47330d13cac925573238713a54ef55;hp=ae89ec9d8385440d3fd1efa698e5185e86affe2d;hb=82e487c56d0947796793b6fd2836264328defe9f;hpb=d2f92cdfd0189491387069da45734816effd8cbd diff --git a/src/logind-seat.c b/src/logind-seat.c index ae89ec9d8..3cf3958c8 100644 --- a/src/logind-seat.c +++ b/src/logind-seat.c @@ -41,7 +41,7 @@ Seat *seat_new(Manager *m, const char *id) { if (!s) return NULL; - s->state_file = strappend("/run/systemd/seat/", id); + s->state_file = strappend("/run/systemd/seats/", id); if (!s->state_file) { free(s); return NULL; @@ -86,7 +86,10 @@ int seat_save(Seat *s) { assert(s); - r = safe_mkdir("/run/systemd/seat", 0755, 0, 0); + if (!s->started) + return 0; + + r = safe_mkdir("/run/systemd/seats", 0755, 0, 0); if (r < 0) goto finish; @@ -99,7 +102,7 @@ int seat_save(Seat *s) { fprintf(f, "# This is private data. Do not parse.\n" "IS_VTCONSOLE=%i\n", - s->manager->vtconsole == s); + seat_is_vtconsole(s)); if (s->active) { assert(s->active->user); @@ -114,27 +117,20 @@ int seat_save(Seat *s) { if (s->sessions) { Session *i; - fputs("OTHER=", f); + fputs("SESSIONS=", f); LIST_FOREACH(sessions_by_seat, i, s->sessions) { - if (i == s->active) - continue; - fprintf(f, "%s%c", i->id, i->sessions_by_seat_next ? ' ' : '\n'); } - fputs("OTHER_UIDS=", f); - LIST_FOREACH(sessions_by_seat, i, s->sessions) { - if (i == s->active) - continue; - + fputs("UIDS=", f); + LIST_FOREACH(sessions_by_seat, i, s->sessions) fprintf(f, "%lu%c", (unsigned long) i->user->uid, i->sessions_by_seat_next ? ' ' : '\n'); - } } fflush(f); @@ -158,6 +154,8 @@ finish: int seat_load(Seat *s) { assert(s); + /* There isn't actually anything to read here ... */ + return 0; } @@ -181,19 +179,22 @@ static int vt_allocate(int vtnr) { return r; } -static int seat_preallocate_vts(Seat *s) { - int i, r = 0; +int seat_preallocate_vts(Seat *s) { + int r = 0; + unsigned i; assert(s); assert(s->manager); + log_debug("Preallocating VTs..."); + if (s->manager->n_autovts <= 0) return 0; - if (s->manager->vtconsole != s) + if (!seat_is_vtconsole(s)) return 0; - for (i = 1; i < s->manager->n_autovts; i++) { + for (i = 1; i <= s->manager->n_autovts; i++) { int q; q = vt_allocate(i); @@ -223,13 +224,49 @@ int seat_apply_acls(Seat *s, Session *old_active) { return r; } +int seat_set_active(Seat *s, Session *session) { + Session *old_active; + + assert(s); + assert(!session || session->seat == s); + + if (session == s->active) + return 0; + + old_active = s->active; + s->active = session; + + seat_apply_acls(s, old_active); + + if (session && session->started) + session_send_changed(session, "Active\0"); + + if (!session || session->started) + seat_send_changed(s, "ActiveSession\0"); + + seat_save(s); + + if (session) { + session_save(session); + user_save(session->user); + } + + if (old_active) { + session_save(old_active); + user_save(old_active->user); + } + + return 0; +} + int seat_active_vt_changed(Seat *s, int vtnr) { - Session *i, *new_active = NULL, *old_active; + Session *i, *new_active = NULL; + int r; assert(s); assert(vtnr >= 1); - if (s->manager->vtconsole != s) + if (!seat_is_vtconsole(s)) return -EINVAL; log_debug("VT changed to %i", vtnr); @@ -240,16 +277,10 @@ int seat_active_vt_changed(Seat *s, int vtnr) { break; } - if (new_active == s->active) - return 0; - - old_active = s->active; - s->active = new_active; - - seat_apply_acls(s, old_active); + r = seat_set_active(s, new_active); manager_spawn_autovt(s->manager, vtnr); - return 0; + return r; } int seat_read_active_vt(Seat *s) { @@ -259,7 +290,7 @@ int seat_read_active_vt(Seat *s) { assert(s); - if (s->manager->vtconsole != s) + if (!seat_is_vtconsole(s)) return 0; lseek(s->manager->console_active_fd, SEEK_SET, 0); @@ -295,19 +326,49 @@ int seat_read_active_vt(Seat *s) { int seat_start(Seat *s) { assert(s); + if (s->started) + return 0; + + log_info("New seat %s.", s->id); + /* Initialize VT magic stuff */ seat_preallocate_vts(s); /* Read current VT */ seat_read_active_vt(s); + s->started = true; + /* Save seat data */ seat_save(s); + seat_send_signal(s, true); + return 0; } int seat_stop(Seat *s) { + int r = 0; + + assert(s); + + if (s->started) + log_info("Removed seat %s.", s->id); + + seat_stop_sessions(s); + + unlink(s->state_file); + seat_add_to_gc_queue(s); + + if (s->started) + seat_send_signal(s, false); + + s->started = false; + + return r; +} + +int seat_stop_sessions(Seat *s) { Session *session; int r = 0, k; @@ -319,16 +380,79 @@ int seat_stop(Seat *s) { r = k; } - unlink(s->state_file); - seat_add_to_gc_queue(s); - return r; } -int seat_check_gc(Seat *s) { +int seat_attach_session(Seat *s, Session *session) { + assert(s); + assert(session); + assert(!session->seat); + + if (!seat_is_vtconsole(s) && s->sessions) + return -EEXIST; + + session->seat = s; + LIST_PREPEND(Session, sessions_by_seat, s->sessions, session); + + seat_send_changed(s, "Sessions\0"); + + if (!seat_is_vtconsole(s)) { + assert(!s->active); + seat_set_active(s, session); + } + + return 0; +} + +bool seat_is_vtconsole(Seat *s) { assert(s); - if (s->manager->vtconsole == s) + return s->manager->vtconsole == s; +} + +int seat_get_idle_hint(Seat *s, dual_timestamp *t) { + Session *session; + bool idle_hint = true; + dual_timestamp ts = { 0, 0 }; + + assert(s); + + LIST_FOREACH(sessions_by_seat, session, s->sessions) { + dual_timestamp k; + int ih; + + ih = session_get_idle_hint(session, &k); + if (ih < 0) + return ih; + + if (!ih) { + if (!idle_hint) { + if (k.monotonic < ts.monotonic) + ts = k; + } else { + idle_hint = false; + ts = k; + } + } else if (idle_hint) { + + if (k.monotonic > ts.monotonic) + ts = k; + } + } + + if (t) + *t = ts; + + return idle_hint; +} + +int seat_check_gc(Seat *s, bool drop_not_started) { + assert(s); + + if (drop_not_started && !s->started) + return 0; + + if (seat_is_vtconsole(s)) return 1; return !!s->devices; @@ -343,3 +467,33 @@ void seat_add_to_gc_queue(Seat *s) { LIST_PREPEND(Seat, gc_queue, s->manager->seat_gc_queue, s); s->in_gc_queue = true; } + +static bool seat_name_valid_char(char c) { + return + (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + c == '-' || + c == '_'; +} + +bool seat_name_is_valid(const char *name) { + const char *p; + + assert(name); + + if (!startswith(name, "seat")) + return false; + + if (!name[4]) + return false; + + for (p = name; *p; p++) + if (!seat_name_valid_char(*p)) + return false; + + if (strlen(name) > 255) + return false; + + return true; +}