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 <cp.michael@samsung.com>
This commit is contained in:
Chris Michael 2015-01-22 12:38:29 -05:00
parent e6970f4f8b
commit c7d557cf4e
1 changed files with 208 additions and 30 deletions

View File

@ -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;
/* try to init dbus */
if (!_ecore_drm_dbus_init(sid))
/* get session id */
if (sd_pid_get_session(getpid(), &dev->session) < 0)
{
free(sid);
ERR("Could not get systemd session: %m");
return EINA_FALSE;
}
active_hdl =
ecore_event_handler_add(ECORE_DRM_EVENT_ACTIVATE,
_ecore_drm_logind_cb_activate, dev);
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))
{
ERR("Session seat '%s' differs from device seat '%s'", seat, dev->seat);
free(seat);
return EINA_FALSE;
}
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)
{
_ecore_drm_dbus_shutdown();
if (active_hdlr) ecore_event_handler_del(active_hdlr);
active_hdlr = NULL;
if (active_hdl)
{
ecore_event_handler_del(active_hdl);
active_hdl = NULL;
}
_ecore_drm_logind_vt_destroy(dev);
_ecore_drm_dbus_session_release(dev->session);
_ecore_drm_dbus_shutdown();
}
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