]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind.c
update TODO
[thirdparty/systemd.git] / src / login / logind.c
CommitLineData
20263082
LP
1/***
2 This file is part of systemd.
3
4 Copyright 2011 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
20263082
LP
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 14 Lesser General Public License for more details.
20263082 15
5430f7f2 16 You should have received a copy of the GNU Lesser General Public License
20263082
LP
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
20#include <errno.h>
20263082
LP
21#include <fcntl.h>
22#include <string.h>
23#include <unistd.h>
20263082 24
b4bbcaa9 25#include "libudev.h"
cc377381 26#include "sd-daemon.h"
07630cea 27
b5efdb8a 28#include "alloc-util.h"
cc377381 29#include "bus-error.h"
07630cea
LP
30#include "bus-util.h"
31#include "conf-parser.h"
a0f29c76 32#include "def.h"
a0956174 33#include "dirent-util.h"
3ffd4af2 34#include "fd-util.h"
6482f626 35#include "formats-util.h"
3ffd4af2 36#include "logind.h"
4b51966c 37#include "selinux-util.h"
24882e06 38#include "signal-util.h"
07630cea
LP
39#include "strv.h"
40#include "udev-util.h"
20263082 41
905f0a39
DM
42static void manager_free(Manager *m);
43
a2ed7077 44static void manager_reset_config(Manager *m) {
20263082 45 m->n_autovts = 6;
98a77df5 46 m->reserve_vt = 6;
66cdd0f2 47 m->remove_ipc = true;
eecd1362 48 m->inhibit_delay_max = 5 * USEC_PER_SEC;
beaafb2e 49 m->handle_power_key = HANDLE_POWEROFF;
8e7fd6ad
LP
50 m->handle_suspend_key = HANDLE_SUSPEND;
51 m->handle_hibernate_key = HANDLE_HIBERNATE;
beaafb2e 52 m->handle_lid_switch = HANDLE_SUSPEND;
3c56cab4 53 m->handle_lid_switch_docked = HANDLE_IGNORE;
a2ed7077
ZJS
54 m->power_key_ignore_inhibited = false;
55 m->suspend_key_ignore_inhibited = false;
56 m->hibernate_key_ignore_inhibited = false;
beaafb2e 57 m->lid_switch_ignore_inhibited = true;
a2ed7077 58
9d10cbee 59 m->holdoff_timeout_usec = 30 * USEC_PER_SEC;
20263082 60
23406ce5
LP
61 m->idle_action_usec = 30 * USEC_PER_MINUTE;
62 m->idle_action = HANDLE_IGNORE;
23406ce5 63
1c231f56 64 m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */
cf7d1a30 65 m->user_tasks_max = UINT64_C(12288);
183e0738 66 m->sessions_max = UINT64_C(8192);
1c231f56 67
95365a57 68 m->kill_user_processes = KILL_USER_PROCESSES;
a2ed7077
ZJS
69
70 m->kill_only_users = strv_free(m->kill_only_users);
71 m->kill_exclude_users = strv_free(m->kill_exclude_users);
72}
73
74static Manager *manager_new(void) {
75 Manager *m;
76 int r;
77
78 m = new0(Manager, 1);
79 if (!m)
80 return NULL;
81
82 m->console_active_fd = -1;
83 m->reserve_vt_fd = -1;
84
85 m->idle_action_not_before_usec = now(CLOCK_MONOTONIC);
86
d5099efc
MS
87 m->devices = hashmap_new(&string_hash_ops);
88 m->seats = hashmap_new(&string_hash_ops);
89 m->sessions = hashmap_new(&string_hash_ops);
90 m->users = hashmap_new(NULL);
91 m->inhibitors = hashmap_new(&string_hash_ops);
92 m->buttons = hashmap_new(&string_hash_ops);
f8e2fb7b 93
d5099efc
MS
94 m->user_units = hashmap_new(&string_hash_ops);
95 m->session_units = hashmap_new(&string_hash_ops);
8c8c4351 96
3cde9e8f 97 if (!m->devices || !m->seats || !m->sessions || !m->users || !m->inhibitors || !m->buttons || !m->user_units || !m->session_units)
ed4ba7e4 98 goto fail;
25d93491 99
20263082 100 m->udev = udev_new();
ed4ba7e4
LP
101 if (!m->udev)
102 goto fail;
20263082 103
afc6adb5 104 r = sd_event_default(&m->event);
ed4ba7e4
LP
105 if (r < 0)
106 goto fail;
cc377381 107
cde93897
LP
108 sd_event_set_watchdog(m->event, true);
109
a2ed7077
ZJS
110 manager_reset_config(m);
111
20263082 112 return m;
ed4ba7e4
LP
113
114fail:
115 manager_free(m);
116 return NULL;
20263082
LP
117}
118
905f0a39 119static void manager_free(Manager *m) {
20263082
LP
120 Session *session;
121 User *u;
122 Device *d;
123 Seat *s;
f8e2fb7b 124 Inhibitor *i;
069cfc85 125 Button *b;
20263082
LP
126
127 assert(m);
128
129 while ((session = hashmap_first(m->sessions)))
130 session_free(session);
131
132 while ((u = hashmap_first(m->users)))
133 user_free(u);
134
135 while ((d = hashmap_first(m->devices)))
136 device_free(d);
137
138 while ((s = hashmap_first(m->seats)))
139 seat_free(s);
140
f8e2fb7b
LP
141 while ((i = hashmap_first(m->inhibitors)))
142 inhibitor_free(i);
143
069cfc85
LP
144 while ((b = hashmap_first(m->buttons)))
145 button_free(b);
146
20263082
LP
147 hashmap_free(m->devices);
148 hashmap_free(m->seats);
f8e2fb7b
LP
149 hashmap_free(m->sessions);
150 hashmap_free(m->users);
151 hashmap_free(m->inhibitors);
069cfc85 152 hashmap_free(m->buttons);
f8e2fb7b 153
fb6becb4
LP
154 hashmap_free(m->user_units);
155 hashmap_free(m->session_units);
8c8c4351 156
cc377381 157 sd_event_source_unref(m->idle_action_event_source);
c0f32805 158 sd_event_source_unref(m->inhibit_timeout_source);
8aaa023a 159 sd_event_source_unref(m->scheduled_shutdown_timeout_source);
867c37f6 160 sd_event_source_unref(m->nologin_timeout_source);
e2fa5721 161 sd_event_source_unref(m->wall_message_timeout_source);
cc377381
LP
162
163 sd_event_source_unref(m->console_active_event_source);
164 sd_event_source_unref(m->udev_seat_event_source);
165 sd_event_source_unref(m->udev_device_event_source);
166 sd_event_source_unref(m->udev_vcsa_event_source);
167 sd_event_source_unref(m->udev_button_event_source);
f9cd6be1 168 sd_event_source_unref(m->lid_switch_ignore_event_source);
20263082 169
03e334a1 170 safe_close(m->console_active_fd);
20263082 171
3e044c49
ME
172 udev_monitor_unref(m->udev_seat_monitor);
173 udev_monitor_unref(m->udev_device_monitor);
174 udev_monitor_unref(m->udev_vcsa_monitor);
175 udev_monitor_unref(m->udev_button_monitor);
176
177 udev_unref(m->udev);
20263082 178
867c37f6 179 if (m->unlink_nologin)
a790812c 180 (void) unlink("/run/nologin");
867c37f6 181
36e34057 182 bus_verify_polkit_async_registry_free(m->polkit_registry);
20263082 183
cc377381
LP
184 sd_bus_unref(m->bus);
185 sd_event_unref(m->event);
20263082 186
03e334a1 187 safe_close(m->reserve_vt_fd);
98a77df5 188
193197e8
LP
189 strv_free(m->kill_only_users);
190 strv_free(m->kill_exclude_users);
191
8aaa023a 192 free(m->scheduled_shutdown_type);
e2fa5721
DM
193 free(m->scheduled_shutdown_tty);
194 free(m->wall_message);
af9792ac 195 free(m->action_job);
20263082
LP
196 free(m);
197}
198
9588bc32 199static int manager_enumerate_devices(Manager *m) {
20263082 200 struct udev_list_entry *item = NULL, *first = NULL;
bf5332d2 201 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
14c3baca 202 int r;
20263082
LP
203
204 assert(m);
205
206 /* Loads devices from udev and creates seats for them as
207 * necessary */
208
209 e = udev_enumerate_new(m->udev);
bf5332d2
LP
210 if (!e)
211 return -ENOMEM;
20263082 212
2d96536d 213 r = udev_enumerate_add_match_tag(e, "master-of-seat");
14c3baca 214 if (r < 0)
bf5332d2 215 return r;
20263082 216
e1202047
LP
217 r = udev_enumerate_add_match_is_initialized(e);
218 if (r < 0)
219 return r;
220
14c3baca
LP
221 r = udev_enumerate_scan_devices(e);
222 if (r < 0)
bf5332d2 223 return r;
20263082
LP
224
225 first = udev_enumerate_get_list_entry(e);
226 udev_list_entry_foreach(item, first) {
bf5332d2 227 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
20263082
LP
228 int k;
229
230 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
bf5332d2
LP
231 if (!d)
232 return -ENOMEM;
20263082 233
bf5332d2 234 k = manager_process_seat_device(m, d);
20263082
LP
235 if (k < 0)
236 r = k;
237 }
238
20263082
LP
239 return r;
240}
241
9588bc32 242static int manager_enumerate_buttons(Manager *m) {
bf5332d2 243 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
069cfc85 244 struct udev_list_entry *item = NULL, *first = NULL;
069cfc85
LP
245 int r;
246
247 assert(m);
248
249 /* Loads buttons from udev */
250
beaafb2e 251 if (m->handle_power_key == HANDLE_IGNORE &&
8e7fd6ad
LP
252 m->handle_suspend_key == HANDLE_IGNORE &&
253 m->handle_hibernate_key == HANDLE_IGNORE &&
3c56cab4
BW
254 m->handle_lid_switch == HANDLE_IGNORE &&
255 m->handle_lid_switch_docked == HANDLE_IGNORE)
6de0e0e5
LP
256 return 0;
257
069cfc85 258 e = udev_enumerate_new(m->udev);
bf5332d2
LP
259 if (!e)
260 return -ENOMEM;
069cfc85
LP
261
262 r = udev_enumerate_add_match_subsystem(e, "input");
263 if (r < 0)
bf5332d2 264 return r;
069cfc85
LP
265
266 r = udev_enumerate_add_match_tag(e, "power-switch");
267 if (r < 0)
bf5332d2 268 return r;
069cfc85 269
e1202047
LP
270 r = udev_enumerate_add_match_is_initialized(e);
271 if (r < 0)
272 return r;
273
069cfc85
LP
274 r = udev_enumerate_scan_devices(e);
275 if (r < 0)
bf5332d2 276 return r;
069cfc85
LP
277
278 first = udev_enumerate_get_list_entry(e);
279 udev_list_entry_foreach(item, first) {
bf5332d2 280 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
069cfc85
LP
281 int k;
282
283 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
bf5332d2
LP
284 if (!d)
285 return -ENOMEM;
069cfc85 286
bf5332d2 287 k = manager_process_button_device(m, d);
069cfc85
LP
288 if (k < 0)
289 r = k;
290 }
291
069cfc85
LP
292 return r;
293}
294
9588bc32 295static int manager_enumerate_seats(Manager *m) {
9444b1f2 296 _cleanup_closedir_ DIR *d = NULL;
20263082
LP
297 struct dirent *de;
298 int r = 0;
299
300 assert(m);
301
302 /* This loads data about seats stored on disk, but does not
303 * actually create any seats. Removes data of seats that no
304 * longer exist. */
305
306 d = opendir("/run/systemd/seats");
307 if (!d) {
308 if (errno == ENOENT)
309 return 0;
310
e1427b13 311 return log_error_errno(errno, "Failed to open /run/systemd/seats: %m");
20263082
LP
312 }
313
9444b1f2 314 FOREACH_DIRENT(de, d, return -errno) {
20263082
LP
315 Seat *s;
316 int k;
317
318 if (!dirent_is_file(de))
319 continue;
320
321 s = hashmap_get(m->seats, de->d_name);
322 if (!s) {
323 unlinkat(dirfd(d), de->d_name, 0);
324 continue;
325 }
326
327 k = seat_load(s);
328 if (k < 0)
329 r = k;
330 }
331
14c3baca
LP
332 return r;
333}
20263082 334
14c3baca 335static int manager_enumerate_linger_users(Manager *m) {
9444b1f2 336 _cleanup_closedir_ DIR *d = NULL;
14c3baca
LP
337 struct dirent *de;
338 int r = 0;
339
9444b1f2
LP
340 assert(m);
341
14c3baca
LP
342 d = opendir("/var/lib/systemd/linger");
343 if (!d) {
344 if (errno == ENOENT)
345 return 0;
346
e1427b13 347 return log_error_errno(errno, "Failed to open /var/lib/systemd/linger/: %m");
14c3baca
LP
348 }
349
9444b1f2 350 FOREACH_DIRENT(de, d, return -errno) {
14c3baca
LP
351 int k;
352
353 if (!dirent_is_file(de))
20263082
LP
354 continue;
355
14c3baca
LP
356 k = manager_add_user_by_name(m, de->d_name, NULL);
357 if (k < 0) {
da927ba9 358 log_notice_errno(k, "Couldn't add lingering user %s: %m", de->d_name);
14c3baca 359 r = k;
20263082
LP
360 }
361 }
362
20263082
LP
363 return r;
364}
365
9588bc32 366static int manager_enumerate_users(Manager *m) {
9444b1f2 367 _cleanup_closedir_ DIR *d = NULL;
20263082 368 struct dirent *de;
14c3baca 369 int r, k;
20263082
LP
370
371 assert(m);
372
9444b1f2 373 /* Add lingering users */
b3629c7d 374 r = manager_enumerate_linger_users(m);
14c3baca 375
9444b1f2 376 /* Read in user data stored on disk */
20263082
LP
377 d = opendir("/run/systemd/users");
378 if (!d) {
379 if (errno == ENOENT)
380 return 0;
381
e1427b13 382 return log_error_errno(errno, "Failed to open /run/systemd/users: %m");
20263082
LP
383 }
384
9444b1f2 385 FOREACH_DIRENT(de, d, return -errno) {
20263082 386 User *u;
20263082
LP
387
388 if (!dirent_is_file(de))
389 continue;
390
9444b1f2 391 k = manager_add_user_by_name(m, de->d_name, &u);
20263082 392 if (k < 0) {
da927ba9 393 log_error_errno(k, "Failed to add user by file name %s: %m", de->d_name);
20263082 394
9444b1f2 395 r = k;
20263082
LP
396 continue;
397 }
398
9444b1f2
LP
399 user_add_to_gc_queue(u);
400
20263082
LP
401 k = user_load(u);
402 if (k < 0)
403 r = k;
404 }
405
20263082
LP
406 return r;
407}
408
9588bc32 409static int manager_enumerate_sessions(Manager *m) {
9444b1f2
LP
410 _cleanup_closedir_ DIR *d = NULL;
411 struct dirent *de;
20263082
LP
412 int r = 0;
413
9444b1f2
LP
414 assert(m);
415
416 /* Read in session data stored on disk */
417 d = opendir("/run/systemd/sessions");
418 if (!d) {
419 if (errno == ENOENT)
420 return 0;
421
e1427b13 422 return log_error_errno(errno, "Failed to open /run/systemd/sessions: %m");
9444b1f2
LP
423 }
424
425 FOREACH_DIRENT(de, d, return -errno) {
426 struct Session *s;
20263082
LP
427 int k;
428
9444b1f2 429 if (!dirent_is_file(de))
14c3baca
LP
430 continue;
431
4b549144
ZJS
432 if (!session_id_valid(de->d_name)) {
433 log_warning("Invalid session file name '%s', ignoring.", de->d_name);
434 r = -EINVAL;
435 continue;
436 }
437
9444b1f2 438 k = manager_add_session(m, de->d_name, &s);
20263082 439 if (k < 0) {
da927ba9 440 log_error_errno(k, "Failed to add session by file name %s: %m", de->d_name);
20263082 441
20263082
LP
442 r = k;
443 continue;
444 }
445
9444b1f2 446 session_add_to_gc_queue(s);
20263082 447
9444b1f2 448 k = session_load(s);
20263082
LP
449 if (k < 0)
450 r = k;
451 }
452
453 return r;
454}
455
9588bc32 456static int manager_enumerate_inhibitors(Manager *m) {
9444b1f2 457 _cleanup_closedir_ DIR *d = NULL;
20263082
LP
458 struct dirent *de;
459 int r = 0;
460
461 assert(m);
462
9444b1f2 463 d = opendir("/run/systemd/inhibit");
20263082
LP
464 if (!d) {
465 if (errno == ENOENT)
466 return 0;
467
e1427b13 468 return log_error_errno(errno, "Failed to open /run/systemd/inhibit: %m");
20263082
LP
469 }
470
9444b1f2 471 FOREACH_DIRENT(de, d, return -errno) {
20263082 472 int k;
9444b1f2 473 Inhibitor *i;
20263082
LP
474
475 if (!dirent_is_file(de))
476 continue;
477
9444b1f2
LP
478 k = manager_add_inhibitor(m, de->d_name, &i);
479 if (k < 0) {
da927ba9 480 log_notice_errno(k, "Couldn't add inhibitor %s: %m", de->d_name);
9444b1f2 481 r = k;
20263082
LP
482 continue;
483 }
484
9444b1f2 485 k = inhibitor_load(i);
20263082
LP
486 if (k < 0)
487 r = k;
488 }
489
20263082
LP
490 return r;
491}
492
cc377381 493static int manager_dispatch_seat_udev(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
7b77ed8c 494 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
cc377381 495 Manager *m = userdata;
20263082
LP
496
497 assert(m);
498
30ed21ce 499 d = udev_monitor_receive_device(m->udev_seat_monitor);
20263082
LP
500 if (!d)
501 return -ENOMEM;
502
7b77ed8c
LP
503 manager_process_seat_device(m, d);
504 return 0;
30ed21ce
LP
505}
506
cc377381 507static int manager_dispatch_device_udev(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
7b77ed8c 508 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
cc377381 509 Manager *m = userdata;
718d006a
DH
510
511 assert(m);
512
513 d = udev_monitor_receive_device(m->udev_device_monitor);
514 if (!d)
515 return -ENOMEM;
516
7b77ed8c
LP
517 manager_process_seat_device(m, d);
518 return 0;
718d006a
DH
519}
520
cc377381 521static int manager_dispatch_vcsa_udev(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
7b77ed8c 522 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
cc377381 523 Manager *m = userdata;
30ed21ce
LP
524 const char *name;
525
526 assert(m);
527
528 d = udev_monitor_receive_device(m->udev_vcsa_monitor);
529 if (!d)
530 return -ENOMEM;
531
532 name = udev_device_get_sysname(d);
533
534 /* Whenever a VCSA device is removed try to reallocate our
535 * VTs, to make sure our auto VTs never go away. */
536
537 if (name && startswith(name, "vcsa") && streq_ptr(udev_device_get_action(d), "remove"))
7b77ed8c 538 seat_preallocate_vts(m->seat0);
30ed21ce 539
7b77ed8c 540 return 0;
20263082
LP
541}
542
cc377381 543static int manager_dispatch_button_udev(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
7b77ed8c 544 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
cc377381 545 Manager *m = userdata;
069cfc85
LP
546
547 assert(m);
548
549 d = udev_monitor_receive_device(m->udev_button_monitor);
550 if (!d)
551 return -ENOMEM;
552
7b77ed8c
LP
553 manager_process_button_device(m, d);
554 return 0;
069cfc85
LP
555}
556
cc377381
LP
557static int manager_dispatch_console(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
558 Manager *m = userdata;
559
20263082 560 assert(m);
92432fcc 561 assert(m->seat0);
cc377381 562 assert(m->console_active_fd == fd);
20263082 563
92432fcc 564 seat_read_active_vt(m->seat0);
20263082
LP
565 return 0;
566}
567
98a77df5
LP
568static int manager_reserve_vt(Manager *m) {
569 _cleanup_free_ char *p = NULL;
570
571 assert(m);
572
573 if (m->reserve_vt <= 0)
574 return 0;
575
576 if (asprintf(&p, "/dev/tty%u", m->reserve_vt) < 0)
577 return log_oom();
578
579 m->reserve_vt_fd = open(p, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
580 if (m->reserve_vt_fd < 0) {
d4d882e5
LP
581
582 /* Don't complain on VT-less systems */
583 if (errno != ENOENT)
56f64d95 584 log_warning_errno(errno, "Failed to pin reserved VT: %m");
98a77df5
LP
585 return -errno;
586 }
587
588 return 0;
589}
590
cc377381 591static int manager_connect_bus(Manager *m) {
4afd3348 592 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
cc377381 593 int r;
31b79c2b 594
cc377381
LP
595 assert(m);
596 assert(!m->bus);
31b79c2b 597
76b54375 598 r = sd_bus_default_system(&m->bus);
f647962d
MS
599 if (r < 0)
600 return log_error_errno(r, "Failed to connect to system bus: %m");
31b79c2b 601
19befb2d 602 r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/login1", "org.freedesktop.login1.Manager", manager_vtable, m);
f647962d
MS
603 if (r < 0)
604 return log_error_errno(r, "Failed to add manager object vtable: %m");
f8e2fb7b 605
19befb2d 606 r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/login1/seat", "org.freedesktop.login1.Seat", seat_vtable, seat_object_find, m);
f647962d
MS
607 if (r < 0)
608 return log_error_errno(r, "Failed to add seat object vtable: %m");
069cfc85 609
19befb2d 610 r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/login1/seat", seat_node_enumerator, m);
f647962d
MS
611 if (r < 0)
612 return log_error_errno(r, "Failed to add seat enumerator: %m");
20263082 613
19befb2d 614 r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/login1/session", "org.freedesktop.login1.Session", session_vtable, session_object_find, m);
f647962d
MS
615 if (r < 0)
616 return log_error_errno(r, "Failed to add session object vtable: %m");
20263082 617
19befb2d 618 r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/login1/session", session_node_enumerator, m);
f647962d
MS
619 if (r < 0)
620 return log_error_errno(r, "Failed to add session enumerator: %m");
20263082 621
19befb2d 622 r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/login1/user", "org.freedesktop.login1.User", user_vtable, user_object_find, m);
f647962d
MS
623 if (r < 0)
624 return log_error_errno(r, "Failed to add user object vtable: %m");
20263082 625
19befb2d 626 r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/login1/user", user_node_enumerator, m);
f647962d
MS
627 if (r < 0)
628 return log_error_errno(r, "Failed to add user enumerator: %m");
20263082 629
cc377381 630 r = sd_bus_add_match(m->bus,
19befb2d 631 NULL,
cc377381
LP
632 "type='signal',"
633 "sender='org.freedesktop.systemd1',"
634 "interface='org.freedesktop.systemd1.Manager',"
635 "member='JobRemoved',"
636 "path='/org/freedesktop/systemd1'",
637 match_job_removed, m);
f647962d
MS
638 if (r < 0)
639 return log_error_errno(r, "Failed to add match for JobRemoved: %m");
943aca8e 640
cc377381 641 r = sd_bus_add_match(m->bus,
19befb2d 642 NULL,
cc377381
LP
643 "type='signal',"
644 "sender='org.freedesktop.systemd1',"
645 "interface='org.freedesktop.systemd1.Manager',"
646 "member='UnitRemoved',"
647 "path='/org/freedesktop/systemd1'",
648 match_unit_removed, m);
f647962d
MS
649 if (r < 0)
650 return log_error_errno(r, "Failed to add match for UnitRemoved: %m");
fb6becb4 651
cc377381 652 r = sd_bus_add_match(m->bus,
19befb2d 653 NULL,
cc377381
LP
654 "type='signal',"
655 "sender='org.freedesktop.systemd1',"
656 "interface='org.freedesktop.DBus.Properties',"
657 "member='PropertiesChanged'",
658 match_properties_changed, m);
f647962d
MS
659 if (r < 0)
660 return log_error_errno(r, "Failed to add match for PropertiesChanged: %m");
fb6becb4 661
cc377381 662 r = sd_bus_add_match(m->bus,
19befb2d 663 NULL,
cc377381
LP
664 "type='signal',"
665 "sender='org.freedesktop.systemd1',"
666 "interface='org.freedesktop.systemd1.Manager',"
667 "member='Reloading',"
668 "path='/org/freedesktop/systemd1'",
669 match_reloading, m);
f647962d
MS
670 if (r < 0)
671 return log_error_errno(r, "Failed to add match for Reloading: %m");
6797c324 672
cc377381 673 r = sd_bus_call_method(
fb6becb4
LP
674 m->bus,
675 "org.freedesktop.systemd1",
676 "/org/freedesktop/systemd1",
677 "org.freedesktop.systemd1.Manager",
678 "Subscribe",
fb6becb4 679 &error,
cc377381 680 NULL, NULL);
fb6becb4 681 if (r < 0) {
cc377381
LP
682 log_error("Failed to enable subscription: %s", bus_error_message(&error, r));
683 return r;
20263082
LP
684 }
685
5bb658a1 686 r = sd_bus_request_name(m->bus, "org.freedesktop.login1", 0);
f647962d
MS
687 if (r < 0)
688 return log_error_errno(r, "Failed to register name: %m");
bafd4449 689
cc377381 690 r = sd_bus_attach_event(m->bus, m->event, 0);
f647962d
MS
691 if (r < 0)
692 return log_error_errno(r, "Failed to attach bus to event loop: %m");
20263082 693
20263082 694 return 0;
20263082
LP
695}
696
92683ad2
DH
697static int manager_vt_switch(sd_event_source *src, const struct signalfd_siginfo *si, void *data) {
698 Manager *m = data;
699 Session *active, *iter;
700
701 /*
702 * We got a VT-switch signal and we have to acknowledge it immediately.
703 * Preferably, we'd just use m->seat0->active->vtfd, but unfortunately,
704 * old user-space might run multiple sessions on a single VT, *sigh*.
705 * Therefore, we have to iterate all sessions and find one with a vtfd
706 * on the requested VT.
707 * As only VTs with active controllers have VT_PROCESS set, our current
708 * notion of the active VT might be wrong (for instance if the switch
709 * happens while we setup VT_PROCESS). Therefore, read the current VT
710 * first and then use s->active->vtnr as reference. Note that this is
711 * not racy, as no further VT-switch can happen as long as we're in
712 * synchronous VT_PROCESS mode.
713 */
714
715 assert(m->seat0);
716 seat_read_active_vt(m->seat0);
717
718 active = m->seat0->active;
719 if (!active || active->vtnr < 1) {
720 log_warning("Received VT_PROCESS signal without a registered session on that VT.");
721 return 0;
722 }
723
724 if (active->vtfd >= 0) {
2ec3ff66 725 session_leave_vt(active);
92683ad2
DH
726 } else {
727 LIST_FOREACH(sessions_by_seat, iter, m->seat0->sessions) {
728 if (iter->vtnr == active->vtnr && iter->vtfd >= 0) {
2ec3ff66 729 session_leave_vt(iter);
92683ad2
DH
730 break;
731 }
732 }
733 }
734
735 return 0;
736}
737
20263082 738static int manager_connect_console(Manager *m) {
cc377381 739 int r;
20263082
LP
740
741 assert(m);
742 assert(m->console_active_fd < 0);
743
74afee9c
LP
744 /* On certain architectures (S390 and Xen, and containers),
745 /dev/tty0 does not exist, so don't fail if we can't open
746 it. */
cc377381 747 if (access("/dev/tty0", F_OK) < 0)
74afee9c 748 return 0;
74afee9c 749
20263082
LP
750 m->console_active_fd = open("/sys/class/tty/tty0/active", O_RDONLY|O_NOCTTY|O_CLOEXEC);
751 if (m->console_active_fd < 0) {
cdc564d2
MS
752
753 /* On some systems the device node /dev/tty0 may exist
754 * even though /sys/class/tty/tty0 does not. */
755 if (errno == ENOENT)
756 return 0;
757
e1427b13 758 return log_error_errno(errno, "Failed to open /sys/class/tty/tty0/active: %m");
20263082
LP
759 }
760
151b9b96 761 r = sd_event_add_io(m->event, &m->console_active_event_source, m->console_active_fd, 0, manager_dispatch_console, m);
cc377381
LP
762 if (r < 0) {
763 log_error("Failed to watch foreground console");
764 return r;
765 }
20263082 766
92683ad2
DH
767 /*
768 * SIGRTMIN is used as global VT-release signal, SIGRTMIN + 1 is used
769 * as VT-acquire signal. We ignore any acquire-events (yes, we still
770 * have to provide a valid signal-number for it!) and acknowledge all
771 * release events immediately.
772 */
773
774 if (SIGRTMIN + 1 > SIGRTMAX) {
775 log_error("Not enough real-time signals available: %u-%u", SIGRTMIN, SIGRTMAX);
776 return -EINVAL;
777 }
778
72c0a2c2
LP
779 assert_se(ignore_signals(SIGRTMIN + 1, -1) >= 0);
780 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN, -1) >= 0);
92683ad2
DH
781
782 r = sd_event_add_signal(m->event, NULL, SIGRTMIN, manager_vt_switch, m);
783 if (r < 0)
784 return r;
785
20263082
LP
786 return 0;
787}
788
789static int manager_connect_udev(Manager *m) {
14c3baca 790 int r;
20263082
LP
791
792 assert(m);
30ed21ce 793 assert(!m->udev_seat_monitor);
718d006a 794 assert(!m->udev_device_monitor);
30ed21ce 795 assert(!m->udev_vcsa_monitor);
069cfc85 796 assert(!m->udev_button_monitor);
20263082 797
30ed21ce
LP
798 m->udev_seat_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
799 if (!m->udev_seat_monitor)
20263082
LP
800 return -ENOMEM;
801
2d96536d 802 r = udev_monitor_filter_add_match_tag(m->udev_seat_monitor, "master-of-seat");
14c3baca
LP
803 if (r < 0)
804 return r;
20263082 805
30ed21ce 806 r = udev_monitor_enable_receiving(m->udev_seat_monitor);
14c3baca
LP
807 if (r < 0)
808 return r;
20263082 809
151b9b96 810 r = sd_event_add_io(m->event, &m->udev_seat_event_source, udev_monitor_get_fd(m->udev_seat_monitor), EPOLLIN, manager_dispatch_seat_udev, m);
cc377381
LP
811 if (r < 0)
812 return r;
069cfc85 813
718d006a
DH
814 m->udev_device_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
815 if (!m->udev_device_monitor)
816 return -ENOMEM;
817
818 r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_device_monitor, "input", NULL);
819 if (r < 0)
820 return r;
821
822 r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_device_monitor, "graphics", NULL);
823 if (r < 0)
824 return r;
825
826 r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_device_monitor, "drm", NULL);
827 if (r < 0)
828 return r;
829
830 r = udev_monitor_enable_receiving(m->udev_device_monitor);
831 if (r < 0)
832 return r;
833
151b9b96 834 r = sd_event_add_io(m->event, &m->udev_device_event_source, udev_monitor_get_fd(m->udev_device_monitor), EPOLLIN, manager_dispatch_device_udev, m);
cc377381
LP
835 if (r < 0)
836 return r;
718d006a 837
6de0e0e5 838 /* Don't watch keys if nobody cares */
beaafb2e 839 if (m->handle_power_key != HANDLE_IGNORE ||
8e7fd6ad
LP
840 m->handle_suspend_key != HANDLE_IGNORE ||
841 m->handle_hibernate_key != HANDLE_IGNORE ||
3c56cab4
BW
842 m->handle_lid_switch != HANDLE_IGNORE ||
843 m->handle_lid_switch_docked != HANDLE_IGNORE) {
069cfc85 844
6de0e0e5
LP
845 m->udev_button_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
846 if (!m->udev_button_monitor)
847 return -ENOMEM;
069cfc85 848
6de0e0e5
LP
849 r = udev_monitor_filter_add_match_tag(m->udev_button_monitor, "power-switch");
850 if (r < 0)
851 return r;
069cfc85 852
6de0e0e5
LP
853 r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_button_monitor, "input", NULL);
854 if (r < 0)
855 return r;
069cfc85 856
6de0e0e5
LP
857 r = udev_monitor_enable_receiving(m->udev_button_monitor);
858 if (r < 0)
859 return r;
069cfc85 860
151b9b96 861 r = sd_event_add_io(m->event, &m->udev_button_event_source, udev_monitor_get_fd(m->udev_button_monitor), EPOLLIN, manager_dispatch_button_udev, m);
cc377381
LP
862 if (r < 0)
863 return r;
6de0e0e5 864 }
069cfc85 865
976c088a 866 /* Don't bother watching VCSA devices, if nobody cares */
6de0e0e5 867 if (m->n_autovts > 0 && m->console_active_fd >= 0) {
30ed21ce 868
6de0e0e5
LP
869 m->udev_vcsa_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
870 if (!m->udev_vcsa_monitor)
871 return -ENOMEM;
30ed21ce 872
6de0e0e5
LP
873 r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_vcsa_monitor, "vc", NULL);
874 if (r < 0)
875 return r;
30ed21ce 876
6de0e0e5
LP
877 r = udev_monitor_enable_receiving(m->udev_vcsa_monitor);
878 if (r < 0)
879 return r;
30ed21ce 880
151b9b96 881 r = sd_event_add_io(m->event, &m->udev_vcsa_event_source, udev_monitor_get_fd(m->udev_vcsa_monitor), EPOLLIN, manager_dispatch_vcsa_udev, m);
cc377381
LP
882 if (r < 0)
883 return r;
6de0e0e5 884 }
20263082
LP
885
886 return 0;
887}
888
905f0a39 889static void manager_gc(Manager *m, bool drop_not_started) {
14c3baca
LP
890 Seat *seat;
891 Session *session;
892 User *user;
893
894 assert(m);
895
896 while ((seat = m->seat_gc_queue)) {
71fda00f 897 LIST_REMOVE(gc_queue, m->seat_gc_queue, seat);
14c3baca
LP
898 seat->in_gc_queue = false;
899
cc377381 900 if (!seat_check_gc(seat, drop_not_started)) {
9bb69af4 901 seat_stop(seat, false);
14c3baca
LP
902 seat_free(seat);
903 }
904 }
905
906 while ((session = m->session_gc_queue)) {
71fda00f 907 LIST_REMOVE(gc_queue, m->session_gc_queue, session);
14c3baca
LP
908 session->in_gc_queue = false;
909
5f41d1f1
LP
910 /* First, if we are not closing yet, initiate stopping */
911 if (!session_check_gc(session, drop_not_started) &&
912 session_get_state(session) != SESSION_CLOSING)
9bb69af4 913 session_stop(session, false);
5f41d1f1 914
491ac9f2
LP
915 /* Normally, this should make the session referenced
916 * again, if it doesn't then let's get rid of it
5f41d1f1
LP
917 * immediately */
918 if (!session_check_gc(session, drop_not_started)) {
405e0255 919 session_finalize(session);
14c3baca
LP
920 session_free(session);
921 }
922 }
923
924 while ((user = m->user_gc_queue)) {
71fda00f 925 LIST_REMOVE(gc_queue, m->user_gc_queue, user);
14c3baca
LP
926 user->in_gc_queue = false;
927
b58b227a
DH
928 /* First step: queue stop jobs */
929 if (!user_check_gc(user, drop_not_started))
9bb69af4 930 user_stop(user, false);
5f41d1f1 931
b58b227a 932 /* Second step: finalize user */
5f41d1f1 933 if (!user_check_gc(user, drop_not_started)) {
405e0255 934 user_finalize(user);
14c3baca
LP
935 user_free(user);
936 }
937 }
938}
939
cc377381
LP
940static int manager_dispatch_idle_action(sd_event_source *s, uint64_t t, void *userdata) {
941 Manager *m = userdata;
23406ce5 942 struct dual_timestamp since;
cc377381 943 usec_t n, elapse;
23406ce5 944 int r;
23406ce5
LP
945
946 assert(m);
947
948 if (m->idle_action == HANDLE_IGNORE ||
cc377381
LP
949 m->idle_action_usec <= 0)
950 return 0;
23406ce5 951
23406ce5
LP
952 n = now(CLOCK_MONOTONIC);
953
954 r = manager_get_idle_hint(m, &since);
955 if (r <= 0)
39ccc87c 956 /* Not idle. Let's check if after a timeout it might be idle then. */
cc377381 957 elapse = n + m->idle_action_usec;
23406ce5
LP
958 else {
959 /* Idle! Let's see if it's time to do something, or if
960 * we shall sleep for longer. */
961
962 if (n >= since.monotonic + m->idle_action_usec &&
963 (m->idle_action_not_before_usec <= 0 || n >= m->idle_action_not_before_usec + m->idle_action_usec)) {
964 log_info("System idle. Taking action.");
965
966 manager_handle_action(m, 0, m->idle_action, false, false);
967 m->idle_action_not_before_usec = n;
968 }
969
cc377381 970 elapse = MAX(since.monotonic, m->idle_action_not_before_usec) + m->idle_action_usec;
23406ce5
LP
971 }
972
cc377381 973 if (!m->idle_action_event_source) {
23406ce5 974
6a0f1f6d
LP
975 r = sd_event_add_time(
976 m->event,
977 &m->idle_action_event_source,
978 CLOCK_MONOTONIC,
979 elapse, USEC_PER_SEC*30,
980 manager_dispatch_idle_action, m);
f647962d
MS
981 if (r < 0)
982 return log_error_errno(r, "Failed to add idle event source: %m");
23406ce5 983
718db961 984 r = sd_event_source_set_priority(m->idle_action_event_source, SD_EVENT_PRIORITY_IDLE+10);
f647962d
MS
985 if (r < 0)
986 return log_error_errno(r, "Failed to set idle event source priority: %m");
cc377381
LP
987 } else {
988 r = sd_event_source_set_time(m->idle_action_event_source, elapse);
f647962d
MS
989 if (r < 0)
990 return log_error_errno(r, "Failed to set idle event timer: %m");
23406ce5 991
cc377381 992 r = sd_event_source_set_enabled(m->idle_action_event_source, SD_EVENT_ONESHOT);
f647962d
MS
993 if (r < 0)
994 return log_error_errno(r, "Failed to enable idle event timer: %m");
23406ce5
LP
995 }
996
997 return 0;
23406ce5 998}
cc377381 999
a2ed7077
ZJS
1000static int manager_parse_config_file(Manager *m) {
1001 assert(m);
1002
1003 return config_parse_many(PKGSYSCONFDIR "/logind.conf",
1004 CONF_PATHS_NULSTR("systemd/logind.conf.d"),
1005 "Login\0",
1006 config_item_perf_lookup, logind_gperf_lookup,
1007 false, m);
1008}
1009
1010static int manager_dispatch_reload_signal(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
1011 Manager *m = userdata;
1012 int r;
1013
1014 manager_reset_config(m);
1015 r = manager_parse_config_file(m);
1016 if (r < 0)
1017 log_warning_errno(r, "Failed to parse config file, using defaults: %m");
1018 else
1019 log_info("Config file reloaded.");
1020
1021 return 0;
1022}
1023
905f0a39 1024static int manager_startup(Manager *m) {
20263082 1025 int r;
14c3baca
LP
1026 Seat *seat;
1027 Session *session;
1028 User *user;
ed4ba7e4 1029 Button *button;
f8e2fb7b 1030 Inhibitor *inhibitor;
14c3baca 1031 Iterator i;
20263082
LP
1032
1033 assert(m);
20263082 1034
a2ed7077
ZJS
1035 assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGHUP, -1) >= 0);
1036
1037 r = sd_event_add_signal(m->event, NULL, SIGHUP, manager_dispatch_reload_signal, m);
1038 if (r < 0)
1039 return log_error_errno(r, "Failed to register SIGHUP handler: %m");
1040
976c088a
LP
1041 /* Connect to console */
1042 r = manager_connect_console(m);
20263082
LP
1043 if (r < 0)
1044 return r;
1045
976c088a
LP
1046 /* Connect to udev */
1047 r = manager_connect_udev(m);
f647962d
MS
1048 if (r < 0)
1049 return log_error_errno(r, "Failed to create udev watchers: %m");
20263082
LP
1050
1051 /* Connect to the bus */
1052 r = manager_connect_bus(m);
1053 if (r < 0)
1054 return r;
1055
14c3baca 1056 /* Instantiate magic seat 0 */
92432fcc 1057 r = manager_add_seat(m, "seat0", &m->seat0);
f647962d
MS
1058 if (r < 0)
1059 return log_error_errno(r, "Failed to add seat0: %m");
14c3baca 1060
9d10cbee 1061 r = manager_set_lid_switch_ignore(m, 0 + m->holdoff_timeout_usec);
f9cd6be1 1062 if (r < 0)
da927ba9 1063 log_warning_errno(r, "Failed to set up lid switch ignore event source: %m");
f9cd6be1 1064
20263082 1065 /* Deserialize state */
042f5988
ZJS
1066 r = manager_enumerate_devices(m);
1067 if (r < 0)
da927ba9 1068 log_warning_errno(r, "Device enumeration failed: %m");
042f5988
ZJS
1069
1070 r = manager_enumerate_seats(m);
1071 if (r < 0)
da927ba9 1072 log_warning_errno(r, "Seat enumeration failed: %m");
042f5988
ZJS
1073
1074 r = manager_enumerate_users(m);
1075 if (r < 0)
da927ba9 1076 log_warning_errno(r, "User enumeration failed: %m");
042f5988
ZJS
1077
1078 r = manager_enumerate_sessions(m);
1079 if (r < 0)
da927ba9 1080 log_warning_errno(r, "Session enumeration failed: %m");
042f5988
ZJS
1081
1082 r = manager_enumerate_inhibitors(m);
1083 if (r < 0)
da927ba9 1084 log_warning_errno(r, "Inhibitor enumeration failed: %m");
042f5988
ZJS
1085
1086 r = manager_enumerate_buttons(m);
1087 if (r < 0)
da927ba9 1088 log_warning_errno(r, "Button enumeration failed: %m");
20263082 1089
4a4b033f
LP
1090 /* Remove stale objects before we start them */
1091 manager_gc(m, false);
1092
98a77df5
LP
1093 /* Reserve the special reserved VT */
1094 manager_reserve_vt(m);
1095
14c3baca
LP
1096 /* And start everything */
1097 HASHMAP_FOREACH(seat, m->seats, i)
1098 seat_start(seat);
1099
1100 HASHMAP_FOREACH(user, m->users, i)
1101 user_start(user);
1102
1103 HASHMAP_FOREACH(session, m->sessions, i)
1104 session_start(session);
20263082 1105
f8e2fb7b
LP
1106 HASHMAP_FOREACH(inhibitor, m->inhibitors, i)
1107 inhibitor_start(inhibitor);
1108
ed4ba7e4 1109 HASHMAP_FOREACH(button, m->buttons, i)
2d62c530 1110 button_check_switches(button);
ed4ba7e4 1111
cc377381 1112 manager_dispatch_idle_action(NULL, 0, m);
23406ce5 1113
20263082
LP
1114 return 0;
1115}
1116
905f0a39 1117static int manager_run(Manager *m) {
cc377381
LP
1118 int r;
1119
20263082
LP
1120 assert(m);
1121
1122 for (;;) {
cc377381
LP
1123 r = sd_event_get_state(m->event);
1124 if (r < 0)
1125 return r;
1126 if (r == SD_EVENT_FINISHED)
1127 return 0;
20263082 1128
4a4b033f 1129 manager_gc(m, true);
14c3baca 1130
418b22b8
DM
1131 r = manager_dispatch_delayed(m, false);
1132 if (r < 0)
1133 return r;
1134 if (r > 0)
1135 continue;
1136
c0f32805 1137 r = sd_event_run(m->event, (uint64_t) -1);
cc377381
LP
1138 if (r < 0)
1139 return r;
20263082 1140 }
20263082
LP
1141}
1142
1143int main(int argc, char *argv[]) {
1144 Manager *m = NULL;
5eda94dd 1145 int r;
20263082
LP
1146
1147 log_set_target(LOG_TARGET_AUTO);
3eff4208 1148 log_set_facility(LOG_AUTH);
20263082
LP
1149 log_parse_environment();
1150 log_open();
1151
4c12626c
LP
1152 umask(0022);
1153
20263082
LP
1154 if (argc != 1) {
1155 log_error("This program takes no arguments.");
1156 r = -EINVAL;
1157 goto finish;
1158 }
1159
c3dacc8b 1160 r = mac_selinux_init();
4b51966c
NI
1161 if (r < 0) {
1162 log_error_errno(r, "Could not initialize labelling: %m");
1163 goto finish;
1164 }
1165
bb27ff66
LP
1166 /* Always create the directories people can create inotify
1167 * watches in. Note that some applications might check for the
ab06eef8 1168 * existence of /run/systemd/seats/ to determine whether
bb27ff66
LP
1169 * logind is available, so please always make sure this check
1170 * stays in. */
1171 mkdir_label("/run/systemd/seats", 0755);
1172 mkdir_label("/run/systemd/users", 0755);
1173 mkdir_label("/run/systemd/sessions", 0755);
1174
20263082
LP
1175 m = manager_new();
1176 if (!m) {
0d0f0c50 1177 r = log_oom();
20263082
LP
1178 goto finish;
1179 }
1180
193197e8
LP
1181 manager_parse_config_file(m);
1182
20263082
LP
1183 r = manager_startup(m);
1184 if (r < 0) {
da927ba9 1185 log_error_errno(r, "Failed to fully start up daemon: %m");
20263082
LP
1186 goto finish;
1187 }
1188
de0671ee 1189 log_debug("systemd-logind running as pid "PID_FMT, getpid());
e6960940
LP
1190
1191 sd_notify(false,
1192 "READY=1\n"
1193 "STATUS=Processing requests...");
1194
20263082
LP
1195 r = manager_run(m);
1196
de0671ee 1197 log_debug("systemd-logind stopped as pid "PID_FMT, getpid());
e6960940 1198
20263082 1199finish:
e6960940 1200 sd_notify(false,
af4ec430 1201 "STOPPING=1\n"
e6960940
LP
1202 "STATUS=Shutting down...");
1203
3e044c49 1204 manager_free(m);
20263082
LP
1205
1206 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1207}