devilhorns pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=c7d557cf4e1cf2b5d4278141363c02ec01d98dfc
commit c7d557cf4e1cf2b5d4278141363c02ec01d98dfc Author: Chris Michael <[email protected]> Date: Thu Jan 22 12:38:29 2015 -0500 ecore-drm: Fix various issues with logind code Summary: This fixes a few issues with the logind code such as: Getting the VT from systemd (if available), Properly setup the VT using proper 'open' flags, adding a 'restore' function to reset the tty properly, and handle take/release session. @fix Signed-off-by: Chris Michael <[email protected]> --- src/lib/ecore_drm/ecore_drm_logind.c | 236 ++++++++++++++++++++++++++++++----- 1 file changed, 207 insertions(+), 29 deletions(-) diff --git a/src/lib/ecore_drm/ecore_drm_logind.c b/src/lib/ecore_drm/ecore_drm_logind.c index 9a8d7f1..dfc5402 100644 --- a/src/lib/ecore_drm/ecore_drm_logind.c +++ b/src/lib/ecore_drm/ecore_drm_logind.c @@ -1,32 +1,154 @@ -#include <sys/stat.h> -#include <sys/ioctl.h> -#include <linux/vt.h> -#include <linux/kd.h> -#include <linux/major.h> #include "ecore_drm_private.h" -#include "ecore_drm_logind.h" #ifndef KDSKBMUTE # define KDSKBMUTE 0x4B51 #endif -static Ecore_Event_Handler *active_hdl; -static char *sid; +static Ecore_Event_Handler *active_hdlr; -static Eina_Bool +#ifdef HAVE_SYSTEMD +static inline Eina_Bool +_ecore_drm_logind_vt_get(Ecore_Drm_Device *dev) +{ + int ret; + char *tty; + + ret = sd_session_get_tty(dev->session, &tty); + if (ret < 0) + { + ERR("Could not get systemd tty: %m"); + return EINA_FALSE; + } + + ret = sscanf(tty, "tty%u", &dev->vt); + free(tty); + + if (ret != 1) return EINA_FALSE; + + return EINA_TRUE; +} +#endif + +static Eina_Bool +_ecore_drm_logind_vt_setup(Ecore_Drm_Device *dev) +{ + struct stat st; + char buff[64]; + struct vt_mode vtmode = { 0 }; + + snprintf(buff, sizeof(buff), "/dev/tty%d", dev->vt); + buff[sizeof(buff) - 1] = 0; + + dev->tty.fd = open(buff, (O_RDWR | O_CLOEXEC | O_NONBLOCK)); + if (dev->tty.fd < 0) + { + ERR("Could not open VT %s %m", buff); + return EINA_FALSE; + } + + if ((fstat(dev->tty.fd, &st) == -1) || + (major(st.st_rdev) != TTY_MAJOR) || + (minor(st.st_rdev) <= 0) || (minor(st.st_rdev) >= 64)) + { + ERR("TTY %s is not a virtual terminal", buff); + goto stat_err; + } + + if (ioctl(dev->tty.fd, KDGKBMODE, &dev->tty.kbd_mode) < 0) + { + ERR("Could not read keyboard mode of %s: %m", buff); + dev->tty.kbd_mode = K_UNICODE; + } + else if (dev->tty.kbd_mode == K_OFF) + dev->tty.kbd_mode = K_UNICODE; + + if ((ioctl(dev->tty.fd, KDSKBMUTE, 1) < 0) && + (ioctl(dev->tty.fd, KDSKBMODE, K_OFF) < 0)) + { + ERR("Could not set K_OFF keyboard mode on %s: %m", buff); + goto stat_err; + } + + if (ioctl(dev->tty.fd, KDSETMODE, KD_GRAPHICS) < 0) + { + ERR("Could not set KD_GRAPHICS mode on %s: %m", buff); + goto kbdmode_err; + } + + vtmode.mode = VT_PROCESS; + vtmode.waitv =0 ; + vtmode.relsig = SIGUSR1; + vtmode.acqsig = SIGUSR2; + + if (ioctl(dev->tty.fd, VT_SETMODE, &vtmode) < 0) + { + ERR("Could not take over virtual terminal: %m"); + goto mode_err; + } + + return EINA_TRUE; + +mode_err: + ioctl(dev->tty.fd, KDSETMODE, KD_TEXT); +kbdmode_err: + ioctl(dev->tty.fd, KDSKBMUTE, 0); + ioctl(dev->tty.fd, KDSKBMODE, dev->tty.kbd_mode); +stat_err: + close(dev->tty.fd); + return EINA_FALSE; +} + +static void +_ecore_drm_logind_vt_destroy(Ecore_Drm_Device *dev) +{ + _ecore_drm_logind_restore(dev); + close(dev->tty.fd); +} + +static Eina_Bool +_ecore_drm_logind_cb_vt_signal(void *data, int type EINA_UNUSED, void *event) +{ + Ecore_Drm_Device *dev; + Ecore_Event_Signal_User *ev; + siginfo_t sig; + + ev = event; + sig = ev->data; + + if (sig.si_code != SI_KERNEL) return ECORE_CALLBACK_RENEW; + if (!(dev = data)) return ECORE_CALLBACK_RENEW; + + switch (ev->number) + { + case 1: + _ecore_drm_event_activate_send(EINA_FALSE); + ioctl(dev->tty.fd, VT_RELDISP, 1); + break; + case 2: + ioctl(dev->tty.fd, VT_RELDISP, VT_ACKACQ); + _ecore_drm_event_activate_send(EINA_TRUE); + break; + default: + break; + } + + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool _ecore_drm_logind_cb_activate(void *data, int type EINA_UNUSED, void *event) { - Ecore_Drm_Event_Activate *e; + Ecore_Drm_Event_Activate *ev; Ecore_Drm_Device *dev; Ecore_Drm_Output *output; Eina_List *l; if ((!event) || (!data)) return ECORE_CALLBACK_RENEW; - e = event; + ev = event; dev = data; - if (e->active) + if (ev->active) { /* set output mode */ EINA_LIST_FOREACH(dev->outputs, l, output) @@ -48,38 +170,94 @@ _ecore_drm_logind_cb_activate(void *data, int type EINA_UNUSED, void *event) return ECORE_CALLBACK_PASS_ON; } -Eina_Bool +Eina_Bool _ecore_drm_logind_connect(Ecore_Drm_Device *dev) { #ifdef HAVE_SYSTEMD - /* get sd-login properties we need */ - if (sd_pid_get_session(getpid(), &sid) < 0) return EINA_FALSE; -#endif + char *seat; + + /* get session id */ + if (sd_pid_get_session(getpid(), &dev->session) < 0) + { + ERR("Could not get systemd session: %m"); + return EINA_FALSE; + } - /* try to init dbus */ - if (!_ecore_drm_dbus_init(sid)) + if (sd_session_get_seat(dev->session, &seat) < 0) + { + ERR("Could not get systemd seat: %m"); + free(seat); + return EINA_FALSE; + } + else if (strcmp(dev->seat, seat)) { - free(sid); + ERR("Session seat '%s' differs from device seat '%s'", seat, dev->seat); + free(seat); return EINA_FALSE; } - active_hdl = - ecore_event_handler_add(ECORE_DRM_EVENT_ACTIVATE, - _ecore_drm_logind_cb_activate, dev); + free(seat); + + if (!_ecore_drm_logind_vt_get(dev)) return EINA_FALSE; +#endif + + if (!_ecore_drm_dbus_init(dev)) return EINA_FALSE; + + /* take control of session */ + if (!_ecore_drm_dbus_session_take(dev->session)) + { + ERR("Could not take control of session"); + goto take_err; + } + + /* setup vt */ + if (!_ecore_drm_logind_vt_setup(dev)) + { + ERR("Could not setup vt '%d'", dev->vt); + goto vt_err; + } + + /* setup handler for vt signals */ + dev->tty.event_hdlr = + ecore_event_handler_add(ECORE_EVENT_SIGNAL_USER, + _ecore_drm_logind_cb_vt_signal, dev); + + active_hdlr = + ecore_event_handler_add(ECORE_DRM_EVENT_ACTIVATE, + _ecore_drm_logind_cb_activate, dev); return EINA_TRUE; + +vt_err: + _ecore_drm_dbus_session_release(dev->session); +take_err: + _ecore_drm_dbus_shutdown(); + return EINA_FALSE; } -void -_ecore_drm_logind_disconnect(Ecore_Drm_Device *dev EINA_UNUSED) +void +_ecore_drm_logind_disconnect(Ecore_Drm_Device *dev) { + if (active_hdlr) ecore_event_handler_del(active_hdlr); + active_hdlr = NULL; + + _ecore_drm_logind_vt_destroy(dev); + _ecore_drm_dbus_session_release(dev->session); _ecore_drm_dbus_shutdown(); +} - if (active_hdl) - { - ecore_event_handler_del(active_hdl); - active_hdl = NULL; - } +void +_ecore_drm_logind_restore(Ecore_Drm_Device *dev) +{ + struct vt_mode vtmode = { 0 }; + + if ((!dev) || (dev->tty.fd < 0)) return; + + ioctl(dev->tty.fd, KDSETMODE, KD_TEXT); + ioctl(dev->tty.fd, KDSKBMUTE, 0); + ioctl(dev->tty.fd, KDSKBMODE, dev->tty.kbd_mode); + vtmode.mode = VT_AUTO; + ioctl(dev->tty.fd, VT_SETMODE, &vtmode); } Eina_Bool --
