chiark / gitweb /
login: add multi-session X wrapper
[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         for (i = 1; i < argc; i++)
50                 if (streq(argv[i], "-seat"))
51                         seat = argv[i+1];
52
53         if (isempty(seat) || streq(seat, "seat0")) {
54                 argv[0] = (char*) X_SERVER;
55                 execv(X_SERVER, argv);
56                 log_error("Failed to execute real X server: %m");
57                 goto fail;
58         }
59
60         udev = udev_new();
61         if (!udev) {
62                 log_error("Failed to allocate udev environment.");
63                 goto fail;
64         }
65
66         enumerator = udev_enumerate_new(udev);
67         if (!enumerator) {
68                 log_error("Failed to allocate udev enumerator.");
69                 goto fail;
70         }
71
72         udev_enumerate_add_match_subsystem(enumerator, "graphics");
73         udev_enumerate_add_match_tag(enumerator, seat);
74
75         r = udev_enumerate_scan_devices(enumerator);
76         if (r < 0) {
77                 log_error("Failed to enumerate devices.");
78                 goto fail;
79         }
80
81         first = udev_enumerate_get_list_entry(enumerator);
82         udev_list_entry_foreach(item, first) {
83                 struct udev_device *d;
84                 const char *dn;
85
86                 d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
87                 if (!d)
88                         continue;
89
90                 dn = udev_device_get_devnode(d);
91
92                 if (!dn) {
93                         device_node = strdup(dn);
94                         if (!device_node) {
95                                 udev_device_unref(d);
96                                 log_error("Out of memory.");
97                                 goto fail;
98                         }
99                 }
100
101                 udev_device_unref(d);
102
103                 if (device_node)
104                         break;
105         }
106
107         if (!device_node) {
108                 log_error("Failed to find device node for seat %s.", seat);
109                 goto fail;
110         }
111
112         r = safe_mkdir("/run/systemd/multi-session-x", 0755, 0, 0);
113         if (r < 0) {
114                 log_error("Failed to create directory: %s", strerror(-r));
115                 goto fail;
116         }
117
118         path = strappend("/run/systemd/multi-session-x/", seat);
119         if (!path) {
120                 log_error("Out of memory");
121                 goto fail;
122         }
123
124         f = fopen(path, "we");
125         if (!f) {
126                 log_error("Failed to write configuration file: %m");
127                 goto fail;
128         }
129
130         fprintf(f,
131                 "Section \"Device\"\n"
132                 "        Identifier \"udev\"\n"
133                 "        Driver \"fbdev\"\n"
134                 "        Option \"fbdev\" \"%s\"\n"
135                 "EndSection\n"
136                 "Section \"ServerFlags\"\n"
137                 "        Option \"AutoAddDevices\" \"True\"\n"
138                 "        Option \"AllowEmptyInput\" \"True\"\n"
139                 "EndSection\n",
140                 device_node);
141
142         fflush(f);
143
144         if (ferror(f)) {
145                 log_error("Failed to write configuration file: %m");
146                 goto fail;
147         }
148
149         fclose(f);
150         f = NULL;
151
152         new_argv = alloca(sizeof(char*) * (argc + 3 + 1));
153         memcpy(new_argv, argv, sizeof(char*) * (argc + 2 + 1));
154
155         new_argv[0] = (char*) X_SERVER;
156         new_argv[argc+0] = (char*) "-config";
157         new_argv[argc+1] = path;
158         new_argv[argc+2] = (char*) "-sharevts";
159         new_argv[argc+3] = NULL;
160
161         udev_enumerate_unref(enumerator);
162         enumerator = NULL;
163
164         udev_unref(udev);
165         udev = NULL;
166
167         free(device_node);
168         device_node = NULL;
169
170         execv(X_SERVER, new_argv);
171         log_error("Failed to execute real X server: %m");
172
173 fail:
174         if (enumerator)
175                 udev_enumerate_unref(enumerator);
176
177         if (udev)
178                 udev_unref(udev);
179
180         free(path);
181         free(device_node);
182
183         if (f)
184                 fclose(f);
185
186         return EXIT_FAILURE;
187 }