]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/locale/localed.c
label: Introduce LabelOps to do pre/post labelling operations
[thirdparty/systemd.git] / src / locale / localed.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <errno.h>
4 #include <sys/stat.h>
5 #include <sys/types.h>
6 #include <unistd.h>
7
8 #include "sd-bus.h"
9
10 #include "alloc-util.h"
11 #include "bus-error.h"
12 #include "bus-locator.h"
13 #include "bus-log-control-api.h"
14 #include "bus-message.h"
15 #include "bus-polkit.h"
16 #include "constants.h"
17 #include "kbd-util.h"
18 #include "localed-util.h"
19 #include "macro.h"
20 #include "main-func.h"
21 #include "missing_capability.h"
22 #include "path-util.h"
23 #include "selinux-util.h"
24 #include "service-util.h"
25 #include "signal-util.h"
26 #include "string-util.h"
27 #include "strv.h"
28 #include "user-util.h"
29
30 static int reload_system_manager(sd_bus *bus) {
31 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
32 int r;
33
34 assert(bus);
35
36 r = bus_call_method(bus, bus_systemd_mgr, "Reload", &error, NULL, NULL);
37 if (r < 0)
38 return log_error_errno(r, "Failed to reload system manager: %s", bus_error_message(&error, r));
39 return 0;
40 }
41
42 static int vconsole_reload(sd_bus *bus) {
43 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
44 int r;
45
46 assert(bus);
47
48 r = bus_call_method(bus, bus_systemd_mgr, "RestartUnit", &error, NULL, "ss", "systemd-vconsole-setup.service", "replace");
49 if (r < 0)
50 return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r));
51 return 0;
52 }
53
54 static int property_get_locale(
55 sd_bus *bus,
56 const char *path,
57 const char *interface,
58 const char *property,
59 sd_bus_message *reply,
60 void *userdata,
61 sd_bus_error *error) {
62
63 Context *c = ASSERT_PTR(userdata);
64 _cleanup_strv_free_ char **l = NULL;
65 int r;
66
67 r = locale_read_data(c, reply);
68 if (r < 0)
69 return r;
70
71 r = locale_context_build_env(&c->locale_context, &l, NULL);
72 if (r < 0)
73 return r;
74
75 return sd_bus_message_append_strv(reply, l);
76 }
77
78 static int property_get_vconsole(
79 sd_bus *bus,
80 const char *path,
81 const char *interface,
82 const char *property,
83 sd_bus_message *reply,
84 void *userdata,
85 sd_bus_error *error) {
86
87 Context *c = ASSERT_PTR(userdata);
88 int r;
89
90 assert(property);
91
92 r = vconsole_read_data(c, reply);
93 if (r < 0)
94 return r;
95
96 if (streq(property, "VConsoleKeymap"))
97 return sd_bus_message_append_basic(reply, 's', c->vc.keymap);
98 if (streq(property, "VConsoleKeymapToggle"))
99 return sd_bus_message_append_basic(reply, 's', c->vc.toggle);
100
101 return -EINVAL;
102 }
103
104 static int property_get_xkb(
105 sd_bus *bus,
106 const char *path,
107 const char *interface,
108 const char *property,
109 sd_bus_message *reply,
110 void *userdata,
111 sd_bus_error *error) {
112
113 Context *c = ASSERT_PTR(userdata);
114 const X11Context *xc;
115 int r;
116
117 assert(property);
118
119 r = vconsole_read_data(c, reply);
120 if (r < 0)
121 return r;
122
123 r = x11_read_data(c, reply);
124 if (r < 0)
125 return r;
126
127 xc = context_get_x11_context(c);
128
129 if (streq(property, "X11Layout"))
130 return sd_bus_message_append_basic(reply, 's', xc->layout);
131 if (streq(property, "X11Model"))
132 return sd_bus_message_append_basic(reply, 's', xc->model);
133 if (streq(property, "X11Variant"))
134 return sd_bus_message_append_basic(reply, 's', xc->variant);
135 if (streq(property, "X11Options"))
136 return sd_bus_message_append_basic(reply, 's', xc->options);
137
138 return -EINVAL;
139 }
140
141 static int process_locale_list_item(
142 const char *assignment,
143 char *new_locale[static _VARIABLE_LC_MAX],
144 bool use_localegen,
145 sd_bus_error *error) {
146
147 assert(assignment);
148 assert(new_locale);
149
150 for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) {
151 const char *name, *e;
152
153 assert_se(name = locale_variable_to_string(p));
154
155 e = startswith(assignment, name);
156 if (!e)
157 continue;
158
159 if (*e != '=')
160 continue;
161
162 e++;
163
164 if (!locale_is_valid(e))
165 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Locale %s is not valid, refusing.", e);
166 if (!use_localegen && locale_is_installed(e) <= 0)
167 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Locale %s not installed, refusing.", e);
168 if (new_locale[p])
169 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Locale variable %s set twice, refusing.", name);
170
171 new_locale[p] = strdup(e);
172 if (!new_locale[p])
173 return -ENOMEM;
174
175 return 0;
176 }
177
178 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Locale assignment %s not valid, refusing.", assignment);
179 }
180
181 static int locale_gen_process_locale(char *new_locale[static _VARIABLE_LC_MAX], sd_bus_error *error) {
182 int r;
183
184 assert(new_locale);
185
186 for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) {
187 if (p == VARIABLE_LANGUAGE)
188 continue;
189 if (isempty(new_locale[p]))
190 continue;
191 if (locale_is_installed(new_locale[p]))
192 continue;
193
194 r = locale_gen_enable_locale(new_locale[p]);
195 if (r == -ENOEXEC) {
196 log_error_errno(r, "Refused to enable locale for generation: %m");
197 return sd_bus_error_setf(error,
198 SD_BUS_ERROR_INVALID_ARGS,
199 "Specified locale is not installed and non-UTF-8 locale will not be auto-generated: %s",
200 new_locale[p]);
201 }
202 if (r == -EINVAL) {
203 log_error_errno(r, "Failed to enable invalid locale %s for generation.", new_locale[p]);
204 return sd_bus_error_setf(error,
205 SD_BUS_ERROR_INVALID_ARGS,
206 "Can not enable locale generation for invalid locale: %s",
207 new_locale[p]);
208 }
209 if (r < 0) {
210 log_error_errno(r, "Failed to enable locale for generation: %m");
211 return sd_bus_error_set_errnof(error, r, "Failed to enable locale generation: %m");
212 }
213
214 r = locale_gen_run();
215 if (r < 0) {
216 log_error_errno(r, "Failed to generate locale: %m");
217 return sd_bus_error_set_errnof(error, r, "Failed to generate locale: %m");
218 }
219 }
220
221 return 0;
222 }
223
224 static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *error) {
225 _cleanup_(locale_variables_freep) char *new_locale[_VARIABLE_LC_MAX] = {};
226 _cleanup_strv_free_ char **l = NULL, **l_set = NULL, **l_unset = NULL;
227 Context *c = ASSERT_PTR(userdata);
228 int interactive, r;
229 bool use_localegen;
230
231 assert(m);
232
233 r = sd_bus_message_read_strv(m, &l);
234 if (r < 0)
235 return bus_log_parse_error(r);
236
237 r = sd_bus_message_read_basic(m, 'b', &interactive);
238 if (r < 0)
239 return bus_log_parse_error(r);
240
241 use_localegen = locale_gen_check_available();
242
243 /* If single locale without variable name is provided, then we assume it is LANG=. */
244 if (strv_length(l) == 1 && !strchr(l[0], '=')) {
245 if (!locale_is_valid(l[0]))
246 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid locale specification: %s", l[0]);
247 if (!use_localegen && locale_is_installed(l[0]) <= 0)
248 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified locale is not installed: %s", l[0]);
249
250 new_locale[VARIABLE_LANG] = strdup(l[0]);
251 if (!new_locale[VARIABLE_LANG])
252 return log_oom();
253
254 l = strv_free(l);
255 }
256
257 /* Check whether a variable is valid */
258 STRV_FOREACH(i, l) {
259 r = process_locale_list_item(*i, new_locale, use_localegen, error);
260 if (r < 0)
261 return r;
262 }
263
264 /* If LANG was specified, but not LANGUAGE, check if we should
265 * set it based on the language fallback table. */
266 if (!isempty(new_locale[VARIABLE_LANG]) &&
267 isempty(new_locale[VARIABLE_LANGUAGE])) {
268 _cleanup_free_ char *language = NULL;
269
270 (void) find_language_fallback(new_locale[VARIABLE_LANG], &language);
271 if (language) {
272 log_debug("Converted LANG=%s to LANGUAGE=%s", new_locale[VARIABLE_LANG], language);
273 free_and_replace(new_locale[VARIABLE_LANGUAGE], language);
274 }
275 }
276
277 r = locale_read_data(c, m);
278 if (r < 0) {
279 log_error_errno(r, "Failed to read locale data: %m");
280 return sd_bus_error_set(error, SD_BUS_ERROR_FAILED, "Failed to read locale data");
281 }
282
283 /* Merge with the current settings */
284 r = locale_context_merge(&c->locale_context, new_locale);
285 if (r < 0)
286 return log_oom();
287
288 locale_variables_simplify(new_locale);
289
290 if (locale_context_equal(&c->locale_context, new_locale)) {
291 log_debug("Locale settings were not modified.");
292 return sd_bus_reply_method_return(m, NULL);
293 }
294
295 r = bus_verify_polkit_async(
296 m,
297 CAP_SYS_ADMIN,
298 "org.freedesktop.locale1.set-locale",
299 NULL,
300 interactive,
301 UID_INVALID,
302 &c->polkit_registry,
303 error);
304 if (r < 0)
305 return r;
306 if (r == 0)
307 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
308
309 /* Generate locale in case it is missing and the system is using locale-gen */
310 if (use_localegen) {
311 r = locale_gen_process_locale(new_locale, error);
312 if (r < 0)
313 return r;
314 }
315
316 locale_context_take(&c->locale_context, new_locale);
317
318 /* Write locale configuration */
319 r = locale_context_save(&c->locale_context, &l_set, &l_unset);
320 if (r < 0) {
321 log_error_errno(r, "Failed to set locale: %m");
322 return sd_bus_error_set_errnof(error, r, "Failed to set locale: %m");
323 }
324
325 /* Since we just updated the locale configuration file, ask the system manager to read it again to
326 * update its default locale settings. It's important to not use UnsetAndSetEnvironment or a similar
327 * method because in this case unsetting variables means restoring them to PID1 default values, which
328 * may be outdated, since locale.conf has just changed and PID1 hasn't read it */
329 (void) reload_system_manager(sd_bus_message_get_bus(m));
330
331 if (!strv_isempty(l_set)) {
332 _cleanup_free_ char *line = NULL;
333
334 line = strv_join(l_set, ", ");
335 log_info("Changed locale to %s.", strnull(line));
336 } else
337 log_info("Changed locale to unset.");
338
339 (void) sd_bus_emit_properties_changed(
340 sd_bus_message_get_bus(m),
341 "/org/freedesktop/locale1",
342 "org.freedesktop.locale1",
343 "Locale", NULL);
344
345 return sd_bus_reply_method_return(m, NULL);
346 }
347
348 static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_error *error) {
349 _cleanup_(x11_context_clear) X11Context converted = {};
350 Context *c = ASSERT_PTR(userdata);
351 int convert, interactive, r;
352 bool x_needs_update;
353 VCContext in;
354
355 assert(m);
356
357 r = sd_bus_message_read(m, "ssbb", &in.keymap, &in.toggle, &convert, &interactive);
358 if (r < 0)
359 return bus_log_parse_error(r);
360
361 vc_context_empty_to_null(&in);
362
363 r = vc_context_verify_and_warn(&in, LOG_ERR, error);
364 if (r < 0)
365 return r;
366
367 r = vconsole_read_data(c, m);
368 if (r < 0) {
369 log_error_errno(r, "Failed to read virtual console keymap data: %m");
370 return sd_bus_error_set_errnof(error, r, "Failed to read virtual console keymap data: %m");
371 }
372
373 r = x11_read_data(c, m);
374 if (r < 0) {
375 log_error_errno(r, "Failed to read X11 keyboard layout data: %m");
376 return sd_bus_error_set_errnof(error, r, "Failed to read X11 keyboard layout data: %m");
377 }
378
379 if (convert) {
380 r = vconsole_convert_to_x11(&in, &converted);
381 if (r < 0) {
382 log_error_errno(r, "Failed to convert keymap data: %m");
383 return sd_bus_error_set_errnof(error, r, "Failed to convert keymap data: %m");
384 }
385
386 if (x11_context_isempty(&converted))
387 log_notice("No conversion found for virtual console keymap \"%s\".", strempty(in.keymap));
388 else
389 log_info("The virtual console keymap '%s' is converted to X11 keyboard layout '%s' model '%s' variant '%s' options '%s'",
390 in.keymap, strempty(converted.layout), strempty(converted.model), strempty(converted.variant), strempty(converted.options));
391
392 /* save the result of conversion to emit changed properties later. */
393 x_needs_update = !x11_context_equal(&c->x11_from_vc, &converted) || !x11_context_equal(&c->x11_from_xorg, &converted);
394 } else
395 x_needs_update = !x11_context_equal(&c->x11_from_vc, &c->x11_from_xorg);
396
397 if (vc_context_equal(&c->vc, &in) && !x_needs_update)
398 return sd_bus_reply_method_return(m, NULL);
399
400 r = bus_verify_polkit_async(
401 m,
402 CAP_SYS_ADMIN,
403 "org.freedesktop.locale1.set-keyboard",
404 NULL,
405 interactive,
406 UID_INVALID,
407 &c->polkit_registry,
408 error);
409 if (r < 0)
410 return r;
411 if (r == 0)
412 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
413
414 r = vc_context_copy(&c->vc, &in);
415 if (r < 0)
416 return log_oom();
417
418 if (x_needs_update) {
419 if (convert) {
420 r = x11_context_copy(&c->x11_from_vc, &converted);
421 if (r < 0)
422 return log_oom();
423 x11_context_replace(&c->x11_from_xorg, &converted);
424 } else {
425 const X11Context *xc = context_get_x11_context(c);
426
427 /* Even if the conversion is not requested, sync the two X11 contexts. */
428 r = x11_context_copy(&c->x11_from_vc, xc);
429 if (r < 0)
430 return log_oom();
431
432 r = x11_context_copy(&c->x11_from_xorg, xc);
433 if (r < 0)
434 return log_oom();
435 }
436 }
437
438 r = vconsole_write_data(c);
439 if (r < 0)
440 log_warning_errno(r, "Failed to write virtual console keymap, ignoring: %m");
441
442 if (x_needs_update) {
443 r = x11_write_data(c);
444 if (r < 0)
445 log_warning_errno(r, "Failed to write X11 keyboard layout, ignoring: %m");
446 }
447
448 log_info("Changed virtual console keymap to '%s' toggle '%s'",
449 strempty(c->vc.keymap), strempty(c->vc.toggle));
450
451 (void) vconsole_reload(sd_bus_message_get_bus(m));
452
453 (void) sd_bus_emit_properties_changed(
454 sd_bus_message_get_bus(m),
455 "/org/freedesktop/locale1",
456 "org.freedesktop.locale1",
457 "VConsoleKeymap", "VConsoleKeymapToggle",
458 x_needs_update ? "X11Layout" : NULL,
459 x_needs_update ? "X11Model" : NULL,
460 x_needs_update ? "X11Variant" : NULL,
461 x_needs_update ? "X11Options" : NULL,
462 NULL);
463
464 return sd_bus_reply_method_return(m, NULL);
465 }
466
467 static int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_error *error) {
468 _cleanup_(vc_context_clear) VCContext converted = {};
469 Context *c = ASSERT_PTR(userdata);
470 int convert, interactive, r;
471 X11Context in;
472
473 assert(m);
474
475 r = sd_bus_message_read(m, "ssssbb", &in.layout, &in.model, &in.variant, &in.options, &convert, &interactive);
476 if (r < 0)
477 return bus_log_parse_error(r);
478
479 x11_context_empty_to_null(&in);
480
481 r = x11_context_verify_and_warn(&in, LOG_ERR, error);
482 if (r < 0)
483 return r;
484
485 r = vconsole_read_data(c, m);
486 if (r < 0) {
487 log_error_errno(r, "Failed to read virtual console keymap data: %m");
488 return sd_bus_error_set_errnof(error, r, "Failed to read virtual console keymap data: %m");
489 }
490
491 r = x11_read_data(c, m);
492 if (r < 0) {
493 log_error_errno(r, "Failed to read x11 keyboard layout data: %m");
494 return sd_bus_error_set(error, SD_BUS_ERROR_FAILED, "Failed to read x11 keyboard layout data");
495 }
496
497 if (convert) {
498 r = x11_convert_to_vconsole(&in, &converted);
499 if (r < 0) {
500 log_error_errno(r, "Failed to convert keymap data: %m");
501 return sd_bus_error_set_errnof(error, r, "Failed to convert keymap data: %m");
502 }
503
504 if (vc_context_isempty(&converted))
505 /* We search for layout-variant match first, but then we also look
506 * for anything which matches just the layout. So it's accurate to say
507 * that we couldn't find anything which matches the layout. */
508 log_notice("No conversion to virtual console map found for \"%s\".", strempty(in.layout));
509 else
510 log_info("The X11 keyboard layout '%s' is converted to virtual console keymap '%s'",
511 in.layout, converted.keymap);
512
513 /* save the result of conversion to emit changed properties later. */
514 convert = !vc_context_equal(&c->vc, &converted);
515 }
516
517 if (x11_context_equal(&c->x11_from_vc, &in) && x11_context_equal(&c->x11_from_xorg, &in) && !convert)
518 return sd_bus_reply_method_return(m, NULL);
519
520 r = bus_verify_polkit_async(
521 m,
522 CAP_SYS_ADMIN,
523 "org.freedesktop.locale1.set-keyboard",
524 NULL,
525 interactive,
526 UID_INVALID,
527 &c->polkit_registry,
528 error);
529 if (r < 0)
530 return r;
531 if (r == 0)
532 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
533
534 r = x11_context_copy(&c->x11_from_vc, &in);
535 if (r < 0)
536 return log_oom();
537
538 r = x11_context_copy(&c->x11_from_xorg, &in);
539 if (r < 0)
540 return log_oom();
541
542 if (convert)
543 vc_context_replace(&c->vc, &converted);
544
545 r = vconsole_write_data(c);
546 if (r < 0)
547 log_warning_errno(r, "Failed to update vconsole.conf, ignoring: %m");
548
549 r = x11_write_data(c);
550 if (r < 0)
551 log_warning_errno(r, "Failed to write X11 keyboard layout, ignoring: %m");
552
553 log_info("Changed X11 keyboard layout to '%s' model '%s' variant '%s' options '%s'",
554 strempty(in.layout),
555 strempty(in.model),
556 strempty(in.variant),
557 strempty(in.options));
558
559 (void) sd_bus_emit_properties_changed(
560 sd_bus_message_get_bus(m),
561 "/org/freedesktop/locale1",
562 "org.freedesktop.locale1",
563 "X11Layout", "X11Model", "X11Variant", "X11Options",
564 convert ? "VConsoleKeymap" : NULL,
565 convert ? "VConsoleKeymapToggle" : NULL,
566 NULL);
567
568 if (convert)
569 (void) vconsole_reload(sd_bus_message_get_bus(m));
570
571 return sd_bus_reply_method_return(m, NULL);
572 }
573
574 static const sd_bus_vtable locale_vtable[] = {
575 SD_BUS_VTABLE_START(0),
576 SD_BUS_PROPERTY("Locale", "as", property_get_locale, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
577 SD_BUS_PROPERTY("X11Layout", "s", property_get_xkb, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
578 SD_BUS_PROPERTY("X11Model", "s", property_get_xkb, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
579 SD_BUS_PROPERTY("X11Variant", "s", property_get_xkb, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
580 SD_BUS_PROPERTY("X11Options", "s", property_get_xkb, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
581 SD_BUS_PROPERTY("VConsoleKeymap", "s", property_get_vconsole, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
582 SD_BUS_PROPERTY("VConsoleKeymapToggle", "s", property_get_vconsole, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
583
584 SD_BUS_METHOD_WITH_ARGS("SetLocale",
585 SD_BUS_ARGS("as", locale, "b", interactive),
586 SD_BUS_NO_RESULT,
587 method_set_locale,
588 SD_BUS_VTABLE_UNPRIVILEGED),
589 SD_BUS_METHOD_WITH_ARGS("SetVConsoleKeyboard",
590 SD_BUS_ARGS("s", keymap, "s", keymap_toggle, "b", convert, "b", interactive),
591 SD_BUS_NO_RESULT,
592 method_set_vc_keyboard,
593 SD_BUS_VTABLE_UNPRIVILEGED),
594 SD_BUS_METHOD_WITH_ARGS("SetX11Keyboard",
595 SD_BUS_ARGS("s", layout, "s", model, "s", variant, "s", options, "b", convert, "b", interactive),
596 SD_BUS_NO_RESULT,
597 method_set_x11_keyboard,
598 SD_BUS_VTABLE_UNPRIVILEGED),
599
600 SD_BUS_VTABLE_END
601 };
602
603 static const BusObjectImplementation manager_object = {
604 "/org/freedesktop/locale1",
605 "org.freedesktop.locale1",
606 .vtables = BUS_VTABLES(locale_vtable),
607 };
608
609 static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
610 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
611 int r;
612
613 assert(c);
614 assert(event);
615 assert(_bus);
616
617 r = sd_bus_default_system(&bus);
618 if (r < 0)
619 return log_error_errno(r, "Failed to get system bus connection: %m");
620
621 r = bus_add_implementation(bus, &manager_object, c);
622 if (r < 0)
623 return r;
624
625 r = bus_log_control_api_register(bus);
626 if (r < 0)
627 return r;
628
629 r = sd_bus_request_name_async(bus, NULL, "org.freedesktop.locale1", 0, NULL, NULL);
630 if (r < 0)
631 return log_error_errno(r, "Failed to request name: %m");
632
633 r = sd_bus_attach_event(bus, event, 0);
634 if (r < 0)
635 return log_error_errno(r, "Failed to attach bus to event loop: %m");
636
637 *_bus = TAKE_PTR(bus);
638
639 return 0;
640 }
641
642 static int run(int argc, char *argv[]) {
643 _cleanup_(context_clear) Context context = {};
644 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
645 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
646 int r;
647
648 log_setup();
649
650 r = service_parse_argv("systemd-localed.service",
651 "Manage system locale settings and key mappings.",
652 BUS_IMPLEMENTATIONS(&manager_object,
653 &log_control_object),
654 argc, argv);
655 if (r <= 0)
656 return r;
657
658 umask(0022);
659
660 r = mac_init();
661 if (r < 0)
662 return r;
663
664 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
665
666 r = sd_event_default(&event);
667 if (r < 0)
668 return log_error_errno(r, "Failed to allocate event loop: %m");
669
670 (void) sd_event_set_watchdog(event, true);
671
672 r = sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
673 if (r < 0)
674 return log_error_errno(r, "Failed to install SIGINT handler: %m");
675
676 r = sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
677 if (r < 0)
678 return log_error_errno(r, "Failed to install SIGTERM handler: %m");
679
680 r = connect_bus(&context, event, &bus);
681 if (r < 0)
682 return r;
683
684 r = bus_event_loop_with_idle(event, bus, "org.freedesktop.locale1", DEFAULT_EXIT_USEC, NULL, NULL);
685 if (r < 0)
686 return log_error_errno(r, "Failed to run event loop: %m");
687
688 return 0;
689 }
690
691 DEFINE_MAIN_FUNCTION(run);