]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/hostname/hostnamed.c
polkit: simplify bus_verify_polkit_async() + drop auth-by-cap dbus feature
[thirdparty/systemd.git] / src / hostname / hostnamed.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
7640a5de 2
7640a5de 3#include <errno.h>
f426cc5d 4#include <sys/utsname.h>
ca78ad1d
ZJS
5#include <sys/stat.h>
6#include <sys/types.h>
cf0fbc49 7#include <unistd.h>
7640a5de 8
b5efdb8a 9#include "alloc-util.h"
21e627da 10#include "bus-common-errors.h"
ce6b138c 11#include "bus-get-properties.h"
ac9f55ed 12#include "bus-log-control-api.h"
269e4d2d 13#include "bus-polkit.h"
28db6fbf 14#include "constants.h"
686d13b9
LP
15#include "env-file-label.h"
16#include "env-file.h"
4d1a6904 17#include "env-util.h"
6bedfcbb 18#include "fileio-label.h"
ee228be1 19#include "fileio.h"
e2054217 20#include "hostname-setup.h"
958b66ea 21#include "hostname-util.h"
21e627da 22#include "id128-util.h"
7ecead8f 23#include "json.h"
85ae63ee 24#include "main-func.h"
36dd5ffd 25#include "missing_capability.h"
7782e0a0 26#include "nscd-flush.h"
d8b4d14d 27#include "nulstr-util.h"
d58ad743 28#include "os-util.h"
6bedfcbb 29#include "parse-util.h"
bb15fafe 30#include "path-util.h"
b9d80698 31#include "sd-device.h"
6bedfcbb 32#include "selinux-util.h"
fc021a5b 33#include "service-util.h"
b22c8bfc 34#include "signal-util.h"
d7f4ad20 35#include "stat-util.h"
60e4fb42 36#include "string-table.h"
6bedfcbb 37#include "strv.h"
ee104e11 38#include "user-util.h"
6bedfcbb 39#include "virt.h"
91f9dcaf 40
799298d6
JG
41#define VALID_DEPLOYMENT_CHARS (DIGITS LETTERS "-.:")
42
f8da67cd
LP
43/* Properties we cache are indexed by an enum, to make invalidation easy and systematic (as we can iterate
44 * through them all, and they are uniformly strings). */
4fc7e4f3 45typedef enum {
d7f4ad20 46 /* Read from /etc/hostname */
7640a5de 47 PROP_STATIC_HOSTNAME,
d7f4ad20
LP
48
49 /* Read from /etc/machine-info */
7640a5de
LP
50 PROP_PRETTY_HOSTNAME,
51 PROP_ICON_NAME,
7871c8e9 52 PROP_CHASSIS,
799298d6 53 PROP_DEPLOYMENT,
ce0f1493 54 PROP_LOCATION,
0924ea2b
LP
55 PROP_HARDWARE_VENDOR,
56 PROP_HARDWARE_MODEL,
d7f4ad20
LP
57
58 /* Read from /etc/os-release (or /usr/lib/os-release) */
44c32988
DH
59 PROP_OS_PRETTY_NAME,
60 PROP_OS_CPE_NAME,
d7f4ad20 61 PROP_OS_HOME_URL,
b563d5ce 62 PROP_OS_SUPPORT_END,
d7f4ad20 63 _PROP_MAX,
2d93c20e 64 _PROP_INVALID = -EINVAL,
4fc7e4f3 65} HostProperty;
7640a5de 66
66a4c743
LP
67typedef struct Context {
68 char *data[_PROP_MAX];
d7f4ad20 69
60e4fb42
ZJS
70 HostnameSource hostname_source;
71
d7f4ad20
LP
72 struct stat etc_hostname_stat;
73 struct stat etc_os_release_stat;
74 struct stat etc_machine_info_stat;
75
66a4c743
LP
76 Hashmap *polkit_registry;
77} Context;
ad740100 78
d7f4ad20 79static void context_reset(Context *c, uint64_t mask) {
66a4c743
LP
80 assert(c);
81
536970d4 82 for (int p = 0; p < _PROP_MAX; p++) {
d7f4ad20
LP
83 if (!FLAGS_SET(mask, UINT64_C(1) << p))
84 continue;
85
a1e58e8e 86 c->data[p] = mfree(c->data[p]);
d7f4ad20 87 }
7640a5de
LP
88}
89
cfb9433d 90static void context_destroy(Context *c) {
66a4c743
LP
91 assert(c);
92
d7f4ad20 93 context_reset(c, UINT64_MAX);
36e34057 94 bus_verify_polkit_async_registry_free(c->polkit_registry);
66a4c743
LP
95}
96
d7f4ad20
LP
97static void context_read_etc_hostname(Context *c) {
98 struct stat current_stat = {};
7640a5de
LP
99 int r;
100
66a4c743
LP
101 assert(c);
102
d7f4ad20
LP
103 if (stat("/etc/hostname", &current_stat) >= 0 &&
104 stat_inode_unmodified(&c->etc_hostname_stat, &current_stat))
105 return;
106
107 context_reset(c, UINT64_C(1) << PROP_STATIC_HOSTNAME);
7640a5de 108
f35cb39e 109 r = read_etc_hostname(NULL, &c->data[PROP_STATIC_HOSTNAME]);
7640a5de 110 if (r < 0 && r != -ENOENT)
d7f4ad20
LP
111 log_warning_errno(r, "Failed to read /etc/hostname, ignoring: %m");
112
113 c->etc_hostname_stat = current_stat;
114}
115
116static void context_read_machine_info(Context *c) {
117 struct stat current_stat = {};
118 int r;
119
120 assert(c);
121
122 if (stat("/etc/machine-info", &current_stat) >= 0 &&
123 stat_inode_unmodified(&c->etc_machine_info_stat, &current_stat))
124 return;
125
126 context_reset(c,
127 (UINT64_C(1) << PROP_PRETTY_HOSTNAME) |
128 (UINT64_C(1) << PROP_ICON_NAME) |
129 (UINT64_C(1) << PROP_CHASSIS) |
130 (UINT64_C(1) << PROP_DEPLOYMENT) |
38639aa2
LP
131 (UINT64_C(1) << PROP_LOCATION) |
132 (UINT64_C(1) << PROP_HARDWARE_VENDOR) |
133 (UINT64_C(1) << PROP_HARDWARE_MODEL));
7640a5de 134
aa8fbc74 135 r = parse_env_file(NULL, "/etc/machine-info",
66a4c743
LP
136 "PRETTY_HOSTNAME", &c->data[PROP_PRETTY_HOSTNAME],
137 "ICON_NAME", &c->data[PROP_ICON_NAME],
138 "CHASSIS", &c->data[PROP_CHASSIS],
799298d6 139 "DEPLOYMENT", &c->data[PROP_DEPLOYMENT],
4fc7e4f3 140 "LOCATION", &c->data[PROP_LOCATION],
0924ea2b
LP
141 "HARDWARE_VENDOR", &c->data[PROP_HARDWARE_VENDOR],
142 "HARDWARE_MODEL", &c->data[PROP_HARDWARE_MODEL]);
7640a5de 143 if (r < 0 && r != -ENOENT)
d7f4ad20
LP
144 log_warning_errno(r, "Failed to read /etc/machine-info, ignoring: %m");
145
146 c->etc_machine_info_stat = current_stat;
147}
148
149static void context_read_os_release(Context *c) {
02b7005e 150 _cleanup_free_ char *os_name = NULL, *os_pretty_name = NULL;
d7f4ad20
LP
151 struct stat current_stat = {};
152 int r;
153
154 assert(c);
155
156 if ((stat("/etc/os-release", &current_stat) >= 0 ||
157 stat("/usr/lib/os-release", &current_stat) >= 0) &&
158 stat_inode_unmodified(&c->etc_os_release_stat, &current_stat))
159 return;
160
161 context_reset(c,
162 (UINT64_C(1) << PROP_OS_PRETTY_NAME) |
163 (UINT64_C(1) << PROP_OS_CPE_NAME) |
b563d5ce
LP
164 (UINT64_C(1) << PROP_OS_HOME_URL) |
165 (UINT64_C(1) << PROP_OS_SUPPORT_END));
7640a5de 166
d58ad743 167 r = parse_os_release(NULL,
02b7005e 168 "PRETTY_NAME", &os_pretty_name,
b563d5ce
LP
169 "NAME", &os_name,
170 "CPE_NAME", &c->data[PROP_OS_CPE_NAME],
171 "HOME_URL", &c->data[PROP_OS_HOME_URL],
172 "SUPPORT_END", &c->data[PROP_OS_SUPPORT_END]);
44c32988 173 if (r < 0 && r != -ENOENT)
d7f4ad20 174 log_warning_errno(r, "Failed to read os-release file, ignoring: %m");
44c32988 175
02b7005e
LP
176 if (free_and_strdup(&c->data[PROP_OS_PRETTY_NAME], os_release_pretty_name(os_pretty_name, os_name)) < 0)
177 log_oom();
178
d7f4ad20 179 c->etc_os_release_stat = current_stat;
7640a5de
LP
180}
181
e7932afe
LP
182static bool use_dmi_data(void) {
183 int r;
184
185 r = getenv_bool("SYSTEMD_HOSTNAME_FORCE_DMI");
186 if (r >= 0) {
187 log_debug("Honouring $SYSTEMD_HOSTNAME_FORCE_DMI override: %s", yes_no(r));
188 return r;
189 }
190 if (r != -ENXIO)
191 log_debug_errno(r, "Failed to parse $SYSTEMD_HOSTNAME_FORCE_DMI, ignoring: %m");
192
193 if (detect_container() > 0) {
194 log_debug("Running in a container, not using DMI hardware data.");
195 return false;
196 }
197
198 return true;
199}
200
8c8b1800
YW
201static int get_dmi_data(const char *database_key, const char *regular_key, char **ret) {
202 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
203 _cleanup_free_ char *b = NULL;
204 const char *s = NULL;
205 int r;
206
e7932afe
LP
207 if (!use_dmi_data())
208 return -ENOENT;
209
8c8b1800
YW
210 r = sd_device_new_from_syspath(&device, "/sys/class/dmi/id");
211 if (r < 0)
212 return log_debug_errno(r, "Failed to open /sys/class/dmi/id device, ignoring: %m");
213
214 if (database_key)
215 (void) sd_device_get_property_value(device, database_key, &s);
216 if (!s && regular_key)
217 (void) sd_device_get_property_value(device, regular_key, &s);
218
e6fccf02
LP
219 if (!ret)
220 return !!s;
221
8c8b1800
YW
222 if (s) {
223 b = strdup(s);
224 if (!b)
225 return -ENOMEM;
226 }
227
e6fccf02 228 *ret = TAKE_PTR(b);
8c8b1800
YW
229 return !!s;
230}
231
232static int get_hardware_vendor(char **ret) {
233 return get_dmi_data("ID_VENDOR_FROM_DATABASE", "ID_VENDOR", ret);
234}
235
236static int get_hardware_model(char **ret) {
237 return get_dmi_data("ID_MODEL_FROM_DATABASE", "ID_MODEL", ret);
238}
239
c52950c2 240static int get_hardware_firmware_data(const char *sysattr, char **ret) {
96976629
YW
241 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
242 _cleanup_free_ char *b = NULL;
243 const char *s = NULL;
244 int r;
245
c52950c2
SS
246 assert(sysattr);
247
e7932afe
LP
248 if (!use_dmi_data())
249 return -ENOENT;
250
96976629
YW
251 r = sd_device_new_from_syspath(&device, "/sys/class/dmi/id");
252 if (r < 0)
253 return log_debug_errno(r, "Failed to open /sys/class/dmi/id device, ignoring: %m");
254
c52950c2 255 (void) sd_device_get_sysattr_value(device, sysattr, &s);
96976629
YW
256 if (!isempty(s)) {
257 b = strdup(s);
258 if (!b)
259 return -ENOMEM;
260 }
261
262 if (ret)
263 *ret = TAKE_PTR(b);
264
265 return !isempty(s);
266}
267
c52950c2
SS
268static int get_hardware_serial(char **ret) {
269 int r;
270
271 r = get_hardware_firmware_data("product_serial", ret);
272 if (r <= 0)
273 return get_hardware_firmware_data("board_serial", ret);
274
275 return r;
276}
277
278static int get_firmware_version(char **ret) {
279 return get_hardware_firmware_data("bios_version", ret);
280}
281
f233bbd6
JW
282static int get_firmware_vendor(char **ret) {
283 return get_hardware_firmware_data("bios_vendor", ret);
284}
285
ad8858c1
JW
286static int get_firmware_date(usec_t *ret) {
287 _cleanup_free_ char *bios_date = NULL, *month = NULL, *day = NULL, *year = NULL;
288 int r;
289
290 assert(ret);
291
292 r = get_hardware_firmware_data("bios_date", &bios_date);
293 if (r < 0)
294 return r;
295 if (r == 0) {
296 *ret = USEC_INFINITY;
297 return 0;
298 }
299
300 const char *p = bios_date;
301 r = extract_many_words(&p, "/", EXTRACT_DONT_COALESCE_SEPARATORS, &month, &day, &year, NULL);
302 if (r < 0)
303 return r;
304 if (r != 3) /* less than three args read? */
305 return -EINVAL;
306 if (!isempty(p)) /* more left in the string? */
307 return -EINVAL;
308
309 unsigned m, d, y;
7dad6de1 310 r = safe_atou_full(month, 10 | SAFE_ATO_REFUSE_PLUS_MINUS | SAFE_ATO_REFUSE_LEADING_WHITESPACE, &m);
ad8858c1
JW
311 if (r < 0)
312 return r;
313 if (m < 1 || m > 12)
314 return -EINVAL;
315 m -= 1;
316
7dad6de1 317 r = safe_atou_full(day, 10 | SAFE_ATO_REFUSE_PLUS_MINUS | SAFE_ATO_REFUSE_LEADING_WHITESPACE, &d);
ad8858c1
JW
318 if (r < 0)
319 return r;
320 if (d < 1 || d > 31)
321 return -EINVAL;
322
7dad6de1 323 r = safe_atou_full(year, 10 | SAFE_ATO_REFUSE_PLUS_MINUS | SAFE_ATO_REFUSE_LEADING_WHITESPACE, &y);
ad8858c1
JW
324 if (r < 0)
325 return r;
326 if (y < 1970 || y > (unsigned) INT_MAX)
327 return -EINVAL;
328 y -= 1900;
329
330 struct tm tm = {
331 .tm_mday = d,
332 .tm_mon = m,
333 .tm_year = y,
334 };
335 time_t v = timegm(&tm);
336 if (v == (time_t) -1)
337 return -errno;
338 if (tm.tm_mday != (int) d || tm.tm_mon != (int) m || tm.tm_year != (int) y)
339 return -EINVAL; /* date was not normalized? (e.g. "30th of feb") */
340
341 *ret = (usec_t) v * USEC_PER_SEC;
342
343 return 0;
ff4d26df
JW
344}
345
e6e6ca82 346static const char* valid_chassis(const char *chassis) {
7871c8e9
LP
347 assert(chassis);
348
e6e6ca82 349 return nulstr_get(
7871c8e9
LP
350 "vm\0"
351 "container\0"
352 "desktop\0"
353 "laptop\0"
34b52450 354 "convertible\0"
7871c8e9
LP
355 "server\0"
356 "tablet\0"
c49e59c1 357 "handset\0"
25fa306e
LP
358 "watch\0"
359 "embedded\0",
7871c8e9
LP
360 chassis);
361}
362
799298d6
JG
363static bool valid_deployment(const char *deployment) {
364 assert(deployment);
365
c2142cf1 366 return in_charset(deployment, VALID_DEPLOYMENT_CHARS);
799298d6
JG
367}
368
7871c8e9 369static const char* fallback_chassis(void) {
e6e6ca82 370 const char *chassis;
68cdeab3 371 _cleanup_free_ char *type = NULL;
1b86c7c5 372 Virtualization v;
7640a5de 373 unsigned t;
1b86c7c5 374 int r;
7871c8e9 375
75f86906 376 v = detect_virtualization();
2ac4d1d4
LP
377 if (v < 0)
378 log_debug_errno(v, "Failed to detect virtualization, ignoring: %m");
379 else if (VIRTUALIZATION_IS_VM(v))
7871c8e9 380 return "vm";
2ac4d1d4 381 else if (VIRTUALIZATION_IS_CONTAINER(v))
7871c8e9
LP
382 return "container";
383
219bfe38 384 r = read_one_line_file("/sys/class/dmi/id/chassis_type", &type);
2ac4d1d4 385 if (r < 0) {
105a4245 386 log_debug_errno(r, "Failed to read DMI chassis type, ignoring: %m");
219bfe38 387 goto try_acpi;
2ac4d1d4 388 }
7871c8e9
LP
389
390 r = safe_atou(type, &t);
2ac4d1d4 391 if (r < 0) {
68cdeab3 392 log_debug_errno(r, "Failed to parse DMI chassis type \"%s\", ignoring: %m", type);
219bfe38 393 goto try_acpi;
2ac4d1d4 394 }
7871c8e9 395
219bfe38 396 /* We only list the really obvious cases here. The DMI data is unreliable enough, so let's not do any
68cdeab3
ZJS
397 * additional guesswork on top of that.
398 *
67840dbf 399 * See the SMBIOS Specification 3.5.0 section 7.4.1 for details about the values listed here:
68cdeab3 400 *
67840dbf 401 * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.5.0.pdf
7871c8e9
LP
402 */
403
219bfe38 404 switch (t) {
7871c8e9 405
67840dbf
LP
406 case 0x03: /* Desktop */
407 case 0x04: /* Low Profile Desktop */
408 case 0x06: /* Mini Tower */
409 case 0x07: /* Tower */
410 case 0x0D: /* All in one (i.e. PC built into monitor) */
411 case 0x23: /* Mini PC */
412 case 0x24: /* Stick PC */
7871c8e9
LP
413 return "desktop";
414
219bfe38
LP
415 case 0x8: /* Portable */
416 case 0x9: /* Laptop */
417 case 0xA: /* Notebook */
418 case 0xE: /* Sub Notebook */
7871c8e9 419 return "laptop";
7640a5de 420
219bfe38
LP
421 case 0xB: /* Hand Held */
422 return "handset";
423
424 case 0x11: /* Main Server Chassis */
425 case 0x1C: /* Blade */
426 case 0x1D: /* Blade Enclosure */
7871c8e9 427 return "server";
7640a5de 428
219bfe38 429 case 0x1E: /* Tablet */
7871c8e9 430 return "tablet";
b70af833
DH
431
432 case 0x1F: /* Convertible */
b4227dbb 433 case 0x20: /* Detachable */
b70af833 434 return "convertible";
2ac4d1d4 435
67840dbf
LP
436 case 0x21: /* IoT Gateway */
437 case 0x22: /* Embedded PC */
438 return "embedded";
439
2ac4d1d4
LP
440 default:
441 log_debug("Unhandled DMI chassis type 0x%02x, ignoring.", t);
7871c8e9
LP
442 }
443
219bfe38 444try_acpi:
68cdeab3 445 type = mfree(type);
219bfe38 446 r = read_one_line_file("/sys/firmware/acpi/pm_profile", &type);
2ac4d1d4 447 if (r < 0) {
105a4245 448 log_debug_errno(r, "Failed read ACPI PM profile, ignoring: %m");
e6e6ca82 449 goto try_devicetree;
2ac4d1d4 450 }
7640a5de
LP
451
452 r = safe_atou(type, &t);
2ac4d1d4 453 if (r < 0) {
68cdeab3 454 log_debug_errno(r, "Failed parse ACPI PM profile \"%s\", ignoring: %m", type);
e6e6ca82 455 goto try_devicetree;
2ac4d1d4 456 }
7640a5de 457
219bfe38
LP
458 /* We only list the really obvious cases here as the ACPI data is not really super reliable.
459 *
460 * See the ACPI 5.0 Spec Section 5.2.9.1 for details:
461 *
462 * http://www.acpi.info/DOWNLOADS/ACPIspec50.pdf
41550d40 463 */
7640a5de 464
79893116 465 switch (t) {
7640a5de 466
219bfe38
LP
467 case 1: /* Desktop */
468 case 3: /* Workstation */
469 case 6: /* Appliance PC */
7871c8e9 470 return "desktop";
7640a5de 471
219bfe38 472 case 2: /* Mobile */
7871c8e9
LP
473 return "laptop";
474
219bfe38
LP
475 case 4: /* Enterprise Server */
476 case 5: /* SOHO Server */
477 case 7: /* Performance Server */
7871c8e9 478 return "server";
f3f4f008 479
219bfe38 480 case 8: /* Tablet */
f3f4f008 481 return "tablet";
2ac4d1d4
LP
482
483 default:
484 log_debug("Unhandled ACPI PM profile 0x%02x, ignoring.", t);
7640a5de
LP
485 }
486
e6e6ca82 487try_devicetree:
68cdeab3 488 type = mfree(type);
e6cbe697 489 r = read_one_line_file("/proc/device-tree/chassis-type", &type);
e6e6ca82
AF
490 if (r < 0) {
491 log_debug_errno(r, "Failed to read device-tree chassis type, ignoring: %m");
492 return NULL;
493 }
494
495 /* Note that the Devicetree specification uses the very same vocabulary
496 * of chassis types as we do, hence we do not need to translate these types:
497 *
498 * https://github.com/devicetree-org/devicetree-specification/blob/master/source/chapter3-devicenodes.rst */
499 chassis = valid_chassis(type);
500 if (!chassis)
68cdeab3 501 log_debug("Invalid device-tree chassis type \"%s\", ignoring.", type);
e6e6ca82 502 return chassis;
7640a5de
LP
503}
504
8c8b1800
YW
505static char* context_get_chassis(Context *c) {
506 const char *fallback;
507 char *dmi;
7871c8e9 508
66a4c743
LP
509 assert(c);
510
511 if (!isempty(c->data[PROP_CHASSIS]))
8c8b1800
YW
512 return strdup(c->data[PROP_CHASSIS]);
513
471fdebf 514 if (get_dmi_data("ID_CHASSIS", NULL, &dmi) > 0)
8c8b1800
YW
515 return dmi;
516
517 fallback = fallback_chassis();
518 if (fallback)
519 return strdup(fallback);
520
521 return NULL;
522}
523
524static char* context_fallback_icon_name(Context *c) {
525 _cleanup_free_ char *chassis = NULL;
526
527 assert(c);
7871c8e9 528
8c8b1800 529 chassis = context_get_chassis(c);
7871c8e9 530 if (chassis)
b910cc72 531 return strjoin("computer-", chassis);
7871c8e9
LP
532
533 return strdup("computer");
534}
535
aa994368
LP
536static int context_update_kernel_hostname(
537 Context *c,
538 const char *transient_hn) {
539
05c6f341 540 _cleanup_free_ char *_hn_free = NULL;
d39079fc 541 const char *hn;
60e4fb42 542 HostnameSource hns;
7d9ec609 543 int r;
7640a5de 544
66a4c743
LP
545 assert(c);
546
d39079fc 547 /* /etc/hostname has the highest preference ... */
60e4fb42 548 if (c->data[PROP_STATIC_HOSTNAME]) {
d39079fc 549 hn = c->data[PROP_STATIC_HOSTNAME];
60e4fb42 550 hns = HOSTNAME_STATIC;
c779a442 551
38b38500 552 /* ... the transient hostname, (ie: DHCP) comes next ... */
60e4fb42 553 } else if (transient_hn) {
aa994368 554 hn = transient_hn;
60e4fb42 555 hns = HOSTNAME_TRANSIENT;
7640a5de 556
c779a442 557 /* ... and the ultimate fallback */
60e4fb42 558 } else {
05c6f341
ZJS
559 hn = _hn_free = get_default_hostname();
560 if (!hn)
561 return log_oom();
562
8770c813 563 hns = HOSTNAME_DEFAULT;
60e4fb42 564 }
c779a442 565
7d9ec609
ZJS
566 r = sethostname_idempotent(hn);
567 if (r < 0)
60e4fb42
ZJS
568 return log_error_errno(r, "Failed to set hostname: %m");
569
570 if (c->hostname_source != hns) {
571 c->hostname_source = hns;
572 r = 1;
573 }
7640a5de 574
7782e0a0 575 (void) nscd_flush_cache(STRV_MAKE("hosts"));
60e4fb42
ZJS
576
577 if (r == 0)
578 log_debug("Hostname was already set to <%s>.", hn);
579 else {
580 log_info("Hostname set to <%s> (%s)", hn, hostname_source_to_string(hns));
581
582 hostname_update_source_hint(hn, hns);
583 }
584
efda832d 585 return r; /* 0 if no change, 1 if something was done */
7640a5de
LP
586}
587
ba12e41d
YW
588static void unset_statp(struct stat **p) {
589 if (!*p)
590 return;
591
592 **p = (struct stat) {};
593}
594
66a4c743 595static int context_write_data_static_hostname(Context *c) {
ba12e41d
YW
596 _cleanup_(unset_statp) struct stat *s = NULL;
597 int r;
598
66a4c743
LP
599 assert(c);
600
ba12e41d
YW
601 /* Make sure that if we fail here, we invalidate the cached information, since it was updated
602 * already, even if we can't make it hit the disk. */
603 s = &c->etc_hostname_stat;
604
66a4c743 605 if (isempty(c->data[PROP_STATIC_HOSTNAME])) {
ba12e41d
YW
606 if (unlink("/etc/hostname") < 0 && errno != ENOENT)
607 return -errno;
608
609 TAKE_PTR(s);
7640a5de
LP
610 return 0;
611 }
536970d4 612
ba12e41d
YW
613 r = write_string_file_atomic_label("/etc/hostname", c->data[PROP_STATIC_HOSTNAME]);
614 if (r < 0)
615 return r;
616
617 TAKE_PTR(s);
618 return 0;
7640a5de
LP
619}
620
f200e8bb 621static int context_write_data_machine_info(Context *c) {
ba12e41d 622 _cleanup_(unset_statp) struct stat *s = NULL;
7640a5de
LP
623 static const char * const name[_PROP_MAX] = {
624 [PROP_PRETTY_HOSTNAME] = "PRETTY_HOSTNAME",
7871c8e9 625 [PROP_ICON_NAME] = "ICON_NAME",
799298d6
JG
626 [PROP_CHASSIS] = "CHASSIS",
627 [PROP_DEPLOYMENT] = "DEPLOYMENT",
ce0f1493 628 [PROP_LOCATION] = "LOCATION",
7640a5de 629 };
0ccad099 630 _cleanup_strv_free_ char **l = NULL;
536970d4 631 int r;
7640a5de 632
66a4c743
LP
633 assert(c);
634
ba12e41d
YW
635 /* Make sure that if we fail here, we invalidate the cached information, since it was updated
636 * already, even if we can't make it hit the disk. */
637 s = &c->etc_machine_info_stat;
638
aa8fbc74 639 r = load_env_file(NULL, "/etc/machine-info", &l);
7640a5de
LP
640 if (r < 0 && r != -ENOENT)
641 return r;
642
536970d4 643 for (int p = PROP_PRETTY_HOSTNAME; p <= PROP_LOCATION; p++) {
7640a5de
LP
644 assert(name[p]);
645
f08231fe
ZJS
646 r = strv_env_assign(&l, name[p], empty_to_null(c->data[p]));
647 if (r < 0)
648 return r;
7640a5de
LP
649 }
650
651 if (strv_isempty(l)) {
ba12e41d
YW
652 if (unlink("/etc/machine-info") < 0 && errno != ENOENT)
653 return -errno;
7640a5de 654
ba12e41d 655 TAKE_PTR(s);
7640a5de
LP
656 return 0;
657 }
658
f155cb6d 659 r = write_env_file_label(AT_FDCWD, "/etc/machine-info", NULL, l);
ba12e41d
YW
660 if (r < 0)
661 return r;
662
663 TAKE_PTR(s);
664 return 0;
7640a5de
LP
665}
666
4fc7e4f3
YW
667static int property_get_hardware_property(
668 sd_bus_message *reply,
669 Context *c,
670 HostProperty prop,
671 int (*getter)(char **)) {
672
673 _cleanup_free_ char *from_dmi = NULL;
674
675 assert(reply);
676 assert(c);
0924ea2b 677 assert(IN_SET(prop, PROP_HARDWARE_VENDOR, PROP_HARDWARE_MODEL));
4fc7e4f3
YW
678 assert(getter);
679
680 context_read_machine_info(c);
681
682 if (isempty(c->data[prop]))
683 (void) getter(&from_dmi);
684
685 return sd_bus_message_append(reply, "s", from_dmi ?: c->data[prop]);
686}
687
b9d80698
FB
688static int property_get_hardware_vendor(
689 sd_bus *bus,
690 const char *path,
691 const char *interface,
692 const char *property,
693 sd_bus_message *reply,
694 void *userdata,
695 sd_bus_error *error) {
b9d80698 696
0924ea2b 697 return property_get_hardware_property(reply, userdata, PROP_HARDWARE_VENDOR, get_hardware_vendor);
b9d80698
FB
698}
699
700static int property_get_hardware_model(
701 sd_bus *bus,
702 const char *path,
703 const char *interface,
704 const char *property,
705 sd_bus_message *reply,
706 void *userdata,
707 sd_bus_error *error) {
b9d80698 708
0924ea2b 709 return property_get_hardware_property(reply, userdata, PROP_HARDWARE_MODEL, get_hardware_model);
b9d80698
FB
710}
711
c52950c2
SS
712static int property_get_firmware_version(
713 sd_bus *bus,
714 const char *path,
715 const char *interface,
716 const char *property,
717 sd_bus_message *reply,
718 void *userdata,
719 sd_bus_error *error) {
720
721 _cleanup_free_ char *firmware_version = NULL;
722
723 (void) get_firmware_version(&firmware_version);
724
725 return sd_bus_message_append(reply, "s", firmware_version);
726}
727
f233bbd6
JW
728static int property_get_firmware_vendor(
729 sd_bus *bus,
730 const char *path,
731 const char *interface,
732 const char *property,
733 sd_bus_message *reply,
734 void *userdata,
735 sd_bus_error *error) {
736
737 _cleanup_free_ char *firmware_vendor = NULL;
738
739 (void) get_firmware_vendor(&firmware_vendor);
740
741 return sd_bus_message_append(reply, "s", firmware_vendor);
742}
743
ff4d26df
JW
744static int property_get_firmware_date(
745 sd_bus *bus,
746 const char *path,
747 const char *interface,
748 const char *property,
749 sd_bus_message *reply,
750 void *userdata,
751 sd_bus_error *error) {
752
ad8858c1 753 usec_t firmware_date = USEC_INFINITY;
ff4d26df
JW
754
755 (void) get_firmware_date(&firmware_date);
756
ad8858c1 757 return sd_bus_message_append(reply, "t", firmware_date);
ff4d26df 758}
aa994368
LP
759static int property_get_hostname(
760 sd_bus *bus,
761 const char *path,
762 const char *interface,
763 const char *property,
764 sd_bus_message *reply,
765 void *userdata,
766 sd_bus_error *error) {
767
05c6f341 768 _cleanup_free_ char *hn = NULL;
aa994368
LP
769 int r;
770
05c6f341
ZJS
771 r = gethostname_strict(&hn);
772 if (r < 0) {
773 if (r != -ENXIO)
774 return r;
aa994368 775
05c6f341
ZJS
776 hn = get_default_hostname();
777 if (!hn)
778 return -ENOMEM;
779 }
780
781 return sd_bus_message_append(reply, "s", hn);
aa994368
LP
782}
783
d7f4ad20
LP
784static int property_get_static_hostname(
785 sd_bus *bus,
786 const char *path,
787 const char *interface,
788 const char *property,
789 sd_bus_message *reply,
790 void *userdata,
791 sd_bus_error *error) {
792
99534007 793 Context *c = ASSERT_PTR(userdata);
d7f4ad20
LP
794
795 context_read_etc_hostname(c);
796
797 return sd_bus_message_append(reply, "s", c->data[PROP_STATIC_HOSTNAME]);
798}
799
8770c813 800static int property_get_default_hostname(
05c6f341
ZJS
801 sd_bus *bus,
802 const char *path,
803 const char *interface,
804 const char *property,
805 sd_bus_message *reply,
806 void *userdata,
807 sd_bus_error *error) {
808
61d44b6b
LP
809 _cleanup_free_ char *hn = NULL;
810
811 hn = get_default_hostname();
05c6f341
ZJS
812 if (!hn)
813 return log_oom();
814
815 return sd_bus_message_append(reply, "s", hn);
816}
ce6b138c 817
f2a434a5 818static void context_determine_hostname_source(Context *c) {
0995accd 819 _cleanup_free_ char *hostname = NULL;
f2a434a5
LP
820 int r;
821
822 assert(c);
823
824 if (c->hostname_source >= 0)
825 return;
826
0995accd 827 (void) gethostname_full(GET_HOSTNAME_ALLOW_LOCALHOST, &hostname);
f2a434a5
LP
828
829 if (streq_ptr(hostname, c->data[PROP_STATIC_HOSTNAME]))
830 c->hostname_source = HOSTNAME_STATIC;
831 else {
0995accd
YW
832 _cleanup_free_ char *fallback = NULL;
833
f2a434a5
LP
834 /* If the hostname was not set by us, try to figure out where it came from. If we set it to
835 * the default hostname, the file will tell us. We compare the string because it is possible
32e27670
LP
836 * that the hostname was set by an older version that had a different fallback, in the initrd
837 * or before we reexecuted. */
f2a434a5
LP
838
839 r = read_one_line_file("/run/systemd/default-hostname", &fallback);
840 if (r < 0 && r != -ENOENT)
841 log_warning_errno(r, "Failed to read /run/systemd/default-hostname, ignoring: %m");
842
843 if (streq_ptr(fallback, hostname))
844 c->hostname_source = HOSTNAME_DEFAULT;
845 else
846 c->hostname_source = HOSTNAME_TRANSIENT;
847 }
848}
849
60e4fb42
ZJS
850static int property_get_hostname_source(
851 sd_bus *bus,
852 const char *path,
853 const char *interface,
854 const char *property,
855 sd_bus_message *reply,
856 void *userdata,
857 sd_bus_error *error) {
858
99534007 859 Context *c = ASSERT_PTR(userdata);
60e4fb42
ZJS
860
861 context_read_etc_hostname(c);
f2a434a5 862 context_determine_hostname_source(c);
60e4fb42
ZJS
863
864 return sd_bus_message_append(reply, "s", hostname_source_to_string(c->hostname_source));
865}
866
d7f4ad20
LP
867static int property_get_machine_info_field(
868 sd_bus *bus,
869 const char *path,
870 const char *interface,
871 const char *property,
872 sd_bus_message *reply,
873 void *userdata,
874 sd_bus_error *error) {
875
876 sd_bus_slot *slot;
877 Context *c;
878
879 /* Acquire the context object without this property's userdata offset added. Explanation: we want
880 * access to two pointers here: a) the main context object we cache all properties in, and b) the
881 * pointer to the property field inside the context object that we are supposed to update and
882 * use. The latter (b) we get in the 'userdata' function parameter, and sd-bus calculates that for us
883 * from the 'userdata' pointer we supplied when the vtable was registered, with the offset we
884 * specified in the vtable added on top. To get the former (a) we need the 'userdata' pointer from
885 * the vtable registration directly, without the offset added. Hence we ask sd-bus what the slot
886 * object is (which encapsulates the vtable registration), and then query the 'userdata' field
887 * directly off it. */
888 assert_se(slot = sd_bus_get_current_slot(bus));
889 assert_se(c = sd_bus_slot_get_userdata(slot));
890
891 context_read_machine_info(c);
892
893 return sd_bus_message_append(reply, "s", *(char**) userdata);
894}
895
896static int property_get_os_release_field(
897 sd_bus *bus,
898 const char *path,
899 const char *interface,
900 const char *property,
901 sd_bus_message *reply,
902 void *userdata,
903 sd_bus_error *error) {
904
905 sd_bus_slot *slot;
906 Context *c;
907
908 /* As above, acquire the current context without this property's userdata offset added. */
909 assert_se(slot = sd_bus_get_current_slot(bus));
910 assert_se(c = sd_bus_slot_get_userdata(slot));
911
912 context_read_os_release(c);
913
914 return sd_bus_message_append(reply, "s", *(char**) userdata);
915}
916
b563d5ce
LP
917static int property_get_os_support_end(
918 sd_bus *bus,
919 const char *path,
920 const char *interface,
921 const char *property,
922 sd_bus_message *reply,
923 void *userdata,
924 sd_bus_error *error) {
925
926 Context *c = userdata;
927 usec_t eol = USEC_INFINITY;
928
929 context_read_os_release(c);
930
931 if (c->data[PROP_OS_SUPPORT_END])
932 (void) os_release_support_ended(c->data[PROP_OS_SUPPORT_END], /* quiet= */ false, &eol);
933
934 return sd_bus_message_append(reply, "t", eol);
935}
936
66a4c743
LP
937static int property_get_icon_name(
938 sd_bus *bus,
939 const char *path,
940 const char *interface,
941 const char *property,
942 sd_bus_message *reply,
ebcf1f97
LP
943 void *userdata,
944 sd_bus_error *error) {
7640a5de 945
66a4c743
LP
946 _cleanup_free_ char *n = NULL;
947 Context *c = userdata;
948 const char *name;
7640a5de 949
d7f4ad20
LP
950 context_read_machine_info(c);
951
66a4c743
LP
952 if (isempty(c->data[PROP_ICON_NAME]))
953 name = n = context_fallback_icon_name(c);
7640a5de 954 else
66a4c743
LP
955 name = c->data[PROP_ICON_NAME];
956
957 if (!name)
958 return -ENOMEM;
7640a5de 959
ebcf1f97 960 return sd_bus_message_append(reply, "s", name);
7640a5de
LP
961}
962
66a4c743
LP
963static int property_get_chassis(
964 sd_bus *bus,
965 const char *path,
966 const char *interface,
967 const char *property,
968 sd_bus_message *reply,
ebcf1f97
LP
969 void *userdata,
970 sd_bus_error *error) {
7871c8e9 971
8c8b1800 972 _cleanup_free_ char *chassis = NULL;
66a4c743 973 Context *c = userdata;
7871c8e9 974
d7f4ad20
LP
975 context_read_machine_info(c);
976
8c8b1800 977 chassis = context_get_chassis(c);
7871c8e9 978
8c8b1800 979 return sd_bus_message_append(reply, "s", chassis);
7871c8e9
LP
980}
981
72f48cd3
LP
982static int property_get_uname_field(
983 sd_bus *bus,
984 const char *path,
985 const char *interface,
986 const char *property,
987 sd_bus_message *reply,
988 void *userdata,
989 sd_bus_error *error) {
990
991 struct utsname u;
992
993 assert_se(uname(&u) >= 0);
994
995 return sd_bus_message_append(reply, "s", (char*) &u + PTR_TO_SIZE(userdata));
996}
997
5db7eb21
YW
998static int property_get_machine_id(
999 sd_bus *bus,
1000 const char *path,
1001 const char *interface,
1002 const char *property,
1003 sd_bus_message *reply,
1004 void *userdata,
1005 sd_bus_error *error) {
1006
1007 sd_id128_t id;
1008 int r;
1009
1010 r = sd_id128_get_machine(&id);
1011 if (r < 0)
1012 return r;
1013
1014 return bus_property_get_id128(bus, path, interface, property, reply, &id, error);
1015}
1016
1017static int property_get_boot_id(
1018 sd_bus *bus,
1019 const char *path,
1020 const char *interface,
1021 const char *property,
1022 sd_bus_message *reply,
1023 void *userdata,
1024 sd_bus_error *error) {
1025
1026 sd_id128_t id;
1027 int r;
1028
1029 r = sd_id128_get_boot(&id);
1030 if (r < 0)
1031 return r;
1032
1033 return bus_property_get_id128(bus, path, interface, property, reply, &id, error);
1034}
1035
19070062 1036static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
99534007 1037 Context *c = ASSERT_PTR(userdata);
66a4c743 1038 const char *name;
aa994368 1039 int interactive, r;
d200735e 1040
19070062 1041 assert(m);
19070062 1042
66a4c743
LP
1043 r = sd_bus_message_read(m, "sb", &name, &interactive);
1044 if (r < 0)
ebcf1f97 1045 return r;
d200735e 1046
60e4fb42 1047 name = empty_to_null(name);
7640a5de 1048
60e4fb42
ZJS
1049 /* We always go through with the procedure below without comparing to the current hostname, because
1050 * we might want to adjust hostname source information even if the actual hostname is unchanged. */
7640a5de 1051
f190ac48 1052 if (name && !hostname_is_valid(name, 0))
ebcf1f97 1053 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", name);
7640a5de 1054
60e4fb42 1055 context_read_etc_hostname(c);
7640a5de 1056
7b36fb9f 1057 r = bus_verify_polkit_async_full(
c529695e 1058 m,
c529695e 1059 "org.freedesktop.hostname1.set-hostname",
7b36fb9f 1060 /* details= */ NULL,
c529695e 1061 interactive,
7b36fb9f 1062 /* good_user= */ UID_INVALID,
c529695e
LP
1063 &c->polkit_registry,
1064 error);
66a4c743 1065 if (r < 0)
ebcf1f97 1066 return r;
66a4c743
LP
1067 if (r == 0)
1068 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7640a5de 1069
aa994368 1070 r = context_update_kernel_hostname(c, name);
60e4fb42 1071 if (r < 0)
1b4cd646 1072 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
60e4fb42 1073 else if (r > 0)
efda832d
ZJS
1074 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m),
1075 "/org/freedesktop/hostname1", "org.freedesktop.hostname1",
1076 "Hostname", "HostnameSource", NULL);
7640a5de 1077
df2d202e 1078 return sd_bus_reply_method_return(m, NULL);
66a4c743 1079}
7640a5de 1080
19070062 1081static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
99534007 1082 Context *c = ASSERT_PTR(userdata);
66a4c743 1083 const char *name;
102d8f81 1084 int interactive;
66a4c743 1085 int r;
7640a5de 1086
19070062 1087 assert(m);
19070062 1088
66a4c743
LP
1089 r = sd_bus_message_read(m, "sb", &name, &interactive);
1090 if (r < 0)
ebcf1f97 1091 return r;
7640a5de 1092
3c6f7c34 1093 name = empty_to_null(name);
7640a5de 1094
d7f4ad20
LP
1095 context_read_etc_hostname(c);
1096
66a4c743 1097 if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME]))
df2d202e 1098 return sd_bus_reply_method_return(m, NULL);
7640a5de 1099
60e4fb42 1100 if (name && !hostname_is_valid(name, 0))
c650f207
YW
1101 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name);
1102
7b36fb9f 1103 r = bus_verify_polkit_async_full(
c529695e 1104 m,
c529695e 1105 "org.freedesktop.hostname1.set-static-hostname",
7b36fb9f 1106 /* details= */ NULL,
c529695e 1107 interactive,
7b36fb9f 1108 /* good_user= */ UID_INVALID,
c529695e
LP
1109 &c->polkit_registry,
1110 error);
66a4c743 1111 if (r < 0)
ebcf1f97 1112 return r;
66a4c743
LP
1113 if (r == 0)
1114 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7640a5de 1115
e8acf091 1116 r = free_and_strdup_warn(&c->data[PROP_STATIC_HOSTNAME], name);
c650f207
YW
1117 if (r < 0)
1118 return r;
7640a5de 1119
66a4c743
LP
1120 r = context_write_data_static_hostname(c);
1121 if (r < 0) {
38b38500 1122 log_error_errno(r, "Failed to write static hostname: %m");
957991b7
YW
1123 if (ERRNO_IS_PRIVILEGE(r))
1124 return sd_bus_error_set(error, BUS_ERROR_FILE_IS_PROTECTED, "Not allowed to update /etc/hostname.");
1125 if (r == -EROFS)
1126 return sd_bus_error_set(error, BUS_ERROR_READ_ONLY_FILESYSTEM, "/etc/hostname is in a read-only filesystem.");
1b4cd646 1127 return sd_bus_error_set_errnof(error, r, "Failed to set static hostname: %m");
66a4c743 1128 }
7640a5de 1129
60e4fb42
ZJS
1130 r = context_update_kernel_hostname(c, NULL);
1131 if (r < 0) {
1132 log_error_errno(r, "Failed to set hostname: %m");
1133 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
1134 }
7640a5de 1135
efda832d 1136 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m),
60e4fb42
ZJS
1137 "/org/freedesktop/hostname1", "org.freedesktop.hostname1",
1138 "StaticHostname", "Hostname", "HostnameSource", NULL);
7640a5de 1139
df2d202e 1140 return sd_bus_reply_method_return(m, NULL);
66a4c743 1141}
7640a5de 1142
19070062 1143static int set_machine_info(Context *c, sd_bus_message *m, int prop, sd_bus_message_handler_t cb, sd_bus_error *error) {
102d8f81 1144 int interactive;
66a4c743
LP
1145 const char *name;
1146 int r;
1147
1148 assert(c);
66a4c743
LP
1149 assert(m);
1150
1151 r = sd_bus_message_read(m, "sb", &name, &interactive);
1152 if (r < 0)
ebcf1f97 1153 return r;
66a4c743 1154
3c6f7c34 1155 name = empty_to_null(name);
66a4c743 1156
d7f4ad20
LP
1157 context_read_machine_info(c);
1158
66a4c743 1159 if (streq_ptr(name, c->data[prop]))
df2d202e 1160 return sd_bus_reply_method_return(m, NULL);
7640a5de 1161
c650f207
YW
1162 if (!isempty(name)) {
1163 /* The icon name might ultimately be used as file
1164 * name, so better be safe than sorry */
1165
1166 if (prop == PROP_ICON_NAME && !filename_is_valid(name))
1167 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid icon name '%s'", name);
1168 if (prop == PROP_PRETTY_HOSTNAME && string_has_cc(name, NULL))
38b38500 1169 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty hostname '%s'", name);
c650f207
YW
1170 if (prop == PROP_CHASSIS && !valid_chassis(name))
1171 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid chassis '%s'", name);
1172 if (prop == PROP_DEPLOYMENT && !valid_deployment(name))
1173 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid deployment '%s'", name);
1174 if (prop == PROP_LOCATION && string_has_cc(name, NULL))
1175 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid location '%s'", name);
1176 }
1177
7b36fb9f
LP
1178 /* Since the pretty hostname should always be changed at the same time as the static one, use the
1179 * same policy action for both... */
66a4c743 1180
7b36fb9f 1181 r = bus_verify_polkit_async_full(
c529695e 1182 m,
c529695e 1183 prop == PROP_PRETTY_HOSTNAME ? "org.freedesktop.hostname1.set-static-hostname" : "org.freedesktop.hostname1.set-machine-info",
7b36fb9f 1184 /* details= */ NULL,
c529695e 1185 interactive,
7b36fb9f 1186 /* good_user= */ UID_INVALID,
c529695e
LP
1187 &c->polkit_registry,
1188 error);
66a4c743 1189 if (r < 0)
ebcf1f97 1190 return r;
66a4c743
LP
1191 if (r == 0)
1192 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1193
e8acf091 1194 r = free_and_strdup_warn(&c->data[prop], name);
c650f207
YW
1195 if (r < 0)
1196 return r;
7640a5de 1197
f200e8bb 1198 r = context_write_data_machine_info(c);
66a4c743 1199 if (r < 0) {
da927ba9 1200 log_error_errno(r, "Failed to write machine info: %m");
957991b7
YW
1201 if (ERRNO_IS_PRIVILEGE(r))
1202 return sd_bus_error_set(error, BUS_ERROR_FILE_IS_PROTECTED, "Not allowed to update /etc/machine-info.");
1203 if (r == -EROFS)
1204 return sd_bus_error_set(error, BUS_ERROR_READ_ONLY_FILESYSTEM, "/etc/machine-info is in a read-only filesystem.");
1b4cd646 1205 return sd_bus_error_set_errnof(error, r, "Failed to write machine info: %m");
66a4c743 1206 }
7640a5de 1207
66a4c743 1208 log_info("Changed %s to '%s'",
38b38500 1209 prop == PROP_PRETTY_HOSTNAME ? "pretty hostname" :
799298d6 1210 prop == PROP_DEPLOYMENT ? "deployment" :
ce0f1493 1211 prop == PROP_LOCATION ? "location" :
66a4c743 1212 prop == PROP_CHASSIS ? "chassis" : "icon name", strna(c->data[prop]));
7640a5de 1213
19070062
LP
1214 (void) sd_bus_emit_properties_changed(
1215 sd_bus_message_get_bus(m),
1216 "/org/freedesktop/hostname1",
1217 "org.freedesktop.hostname1",
1218 prop == PROP_PRETTY_HOSTNAME ? "PrettyHostname" :
1219 prop == PROP_DEPLOYMENT ? "Deployment" :
1220 prop == PROP_LOCATION ? "Location" :
1221 prop == PROP_CHASSIS ? "Chassis" : "IconName" , NULL);
7640a5de 1222
df2d202e 1223 return sd_bus_reply_method_return(m, NULL);
66a4c743 1224}
7640a5de 1225
19070062
LP
1226static int method_set_pretty_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1227 return set_machine_info(userdata, m, PROP_PRETTY_HOSTNAME, method_set_pretty_hostname, error);
7640a5de
LP
1228}
1229
19070062
LP
1230static int method_set_icon_name(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1231 return set_machine_info(userdata, m, PROP_ICON_NAME, method_set_icon_name, error);
66a4c743
LP
1232}
1233
19070062
LP
1234static int method_set_chassis(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1235 return set_machine_info(userdata, m, PROP_CHASSIS, method_set_chassis, error);
66a4c743
LP
1236}
1237
19070062
LP
1238static int method_set_deployment(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1239 return set_machine_info(userdata, m, PROP_DEPLOYMENT, method_set_deployment, error);
799298d6
JG
1240}
1241
19070062
LP
1242static int method_set_location(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1243 return set_machine_info(userdata, m, PROP_LOCATION, method_set_location, error);
ce0f1493
LP
1244}
1245
21e627da
YW
1246static int method_get_product_uuid(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1247 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
99534007 1248 Context *c = ASSERT_PTR(userdata);
21e627da 1249 int interactive, r;
5704cd73 1250 sd_id128_t uuid;
21e627da
YW
1251
1252 assert(m);
21e627da 1253
21e627da
YW
1254 r = sd_bus_message_read(m, "b", &interactive);
1255 if (r < 0)
1256 return r;
1257
7b36fb9f 1258 r = bus_verify_polkit_async_full(
21e627da 1259 m,
21e627da 1260 "org.freedesktop.hostname1.get-product-uuid",
7b36fb9f 1261 /* details= */ NULL,
21e627da 1262 interactive,
7b36fb9f 1263 /* good_user= */ UID_INVALID,
21e627da
YW
1264 &c->polkit_registry,
1265 error);
1266 if (r < 0)
1267 return r;
1268 if (r == 0)
1269 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1270
66ee2298
LP
1271 r = id128_get_product(&uuid);
1272 if (r < 0) {
1273 if (r == -EADDRNOTAVAIL)
1274 log_debug_errno(r, "DMI product UUID is all 0x00 or all 0xFF, ignoring.");
1275 else
1276 log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
1277 "Failed to read product UUID, ignoring: %m");
1278
1279 return sd_bus_error_set(error, BUS_ERROR_NO_PRODUCT_UUID,
1280 "Failed to read product UUID from firmware.");
1281 }
1282
21e627da
YW
1283 r = sd_bus_message_new_method_return(m, &reply);
1284 if (r < 0)
1285 return r;
1286
c52e295d 1287 r = sd_bus_message_append_array(reply, 'y', uuid.bytes, sizeof(uuid.bytes));
21e627da
YW
1288 if (r < 0)
1289 return r;
1290
1291 return sd_bus_send(NULL, reply, NULL);
1292}
1293
96976629
YW
1294static int method_get_hardware_serial(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1295 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1296 _cleanup_free_ char *serial = NULL;
99534007 1297 Context *c = ASSERT_PTR(userdata);
ff28d259 1298 int r;
96976629
YW
1299
1300 assert(m);
96976629 1301
96976629
YW
1302 r = bus_verify_polkit_async(
1303 m,
96976629 1304 "org.freedesktop.hostname1.get-hardware-serial",
7b36fb9f 1305 /* details= */ NULL,
96976629
YW
1306 &c->polkit_registry,
1307 error);
1308 if (r < 0)
1309 return r;
1310 if (r == 0)
1311 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1312
1313 r = get_hardware_serial(&serial);
1314 if (r < 0)
1315 return r;
1316
1317 r = sd_bus_message_new_method_return(m, &reply);
1318 if (r < 0)
1319 return r;
1320
1321 r = sd_bus_message_append(reply, "s", serial);
1322 if (r < 0)
1323 return r;
1324
1325 return sd_bus_send(NULL, reply, NULL);
1326}
1327
7ecead8f 1328static int method_describe(sd_bus_message *m, void *userdata, sd_bus_error *error) {
96976629 1329 _cleanup_free_ char *hn = NULL, *dhn = NULL, *in = NULL, *text = NULL,
f233bbd6 1330 *chassis = NULL, *vendor = NULL, *model = NULL, *serial = NULL, *firmware_version = NULL,
ad8858c1 1331 *firmware_vendor = NULL;
b563d5ce 1332 usec_t firmware_date = USEC_INFINITY, eol = USEC_INFINITY;
7ecead8f
LP
1333 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1334 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
5db7eb21 1335 sd_id128_t machine_id, boot_id, product_uuid = SD_ID128_NULL;
99534007 1336 Context *c = ASSERT_PTR(userdata);
7ecead8f
LP
1337 bool privileged;
1338 struct utsname u;
1339 int r;
1340
1341 assert(m);
7ecead8f
LP
1342
1343 r = bus_verify_polkit_async(
1344 m,
96976629 1345 "org.freedesktop.hostname1.get-description",
7b36fb9f 1346 /* details= */ NULL,
7ecead8f 1347 &c->polkit_registry,
b56ee692 1348 error);
7ecead8f
LP
1349 if (r == 0)
1350 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1351
1352 /* We ignore all authentication errors here, since most data is unprivileged, the one exception being
1353 * the product ID which we'll check explicitly. */
1354 privileged = r > 0;
1355
1356 context_read_etc_hostname(c);
1357 context_read_machine_info(c);
1358 context_read_os_release(c);
1359 context_determine_hostname_source(c);
1360
1361 r = gethostname_strict(&hn);
1362 if (r < 0) {
1363 if (r != -ENXIO)
1364 return log_error_errno(r, "Failed to read local host name: %m");
1365
1366 hn = get_default_hostname();
1367 if (!hn)
1368 return log_oom();
1369 }
1370
1371 dhn = get_default_hostname();
1372 if (!dhn)
1373 return log_oom();
1374
1375 if (isempty(c->data[PROP_ICON_NAME]))
1376 in = context_fallback_icon_name(c);
1377
8c8b1800 1378 chassis = context_get_chassis(c);
7ecead8f
LP
1379
1380 assert_se(uname(&u) >= 0);
1381
0924ea2b 1382 if (isempty(c->data[PROP_HARDWARE_VENDOR]))
4fc7e4f3 1383 (void) get_hardware_vendor(&vendor);
0924ea2b 1384 if (isempty(c->data[PROP_HARDWARE_MODEL]))
4fc7e4f3 1385 (void) get_hardware_model(&model);
7ecead8f 1386
96976629
YW
1387 if (privileged) {
1388 /* The product UUID and hardware serial is only available to privileged clients */
1389 (void) id128_get_product(&product_uuid);
1390 (void) get_hardware_serial(&serial);
1391 }
c52950c2 1392 (void) get_firmware_version(&firmware_version);
f233bbd6 1393 (void) get_firmware_vendor(&firmware_vendor);
ff4d26df 1394 (void) get_firmware_date(&firmware_date);
7ecead8f 1395
b563d5ce
LP
1396 if (c->data[PROP_OS_SUPPORT_END])
1397 (void) os_release_support_ended(c->data[PROP_OS_SUPPORT_END], /* quiet= */ false, &eol);
1398
5db7eb21
YW
1399 r = sd_id128_get_machine(&machine_id);
1400 if (r < 0)
1401 return log_error_errno(r, "Failed to get machine ID: %m");
1402
1403 r = sd_id128_get_boot(&boot_id);
1404 if (r < 0)
1405 return log_error_errno(r, "Failed to get boot ID: %m");
1406
7ecead8f
LP
1407 r = json_build(&v, JSON_BUILD_OBJECT(
1408 JSON_BUILD_PAIR("Hostname", JSON_BUILD_STRING(hn)),
1409 JSON_BUILD_PAIR("StaticHostname", JSON_BUILD_STRING(c->data[PROP_STATIC_HOSTNAME])),
1410 JSON_BUILD_PAIR("PrettyHostname", JSON_BUILD_STRING(c->data[PROP_PRETTY_HOSTNAME])),
1411 JSON_BUILD_PAIR("DefaultHostname", JSON_BUILD_STRING(dhn)),
1412 JSON_BUILD_PAIR("HostnameSource", JSON_BUILD_STRING(hostname_source_to_string(c->hostname_source))),
1413 JSON_BUILD_PAIR("IconName", JSON_BUILD_STRING(in ?: c->data[PROP_ICON_NAME])),
8c8b1800 1414 JSON_BUILD_PAIR("Chassis", JSON_BUILD_STRING(chassis)),
7ecead8f
LP
1415 JSON_BUILD_PAIR("Deployment", JSON_BUILD_STRING(c->data[PROP_DEPLOYMENT])),
1416 JSON_BUILD_PAIR("Location", JSON_BUILD_STRING(c->data[PROP_LOCATION])),
1417 JSON_BUILD_PAIR("KernelName", JSON_BUILD_STRING(u.sysname)),
1418 JSON_BUILD_PAIR("KernelRelease", JSON_BUILD_STRING(u.release)),
1419 JSON_BUILD_PAIR("KernelVersion", JSON_BUILD_STRING(u.version)),
1420 JSON_BUILD_PAIR("OperatingSystemPrettyName", JSON_BUILD_STRING(c->data[PROP_OS_PRETTY_NAME])),
1421 JSON_BUILD_PAIR("OperatingSystemCPEName", JSON_BUILD_STRING(c->data[PROP_OS_CPE_NAME])),
1422 JSON_BUILD_PAIR("OperatingSystemHomeURL", JSON_BUILD_STRING(c->data[PROP_OS_HOME_URL])),
b563d5ce 1423 JSON_BUILD_PAIR_FINITE_USEC("OperatingSystemSupportEnd", eol),
0924ea2b
LP
1424 JSON_BUILD_PAIR("HardwareVendor", JSON_BUILD_STRING(vendor ?: c->data[PROP_HARDWARE_VENDOR])),
1425 JSON_BUILD_PAIR("HardwareModel", JSON_BUILD_STRING(model ?: c->data[PROP_HARDWARE_MODEL])),
96976629 1426 JSON_BUILD_PAIR("HardwareSerial", JSON_BUILD_STRING(serial)),
c52950c2 1427 JSON_BUILD_PAIR("FirmwareVersion", JSON_BUILD_STRING(firmware_version)),
f233bbd6 1428 JSON_BUILD_PAIR("FirmwareVendor", JSON_BUILD_STRING(firmware_vendor)),
ad8858c1 1429 JSON_BUILD_PAIR_FINITE_USEC("FirmwareDate", firmware_date),
5db7eb21
YW
1430 JSON_BUILD_PAIR_ID128("MachineID", machine_id),
1431 JSON_BUILD_PAIR_ID128("BootID", boot_id),
7ecead8f
LP
1432 JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(product_uuid), "ProductUUID", JSON_BUILD_ID128(product_uuid)),
1433 JSON_BUILD_PAIR_CONDITION(sd_id128_is_null(product_uuid), "ProductUUID", JSON_BUILD_NULL)));
1434
1435 if (r < 0)
1436 return log_error_errno(r, "Failed to build JSON data: %m");
1437
1438 r = json_variant_format(v, 0, &text);
1439 if (r < 0)
1440 return log_error_errno(r, "Failed to format JSON data: %m");
1441
1442 r = sd_bus_message_new_method_return(m, &reply);
1443 if (r < 0)
1444 return r;
1445
1446 r = sd_bus_message_append(reply, "s", text);
1447 if (r < 0)
1448 return r;
1449
1450 return sd_bus_send(NULL, reply, NULL);
1451}
1452
66a4c743
LP
1453static const sd_bus_vtable hostname_vtable[] = {
1454 SD_BUS_VTABLE_START(0),
aa994368 1455 SD_BUS_PROPERTY("Hostname", "s", property_get_hostname, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
d7f4ad20
LP
1456 SD_BUS_PROPERTY("StaticHostname", "s", property_get_static_hostname, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1457 SD_BUS_PROPERTY("PrettyHostname", "s", property_get_machine_info_field, offsetof(Context, data) + sizeof(char*) * PROP_PRETTY_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
8770c813 1458 SD_BUS_PROPERTY("DefaultHostname", "s", property_get_default_hostname, 0, SD_BUS_VTABLE_PROPERTY_CONST),
60e4fb42 1459 SD_BUS_PROPERTY("HostnameSource", "s", property_get_hostname_source, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
66a4c743
LP
1460 SD_BUS_PROPERTY("IconName", "s", property_get_icon_name, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1461 SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
d7f4ad20
LP
1462 SD_BUS_PROPERTY("Deployment", "s", property_get_machine_info_field, offsetof(Context, data) + sizeof(char*) * PROP_DEPLOYMENT, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1463 SD_BUS_PROPERTY("Location", "s", property_get_machine_info_field, offsetof(Context, data) + sizeof(char*) * PROP_LOCATION, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
72f48cd3
LP
1464 SD_BUS_PROPERTY("KernelName", "s", property_get_uname_field, offsetof(struct utsname, sysname), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
1465 SD_BUS_PROPERTY("KernelRelease", "s", property_get_uname_field, offsetof(struct utsname, release), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
1466 SD_BUS_PROPERTY("KernelVersion", "s", property_get_uname_field, offsetof(struct utsname, version), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
d7f4ad20
LP
1467 SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", property_get_os_release_field, offsetof(Context, data) + sizeof(char*) * PROP_OS_PRETTY_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
1468 SD_BUS_PROPERTY("OperatingSystemCPEName", "s", property_get_os_release_field, offsetof(Context, data) + sizeof(char*) * PROP_OS_CPE_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
b563d5ce 1469 SD_BUS_PROPERTY("OperatingSystemSupportEnd", "t", property_get_os_support_end, 0, SD_BUS_VTABLE_PROPERTY_CONST),
d7f4ad20 1470 SD_BUS_PROPERTY("HomeURL", "s", property_get_os_release_field, offsetof(Context, data) + sizeof(char*) * PROP_OS_HOME_URL, SD_BUS_VTABLE_PROPERTY_CONST),
b9d80698
FB
1471 SD_BUS_PROPERTY("HardwareVendor", "s", property_get_hardware_vendor, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1472 SD_BUS_PROPERTY("HardwareModel", "s", property_get_hardware_model, 0, SD_BUS_VTABLE_PROPERTY_CONST),
c52950c2 1473 SD_BUS_PROPERTY("FirmwareVersion", "s", property_get_firmware_version, 0, SD_BUS_VTABLE_PROPERTY_CONST),
f233bbd6 1474 SD_BUS_PROPERTY("FirmwareVendor", "s", property_get_firmware_vendor, 0, SD_BUS_VTABLE_PROPERTY_CONST),
ad8858c1 1475 SD_BUS_PROPERTY("FirmwareDate", "t", property_get_firmware_date, 0, SD_BUS_VTABLE_PROPERTY_CONST),
5db7eb21
YW
1476 SD_BUS_PROPERTY("MachineID", "ay", property_get_machine_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1477 SD_BUS_PROPERTY("BootID", "ay", property_get_boot_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
106d79be 1478
92c9f47d
SS
1479 SD_BUS_METHOD_WITH_ARGS("SetHostname",
1480 SD_BUS_ARGS("s", hostname, "b", interactive),
1481 SD_BUS_NO_RESULT,
1482 method_set_hostname,
1483 SD_BUS_VTABLE_UNPRIVILEGED),
1484 SD_BUS_METHOD_WITH_ARGS("SetStaticHostname",
1485 SD_BUS_ARGS("s", hostname, "b", interactive),
1486 SD_BUS_NO_RESULT,
1487 method_set_static_hostname,
1488 SD_BUS_VTABLE_UNPRIVILEGED),
1489 SD_BUS_METHOD_WITH_ARGS("SetPrettyHostname",
1490 SD_BUS_ARGS("s", hostname, "b", interactive),
1491 SD_BUS_NO_RESULT,
1492 method_set_pretty_hostname,
1493 SD_BUS_VTABLE_UNPRIVILEGED),
1494 SD_BUS_METHOD_WITH_ARGS("SetIconName",
1495 SD_BUS_ARGS("s", icon, "b", interactive),
1496 SD_BUS_NO_RESULT,
1497 method_set_icon_name,
1498 SD_BUS_VTABLE_UNPRIVILEGED),
1499 SD_BUS_METHOD_WITH_ARGS("SetChassis",
1500 SD_BUS_ARGS("s", chassis, "b", interactive),
1501 SD_BUS_NO_RESULT,
1502 method_set_chassis,
1503 SD_BUS_VTABLE_UNPRIVILEGED),
1504 SD_BUS_METHOD_WITH_ARGS("SetDeployment",
1505 SD_BUS_ARGS("s", deployment, "b", interactive),
1506 SD_BUS_NO_RESULT,
1507 method_set_deployment,
1508 SD_BUS_VTABLE_UNPRIVILEGED),
1509 SD_BUS_METHOD_WITH_ARGS("SetLocation",
1510 SD_BUS_ARGS("s", location, "b", interactive),
1511 SD_BUS_NO_RESULT,
1512 method_set_location,
1513 SD_BUS_VTABLE_UNPRIVILEGED),
1514 SD_BUS_METHOD_WITH_ARGS("GetProductUUID",
1515 SD_BUS_ARGS("b", interactive),
1516 SD_BUS_RESULT("ay", uuid),
1517 method_get_product_uuid,
1518 SD_BUS_VTABLE_UNPRIVILEGED),
1519 SD_BUS_METHOD_WITH_ARGS("GetHardwareSerial",
1520 SD_BUS_NO_ARGS,
1521 SD_BUS_RESULT("s", serial),
1522 method_get_hardware_serial,
1523 SD_BUS_VTABLE_UNPRIVILEGED),
7ecead8f
LP
1524 SD_BUS_METHOD_WITH_ARGS("Describe",
1525 SD_BUS_NO_ARGS,
1526 SD_BUS_RESULT("s", json),
1527 method_describe,
1528 SD_BUS_VTABLE_UNPRIVILEGED),
106d79be 1529
66a4c743
LP
1530 SD_BUS_VTABLE_END,
1531};
1532
670139db
ZJS
1533static const BusObjectImplementation manager_object = {
1534 "/org/freedesktop/hostname1",
1535 "org.freedesktop.hostname1",
1536 .vtables = BUS_VTABLES(hostname_vtable),
1537};
1538
2ac4d1d4 1539static int connect_bus(Context *c, sd_event *event, sd_bus **ret) {
4afd3348 1540 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
7640a5de
LP
1541 int r;
1542
66a4c743
LP
1543 assert(c);
1544 assert(event);
2ac4d1d4 1545 assert(ret);
d0baa06f 1546
76b54375 1547 r = sd_bus_default_system(&bus);
23bbb0de
MS
1548 if (r < 0)
1549 return log_error_errno(r, "Failed to get system bus connection: %m");
d0baa06f 1550
670139db 1551 r = bus_add_implementation(bus, &manager_object, c);
23bbb0de 1552 if (r < 0)
670139db 1553 return r;
d0baa06f 1554
ac9f55ed
LP
1555 r = bus_log_control_api_register(bus);
1556 if (r < 0)
1557 return r;
1558
0c0b9306 1559 r = sd_bus_request_name_async(bus, NULL, "org.freedesktop.hostname1", 0, NULL, NULL);
23bbb0de 1560 if (r < 0)
0c0b9306 1561 return log_error_errno(r, "Failed to request name: %m");
add10b5a 1562
66a4c743 1563 r = sd_bus_attach_event(bus, event, 0);
23bbb0de
MS
1564 if (r < 0)
1565 return log_error_errno(r, "Failed to attach bus to event loop: %m");
d0baa06f 1566
2ac4d1d4 1567 *ret = TAKE_PTR(bus);
66a4c743 1568 return 0;
d0baa06f
LP
1569}
1570
85ae63ee 1571static int run(int argc, char *argv[]) {
60e4fb42
ZJS
1572 _cleanup_(context_destroy) Context context = {
1573 .hostname_source = _HOSTNAME_INVALID, /* appropriate value will be set later */
1574 };
4afd3348
LP
1575 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
1576 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
d0baa06f 1577 int r;
d0baa06f 1578
d2acb93d 1579 log_setup();
7640a5de 1580
fc021a5b
ZJS
1581 r = service_parse_argv("systemd-hostnamed.service",
1582 "Manage the system hostname and related metadata.",
670139db
ZJS
1583 BUS_IMPLEMENTATIONS(&manager_object,
1584 &log_control_object),
fc021a5b
ZJS
1585 argc, argv);
1586 if (r <= 0)
1587 return r;
1588
4c12626c 1589 umask(0022);
a9ba0e32 1590
a452c807 1591 r = mac_init();
a9ba0e32
CG
1592 if (r < 0)
1593 return r;
4c12626c 1594
b22c8bfc
YW
1595 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
1596
afc6adb5 1597 r = sd_event_default(&event);
85ae63ee
YW
1598 if (r < 0)
1599 return log_error_errno(r, "Failed to allocate event loop: %m");
7640a5de 1600
b22c8bfc
YW
1601 (void) sd_event_set_watchdog(event, true);
1602
1603 r = sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
85ae63ee
YW
1604 if (r < 0)
1605 return log_error_errno(r, "Failed to install SIGINT handler: %m");
b22c8bfc
YW
1606
1607 r = sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
85ae63ee
YW
1608 if (r < 0)
1609 return log_error_errno(r, "Failed to install SIGTERM handler: %m");
cde93897 1610
66a4c743 1611 r = connect_bus(&context, event, &bus);
d0baa06f 1612 if (r < 0)
85ae63ee 1613 return r;
7640a5de 1614
37224a5f 1615 r = bus_event_loop_with_idle(event, bus, "org.freedesktop.hostname1", DEFAULT_EXIT_USEC, NULL, NULL);
85ae63ee
YW
1616 if (r < 0)
1617 return log_error_errno(r, "Failed to run event loop: %m");
7640a5de 1618
85ae63ee 1619 return 0;
7640a5de 1620}
85ae63ee
YW
1621
1622DEFINE_MAIN_FUNCTION(run);