1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright © 2013 Red Hat Inc.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Permission is hereby granted, free of charge, to any person obtaining a
5*4882a593Smuzhiyun * copy of this software and associated documentation files (the "Software"),
6*4882a593Smuzhiyun * to deal in the Software without restriction, including without limitation
7*4882a593Smuzhiyun * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*4882a593Smuzhiyun * and/or sell copies of the Software, and to permit persons to whom the
9*4882a593Smuzhiyun * Software is furnished to do so, subject to the following conditions:
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * The above copyright notice and this permission notice (including the next
12*4882a593Smuzhiyun * paragraph) shall be included in all copies or substantial portions of the
13*4882a593Smuzhiyun * Software.
14*4882a593Smuzhiyun *
15*4882a593Smuzhiyun * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*4882a593Smuzhiyun * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*4882a593Smuzhiyun * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18*4882a593Smuzhiyun * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*4882a593Smuzhiyun * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20*4882a593Smuzhiyun * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21*4882a593Smuzhiyun * DEALINGS IN THE SOFTWARE.
22*4882a593Smuzhiyun *
23*4882a593Smuzhiyun * Author: Hans de Goede <hdegoede@redhat.com>
24*4882a593Smuzhiyun */
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #ifdef HAVE_XORG_CONFIG_H
27*4882a593Smuzhiyun #include <xorg-config.h>
28*4882a593Smuzhiyun #endif
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #include <dbus/dbus.h>
31*4882a593Smuzhiyun #include <string.h>
32*4882a593Smuzhiyun #include <sys/types.h>
33*4882a593Smuzhiyun #include <unistd.h>
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun #include "os.h"
36*4882a593Smuzhiyun #include "dbus-core.h"
37*4882a593Smuzhiyun #include "linux.h"
38*4882a593Smuzhiyun #include "xf86.h"
39*4882a593Smuzhiyun #include "xf86platformBus.h"
40*4882a593Smuzhiyun #include "xf86Xinput.h"
41*4882a593Smuzhiyun #include "globals.h"
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun #include "systemd-logind.h"
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun struct systemd_logind_info {
46*4882a593Smuzhiyun DBusConnection *conn;
47*4882a593Smuzhiyun char *session;
48*4882a593Smuzhiyun Bool active;
49*4882a593Smuzhiyun Bool vt_active;
50*4882a593Smuzhiyun };
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun static struct systemd_logind_info logind_info;
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun static InputInfoPtr
systemd_logind_find_info_ptr_by_devnum(InputInfoPtr start,int major,int minor)55*4882a593Smuzhiyun systemd_logind_find_info_ptr_by_devnum(InputInfoPtr start,
56*4882a593Smuzhiyun int major, int minor)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun InputInfoPtr pInfo;
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun for (pInfo = start; pInfo; pInfo = pInfo->next)
61*4882a593Smuzhiyun if (pInfo->major == major && pInfo->minor == minor &&
62*4882a593Smuzhiyun (pInfo->flags & XI86_SERVER_FD))
63*4882a593Smuzhiyun return pInfo;
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun return NULL;
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun static void
systemd_logind_set_input_fd_for_all_devs(int major,int minor,int fd,Bool enable)69*4882a593Smuzhiyun systemd_logind_set_input_fd_for_all_devs(int major, int minor, int fd,
70*4882a593Smuzhiyun Bool enable)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun InputInfoPtr pInfo;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun pInfo = systemd_logind_find_info_ptr_by_devnum(xf86InputDevs, major, minor);
75*4882a593Smuzhiyun while (pInfo) {
76*4882a593Smuzhiyun pInfo->fd = fd;
77*4882a593Smuzhiyun pInfo->options = xf86ReplaceIntOption(pInfo->options, "fd", fd);
78*4882a593Smuzhiyun if (enable)
79*4882a593Smuzhiyun xf86EnableInputDeviceForVTSwitch(pInfo);
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun pInfo = systemd_logind_find_info_ptr_by_devnum(pInfo->next, major, minor);
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun int
systemd_logind_take_fd(int _major,int _minor,const char * path,Bool * paused_ret)86*4882a593Smuzhiyun systemd_logind_take_fd(int _major, int _minor, const char *path,
87*4882a593Smuzhiyun Bool *paused_ret)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun struct systemd_logind_info *info = &logind_info;
90*4882a593Smuzhiyun InputInfoPtr pInfo;
91*4882a593Smuzhiyun DBusError error;
92*4882a593Smuzhiyun DBusMessage *msg = NULL;
93*4882a593Smuzhiyun DBusMessage *reply = NULL;
94*4882a593Smuzhiyun dbus_int32_t major = _major;
95*4882a593Smuzhiyun dbus_int32_t minor = _minor;
96*4882a593Smuzhiyun dbus_bool_t paused;
97*4882a593Smuzhiyun int fd = -1;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun if (!info->session || major == 0)
100*4882a593Smuzhiyun return -1;
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun /* logind does not support mouse devs (with evdev we don't need them) */
103*4882a593Smuzhiyun if (strstr(path, "mouse"))
104*4882a593Smuzhiyun return -1;
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun /* Check if we already have an InputInfo entry with this major, minor
107*4882a593Smuzhiyun * (shared device-nodes happen ie with Wacom tablets). */
108*4882a593Smuzhiyun pInfo = systemd_logind_find_info_ptr_by_devnum(xf86InputDevs, major, minor);
109*4882a593Smuzhiyun if (pInfo) {
110*4882a593Smuzhiyun LogMessage(X_INFO, "systemd-logind: returning pre-existing fd for %s %u:%u\n",
111*4882a593Smuzhiyun path, major, minor);
112*4882a593Smuzhiyun *paused_ret = FALSE;
113*4882a593Smuzhiyun return pInfo->fd;
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun dbus_error_init(&error);
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun msg = dbus_message_new_method_call("org.freedesktop.login1", info->session,
119*4882a593Smuzhiyun "org.freedesktop.login1.Session", "TakeDevice");
120*4882a593Smuzhiyun if (!msg) {
121*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: out of memory\n");
122*4882a593Smuzhiyun goto cleanup;
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &major,
126*4882a593Smuzhiyun DBUS_TYPE_UINT32, &minor,
127*4882a593Smuzhiyun DBUS_TYPE_INVALID)) {
128*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: out of memory\n");
129*4882a593Smuzhiyun goto cleanup;
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun reply = dbus_connection_send_with_reply_and_block(info->conn, msg,
133*4882a593Smuzhiyun DBUS_TIMEOUT_USE_DEFAULT, &error);
134*4882a593Smuzhiyun if (!reply) {
135*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: failed to take device %s: %s\n",
136*4882a593Smuzhiyun path, error.message);
137*4882a593Smuzhiyun goto cleanup;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun if (!dbus_message_get_args(reply, &error,
141*4882a593Smuzhiyun DBUS_TYPE_UNIX_FD, &fd,
142*4882a593Smuzhiyun DBUS_TYPE_BOOLEAN, &paused,
143*4882a593Smuzhiyun DBUS_TYPE_INVALID)) {
144*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: TakeDevice %s: %s\n",
145*4882a593Smuzhiyun path, error.message);
146*4882a593Smuzhiyun goto cleanup;
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun *paused_ret = paused;
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun LogMessage(X_INFO, "systemd-logind: got fd for %s %u:%u fd %d paused %d\n",
152*4882a593Smuzhiyun path, major, minor, fd, paused);
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun cleanup:
155*4882a593Smuzhiyun if (msg)
156*4882a593Smuzhiyun dbus_message_unref(msg);
157*4882a593Smuzhiyun if (reply)
158*4882a593Smuzhiyun dbus_message_unref(reply);
159*4882a593Smuzhiyun dbus_error_free(&error);
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun return fd;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun void
systemd_logind_release_fd(int _major,int _minor,int fd)165*4882a593Smuzhiyun systemd_logind_release_fd(int _major, int _minor, int fd)
166*4882a593Smuzhiyun {
167*4882a593Smuzhiyun struct systemd_logind_info *info = &logind_info;
168*4882a593Smuzhiyun InputInfoPtr pInfo;
169*4882a593Smuzhiyun DBusError error;
170*4882a593Smuzhiyun DBusMessage *msg = NULL;
171*4882a593Smuzhiyun DBusMessage *reply = NULL;
172*4882a593Smuzhiyun dbus_int32_t major = _major;
173*4882a593Smuzhiyun dbus_int32_t minor = _minor;
174*4882a593Smuzhiyun int matches = 0;
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun if (!info->session || major == 0)
177*4882a593Smuzhiyun goto close;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun /* Only release the fd if there is only 1 InputInfo left for this major
180*4882a593Smuzhiyun * and minor, otherwise other InputInfo's are still referencing the fd. */
181*4882a593Smuzhiyun pInfo = systemd_logind_find_info_ptr_by_devnum(xf86InputDevs, major, minor);
182*4882a593Smuzhiyun while (pInfo) {
183*4882a593Smuzhiyun matches++;
184*4882a593Smuzhiyun pInfo = systemd_logind_find_info_ptr_by_devnum(pInfo->next, major, minor);
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun if (matches > 1) {
187*4882a593Smuzhiyun LogMessage(X_INFO, "systemd-logind: not releasing fd for %u:%u, still in use\n", major, minor);
188*4882a593Smuzhiyun return;
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun LogMessage(X_INFO, "systemd-logind: releasing fd for %u:%u\n", major, minor);
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun dbus_error_init(&error);
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun msg = dbus_message_new_method_call("org.freedesktop.login1", info->session,
196*4882a593Smuzhiyun "org.freedesktop.login1.Session", "ReleaseDevice");
197*4882a593Smuzhiyun if (!msg) {
198*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: out of memory\n");
199*4882a593Smuzhiyun goto cleanup;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &major,
203*4882a593Smuzhiyun DBUS_TYPE_UINT32, &minor,
204*4882a593Smuzhiyun DBUS_TYPE_INVALID)) {
205*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: out of memory\n");
206*4882a593Smuzhiyun goto cleanup;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun reply = dbus_connection_send_with_reply_and_block(info->conn, msg,
210*4882a593Smuzhiyun DBUS_TIMEOUT_USE_DEFAULT, &error);
211*4882a593Smuzhiyun if (!reply)
212*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: failed to release device: %s\n",
213*4882a593Smuzhiyun error.message);
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun cleanup:
216*4882a593Smuzhiyun if (msg)
217*4882a593Smuzhiyun dbus_message_unref(msg);
218*4882a593Smuzhiyun if (reply)
219*4882a593Smuzhiyun dbus_message_unref(reply);
220*4882a593Smuzhiyun dbus_error_free(&error);
221*4882a593Smuzhiyun close:
222*4882a593Smuzhiyun if (fd != -1)
223*4882a593Smuzhiyun close(fd);
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun int
systemd_logind_controls_session(void)227*4882a593Smuzhiyun systemd_logind_controls_session(void)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun return logind_info.session ? 1 : 0;
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun void
systemd_logind_vtenter(void)233*4882a593Smuzhiyun systemd_logind_vtenter(void)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun struct systemd_logind_info *info = &logind_info;
236*4882a593Smuzhiyun InputInfoPtr pInfo;
237*4882a593Smuzhiyun int i;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun if (!info->session)
240*4882a593Smuzhiyun return; /* Not using systemd-logind */
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun if (!info->active)
243*4882a593Smuzhiyun return; /* Session not active */
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun if (info->vt_active)
246*4882a593Smuzhiyun return; /* Already did vtenter */
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun for (i = 0; i < xf86_num_platform_devices; i++) {
249*4882a593Smuzhiyun if (xf86_platform_devices[i].flags & XF86_PDEV_PAUSED)
250*4882a593Smuzhiyun break;
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun if (i != xf86_num_platform_devices)
253*4882a593Smuzhiyun return; /* Some drm nodes are still paused wait for resume */
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun xf86VTEnter();
256*4882a593Smuzhiyun info->vt_active = TRUE;
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun /* Activate any input devices which were resumed before the drm nodes */
259*4882a593Smuzhiyun for (pInfo = xf86InputDevs; pInfo; pInfo = pInfo->next)
260*4882a593Smuzhiyun if ((pInfo->flags & XI86_SERVER_FD) && pInfo->fd != -1)
261*4882a593Smuzhiyun xf86EnableInputDeviceForVTSwitch(pInfo);
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun /* Do delayed input probing, this must be done after the above enabling */
264*4882a593Smuzhiyun xf86InputEnableVTProbe();
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun static void
systemd_logind_ack_pause(struct systemd_logind_info * info,dbus_int32_t minor,dbus_int32_t major)268*4882a593Smuzhiyun systemd_logind_ack_pause(struct systemd_logind_info *info,
269*4882a593Smuzhiyun dbus_int32_t minor, dbus_int32_t major)
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun DBusError error;
272*4882a593Smuzhiyun DBusMessage *msg = NULL;
273*4882a593Smuzhiyun DBusMessage *reply = NULL;
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun dbus_error_init(&error);
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun msg = dbus_message_new_method_call("org.freedesktop.login1", info->session,
278*4882a593Smuzhiyun "org.freedesktop.login1.Session", "PauseDeviceComplete");
279*4882a593Smuzhiyun if (!msg) {
280*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: out of memory\n");
281*4882a593Smuzhiyun goto cleanup;
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &major,
285*4882a593Smuzhiyun DBUS_TYPE_UINT32, &minor,
286*4882a593Smuzhiyun DBUS_TYPE_INVALID)) {
287*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: out of memory\n");
288*4882a593Smuzhiyun goto cleanup;
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun reply = dbus_connection_send_with_reply_and_block(info->conn, msg,
292*4882a593Smuzhiyun DBUS_TIMEOUT_USE_DEFAULT, &error);
293*4882a593Smuzhiyun if (!reply)
294*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: failed to ack pause: %s\n",
295*4882a593Smuzhiyun error.message);
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun cleanup:
298*4882a593Smuzhiyun if (msg)
299*4882a593Smuzhiyun dbus_message_unref(msg);
300*4882a593Smuzhiyun if (reply)
301*4882a593Smuzhiyun dbus_message_unref(reply);
302*4882a593Smuzhiyun dbus_error_free(&error);
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun static DBusHandlerResult
message_filter(DBusConnection * connection,DBusMessage * message,void * data)306*4882a593Smuzhiyun message_filter(DBusConnection * connection, DBusMessage * message, void *data)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun struct systemd_logind_info *info = data;
309*4882a593Smuzhiyun struct xf86_platform_device *pdev = NULL;
310*4882a593Smuzhiyun InputInfoPtr pInfo = NULL;
311*4882a593Smuzhiyun int ack = 0, pause = 0, fd = -1;
312*4882a593Smuzhiyun DBusError error;
313*4882a593Smuzhiyun dbus_int32_t major, minor;
314*4882a593Smuzhiyun char *pause_str;
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL)
317*4882a593Smuzhiyun return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun dbus_error_init(&error);
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun if (dbus_message_is_signal(message,
322*4882a593Smuzhiyun "org.freedesktop.DBus", "NameOwnerChanged")) {
323*4882a593Smuzhiyun char *name, *old_owner, *new_owner;
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun dbus_message_get_args(message, &error,
326*4882a593Smuzhiyun DBUS_TYPE_STRING, &name,
327*4882a593Smuzhiyun DBUS_TYPE_STRING, &old_owner,
328*4882a593Smuzhiyun DBUS_TYPE_STRING, &new_owner, DBUS_TYPE_INVALID);
329*4882a593Smuzhiyun if (dbus_error_is_set(&error)) {
330*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: NameOwnerChanged: %s\n",
331*4882a593Smuzhiyun error.message);
332*4882a593Smuzhiyun dbus_error_free(&error);
333*4882a593Smuzhiyun return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun if (name && strcmp(name, "org.freedesktop.login1") == 0)
337*4882a593Smuzhiyun FatalError("systemd-logind disappeared (stopped/restarted?)\n");
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun if (strcmp(dbus_message_get_path(message), info->session) != 0)
343*4882a593Smuzhiyun return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun if (dbus_message_is_signal(message, "org.freedesktop.login1.Session",
346*4882a593Smuzhiyun "PauseDevice")) {
347*4882a593Smuzhiyun if (!dbus_message_get_args(message, &error,
348*4882a593Smuzhiyun DBUS_TYPE_UINT32, &major,
349*4882a593Smuzhiyun DBUS_TYPE_UINT32, &minor,
350*4882a593Smuzhiyun DBUS_TYPE_STRING, &pause_str,
351*4882a593Smuzhiyun DBUS_TYPE_INVALID)) {
352*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: PauseDevice: %s\n",
353*4882a593Smuzhiyun error.message);
354*4882a593Smuzhiyun dbus_error_free(&error);
355*4882a593Smuzhiyun return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun if (strcmp(pause_str, "pause") == 0) {
359*4882a593Smuzhiyun pause = 1;
360*4882a593Smuzhiyun ack = 1;
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun else if (strcmp(pause_str, "force") == 0) {
363*4882a593Smuzhiyun pause = 1;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun else if (strcmp(pause_str, "gone") == 0) {
366*4882a593Smuzhiyun /* Device removal is handled through udev */
367*4882a593Smuzhiyun return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun else {
370*4882a593Smuzhiyun LogMessage(X_WARNING, "systemd-logind: unknown pause type: %s\n",
371*4882a593Smuzhiyun pause_str);
372*4882a593Smuzhiyun return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun else if (dbus_message_is_signal(message, "org.freedesktop.login1.Session",
376*4882a593Smuzhiyun "ResumeDevice")) {
377*4882a593Smuzhiyun if (!dbus_message_get_args(message, &error,
378*4882a593Smuzhiyun DBUS_TYPE_UINT32, &major,
379*4882a593Smuzhiyun DBUS_TYPE_UINT32, &minor,
380*4882a593Smuzhiyun DBUS_TYPE_UNIX_FD, &fd,
381*4882a593Smuzhiyun DBUS_TYPE_INVALID)) {
382*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: ResumeDevice: %s\n",
383*4882a593Smuzhiyun error.message);
384*4882a593Smuzhiyun dbus_error_free(&error);
385*4882a593Smuzhiyun return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun } else
388*4882a593Smuzhiyun return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun LogMessage(X_INFO, "systemd-logind: got %s for %u:%u\n",
391*4882a593Smuzhiyun pause ? "pause" : "resume", major, minor);
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun pdev = xf86_find_platform_device_by_devnum(major, minor);
394*4882a593Smuzhiyun if (!pdev)
395*4882a593Smuzhiyun pInfo = systemd_logind_find_info_ptr_by_devnum(xf86InputDevs,
396*4882a593Smuzhiyun major, minor);
397*4882a593Smuzhiyun if (!pdev && !pInfo) {
398*4882a593Smuzhiyun LogMessage(X_WARNING, "systemd-logind: could not find dev %u:%u\n",
399*4882a593Smuzhiyun major, minor);
400*4882a593Smuzhiyun return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun if (pause) {
404*4882a593Smuzhiyun /* Our VT_PROCESS usage guarantees we've already given up the vt */
405*4882a593Smuzhiyun info->active = info->vt_active = FALSE;
406*4882a593Smuzhiyun /* Note the actual vtleave has already been handled by xf86Events.c */
407*4882a593Smuzhiyun if (pdev)
408*4882a593Smuzhiyun pdev->flags |= XF86_PDEV_PAUSED;
409*4882a593Smuzhiyun else {
410*4882a593Smuzhiyun close(pInfo->fd);
411*4882a593Smuzhiyun systemd_logind_set_input_fd_for_all_devs(major, minor, -1, FALSE);
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun if (ack)
414*4882a593Smuzhiyun systemd_logind_ack_pause(info, major, minor);
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun else {
417*4882a593Smuzhiyun /* info->vt_active gets set by systemd_logind_vtenter() */
418*4882a593Smuzhiyun info->active = TRUE;
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun if (pdev)
421*4882a593Smuzhiyun pdev->flags &= ~XF86_PDEV_PAUSED;
422*4882a593Smuzhiyun else
423*4882a593Smuzhiyun systemd_logind_set_input_fd_for_all_devs(major, minor, fd,
424*4882a593Smuzhiyun info->vt_active);
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun /* Always call vtenter(), in case there are only legacy video devs */
427*4882a593Smuzhiyun systemd_logind_vtenter();
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun return DBUS_HANDLER_RESULT_HANDLED;
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun static void
connect_hook(DBusConnection * connection,void * data)433*4882a593Smuzhiyun connect_hook(DBusConnection *connection, void *data)
434*4882a593Smuzhiyun {
435*4882a593Smuzhiyun struct systemd_logind_info *info = data;
436*4882a593Smuzhiyun DBusError error;
437*4882a593Smuzhiyun DBusMessage *msg = NULL;
438*4882a593Smuzhiyun DBusMessage *reply = NULL;
439*4882a593Smuzhiyun dbus_int32_t arg;
440*4882a593Smuzhiyun char *session = NULL;
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun dbus_error_init(&error);
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun msg = dbus_message_new_method_call("org.freedesktop.login1",
445*4882a593Smuzhiyun "/org/freedesktop/login1", "org.freedesktop.login1.Manager",
446*4882a593Smuzhiyun "GetSessionByPID");
447*4882a593Smuzhiyun if (!msg) {
448*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: out of memory\n");
449*4882a593Smuzhiyun goto cleanup;
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun arg = getpid();
453*4882a593Smuzhiyun if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &arg,
454*4882a593Smuzhiyun DBUS_TYPE_INVALID)) {
455*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: out of memory\n");
456*4882a593Smuzhiyun goto cleanup;
457*4882a593Smuzhiyun }
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun reply = dbus_connection_send_with_reply_and_block(connection, msg,
460*4882a593Smuzhiyun DBUS_TIMEOUT_USE_DEFAULT, &error);
461*4882a593Smuzhiyun if (!reply) {
462*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: failed to get session: %s\n",
463*4882a593Smuzhiyun error.message);
464*4882a593Smuzhiyun goto cleanup;
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun dbus_message_unref(msg);
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun if (!dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &session,
469*4882a593Smuzhiyun DBUS_TYPE_INVALID)) {
470*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: GetSessionByPID: %s\n",
471*4882a593Smuzhiyun error.message);
472*4882a593Smuzhiyun goto cleanup;
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun session = XNFstrdup(session);
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun dbus_message_unref(reply);
477*4882a593Smuzhiyun reply = NULL;
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun msg = dbus_message_new_method_call("org.freedesktop.login1",
481*4882a593Smuzhiyun session, "org.freedesktop.login1.Session", "TakeControl");
482*4882a593Smuzhiyun if (!msg) {
483*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: out of memory\n");
484*4882a593Smuzhiyun goto cleanup;
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun arg = FALSE; /* Don't forcibly take over over the session */
488*4882a593Smuzhiyun if (!dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &arg,
489*4882a593Smuzhiyun DBUS_TYPE_INVALID)) {
490*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: out of memory\n");
491*4882a593Smuzhiyun goto cleanup;
492*4882a593Smuzhiyun }
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun reply = dbus_connection_send_with_reply_and_block(connection, msg,
495*4882a593Smuzhiyun DBUS_TIMEOUT_USE_DEFAULT, &error);
496*4882a593Smuzhiyun if (!reply) {
497*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: TakeControl failed: %s\n",
498*4882a593Smuzhiyun error.message);
499*4882a593Smuzhiyun goto cleanup;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun dbus_bus_add_match(connection,
503*4882a593Smuzhiyun "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',path='/org/freedesktop/DBus'",
504*4882a593Smuzhiyun &error);
505*4882a593Smuzhiyun if (dbus_error_is_set(&error)) {
506*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: could not add match: %s\n",
507*4882a593Smuzhiyun error.message);
508*4882a593Smuzhiyun goto cleanup;
509*4882a593Smuzhiyun }
510*4882a593Smuzhiyun
511*4882a593Smuzhiyun dbus_bus_add_match(connection,
512*4882a593Smuzhiyun "type='signal',sender='org.freedesktop.login1',interface='org.freedesktop.login1.Session',member='PauseDevice'",
513*4882a593Smuzhiyun &error);
514*4882a593Smuzhiyun if (dbus_error_is_set(&error)) {
515*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: could not add match: %s\n",
516*4882a593Smuzhiyun error.message);
517*4882a593Smuzhiyun goto cleanup;
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun dbus_bus_add_match(connection,
521*4882a593Smuzhiyun "type='signal',sender='org.freedesktop.login1',interface='org.freedesktop.login1.Session',member='ResumeDevice'",
522*4882a593Smuzhiyun &error);
523*4882a593Smuzhiyun if (dbus_error_is_set(&error)) {
524*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: could not add match: %s\n",
525*4882a593Smuzhiyun error.message);
526*4882a593Smuzhiyun goto cleanup;
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun /*
530*4882a593Smuzhiyun * HdG: This is not useful with systemd <= 208 since the signal only
531*4882a593Smuzhiyun * contains invalidated property names there, rather than property, val
532*4882a593Smuzhiyun * pairs as it should. Instead we just use the first resume / pause now.
533*4882a593Smuzhiyun */
534*4882a593Smuzhiyun #if 0
535*4882a593Smuzhiyun snprintf(match, sizeof(match),
536*4882a593Smuzhiyun "type='signal',sender='org.freedesktop.login1',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',path='%s'",
537*4882a593Smuzhiyun session);
538*4882a593Smuzhiyun dbus_bus_add_match(connection, match, &error);
539*4882a593Smuzhiyun if (dbus_error_is_set(&error)) {
540*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: could not add match: %s\n",
541*4882a593Smuzhiyun error.message);
542*4882a593Smuzhiyun goto cleanup;
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun #endif
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun if (!dbus_connection_add_filter(connection, message_filter, info, NULL)) {
547*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: could not add filter: %s\n",
548*4882a593Smuzhiyun error.message);
549*4882a593Smuzhiyun goto cleanup;
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun LogMessage(X_INFO, "systemd-logind: took control of session %s\n",
553*4882a593Smuzhiyun session);
554*4882a593Smuzhiyun info->conn = connection;
555*4882a593Smuzhiyun info->session = session;
556*4882a593Smuzhiyun info->vt_active = info->active = TRUE; /* The server owns the vt during init */
557*4882a593Smuzhiyun session = NULL;
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun cleanup:
560*4882a593Smuzhiyun free(session);
561*4882a593Smuzhiyun if (msg)
562*4882a593Smuzhiyun dbus_message_unref(msg);
563*4882a593Smuzhiyun if (reply)
564*4882a593Smuzhiyun dbus_message_unref(reply);
565*4882a593Smuzhiyun dbus_error_free(&error);
566*4882a593Smuzhiyun }
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun static void
systemd_logind_release_control(struct systemd_logind_info * info)569*4882a593Smuzhiyun systemd_logind_release_control(struct systemd_logind_info *info)
570*4882a593Smuzhiyun {
571*4882a593Smuzhiyun DBusError error;
572*4882a593Smuzhiyun DBusMessage *msg = NULL;
573*4882a593Smuzhiyun DBusMessage *reply = NULL;
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun dbus_error_init(&error);
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun msg = dbus_message_new_method_call("org.freedesktop.login1",
578*4882a593Smuzhiyun info->session, "org.freedesktop.login1.Session", "ReleaseControl");
579*4882a593Smuzhiyun if (!msg) {
580*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: out of memory\n");
581*4882a593Smuzhiyun goto cleanup;
582*4882a593Smuzhiyun }
583*4882a593Smuzhiyun
584*4882a593Smuzhiyun reply = dbus_connection_send_with_reply_and_block(info->conn, msg,
585*4882a593Smuzhiyun DBUS_TIMEOUT_USE_DEFAULT, &error);
586*4882a593Smuzhiyun if (!reply) {
587*4882a593Smuzhiyun LogMessage(X_ERROR, "systemd-logind: ReleaseControl failed: %s\n",
588*4882a593Smuzhiyun error.message);
589*4882a593Smuzhiyun goto cleanup;
590*4882a593Smuzhiyun }
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun cleanup:
593*4882a593Smuzhiyun if (msg)
594*4882a593Smuzhiyun dbus_message_unref(msg);
595*4882a593Smuzhiyun if (reply)
596*4882a593Smuzhiyun dbus_message_unref(reply);
597*4882a593Smuzhiyun dbus_error_free(&error);
598*4882a593Smuzhiyun }
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun static void
disconnect_hook(void * data)601*4882a593Smuzhiyun disconnect_hook(void *data)
602*4882a593Smuzhiyun {
603*4882a593Smuzhiyun struct systemd_logind_info *info = data;
604*4882a593Smuzhiyun
605*4882a593Smuzhiyun free(info->session);
606*4882a593Smuzhiyun info->session = NULL;
607*4882a593Smuzhiyun info->conn = NULL;
608*4882a593Smuzhiyun }
609*4882a593Smuzhiyun
610*4882a593Smuzhiyun static struct dbus_core_hook core_hook = {
611*4882a593Smuzhiyun .connect = connect_hook,
612*4882a593Smuzhiyun .disconnect = disconnect_hook,
613*4882a593Smuzhiyun .data = &logind_info,
614*4882a593Smuzhiyun };
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun int
systemd_logind_init(void)617*4882a593Smuzhiyun systemd_logind_init(void)
618*4882a593Smuzhiyun {
619*4882a593Smuzhiyun if (!ServerIsNotSeat0() && linux_parse_vt_settings(TRUE) && !linux_get_keeptty()) {
620*4882a593Smuzhiyun LogMessage(X_INFO,
621*4882a593Smuzhiyun "systemd-logind: logind integration requires -keeptty and "
622*4882a593Smuzhiyun "-keeptty was not provided, disabling logind integration\n");
623*4882a593Smuzhiyun return 1;
624*4882a593Smuzhiyun }
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun return dbus_core_add_hook(&core_hook);
627*4882a593Smuzhiyun }
628*4882a593Smuzhiyun
629*4882a593Smuzhiyun void
systemd_logind_fini(void)630*4882a593Smuzhiyun systemd_logind_fini(void)
631*4882a593Smuzhiyun {
632*4882a593Smuzhiyun if (logind_info.session)
633*4882a593Smuzhiyun systemd_logind_release_control(&logind_info);
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun dbus_core_remove_hook(&core_hook);
636*4882a593Smuzhiyun }
637