1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
9 #include <xkbcommon/xkbcommon.h>
15 #include "alloc-util.h"
16 #include "bus-error.h"
17 #include "bus-log-control-api.h"
18 #include "bus-message.h"
19 #include "bus-polkit.h"
21 #include "dlfcn-util.h"
23 #include "keymap-util.h"
24 #include "locale-util.h"
26 #include "main-func.h"
27 #include "missing_capability.h"
28 #include "path-util.h"
29 #include "selinux-util.h"
30 #include "service-util.h"
31 #include "signal-util.h"
32 #include "string-util.h"
34 #include "user-util.h"
36 static int locale_update_system_manager(Context
*c
, sd_bus
*bus
) {
37 _cleanup_free_
char **l_unset
= NULL
;
38 _cleanup_strv_free_
char **l_set
= NULL
;
39 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
40 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
41 size_t c_set
= 0, c_unset
= 0;
46 l_unset
= new0(char*, _VARIABLE_LC_MAX
);
50 l_set
= new0(char*, _VARIABLE_LC_MAX
);
54 for (LocaleVariable p
= 0; p
< _VARIABLE_LC_MAX
; p
++) {
57 name
= locale_variable_to_string(p
);
60 if (isempty(c
->locale
[p
]))
61 l_unset
[c_set
++] = (char*) name
;
65 s
= strjoin(name
, "=", c
->locale
[p
]);
73 assert(c_set
+ c_unset
== _VARIABLE_LC_MAX
);
74 r
= sd_bus_message_new_method_call(bus
, &m
,
75 "org.freedesktop.systemd1",
76 "/org/freedesktop/systemd1",
77 "org.freedesktop.systemd1.Manager",
78 "UnsetAndSetEnvironment");
80 return bus_log_create_error(r
);
82 r
= sd_bus_message_append_strv(m
, l_unset
);
84 return bus_log_create_error(r
);
86 r
= sd_bus_message_append_strv(m
, l_set
);
88 return bus_log_create_error(r
);
90 r
= sd_bus_call(bus
, m
, 0, &error
, NULL
);
92 return log_error_errno(r
, "Failed to update the manager environment: %s", bus_error_message(&error
, r
));
97 static int vconsole_reload(sd_bus
*bus
) {
98 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
103 r
= sd_bus_call_method(bus
,
104 "org.freedesktop.systemd1",
105 "/org/freedesktop/systemd1",
106 "org.freedesktop.systemd1.Manager",
110 "ss", "systemd-vconsole-setup.service", "replace");
113 return log_error_errno(r
, "Failed to issue method call: %s", bus_error_message(&error
, r
));
118 static int vconsole_convert_to_x11_and_emit(Context
*c
, sd_bus_message
*m
) {
123 r
= x11_read_data(c
, m
);
127 r
= vconsole_convert_to_x11(c
);
132 r
= x11_write_data(c
);
134 return log_error_errno(r
, "Failed to write X11 keyboard layout: %m");
136 sd_bus_emit_properties_changed(sd_bus_message_get_bus(m
),
137 "/org/freedesktop/locale1",
138 "org.freedesktop.locale1",
139 "X11Layout", "X11Model", "X11Variant", "X11Options", NULL
);
144 static int x11_convert_to_vconsole_and_emit(Context
*c
, sd_bus_message
*m
) {
149 r
= vconsole_read_data(c
, m
);
153 r
= x11_convert_to_vconsole(c
);
158 r
= vconsole_write_data(c
);
160 log_error_errno(r
, "Failed to save virtual console keymap: %m");
162 sd_bus_emit_properties_changed(sd_bus_message_get_bus(m
),
163 "/org/freedesktop/locale1",
164 "org.freedesktop.locale1",
165 "VConsoleKeymap", "VConsoleKeymapToggle", NULL
);
167 return vconsole_reload(sd_bus_message_get_bus(m
));
170 static int property_get_locale(
173 const char *interface
,
174 const char *property
,
175 sd_bus_message
*reply
,
177 sd_bus_error
*error
) {
179 Context
*c
= userdata
;
180 _cleanup_strv_free_
char **l
= NULL
;
183 r
= locale_read_data(c
, reply
);
187 l
= new0(char*, _VARIABLE_LC_MAX
+1);
191 for (LocaleVariable p
= 0, q
= 0; p
< _VARIABLE_LC_MAX
; p
++) {
195 name
= locale_variable_to_string(p
);
198 if (isempty(c
->locale
[p
]))
201 if (asprintf(&t
, "%s=%s", name
, c
->locale
[p
]) < 0)
207 return sd_bus_message_append_strv(reply
, l
);
210 static int property_get_vconsole(
213 const char *interface
,
214 const char *property
,
215 sd_bus_message
*reply
,
217 sd_bus_error
*error
) {
219 Context
*c
= userdata
;
222 r
= vconsole_read_data(c
, reply
);
226 if (streq(property
, "VConsoleKeymap"))
227 return sd_bus_message_append_basic(reply
, 's', c
->vc_keymap
);
228 else if (streq(property
, "VConsoleKeymapToggle"))
229 return sd_bus_message_append_basic(reply
, 's', c
->vc_keymap_toggle
);
234 static int property_get_xkb(
237 const char *interface
,
238 const char *property
,
239 sd_bus_message
*reply
,
241 sd_bus_error
*error
) {
243 Context
*c
= userdata
;
246 r
= x11_read_data(c
, reply
);
250 if (streq(property
, "X11Layout"))
251 return sd_bus_message_append_basic(reply
, 's', c
->x11_layout
);
252 else if (streq(property
, "X11Model"))
253 return sd_bus_message_append_basic(reply
, 's', c
->x11_model
);
254 else if (streq(property
, "X11Variant"))
255 return sd_bus_message_append_basic(reply
, 's', c
->x11_variant
);
256 else if (streq(property
, "X11Options"))
257 return sd_bus_message_append_basic(reply
, 's', c
->x11_options
);
262 static int process_locale_list_item(
263 const char *assignment
,
264 char *new_locale
[static _VARIABLE_LC_MAX
],
266 sd_bus_error
*error
) {
271 for (LocaleVariable p
= 0; p
< _VARIABLE_LC_MAX
; p
++) {
272 const char *name
, *e
;
274 assert_se(name
= locale_variable_to_string(p
));
276 e
= startswith(assignment
, name
);
285 if (!locale_is_valid(e
))
286 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Locale %s is not valid, refusing.", e
);
287 if (!use_localegen
&& locale_is_installed(e
) <= 0)
288 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Locale %s not installed, refusing.", e
);
290 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Locale variable %s set twice, refusing.", name
);
292 new_locale
[p
] = strdup(e
);
299 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Locale assignment %s not valid, refusing.", assignment
);
302 static int locale_gen_process_locale(char *new_locale
[static _VARIABLE_LC_MAX
],
303 sd_bus_error
*error
) {
307 for (LocaleVariable p
= 0; p
< _VARIABLE_LC_MAX
; p
++) {
308 if (p
== VARIABLE_LANGUAGE
)
310 if (isempty(new_locale
[p
]))
312 if (locale_is_installed(new_locale
[p
]))
315 r
= locale_gen_enable_locale(new_locale
[p
]);
317 log_error_errno(r
, "Refused to enable locale for generation: %m");
318 return sd_bus_error_setf(error
,
319 SD_BUS_ERROR_INVALID_ARGS
,
320 "Specified locale is not installed and non-UTF-8 locale will not be auto-generated: %s",
322 } else if (r
== -EINVAL
) {
323 log_error_errno(r
, "Failed to enable invalid locale %s for generation.", new_locale
[p
]);
324 return sd_bus_error_setf(error
,
325 SD_BUS_ERROR_INVALID_ARGS
,
326 "Can not enable locale generation for invalid locale: %s",
329 log_error_errno(r
, "Failed to enable locale for generation: %m");
330 return sd_bus_error_set_errnof(error
, r
, "Failed to enable locale generation: %m");
333 r
= locale_gen_run();
335 log_error_errno(r
, "Failed to generate locale: %m");
336 return sd_bus_error_set_errnof(error
, r
, "Failed to generate locale: %m");
343 static int method_set_locale(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
344 _cleanup_(locale_variables_freep
) char *new_locale
[_VARIABLE_LC_MAX
] = {};
345 _cleanup_strv_free_
char **settings
= NULL
, **l
= NULL
;
346 Context
*c
= userdata
;
347 bool modified
= false;
354 r
= sd_bus_message_read_strv(m
, &l
);
358 r
= sd_bus_message_read_basic(m
, 'b', &interactive
);
362 use_localegen
= locale_gen_check_available();
364 /* If single locale without variable name is provided, then we assume it is LANG=. */
365 if (strv_length(l
) == 1 && !strchr(l
[0], '=')) {
366 if (!locale_is_valid(l
[0]))
367 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid locale specification: %s", l
[0]);
368 if (!use_localegen
&& locale_is_installed(l
[0]) <= 0)
369 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Specified locale is not installed: %s", l
[0]);
371 new_locale
[VARIABLE_LANG
] = strdup(l
[0]);
372 if (!new_locale
[VARIABLE_LANG
])
378 /* Check whether a variable is valid */
380 r
= process_locale_list_item(*i
, new_locale
, use_localegen
, error
);
385 /* If LANG was specified, but not LANGUAGE, check if we should
386 * set it based on the language fallback table. */
387 if (!isempty(new_locale
[VARIABLE_LANG
]) &&
388 isempty(new_locale
[VARIABLE_LANGUAGE
])) {
389 _cleanup_free_
char *language
= NULL
;
391 (void) find_language_fallback(new_locale
[VARIABLE_LANG
], &language
);
393 log_debug("Converted LANG=%s to LANGUAGE=%s", new_locale
[VARIABLE_LANG
], language
);
394 free_and_replace(new_locale
[VARIABLE_LANGUAGE
], language
);
398 r
= locale_read_data(c
, m
);
400 log_error_errno(r
, "Failed to read locale data: %m");
401 return sd_bus_error_set(error
, SD_BUS_ERROR_FAILED
, "Failed to read locale data");
404 /* Merge with the current settings */
405 for (LocaleVariable p
= 0; p
< _VARIABLE_LC_MAX
; p
++)
406 if (!isempty(c
->locale
[p
]) && isempty(new_locale
[p
])) {
407 new_locale
[p
] = strdup(c
->locale
[p
]);
412 locale_simplify(new_locale
);
414 for (LocaleVariable p
= 0; p
< _VARIABLE_LC_MAX
; p
++)
415 if (!streq_ptr(c
->locale
[p
], new_locale
[p
])) {
421 log_debug("Locale settings were not modified.");
422 return sd_bus_reply_method_return(m
, NULL
);
425 r
= bus_verify_polkit_async(
428 "org.freedesktop.locale1.set-locale",
437 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
439 /* Generate locale in case it is missing and the system is using locale-gen */
441 r
= locale_gen_process_locale(new_locale
, error
);
446 for (LocaleVariable p
= 0; p
< _VARIABLE_LC_MAX
; p
++)
447 free_and_replace(c
->locale
[p
], new_locale
[p
]);
449 /* Write locale configuration */
450 r
= locale_write_data(c
, &settings
);
452 log_error_errno(r
, "Failed to set locale: %m");
453 return sd_bus_error_set_errnof(error
, r
, "Failed to set locale: %m");
456 (void) locale_update_system_manager(c
, sd_bus_message_get_bus(m
));
459 _cleanup_free_
char *line
= NULL
;
461 line
= strv_join(settings
, ", ");
462 log_info("Changed locale to %s.", strnull(line
));
464 log_info("Changed locale to unset.");
466 (void) sd_bus_emit_properties_changed(
467 sd_bus_message_get_bus(m
),
468 "/org/freedesktop/locale1",
469 "org.freedesktop.locale1",
472 return sd_bus_reply_method_return(m
, NULL
);
475 static int method_set_vc_keyboard(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
476 Context
*c
= userdata
;
477 const char *name
, *keymap
, *keymap_toggle
;
478 int convert
, interactive
, r
;
483 r
= sd_bus_message_read(m
, "ssbb", &keymap
, &keymap_toggle
, &convert
, &interactive
);
487 keymap
= empty_to_null(keymap
);
488 keymap_toggle
= empty_to_null(keymap_toggle
);
490 r
= vconsole_read_data(c
, m
);
492 log_error_errno(r
, "Failed to read virtual console keymap data: %m");
493 return sd_bus_error_set_errnof(error
, r
, "Failed to read virtual console keymap data: %m");
496 FOREACH_STRING(name
, keymap
?: keymap_toggle
, keymap
? keymap_toggle
: NULL
) {
497 r
= keymap_exists(name
); /* This also verifies that the keymap name is kosher. */
499 log_error_errno(r
, "Failed to check keymap %s: %m", name
);
500 return sd_bus_error_set_errnof(error
, r
, "Failed to check keymap %s: %m", name
);
503 return sd_bus_error_setf(error
, SD_BUS_ERROR_FAILED
, "Keymap %s is not installed.", name
);
506 if (streq_ptr(keymap
, c
->vc_keymap
) &&
507 streq_ptr(keymap_toggle
, c
->vc_keymap_toggle
))
508 return sd_bus_reply_method_return(m
, NULL
);
510 r
= bus_verify_polkit_async(
513 "org.freedesktop.locale1.set-keyboard",
522 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
524 if (free_and_strdup(&c
->vc_keymap
, keymap
) < 0 ||
525 free_and_strdup(&c
->vc_keymap_toggle
, keymap_toggle
) < 0)
528 r
= vconsole_write_data(c
);
530 log_error_errno(r
, "Failed to set virtual console keymap: %m");
531 return sd_bus_error_set_errnof(error
, r
, "Failed to set virtual console keymap: %m");
534 log_info("Changed virtual console keymap to '%s' toggle '%s'",
535 strempty(c
->vc_keymap
), strempty(c
->vc_keymap_toggle
));
537 (void) vconsole_reload(sd_bus_message_get_bus(m
));
539 (void) sd_bus_emit_properties_changed(
540 sd_bus_message_get_bus(m
),
541 "/org/freedesktop/locale1",
542 "org.freedesktop.locale1",
543 "VConsoleKeymap", "VConsoleKeymapToggle", NULL
);
546 r
= vconsole_convert_to_x11_and_emit(c
, m
);
548 log_error_errno(r
, "Failed to convert keymap data: %m");
551 return sd_bus_reply_method_return(m
, NULL
);
557 static void log_xkb(struct xkb_context
*ctx
, enum xkb_log_level lvl
, const char *format
, va_list args
) {
560 fmt
= strjoina("libxkbcommon: ", format
);
561 DISABLE_WARNING_FORMAT_NONLITERAL
;
562 log_internalv(LOG_DEBUG
, 0, PROJECT_FILE
, __LINE__
, __func__
, fmt
, args
);
566 #define LOAD_SYMBOL(symbol, dl, name) \
568 (symbol) = (typeof(symbol)) dlvsym((dl), (name), "V_0.5.0"); \
569 (symbol) ? 0 : -EOPNOTSUPP; \
572 static int verify_xkb_rmlvo(const char *model
, const char *layout
, const char *variant
, const char *options
) {
574 /* We dlopen() the library in order to make the dependency soft. The library (and what it pulls in) is huge
575 * after all, hence let's support XKB maps when the library is around, and refuse otherwise. The function
576 * pointers to the shared library are below: */
578 struct xkb_context
* (*symbol_xkb_context_new
)(enum xkb_context_flags flags
) = NULL
;
579 void (*symbol_xkb_context_unref
)(struct xkb_context
*context
) = NULL
;
580 void (*symbol_xkb_context_set_log_fn
)(struct xkb_context
*context
, void (*log_fn
)(struct xkb_context
*context
, enum xkb_log_level level
, const char *format
, va_list args
)) = NULL
;
581 struct xkb_keymap
* (*symbol_xkb_keymap_new_from_names
)(struct xkb_context
*context
, const struct xkb_rule_names
*names
, enum xkb_keymap_compile_flags flags
) = NULL
;
582 void (*symbol_xkb_keymap_unref
)(struct xkb_keymap
*keymap
) = NULL
;
584 const struct xkb_rule_names rmlvo
= {
590 struct xkb_context
*ctx
= NULL
;
591 struct xkb_keymap
*km
= NULL
;
592 _cleanup_(dlclosep
) void *dl
= NULL
;
595 /* Compile keymap from RMLVO information to check out its validity */
597 dl
= dlopen("libxkbcommon.so.0", RTLD_LAZY
);
601 r
= LOAD_SYMBOL(symbol_xkb_context_new
, dl
, "xkb_context_new");
605 r
= LOAD_SYMBOL(symbol_xkb_context_unref
, dl
, "xkb_context_unref");
609 r
= LOAD_SYMBOL(symbol_xkb_context_set_log_fn
, dl
, "xkb_context_set_log_fn");
613 r
= LOAD_SYMBOL(symbol_xkb_keymap_new_from_names
, dl
, "xkb_keymap_new_from_names");
617 r
= LOAD_SYMBOL(symbol_xkb_keymap_unref
, dl
, "xkb_keymap_unref");
621 ctx
= symbol_xkb_context_new(XKB_CONTEXT_NO_ENVIRONMENT_NAMES
);
627 symbol_xkb_context_set_log_fn(ctx
, log_xkb
);
629 km
= symbol_xkb_keymap_new_from_names(ctx
, &rmlvo
, XKB_KEYMAP_COMPILE_NO_FLAGS
);
638 if (symbol_xkb_keymap_unref
&& km
)
639 symbol_xkb_keymap_unref(km
);
641 if (symbol_xkb_context_unref
&& ctx
)
642 symbol_xkb_context_unref(ctx
);
649 static int verify_xkb_rmlvo(const char *model
, const char *layout
, const char *variant
, const char *options
) {
655 static int method_set_x11_keyboard(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
656 Context
*c
= userdata
;
657 const char *layout
, *model
, *variant
, *options
;
658 int convert
, interactive
, r
;
663 r
= sd_bus_message_read(m
, "ssssbb", &layout
, &model
, &variant
, &options
, &convert
, &interactive
);
667 layout
= empty_to_null(layout
);
668 model
= empty_to_null(model
);
669 variant
= empty_to_null(variant
);
670 options
= empty_to_null(options
);
672 r
= x11_read_data(c
, m
);
674 log_error_errno(r
, "Failed to read x11 keyboard layout data: %m");
675 return sd_bus_error_set(error
, SD_BUS_ERROR_FAILED
, "Failed to read x11 keyboard layout data");
678 if (streq_ptr(layout
, c
->x11_layout
) &&
679 streq_ptr(model
, c
->x11_model
) &&
680 streq_ptr(variant
, c
->x11_variant
) &&
681 streq_ptr(options
, c
->x11_options
))
682 return sd_bus_reply_method_return(m
, NULL
);
684 if ((layout
&& !string_is_safe(layout
)) ||
685 (model
&& !string_is_safe(model
)) ||
686 (variant
&& !string_is_safe(variant
)) ||
687 (options
&& !string_is_safe(options
)))
688 return sd_bus_error_set(error
, SD_BUS_ERROR_INVALID_ARGS
, "Received invalid keyboard data");
690 r
= verify_xkb_rmlvo(model
, layout
, variant
, options
);
692 log_error_errno(r
, "Cannot compile XKB keymap for new x11 keyboard layout ('%s' / '%s' / '%s' / '%s'): %m",
693 strempty(model
), strempty(layout
), strempty(variant
), strempty(options
));
695 if (r
== -EOPNOTSUPP
)
696 return sd_bus_error_set(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Local keyboard configuration not supported on this system.");
698 return sd_bus_error_set(error
, SD_BUS_ERROR_INVALID_ARGS
, "Specified keymap cannot be compiled, refusing as invalid.");
701 r
= bus_verify_polkit_async(
704 "org.freedesktop.locale1.set-keyboard",
713 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
715 if (free_and_strdup(&c
->x11_layout
, layout
) < 0 ||
716 free_and_strdup(&c
->x11_model
, model
) < 0 ||
717 free_and_strdup(&c
->x11_variant
, variant
) < 0 ||
718 free_and_strdup(&c
->x11_options
, options
) < 0)
721 r
= x11_write_data(c
);
723 log_error_errno(r
, "Failed to set X11 keyboard layout: %m");
724 return sd_bus_error_set_errnof(error
, r
, "Failed to set X11 keyboard layout: %m");
727 log_info("Changed X11 keyboard layout to '%s' model '%s' variant '%s' options '%s'",
728 strempty(c
->x11_layout
),
729 strempty(c
->x11_model
),
730 strempty(c
->x11_variant
),
731 strempty(c
->x11_options
));
733 (void) sd_bus_emit_properties_changed(
734 sd_bus_message_get_bus(m
),
735 "/org/freedesktop/locale1",
736 "org.freedesktop.locale1",
737 "X11Layout", "X11Model", "X11Variant", "X11Options", NULL
);
740 r
= x11_convert_to_vconsole_and_emit(c
, m
);
742 log_error_errno(r
, "Failed to convert keymap data: %m");
745 return sd_bus_reply_method_return(m
, NULL
);
748 static const sd_bus_vtable locale_vtable
[] = {
749 SD_BUS_VTABLE_START(0),
750 SD_BUS_PROPERTY("Locale", "as", property_get_locale
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
751 SD_BUS_PROPERTY("X11Layout", "s", property_get_xkb
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
752 SD_BUS_PROPERTY("X11Model", "s", property_get_xkb
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
753 SD_BUS_PROPERTY("X11Variant", "s", property_get_xkb
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
754 SD_BUS_PROPERTY("X11Options", "s", property_get_xkb
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
755 SD_BUS_PROPERTY("VConsoleKeymap", "s", property_get_vconsole
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
756 SD_BUS_PROPERTY("VConsoleKeymapToggle", "s", property_get_vconsole
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
758 SD_BUS_METHOD_WITH_NAMES("SetLocale",
761 SD_BUS_PARAM(interactive
),
764 SD_BUS_VTABLE_UNPRIVILEGED
),
765 SD_BUS_METHOD_WITH_NAMES("SetVConsoleKeyboard",
768 SD_BUS_PARAM(keymap_toggle
)
769 SD_BUS_PARAM(convert
)
770 SD_BUS_PARAM(interactive
),
772 method_set_vc_keyboard
,
773 SD_BUS_VTABLE_UNPRIVILEGED
),
774 SD_BUS_METHOD_WITH_NAMES("SetX11Keyboard",
778 SD_BUS_PARAM(variant
)
779 SD_BUS_PARAM(options
)
780 SD_BUS_PARAM(convert
)
781 SD_BUS_PARAM(interactive
),
783 method_set_x11_keyboard
,
784 SD_BUS_VTABLE_UNPRIVILEGED
),
789 static const BusObjectImplementation manager_object
= {
790 "/org/freedesktop/locale1",
791 "org.freedesktop.locale1",
792 .vtables
= BUS_VTABLES(locale_vtable
),
795 static int connect_bus(Context
*c
, sd_event
*event
, sd_bus
**_bus
) {
796 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
803 r
= sd_bus_default_system(&bus
);
805 return log_error_errno(r
, "Failed to get system bus connection: %m");
807 r
= bus_add_implementation(bus
, &manager_object
, c
);
811 r
= bus_log_control_api_register(bus
);
815 r
= sd_bus_request_name_async(bus
, NULL
, "org.freedesktop.locale1", 0, NULL
, NULL
);
817 return log_error_errno(r
, "Failed to request name: %m");
819 r
= sd_bus_attach_event(bus
, event
, 0);
821 return log_error_errno(r
, "Failed to attach bus to event loop: %m");
823 *_bus
= TAKE_PTR(bus
);
828 static int run(int argc
, char *argv
[]) {
829 _cleanup_(context_clear
) Context context
= {
830 .locale_mtime
= USEC_INFINITY
,
831 .vc_mtime
= USEC_INFINITY
,
832 .x11_mtime
= USEC_INFINITY
,
834 _cleanup_(sd_event_unrefp
) sd_event
*event
= NULL
;
835 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
840 r
= service_parse_argv("systemd-localed.service",
841 "Manage system locale settings and key mappings.",
842 BUS_IMPLEMENTATIONS(&manager_object
,
843 &log_control_object
),
850 r
= mac_selinux_init();
854 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGTERM
, SIGINT
, -1) >= 0);
856 r
= sd_event_default(&event
);
858 return log_error_errno(r
, "Failed to allocate event loop: %m");
860 (void) sd_event_set_watchdog(event
, true);
862 r
= sd_event_add_signal(event
, NULL
, SIGINT
, NULL
, NULL
);
864 return log_error_errno(r
, "Failed to install SIGINT handler: %m");
866 r
= sd_event_add_signal(event
, NULL
, SIGTERM
, NULL
, NULL
);
868 return log_error_errno(r
, "Failed to install SIGTERM handler: %m");
870 r
= connect_bus(&context
, event
, &bus
);
874 r
= bus_event_loop_with_idle(event
, bus
, "org.freedesktop.locale1", DEFAULT_EXIT_USEC
, NULL
, NULL
);
876 return log_error_errno(r
, "Failed to run event loop: %m");
881 DEFINE_MAIN_FUNCTION(run
);