chiark / gitweb /
login: track login class (i.e. one of "user", "greeter", "lock-screen") for each...
[elogind.git] / src / login / multi-seat-x.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2011 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <string.h>
23 #include <unistd.h>
24
25 #include <libudev.h>
26
27 #include "util.h"
28
29 int main(int argc, char *argv[]) {
30
31         struct udev *udev = NULL;
32         struct udev_enumerate *enumerator = NULL;
33         struct udev_list_entry *first, *item;
34         int i;
35         const char *seat = NULL;
36         char **new_argv;
37         char *path = NULL, *device_node = NULL;
38         int r;
39         FILE *f = NULL;
40
41         /* This binary will go away as soon as X natively supports
42          * display enumeration with udev in a way that covers both PCI
43          * and USB. */
44
45         /* This will simply determine the fb device id of the graphics
46          * device assigned to a seat and write a configuration file
47          * from it and then spawn the real X server. */
48
49         /* If this file is removed, don't forget to remove the code
50          * that invokes this in gdm and other display managers. */
51
52         for (i = 1; i < argc; i++)
53                 if (streq(argv[i], "-seat"))
54                         seat = argv[i+1];
55
56         if (isempty(seat) || streq(seat, "seat0")) {
57                 argv[0] = (char*) X_SERVER;
58                 execv(X_SERVER, argv);
59                 log_error("Failed to execute real X server: %m");
60                 goto fail;
61         }
62
63         udev = udev_new();
64         if (!udev) {
65                 log_error("Failed to allocate udev environment.");
66                 goto fail;
67         }
68
69         enumerator = udev_enumerate_new(udev);
70         if (!enumerator) {
71                 log_error("Failed to allocate udev enumerator.");
72                 goto fail;
73         }
74
75         udev_enumerate_add_match_subsystem(enumerator, "graphics");
76         udev_enumerate_add_match_tag(enumerator, seat);
77
78         r = udev_enumerate_scan_devices(enumerator);
79         if (r < 0) {
80                 log_error("Failed to enumerate devices.");
81                 goto fail;
82         }
83
84         first = udev_enumerate_get_list_entry(enumerator);
85         udev_list_entry_foreach(item, first) {
86                 struct udev_device *d;
87                 const char *dn;
88
89                 d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
90                 if (!d)
91                         continue;
92
93                 dn = udev_device_get_devnode(d);
94
95                 if (dn) {
96                         device_node = strdup(dn);
97                         if (!device_node) {
98                                 udev_device_unref(d);
99                                 log_error("Out of memory.");
100                                 goto fail;
101                         }
102                 }
103
104                 udev_device_unref(d);
105
106                 if (device_node)
107                         break;
108         }
109
110         if (!device_node) {
111                 log_error("Failed to find device node for seat %s.", seat);
112                 goto fail;
113         }
114
115         r = safe_mkdir("/run/systemd/multi-session-x", 0755, 0, 0);
116         if (r < 0) {
117                 log_error("Failed to create directory: %s", strerror(-r));
118                 goto fail;
119         }
120
121         path = strappend("/run/systemd/multi-session-x/", seat);
122         if (!path) {
123                 log_error("Out of memory");
124                 goto fail;
125         }
126
127         f = fopen(path, "we");
128         if (!f) {
129                 log_error("Failed to write configuration file: %m");
130                 goto fail;
131         }
132
133         fprintf(f,
134                 "Section \"Device\"\n"
135                 "        Identifier \"udev\"\n"
136                 "        Driver \"fbdev\"\n"
137                 "        Option \"fbdev\" \"%s\"\n"
138                 "EndSection\n"
139                 "Section \"ServerFlags\"\n"
140                 "        Option \"AutoAddDevices\" \"True\"\n"
141                 "        Option \"AllowEmptyInput\" \"True\"\n"
142                 "        Option \"DontVTSwitch\" \"True\"\n"
143                 "EndSection\n"
144                 "Section \"InputClass\"\n"
145                 "        Identifier \"Force Input Devices to Seat\"\n"
146                 "        Option \"GrabDevice\" \"True\"\n"
147                 "EndSection\n",
148                 device_node);
149
150         fflush(f);
151
152         if (ferror(f)) {
153                 log_error("Failed to write configuration file: %m");
154                 goto fail;
155         }
156
157         fclose(f);
158         f = NULL;
159
160         new_argv = alloca(sizeof(char*) * (argc + 3 + 1));
161         memcpy(new_argv, argv, sizeof(char*) * (argc + 2 + 1));
162
163         new_argv[0] = (char*) X_SERVER;
164         new_argv[argc+0] = (char*) "-config";
165         new_argv[argc+1] = path;
166         new_argv[argc+2] = (char*) "-sharevts";
167         new_argv[argc+3] = NULL;
168
169         udev_enumerate_unref(enumerator);
170         enumerator = NULL;
171
172         udev_unref(udev);
173         udev = NULL;
174
175         free(device_node);
176         device_node = NULL;
177
178         execv(X_SERVER, new_argv);
179         log_error("Failed to execute real X server: %m");
180
181 fail:
182         if (enumerator)
183                 udev_enumerate_unref(enumerator);
184
185         if (udev)
186                 udev_unref(udev);
187
188         free(path);
189         free(device_node);
190
191         if (f)
192                 fclose(f);
193
194         return EXIT_FAILURE;
195 }