]>
Commit | Line | Data |
---|---|---|
3f49d45a LP |
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 | |
5430f7f2 LP |
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 | |
3f49d45a LP |
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 | |
5430f7f2 | 16 | Lesser General Public License for more details. |
3f49d45a | 17 | |
5430f7f2 | 18 | You should have received a copy of the GNU Lesser General Public License |
3f49d45a LP |
19 | along with systemd; If not, see <http://www.gnu.org/licenses/>. |
20 | ***/ | |
21 | ||
22 | #include <errno.h> | |
a185c5aa | 23 | #include <string.h> |
adacb957 | 24 | #include <sys/capability.h> |
3f49d45a | 25 | |
cc377381 LP |
26 | #include "util.h" |
27 | #include "bus-util.h" | |
28 | #include "strv.h" | |
718db961 | 29 | #include "bus-errors.h" |
3f49d45a LP |
30 | #include "logind.h" |
31 | #include "logind-seat.h" | |
3f49d45a | 32 | |
cc377381 LP |
33 | static int property_get_active_session( |
34 | sd_bus *bus, | |
35 | const char *path, | |
36 | const char *interface, | |
37 | const char *property, | |
38 | sd_bus_message *reply, | |
ebcf1f97 LP |
39 | void *userdata, |
40 | sd_bus_error *error) { | |
cc377381 | 41 | |
7fd1b19b | 42 | _cleanup_free_ char *p = NULL; |
cc377381 | 43 | Seat *s = userdata; |
3f49d45a | 44 | |
cc377381 LP |
45 | assert(bus); |
46 | assert(reply); | |
3f49d45a LP |
47 | assert(s); |
48 | ||
cc377381 LP |
49 | p = s->active ? session_bus_path(s->active) : strdup("/"); |
50 | if (!p) | |
3f49d45a LP |
51 | return -ENOMEM; |
52 | ||
cc377381 LP |
53 | return sd_bus_message_append(reply, "(so)", s->active ? s->active->id : "", p); |
54 | } | |
3f49d45a | 55 | |
cc377381 LP |
56 | static int property_get_can_multi_session( |
57 | sd_bus *bus, | |
58 | const char *path, | |
59 | const char *interface, | |
60 | const char *property, | |
61 | sd_bus_message *reply, | |
ebcf1f97 LP |
62 | void *userdata, |
63 | sd_bus_error *error) { | |
3f49d45a | 64 | |
cc377381 | 65 | Seat *s = userdata; |
3f49d45a | 66 | |
cc377381 LP |
67 | assert(bus); |
68 | assert(reply); | |
69 | assert(s); | |
3f49d45a | 70 | |
cc377381 | 71 | return sd_bus_message_append(reply, "b", seat_can_multi_session(s)); |
3f49d45a LP |
72 | } |
73 | ||
cc377381 LP |
74 | static int property_get_can_tty( |
75 | sd_bus *bus, | |
76 | const char *path, | |
77 | const char *interface, | |
78 | const char *property, | |
79 | sd_bus_message *reply, | |
ebcf1f97 LP |
80 | void *userdata, |
81 | sd_bus_error *error) { | |
cc377381 LP |
82 | |
83 | Seat *s = userdata; | |
84 | ||
85 | assert(bus); | |
86 | assert(reply); | |
87 | assert(s); | |
88 | ||
89 | return sd_bus_message_append(reply, "b", seat_can_tty(s)); | |
90 | } | |
91 | ||
92 | static int property_get_can_graphical( | |
93 | sd_bus *bus, | |
94 | const char *path, | |
95 | const char *interface, | |
96 | const char *property, | |
97 | sd_bus_message *reply, | |
ebcf1f97 LP |
98 | void *userdata, |
99 | sd_bus_error *error) { | |
cc377381 LP |
100 | |
101 | Seat *s = userdata; | |
102 | ||
103 | assert(bus); | |
104 | assert(reply); | |
105 | assert(s); | |
106 | ||
a0a6be9f | 107 | return sd_bus_message_append(reply, "b", seat_can_graphical(s)); |
cc377381 LP |
108 | } |
109 | ||
110 | static int property_get_sessions( | |
111 | sd_bus *bus, | |
112 | const char *path, | |
113 | const char *interface, | |
114 | const char *property, | |
115 | sd_bus_message *reply, | |
ebcf1f97 LP |
116 | void *userdata, |
117 | sd_bus_error *error) { | |
cc377381 LP |
118 | |
119 | Seat *s = userdata; | |
3f49d45a | 120 | Session *session; |
cc377381 | 121 | int r; |
3f49d45a | 122 | |
cc377381 LP |
123 | assert(bus); |
124 | assert(reply); | |
3f49d45a LP |
125 | assert(s); |
126 | ||
cc377381 LP |
127 | r = sd_bus_message_open_container(reply, 'a', "(so)"); |
128 | if (r < 0) | |
129 | return r; | |
3f49d45a LP |
130 | |
131 | LIST_FOREACH(sessions_by_seat, session, s->sessions) { | |
7fd1b19b | 132 | _cleanup_free_ char *p = NULL; |
3f49d45a | 133 | |
3f49d45a LP |
134 | p = session_bus_path(session); |
135 | if (!p) | |
136 | return -ENOMEM; | |
137 | ||
cc377381 LP |
138 | r = sd_bus_message_append(reply, "(so)", session->id, p); |
139 | if (r < 0) | |
140 | return r; | |
3f49d45a | 141 | |
3f49d45a LP |
142 | } |
143 | ||
cc377381 LP |
144 | r = sd_bus_message_close_container(reply); |
145 | if (r < 0) | |
146 | return r; | |
3f49d45a | 147 | |
cc377381 | 148 | return 1; |
3f49d45a LP |
149 | } |
150 | ||
cc377381 LP |
151 | static int property_get_idle_hint( |
152 | sd_bus *bus, | |
153 | const char *path, | |
154 | const char *interface, | |
155 | const char *property, | |
156 | sd_bus_message *reply, | |
ebcf1f97 LP |
157 | void *userdata, |
158 | sd_bus_error *error) { | |
f401e48c | 159 | |
cc377381 | 160 | Seat *s = userdata; |
f1a8e221 | 161 | |
cc377381 LP |
162 | assert(bus); |
163 | assert(reply); | |
f1a8e221 LP |
164 | assert(s); |
165 | ||
cc377381 | 166 | return sd_bus_message_append(reply, "b", seat_get_idle_hint(s, NULL) > 0); |
f1a8e221 LP |
167 | } |
168 | ||
cc377381 LP |
169 | static int property_get_idle_since_hint( |
170 | sd_bus *bus, | |
171 | const char *path, | |
172 | const char *interface, | |
173 | const char *property, | |
174 | sd_bus_message *reply, | |
ebcf1f97 LP |
175 | void *userdata, |
176 | sd_bus_error *error) { | |
cc377381 LP |
177 | |
178 | Seat *s = userdata; | |
179 | dual_timestamp t; | |
180 | uint64_t u; | |
181 | int r; | |
f1a8e221 | 182 | |
cc377381 LP |
183 | assert(bus); |
184 | assert(reply); | |
f1a8e221 LP |
185 | assert(s); |
186 | ||
cc377381 LP |
187 | r = seat_get_idle_hint(s, &t); |
188 | if (r < 0) | |
189 | return r; | |
f1a8e221 | 190 | |
cc377381 | 191 | u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic; |
f1a8e221 | 192 | |
cc377381 | 193 | return sd_bus_message_append(reply, "t", u); |
f1a8e221 LP |
194 | } |
195 | ||
ebcf1f97 | 196 | static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { |
cc377381 LP |
197 | Seat *s = userdata; |
198 | int r; | |
a185c5aa | 199 | |
cc377381 LP |
200 | assert(bus); |
201 | assert(message); | |
a185c5aa LP |
202 | assert(s); |
203 | ||
cc377381 LP |
204 | r = seat_stop_sessions(s); |
205 | if (r < 0) | |
ebcf1f97 | 206 | return r; |
a185c5aa | 207 | |
df2d202e | 208 | return sd_bus_reply_method_return(message, NULL); |
a185c5aa LP |
209 | } |
210 | ||
ebcf1f97 | 211 | static int method_activate_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { |
cc377381 LP |
212 | Seat *s = userdata; |
213 | const char *name; | |
214 | Session *session; | |
215 | int r; | |
a185c5aa | 216 | |
cc377381 LP |
217 | assert(bus); |
218 | assert(message); | |
a185c5aa LP |
219 | assert(s); |
220 | ||
cc377381 LP |
221 | r = sd_bus_message_read(message, "s", &name); |
222 | if (r < 0) | |
ebcf1f97 | 223 | return r; |
a185c5aa | 224 | |
cc377381 LP |
225 | session = hashmap_get(s->manager->sessions, name); |
226 | if (!session) | |
ebcf1f97 | 227 | return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name); |
a185c5aa | 228 | |
cc377381 | 229 | if (session->seat != s) |
ebcf1f97 | 230 | return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", name, s->id); |
a185c5aa | 231 | |
cc377381 LP |
232 | r = session_activate(session); |
233 | if (r < 0) | |
ebcf1f97 | 234 | return r; |
3f49d45a | 235 | |
df2d202e | 236 | return sd_bus_reply_method_return(message, NULL); |
3f49d45a LP |
237 | } |
238 | ||
cc377381 LP |
239 | const sd_bus_vtable seat_vtable[] = { |
240 | SD_BUS_VTABLE_START(0), | |
a185c5aa | 241 | |
556089dc | 242 | SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Seat, id), SD_BUS_VTABLE_PROPERTY_CONST), |
cc377381 | 243 | SD_BUS_PROPERTY("ActiveSession", "(so)", property_get_active_session, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
556089dc LP |
244 | SD_BUS_PROPERTY("CanMultiSession", "b", property_get_can_multi_session, 0, SD_BUS_VTABLE_PROPERTY_CONST), |
245 | SD_BUS_PROPERTY("CanTTY", "b", property_get_can_tty, 0, SD_BUS_VTABLE_PROPERTY_CONST), | |
cc377381 LP |
246 | SD_BUS_PROPERTY("CanGraphical", "b", property_get_can_graphical, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
247 | SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), | |
248 | SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), | |
249 | SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), | |
250 | SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), | |
3f49d45a | 251 | |
adacb957 LP |
252 | SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)), |
253 | SD_BUS_METHOD("ActivateSession", "s", NULL, method_activate_session, SD_BUS_VTABLE_UNPRIVILEGED), | |
a185c5aa | 254 | |
cc377381 LP |
255 | SD_BUS_VTABLE_END |
256 | }; | |
a185c5aa | 257 | |
f00c3121 | 258 | int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) { |
cc377381 LP |
259 | Manager *m = userdata; |
260 | Seat *seat; | |
927b1649 | 261 | int r; |
a185c5aa | 262 | |
cc377381 LP |
263 | assert(bus); |
264 | assert(path); | |
265 | assert(interface); | |
266 | assert(found); | |
267 | assert(m); | |
a185c5aa | 268 | |
927b1649 | 269 | if (streq(path, "/org/freedesktop/login1/seat/self")) { |
5b12334d | 270 | _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; |
927b1649 LP |
271 | sd_bus_message *message; |
272 | Session *session; | |
273 | pid_t pid; | |
a185c5aa | 274 | |
927b1649 LP |
275 | message = sd_bus_get_current(bus); |
276 | if (!message) | |
277 | return 0; | |
278 | ||
5b12334d | 279 | r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds); |
927b1649 | 280 | if (r < 0) |
5b12334d LP |
281 | return r; |
282 | ||
283 | r = sd_bus_creds_get_pid(creds, &pid); | |
284 | if (r < 0) | |
285 | return r; | |
927b1649 LP |
286 | |
287 | r = manager_get_session_by_pid(m, pid, &session); | |
288 | if (r <= 0) | |
289 | return 0; | |
290 | ||
291 | if (!session->seat) | |
292 | return 0; | |
a185c5aa | 293 | |
927b1649 LP |
294 | seat = session->seat; |
295 | } else { | |
296 | _cleanup_free_ char *e = NULL; | |
297 | const char *p; | |
298 | ||
299 | p = startswith(path, "/org/freedesktop/login1/seat/"); | |
300 | if (!p) | |
301 | return 0; | |
302 | ||
28383ba1 | 303 | e = sd_bus_label_unescape(p); |
927b1649 LP |
304 | if (!e) |
305 | return -ENOMEM; | |
306 | ||
307 | seat = hashmap_get(m->seats, e); | |
308 | if (!seat) | |
309 | return 0; | |
310 | } | |
a185c5aa | 311 | |
cc377381 LP |
312 | *found = seat; |
313 | return 1; | |
314 | } | |
a185c5aa | 315 | |
cc377381 LP |
316 | char *seat_bus_path(Seat *s) { |
317 | _cleanup_free_ char *t = NULL; | |
a185c5aa | 318 | |
cc377381 | 319 | assert(s); |
a185c5aa | 320 | |
28383ba1 | 321 | t = sd_bus_label_escape(s->id); |
cc377381 LP |
322 | if (!t) |
323 | return NULL; | |
a185c5aa | 324 | |
cc377381 | 325 | return strappend("/org/freedesktop/login1/seat/", t); |
3f49d45a LP |
326 | } |
327 | ||
f00c3121 | 328 | int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) { |
cc377381 | 329 | _cleanup_strv_free_ char **l = NULL; |
3f49d45a | 330 | Manager *m = userdata; |
cc377381 LP |
331 | Seat *seat; |
332 | Iterator i; | |
3f49d45a LP |
333 | int r; |
334 | ||
cc377381 LP |
335 | assert(bus); |
336 | assert(path); | |
337 | assert(nodes); | |
3f49d45a | 338 | |
cc377381 LP |
339 | HASHMAP_FOREACH(seat, m->seats, i) { |
340 | char *p; | |
3f49d45a | 341 | |
cc377381 LP |
342 | p = seat_bus_path(seat); |
343 | if (!p) | |
344 | return -ENOMEM; | |
3f49d45a | 345 | |
cc377381 LP |
346 | r = strv_push(&l, p); |
347 | if (r < 0) { | |
348 | free(p); | |
349 | return r; | |
3f49d45a | 350 | } |
3f49d45a LP |
351 | } |
352 | ||
cc377381 LP |
353 | *nodes = l; |
354 | l = NULL; | |
3f49d45a | 355 | |
cc377381 | 356 | return 1; |
3f49d45a | 357 | } |
da119395 LP |
358 | |
359 | int seat_send_signal(Seat *s, bool new_seat) { | |
ce0fc5f5 | 360 | _cleanup_free_ char *p = NULL; |
da119395 LP |
361 | |
362 | assert(s); | |
363 | ||
da119395 LP |
364 | p = seat_bus_path(s); |
365 | if (!p) | |
4654e558 | 366 | return -ENOMEM; |
da119395 | 367 | |
cc377381 LP |
368 | return sd_bus_emit_signal( |
369 | s->manager->bus, | |
370 | "/org/freedesktop/login1", | |
371 | "org.freedesktop.login1.Manager", | |
372 | new_seat ? "SeatNew" : "SeatRemoved", | |
373 | "so", s->id, p); | |
da119395 | 374 | } |
9418f147 | 375 | |
cc377381 | 376 | int seat_send_changed(Seat *s, const char *properties, ...) { |
ce0fc5f5 | 377 | _cleanup_free_ char *p = NULL; |
cc377381 | 378 | char **l; |
9418f147 LP |
379 | |
380 | assert(s); | |
381 | ||
ed18b08b LP |
382 | if (!s->started) |
383 | return 0; | |
384 | ||
9418f147 LP |
385 | p = seat_bus_path(s); |
386 | if (!p) | |
387 | return -ENOMEM; | |
388 | ||
cc377381 | 389 | l = strv_from_stdarg_alloca(properties); |
9418f147 | 390 | |
cc377381 | 391 | return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Seat", l); |
9418f147 | 392 | } |