chiark / gitweb /
370b12fcf492107e11d1def7af0ba68f90a12884
[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 \"ServerFlags\"\n"
136                 "        Option \"AutoAddDevices\" \"True\"\n"
137                 "        Option \"AllowEmptyInput\" \"True\"\n"
138                 "        Option \"DontVTSwitch\" \"True\"\n"
139                 "EndSection\n"
140                 "Section \"InputClass\"\n"
141                 "        Identifier \"Force Input Devices to Seat\"\n"
142                 "        Option \"GrabDevice\" \"True\"\n"
143                 "EndSection\n");
144
145         fflush(f);
146
147         if (ferror(f)) {
148                 log_error("Failed to write configuration file: %m");
149                 goto fail;
150         }
151
152         fclose(f);
153         f = NULL;
154
155         new_argv = alloca(sizeof(char*) * (argc + 3 + 1));
156         memcpy(new_argv, argv, sizeof(char*) * (argc + 2 + 1));
157
158         new_argv[0] = (char*) X_SERVER;
159         new_argv[argc+0] = (char*) "-config";
160         new_argv[argc+1] = path;
161         new_argv[argc+2] = (char*) "-sharevts";
162         new_argv[argc+3] = NULL;
163
164         udev_enumerate_unref(enumerator);
165         enumerator = NULL;
166
167         udev_unref(udev);
168         udev = NULL;
169
170         free(device_node);
171         device_node = NULL;
172
173         execv(X_SERVER, new_argv);
174         log_error("Failed to execute real X server: %m");
175
176 fail:
177         if (enumerator)
178                 udev_enumerate_unref(enumerator);
179
180         if (udev)
181                 udev_unref(udev);
182
183         free(path);
184         free(device_node);
185
186         if (f)
187                 fclose(f);
188
189         return EXIT_FAILURE;
190 }