chiark / gitweb /
59f70882d41104ea0e863f5aee7914621b4056d3
[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 Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 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   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser 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 #include "mkdir.h"
29
30 int main(int argc, char *argv[]) {
31
32         struct udev *udev = NULL;
33         struct udev_enumerate *enumerator = NULL;
34         struct udev_list_entry *first, *item;
35         int i;
36         const char *seat = NULL;
37         char **new_argv;
38         char *path = NULL, *device_node = NULL;
39         int r;
40         FILE *f = NULL;
41
42         /* This binary will go away as soon as X natively supports
43          * display enumeration with udev in a way that covers both PCI
44          * and USB. */
45
46         /* This will simply determine the fb device id of the graphics
47          * device assigned to a seat and write a configuration file
48          * from it and then spawn the real X server. */
49
50         /* If this file is removed, don't forget to remove the code
51          * that invokes this in gdm and other display managers. */
52
53         for (i = 1; i < argc; i++)
54                 if (streq(argv[i], "-seat"))
55                         seat = argv[i+1];
56
57         if (isempty(seat) || streq(seat, "seat0")) {
58                 argv[0] = (char*) X_SERVER;
59                 execv(X_SERVER, argv);
60                 log_error("Failed to execute real X server: %m");
61                 goto fail;
62         }
63
64         udev = udev_new();
65         if (!udev) {
66                 log_error("Failed to allocate udev environment.");
67                 goto fail;
68         }
69
70         enumerator = udev_enumerate_new(udev);
71         if (!enumerator) {
72                 log_error("Failed to allocate udev enumerator.");
73                 goto fail;
74         }
75
76         udev_enumerate_add_match_subsystem(enumerator, "graphics");
77         udev_enumerate_add_match_tag(enumerator, seat);
78
79         r = udev_enumerate_scan_devices(enumerator);
80         if (r < 0) {
81                 log_error("Failed to enumerate devices.");
82                 goto fail;
83         }
84
85         first = udev_enumerate_get_list_entry(enumerator);
86         udev_list_entry_foreach(item, first) {
87                 struct udev_device *d;
88                 const char *dn;
89
90                 d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
91                 if (!d)
92                         continue;
93
94                 dn = udev_device_get_devnode(d);
95
96                 if (dn) {
97                         device_node = strdup(dn);
98                         if (!device_node) {
99                                 udev_device_unref(d);
100                                 log_oom();
101                                 goto fail;
102                         }
103                 }
104
105                 udev_device_unref(d);
106
107                 if (device_node)
108                         break;
109         }
110
111         if (!device_node) {
112                 log_error("Failed to find device node for seat %s.", seat);
113                 goto fail;
114         }
115
116         r = mkdir_safe_label("/run/systemd/multi-session-x", 0755, 0, 0);
117         if (r < 0) {
118                 log_error("Failed to create directory: %s", strerror(-r));
119                 goto fail;
120         }
121
122         path = strappend("/run/systemd/multi-session-x/", seat);
123         if (!path) {
124                 log_oom();
125                 goto fail;
126         }
127
128         f = fopen(path, "we");
129         if (!f) {
130                 log_error("Failed to write configuration file: %m");
131                 goto fail;
132         }
133
134         fprintf(f,
135                 "Section \"Device\"\n"
136                 "        Identifier \"udev\"\n"
137                 "        Driver \"fbdev\"\n"
138                 "        Option \"fbdev\" \"%s\"\n"
139                 "EndSection\n"
140                 "Section \"ServerFlags\"\n"
141                 "        Option \"AutoAddDevices\" \"True\"\n"
142                 "        Option \"AllowEmptyInput\" \"True\"\n"
143                 "        Option \"DontVTSwitch\" \"True\"\n"
144                 "EndSection\n"
145                 "Section \"InputClass\"\n"
146                 "        Identifier \"Force Input Devices to Seat\"\n"
147                 "        Option \"GrabDevice\" \"True\"\n"
148                 "EndSection\n",
149                 device_node);
150
151         fflush(f);
152
153         if (ferror(f)) {
154                 log_error("Failed to write configuration file: %m");
155                 goto fail;
156         }
157
158         fclose(f);
159         f = NULL;
160
161         new_argv = alloca(sizeof(char*) * (argc + 3 + 1));
162         memcpy(new_argv, argv, sizeof(char*) * (argc + 2 + 1));
163
164         new_argv[0] = (char*) X_SERVER;
165         new_argv[argc+0] = (char*) "-config";
166         new_argv[argc+1] = path;
167         new_argv[argc+2] = (char*) "-sharevts";
168         new_argv[argc+3] = NULL;
169
170         udev_enumerate_unref(enumerator);
171         enumerator = NULL;
172
173         udev_unref(udev);
174         udev = NULL;
175
176         free(device_node);
177         device_node = NULL;
178
179         execv(X_SERVER, new_argv);
180         log_error("Failed to execute real X server: %m");
181
182 fail:
183         if (enumerator)
184                 udev_enumerate_unref(enumerator);
185
186         if (udev)
187                 udev_unref(udev);
188
189         free(path);
190         free(device_node);
191
192         if (f)
193                 fclose(f);
194
195         return EXIT_FAILURE;
196 }