From 092e6cd19adf1ff6bc979034cbe287d92ca2efd7 Mon Sep 17 00:00:00 2001 From: Thorsten Kukuk Date: Wed, 19 Apr 2023 16:11:55 +0200 Subject: sd-login: add SetTTY session object #26611 --- src/login/logind-session-dbus.c | 41 +++++++++++++++++++++++++++++++++++ src/login/logind-session.c | 20 +++++++++++++++++ src/login/logind-session.h | 1 + src/login/org.freedesktop.login1.conf | 4 ++++ src/login/test-session-properties.c | 32 +++++++++++++++++++++++++++ 5 files changed, 98 insertions(+) (limited to 'src/login') diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c index e3bebc9188..00a0e8fd58 100644 --- a/src/login/logind-session-dbus.c +++ b/src/login/logind-session-dbus.c @@ -23,6 +23,7 @@ #include "path-util.h" #include "signal-util.h" #include "strv.h" +#include "terminal-util.h" #include "user-util.h" static int property_get_user( @@ -421,6 +422,41 @@ static int method_set_display(sd_bus_message *message, void *userdata, sd_bus_er return sd_bus_reply_method_return(message, NULL); } +static int method_set_tty(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Session *s = ASSERT_PTR(userdata); + int fd, r, flags; + _cleanup_free_ char *q = NULL; + + assert(message); + + r = sd_bus_message_read(message, "h", &fd); + if (r < 0) + return r; + + if (!session_is_controller(s, sd_bus_message_get_sender(message))) + return sd_bus_error_set(error, BUS_ERROR_NOT_IN_CONTROL, "You must be in control of this session to set tty"); + + assert(fd >= 0); + + flags = fcntl(fd, F_GETFL, 0); + if (flags < 0) + return -errno; + if ((flags & O_ACCMODE) != O_RDWR) + return -EACCES; + if (FLAGS_SET(flags, O_PATH)) + return -ENOTTY; + + r = getttyname_malloc(fd, &q); + if (r < 0) + return r; + + r = session_set_tty(s, q); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + static int method_take_device(sd_bus_message *message, void *userdata, sd_bus_error *error) { Session *s = ASSERT_PTR(userdata); uint32_t major, minor; @@ -909,6 +945,11 @@ static const sd_bus_vtable session_vtable[] = { SD_BUS_NO_RESULT, method_set_display, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("SetTTY", + SD_BUS_ARGS("h", tty_fd), + SD_BUS_NO_RESULT, + method_set_tty, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_ARGS("TakeDevice", SD_BUS_ARGS("u", major, "u", minor), SD_BUS_RESULT("h", fd, "b", inactive), diff --git a/src/login/logind-session.c b/src/login/logind-session.c index e7c917cdee..92d588b276 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -1132,6 +1132,23 @@ int session_set_display(Session *s, const char *display) { return 1; } +int session_set_tty(Session *s, const char *tty) { + int r; + + assert(s); + assert(tty); + + r = free_and_strdup(&s->tty, tty); + if (r <= 0) /* 0 means the strings were equal */ + return r; + + session_save(s); + + session_send_changed(s, "TTY", NULL); + + return 1; +} + static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) { Session *s = ASSERT_PTR(userdata); @@ -1349,6 +1366,9 @@ error: static void session_restore_vt(Session *s) { int r; + if (s->vtfd < 0) + return; + r = vt_restore(s->vtfd); if (r == -EIO) { int vt, old_fd; diff --git a/src/login/logind-session.h b/src/login/logind-session.h index 4c28607986..bf45301705 100644 --- a/src/login/logind-session.h +++ b/src/login/logind-session.h @@ -140,6 +140,7 @@ int session_get_locked_hint(Session *s); void session_set_locked_hint(Session *s, bool b); void session_set_type(Session *s, SessionType t); int session_set_display(Session *s, const char *display); +int session_set_tty(Session *s, const char *tty); int session_create_fifo(Session *s); int session_start(Session *s, sd_bus_message *properties, sd_bus_error *error); int session_stop(Session *s, bool force); diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf index bf905e3b0f..8ba094bcff 100644 --- a/src/login/org.freedesktop.login1.conf +++ b/src/login/org.freedesktop.login1.conf @@ -350,6 +350,10 @@ send_interface="org.freedesktop.login1.Session" send_member="SetDisplay"/> + + diff --git a/src/login/test-session-properties.c b/src/login/test-session-properties.c index 44d54811c3..0bfde42213 100644 --- a/src/login/test-session-properties.c +++ b/src/login/test-session-properties.c @@ -6,10 +6,16 @@ * ./test-session-properties /org/freedesktop/login1/session/_32 */ +#include +#include +#include + #include "alloc-util.h" #include "bus-common-errors.h" #include "bus-locator.h" +#include "path-util.h" #include "string-util.h" +#include "terminal-util.h" #include "tests.h" static BusLocator session; @@ -94,6 +100,32 @@ TEST(set_display) { assert_se(isempty(display)); } +/* Tests org.freedesktop.logind.Session SetTTY */ +TEST(set_tty) { + _cleanup_(sd_bus_flush_close_unrefp) sd_bus* bus = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_free_ char *tty = NULL; + const char *path = "/dev/tty2"; /* testsuite uses tty2 */ + int fd; + + fd = open(path, O_RDWR|O_CLOEXEC|O_NOCTTY); + assert_se(fd >= 0); + + assert_se(sd_bus_open_system(&bus) >= 0); + + /* tty can only be set by the session controller (which we're not ATM) */ + assert_se(bus_call_method(bus, &session, "SetTTY", &error, NULL, "h", fd) < 0); + assert_se(sd_bus_error_has_name(&error, BUS_ERROR_NOT_IN_CONTROL)); + + assert_se(bus_call_method(bus, &session, "TakeControl", NULL, NULL, "b", true) >= 0); + + /* tty can be set */ + assert_se(bus_call_method(bus, &session, "SetTTY", NULL, NULL, "h", fd) >= 0); + tty = mfree(tty); + assert_se(bus_get_property_string(bus, &session, "TTY", NULL, &tty) >= 0); + assert_se(streq(tty, "tty2")); +} + static int intro(void) { if (saved_argc <= 1) return EXIT_FAILURE; -- cgit v1.2.1