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