]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/hostname/hostnamed.c
man/systemd-sysext: list ephemeral/ephemeral-import in the list of options
[thirdparty/systemd.git] / src / hostname / hostnamed.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
7640a5de 2
ca78ad1d 3#include <sys/stat.h>
1cf40697 4#include <sys/utsname.h>
cf0fbc49 5#include <unistd.h>
7640a5de 6
8857aa74 7#include "sd-bus.h"
19b8e712 8#include "sd-device.h"
8857aa74 9#include "sd-event.h"
309a747f 10#include "sd-json.h"
19b8e712 11
b5efdb8a 12#include "alloc-util.h"
1e4e5572 13#include "bitfield.h"
21e627da 14#include "bus-common-errors.h"
ce6b138c 15#include "bus-get-properties.h"
ac9f55ed 16#include "bus-log-control-api.h"
86b9a3e3 17#include "bus-object.h"
269e4d2d 18#include "bus-polkit.h"
76d62b63 19#include "bus-util.h"
28db6fbf 20#include "constants.h"
9737e2c8 21#include "daemon-util.h"
b3d75a3b 22#include "device-private.h"
686d13b9 23#include "env-file.h"
4d1a6904 24#include "env-util.h"
8857aa74 25#include "extract-word.h"
ee228be1 26#include "fileio.h"
8857aa74 27#include "hashmap.h"
e2054217 28#include "hostname-setup.h"
958b66ea 29#include "hostname-util.h"
21e627da 30#include "id128-util.h"
309a747f 31#include "json-util.h"
8857aa74 32#include "label-util.h"
93a1f792 33#include "log.h"
85ae63ee 34#include "main-func.h"
d8b4d14d 35#include "nulstr-util.h"
d58ad743 36#include "os-util.h"
6bedfcbb 37#include "parse-util.h"
bb15fafe 38#include "path-util.h"
fc021a5b 39#include "service-util.h"
19b8e712 40#include "socket-util.h"
d7f4ad20 41#include "stat-util.h"
8857aa74 42#include "string-util.h"
6bedfcbb 43#include "strv.h"
8857aa74 44#include "time-util.h"
64724e05 45#include "utf8.h"
0a6598bb 46#include "varlink-io.systemd.Hostname.h"
c8127075 47#include "varlink-io.systemd.service.h"
fd409ff0 48#include "varlink-util.h"
6bedfcbb 49#include "virt.h"
91f9dcaf 50
799298d6
JG
51#define VALID_DEPLOYMENT_CHARS (DIGITS LETTERS "-.:")
52
f8da67cd
LP
53/* Properties we cache are indexed by an enum, to make invalidation easy and systematic (as we can iterate
54 * through them all, and they are uniformly strings). */
4fc7e4f3 55typedef enum {
d7f4ad20 56 /* Read from /etc/hostname */
7640a5de 57 PROP_STATIC_HOSTNAME,
af9c45d5 58 PROP_STATIC_HOSTNAME_SUBSTITUTED_WILDCARDS,
d7f4ad20
LP
59
60 /* Read from /etc/machine-info */
7640a5de
LP
61 PROP_PRETTY_HOSTNAME,
62 PROP_ICON_NAME,
7871c8e9 63 PROP_CHASSIS,
799298d6 64 PROP_DEPLOYMENT,
ce0f1493 65 PROP_LOCATION,
0924ea2b
LP
66 PROP_HARDWARE_VENDOR,
67 PROP_HARDWARE_MODEL,
79e9fb68 68 PROP_HARDWARE_SKU,
29a352e8 69 PROP_HARDWARE_VERSION,
d7f4ad20
LP
70
71 /* Read from /etc/os-release (or /usr/lib/os-release) */
44c32988
DH
72 PROP_OS_PRETTY_NAME,
73 PROP_OS_CPE_NAME,
d7f4ad20 74 PROP_OS_HOME_URL,
b563d5ce 75 PROP_OS_SUPPORT_END,
bc60034f
LP
76 PROP_OS_IMAGE_ID,
77 PROP_OS_IMAGE_VERSION,
d7f4ad20 78 _PROP_MAX,
2d93c20e 79 _PROP_INVALID = -EINVAL,
4fc7e4f3 80} HostProperty;
7640a5de 81
66a4c743
LP
82typedef struct Context {
83 char *data[_PROP_MAX];
d7f4ad20 84
60e4fb42
ZJS
85 HostnameSource hostname_source;
86
d7f4ad20
LP
87 struct stat etc_hostname_stat;
88 struct stat etc_os_release_stat;
89 struct stat etc_machine_info_stat;
90
96520e8b
LP
91 sd_event *event;
92 sd_bus *bus;
25ff515b 93 sd_varlink_server *varlink_server;
66a4c743 94 Hashmap *polkit_registry;
c1507748 95 sd_device *device_dmi;
b3d75a3b 96 sd_device *device_acpi;
3e91aed6 97 sd_device *device_tree;
66a4c743 98} Context;
ad740100 99
d7f4ad20 100static void context_reset(Context *c, uint64_t mask) {
66a4c743
LP
101 assert(c);
102
2af3cad0 103 for (HostProperty p = 0; p < _PROP_MAX; p++) {
1e4e5572 104 if (!BIT_SET(mask, p))
d7f4ad20
LP
105 continue;
106
a1e58e8e 107 c->data[p] = mfree(c->data[p]);
d7f4ad20 108 }
7640a5de
LP
109}
110
cfb9433d 111static void context_destroy(Context *c) {
66a4c743
LP
112 assert(c);
113
d7f4ad20 114 context_reset(c, UINT64_MAX);
2a1ffd3e 115 hashmap_free(c->polkit_registry);
96520e8b
LP
116 sd_event_unref(c->event);
117 sd_bus_flush_close_unref(c->bus);
25ff515b 118 sd_varlink_server_unref(c->varlink_server);
c1507748 119 sd_device_unref(c->device_dmi);
b3d75a3b 120 sd_device_unref(c->device_acpi);
3e91aed6 121 sd_device_unref(c->device_tree);
66a4c743
LP
122}
123
d7f4ad20
LP
124static void context_read_etc_hostname(Context *c) {
125 struct stat current_stat = {};
7640a5de
LP
126 int r;
127
66a4c743
LP
128 assert(c);
129
0dc39dff 130 if (stat(etc_hostname(), &current_stat) >= 0 &&
d7f4ad20
LP
131 stat_inode_unmodified(&c->etc_hostname_stat, &current_stat))
132 return;
133
af9c45d5
LP
134 context_reset(c,
135 (UINT64_C(1) << PROP_STATIC_HOSTNAME) |
136 (UINT64_C(1) << PROP_STATIC_HOSTNAME_SUBSTITUTED_WILDCARDS));
7640a5de 137
af9c45d5
LP
138 r = read_etc_hostname(/* path= */ NULL, /* substitute_wildcards= */ false, &c->data[PROP_STATIC_HOSTNAME]);
139 if (r < 0) {
140 if (r != -ENOENT)
141 log_warning_errno(r, "Failed to read /etc/hostname, ignoring: %m");
142 } else {
143 _cleanup_free_ char *substituted = strdup(c->data[PROP_STATIC_HOSTNAME]);
144 if (!substituted)
145 return (void) log_oom();
146
147 r = hostname_substitute_wildcards(substituted);
148 if (r < 0)
149 log_warning_errno(r, "Failed to substitute wildcards in /etc/hostname, ignoring: %m");
150 else
151 c->data[PROP_STATIC_HOSTNAME_SUBSTITUTED_WILDCARDS] = TAKE_PTR(substituted);
152 }
d7f4ad20
LP
153
154 c->etc_hostname_stat = current_stat;
155}
156
157static void context_read_machine_info(Context *c) {
158 struct stat current_stat = {};
159 int r;
160
161 assert(c);
162
0dc39dff 163 if (stat(etc_machine_info(), &current_stat) >= 0 &&
d7f4ad20
LP
164 stat_inode_unmodified(&c->etc_machine_info_stat, &current_stat))
165 return;
166
167 context_reset(c,
168 (UINT64_C(1) << PROP_PRETTY_HOSTNAME) |
169 (UINT64_C(1) << PROP_ICON_NAME) |
170 (UINT64_C(1) << PROP_CHASSIS) |
171 (UINT64_C(1) << PROP_DEPLOYMENT) |
38639aa2
LP
172 (UINT64_C(1) << PROP_LOCATION) |
173 (UINT64_C(1) << PROP_HARDWARE_VENDOR) |
79e9fb68 174 (UINT64_C(1) << PROP_HARDWARE_MODEL) |
29a352e8
SH
175 (UINT64_C(1) << PROP_HARDWARE_SKU) |
176 (UINT64_C(1) << PROP_HARDWARE_VERSION));
7640a5de 177
0dc39dff 178 r = parse_env_file(NULL, etc_machine_info(),
66a4c743
LP
179 "PRETTY_HOSTNAME", &c->data[PROP_PRETTY_HOSTNAME],
180 "ICON_NAME", &c->data[PROP_ICON_NAME],
181 "CHASSIS", &c->data[PROP_CHASSIS],
799298d6 182 "DEPLOYMENT", &c->data[PROP_DEPLOYMENT],
4fc7e4f3 183 "LOCATION", &c->data[PROP_LOCATION],
0924ea2b 184 "HARDWARE_VENDOR", &c->data[PROP_HARDWARE_VENDOR],
79e9fb68 185 "HARDWARE_MODEL", &c->data[PROP_HARDWARE_MODEL],
29a352e8
SH
186 "HARDWARE_SKU", &c->data[PROP_HARDWARE_SKU],
187 "HARDWARE_VERSION", &c->data[PROP_HARDWARE_VERSION]);
7640a5de 188 if (r < 0 && r != -ENOENT)
d7f4ad20
LP
189 log_warning_errno(r, "Failed to read /etc/machine-info, ignoring: %m");
190
191 c->etc_machine_info_stat = current_stat;
192}
193
194static void context_read_os_release(Context *c) {
02b7005e 195 _cleanup_free_ char *os_name = NULL, *os_pretty_name = NULL;
d7f4ad20
LP
196 struct stat current_stat = {};
197 int r;
198
199 assert(c);
200
201 if ((stat("/etc/os-release", &current_stat) >= 0 ||
202 stat("/usr/lib/os-release", &current_stat) >= 0) &&
203 stat_inode_unmodified(&c->etc_os_release_stat, &current_stat))
204 return;
205
206 context_reset(c,
207 (UINT64_C(1) << PROP_OS_PRETTY_NAME) |
208 (UINT64_C(1) << PROP_OS_CPE_NAME) |
b563d5ce 209 (UINT64_C(1) << PROP_OS_HOME_URL) |
bc60034f
LP
210 (UINT64_C(1) << PROP_OS_SUPPORT_END) |
211 (UINT64_C(1) << PROP_OS_IMAGE_ID) |
212 (UINT64_C(1) << PROP_OS_IMAGE_VERSION));
7640a5de 213
d58ad743 214 r = parse_os_release(NULL,
bc60034f
LP
215 "PRETTY_NAME", &os_pretty_name,
216 "NAME", &os_name,
217 "CPE_NAME", &c->data[PROP_OS_CPE_NAME],
218 "HOME_URL", &c->data[PROP_OS_HOME_URL],
219 "SUPPORT_END", &c->data[PROP_OS_SUPPORT_END],
220 "IMAGE_ID", &c->data[PROP_OS_IMAGE_ID],
221 "IMAGE_VERSION", &c->data[PROP_OS_IMAGE_VERSION]);
44c32988 222 if (r < 0 && r != -ENOENT)
d7f4ad20 223 log_warning_errno(r, "Failed to read os-release file, ignoring: %m");
44c32988 224
02b7005e
LP
225 if (free_and_strdup(&c->data[PROP_OS_PRETTY_NAME], os_release_pretty_name(os_pretty_name, os_name)) < 0)
226 log_oom();
227
d7f4ad20 228 c->etc_os_release_stat = current_stat;
7640a5de
LP
229}
230
e7932afe
LP
231static bool use_dmi_data(void) {
232 int r;
233
234 r = getenv_bool("SYSTEMD_HOSTNAME_FORCE_DMI");
235 if (r >= 0) {
236 log_debug("Honouring $SYSTEMD_HOSTNAME_FORCE_DMI override: %s", yes_no(r));
237 return r;
238 }
239 if (r != -ENXIO)
240 log_debug_errno(r, "Failed to parse $SYSTEMD_HOSTNAME_FORCE_DMI, ignoring: %m");
241
242 if (detect_container() > 0) {
243 log_debug("Running in a container, not using DMI hardware data.");
244 return false;
245 }
246
247 return true;
248}
249
c1507748 250static int context_acquire_dmi_device(Context *c) {
8c8b1800
YW
251 int r;
252
c1507748
YW
253 assert(c);
254 assert(!c->device_dmi);
255
e7932afe 256 if (!use_dmi_data())
c1507748 257 return 0;
e7932afe 258
c1507748
YW
259 r = sd_device_new_from_syspath(&c->device_dmi, "/sys/class/dmi/id/");
260 if (ERRNO_IS_NEG_DEVICE_ABSENT(r)) {
261 log_debug_errno(r, "Failed to open /sys/class/dmi/id/ device, ignoring: %m");
262 return 0;
263 }
8c8b1800 264 if (r < 0)
c1507748 265 return log_error_errno(r, "Failed to open /sys/class/dmi/id/ device: %m");
8c8b1800 266
c1507748 267 return 1;
8c8b1800
YW
268}
269
b3d75a3b
YW
270static int context_acquire_acpi_device(Context *c) {
271 int r;
272
273 assert(c);
274 assert(!c->device_acpi);
275
276 r = sd_device_new_from_syspath(&c->device_acpi, "/sys/firmware/acpi/");
277 if (ERRNO_IS_NEG_DEVICE_ABSENT(r)) {
278 log_debug_errno(r, "Failed to open /sys/firmware/acpi/ device, ignoring: %m");
279 return 0;
280 }
281 if (r < 0)
282 return log_error_errno(r, "Failed to open /sys/firmware/acpi/ device: %m");
283
284 return 1;
285}
286
3e91aed6
YW
287static int context_acquire_device_tree(Context *c) {
288 int r;
289
290 assert(c);
291 assert(!c->device_tree);
292
c0b3b3af 293 r = sd_device_new_from_path(&c->device_tree, "/proc/device-tree/");
3e91aed6
YW
294 if (ERRNO_IS_NEG_DEVICE_ABSENT(r)) {
295 log_debug_errno(r, "Failed to open /proc/device-tree/ device, ignoring: %m");
296 return 0;
297 }
298 if (r < 0)
299 return log_error_errno(r, "Failed to open /proc/device-tree/ device: %m");
300
301 return 1;
302}
303
c1507748
YW
304static bool string_is_safe_for_dbus(const char *s) {
305 assert(s);
8c8b1800 306
c1507748
YW
307 /* Do some superficial validation: do not allow CCs and make sure D-Bus won't kick us off the bus
308 * because we send invalid UTF-8 data */
309
310 if (string_has_cc(s, /* ok= */ NULL))
311 return false;
312
313 return utf8_is_valid(s);
8c8b1800
YW
314}
315
c1507748
YW
316static int get_dmi_property(Context *c, const char *key, char **ret) {
317 const char *s;
96976629
YW
318 int r;
319
c1507748
YW
320 assert(c);
321 assert(key);
322 assert(ret);
c52950c2 323
c1507748
YW
324 if (!c->device_dmi)
325 return -ENODEV;
e7932afe 326
c1507748 327 r = sd_device_get_property_value(c->device_dmi, key, &s);
96976629 328 if (r < 0)
c1507748 329 return r;
96976629 330
c1507748
YW
331 if (!string_is_safe_for_dbus(s))
332 return -ENXIO;
96976629 333
c1507748 334 return strdup_to(ret, s);
96976629
YW
335}
336
c1507748
YW
337static int get_dmi_properties(Context *c, const char * const * keys, char **ret) {
338 int r = -ENOENT;
64724e05 339
c1507748
YW
340 assert(c);
341 assert(ret);
342
343 STRV_FOREACH(k, keys) {
344 r = get_dmi_property(c, *k, ret);
345 if (r >= 0 || !ERRNO_IS_NEG_DEVICE_ABSENT(r))
346 return r;
64724e05 347 }
c1507748
YW
348
349 return r;
350}
351
7e638ccf
JW
352static int get_chassis_asset_tag(Context *c, char **ret) {
353 return get_dmi_property(c, "ID_CHASSIS_ASSET_TAG", ret);
354}
355
c1507748
YW
356static int get_hardware_vendor(Context *c, char **ret) {
357 return get_dmi_properties(c, STRV_MAKE_CONST("ID_VENDOR_FROM_DATABASE", "ID_VENDOR"), ret);
358}
359
360static int get_hardware_model(Context *c, char **ret) {
361 return get_dmi_properties(c, STRV_MAKE_CONST("ID_MODEL_FROM_DATABASE", "ID_MODEL"), ret);
362}
363
79e9fb68
SH
364static int get_hardware_sku(Context *c, char **ret) {
365 _cleanup_free_ char *model = NULL, *sku = NULL;
366 int r;
367
368 r = get_dmi_property(c, "ID_SKU", &sku);
369 if (r < 0)
370 return r;
371
372 /* Suppress reporting the SKU field, if it's the same string as the
373 * model field, which it appears to be on various systems */
374 r = get_hardware_model(c, &model);
375 if (r < 0) {
376 if (r != -ENOENT)
377 return r;
378 } else if (streq_ptr(sku, model))
379 return -ENOENT;
380
381 *ret = TAKE_PTR(sku);
382 return 0;
383}
384
29a352e8
SH
385static int get_hardware_version(Context *c, char **ret) {
386 _cleanup_free_ char *version = NULL;
387 int r;
388
389 r = get_dmi_property(c, "ID_HARDWARE_VERSION", &version);
390 if (r < 0)
391 return r;
392
393 /* Suppress reporting the version field, if it's the same string as the
394 * model or sku field, which it appears to be on various systems */
dda0e5aa
YW
395 int (*getter)(Context *c, char **ret);
396 FOREACH_ARGUMENT(getter, get_hardware_model, get_hardware_sku) {
29a352e8
SH
397 _cleanup_free_ char *value = NULL;
398
dda0e5aa
YW
399 r = getter(c, &value);
400 if (r == -ENOENT)
401 continue;
402 if (r < 0)
403 return r;
404 if (streq_ptr(version, value))
29a352e8
SH
405 return -ENOENT;
406 }
407
408 *ret = TAKE_PTR(version);
409 return 0;
410}
411
c1507748
YW
412static int get_sysattr(sd_device *device, const char *key, char **ret) {
413 const char *s;
414 int r;
415
416 assert(key);
417 assert(ret);
418
419 if (!device)
420 return -ENODEV;
421
422 r = sd_device_get_sysattr_value(device, key, &s);
64724e05
LP
423 if (r < 0)
424 return r;
64724e05 425
c1507748
YW
426 if (!string_is_safe_for_dbus(s))
427 return -ENXIO;
64724e05 428
c1507748
YW
429 return strdup_to(ret, empty_to_null(s));
430}
64724e05 431
c1507748
YW
432static int get_dmi_sysattr(Context *c, const char *key, char **ret) {
433 return get_sysattr(ASSERT_PTR(c)->device_dmi, key, ret);
434}
c52950c2 435
3e91aed6
YW
436static int get_device_tree_sysattr(Context *c, const char *key, char **ret) {
437 return get_sysattr(ASSERT_PTR(c)->device_tree, key, ret);
438}
439
c1507748
YW
440static int get_hardware_serial(Context *c, char **ret) {
441 int r;
c52950c2 442
c1507748
YW
443 assert(c);
444 assert(ret);
445
446 FOREACH_STRING(attr, "product_serial", "board_serial") {
447 r = get_dmi_sysattr(c, attr, ret);
448 if (r >= 0 || !ERRNO_IS_NEG_DEVICE_ABSENT(r))
449 return r;
450 }
451
3e91aed6 452 return get_device_tree_sysattr(c, "serial-number", ret);
c52950c2
SS
453}
454
c1507748
YW
455static int get_firmware_version(Context *c, char **ret) {
456 return get_dmi_sysattr(c, "bios_version", ret);
c52950c2
SS
457}
458
c1507748
YW
459static int get_firmware_vendor(Context *c, char **ret) {
460 return get_dmi_sysattr(c, "bios_vendor", ret);
f233bbd6
JW
461}
462
c1507748 463static int get_firmware_date(Context *c, usec_t *ret) {
f3525b78
LP
464 _cleanup_free_ char *bios_date = NULL, *month = NULL, *day = NULL, *year = NULL;
465 int r;
ad8858c1 466
c1507748 467 assert(c);
f3525b78 468 assert(ret);
ad8858c1 469
c1507748
YW
470 r = get_dmi_sysattr(c, "bios_date", &bios_date);
471 if (ERRNO_IS_NEG_DEVICE_ABSENT(r)) {
ad8858c1
JW
472 *ret = USEC_INFINITY;
473 return 0;
f3525b78 474 }
c1507748
YW
475 if (r < 0)
476 return r;
ad8858c1 477
f3525b78 478 const char *p = bios_date;
4f495126 479 r = extract_many_words(&p, "/", EXTRACT_DONT_COALESCE_SEPARATORS, &month, &day, &year);
f3525b78 480 if (r < 0)
ad8858c1 481 return r;
f3525b78 482 if (r != 3) /* less than three args read? */
ad8858c1 483 return -EINVAL;
f3525b78 484 if (!isempty(p)) /* more left in the string? */
ad8858c1
JW
485 return -EINVAL;
486
f3525b78
LP
487 unsigned m, d, y;
488 r = safe_atou_full(month, 10 | SAFE_ATO_REFUSE_PLUS_MINUS | SAFE_ATO_REFUSE_LEADING_WHITESPACE, &m);
489 if (r < 0)
ad8858c1 490 return r;
f3525b78 491 if (m < 1 || m > 12)
ad8858c1 492 return -EINVAL;
f3525b78 493 m -= 1;
ad8858c1 494
f3525b78
LP
495 r = safe_atou_full(day, 10 | SAFE_ATO_REFUSE_PLUS_MINUS | SAFE_ATO_REFUSE_LEADING_WHITESPACE, &d);
496 if (r < 0)
ad8858c1 497 return r;
f3525b78 498 if (d < 1 || d > 31)
ad8858c1
JW
499 return -EINVAL;
500
f3525b78
LP
501 r = safe_atou_full(year, 10 | SAFE_ATO_REFUSE_PLUS_MINUS | SAFE_ATO_REFUSE_LEADING_WHITESPACE, &y);
502 if (r < 0)
ad8858c1 503 return r;
f3525b78 504 if (y < 1970 || y > (unsigned) INT_MAX)
ad8858c1 505 return -EINVAL;
f3525b78 506 y -= 1900;
ad8858c1 507
f3525b78 508 struct tm tm = {
ad8858c1
JW
509 .tm_mday = d,
510 .tm_mon = m,
511 .tm_year = y,
f3525b78 512 };
6f5cf415
LP
513
514 usec_t v;
515 r = mktime_or_timegm_usec(&tm, /* utc= */ true, &v);
516 if (r < 0)
517 return r;
f3525b78 518 if (tm.tm_mday != (int) d || tm.tm_mon != (int) m || tm.tm_year != (int) y)
ad8858c1
JW
519 return -EINVAL; /* date was not normalized? (e.g. "30th of feb") */
520
6f5cf415 521 *ret = v;
f3525b78 522 return 0;
ff4d26df
JW
523}
524
e6e6ca82 525static const char* valid_chassis(const char *chassis) {
7871c8e9
LP
526 assert(chassis);
527
e6e6ca82 528 return nulstr_get(
7871c8e9
LP
529 "vm\0"
530 "container\0"
531 "desktop\0"
532 "laptop\0"
34b52450 533 "convertible\0"
7871c8e9
LP
534 "server\0"
535 "tablet\0"
c49e59c1 536 "handset\0"
25fa306e
LP
537 "watch\0"
538 "embedded\0",
7871c8e9
LP
539 chassis);
540}
541
799298d6
JG
542static bool valid_deployment(const char *deployment) {
543 assert(deployment);
544
c2142cf1 545 return in_charset(deployment, VALID_DEPLOYMENT_CHARS);
799298d6
JG
546}
547
b3d75a3b
YW
548static const char* fallback_chassis_by_virtualization(void) {
549 Virtualization v = detect_virtualization();
550 if (v < 0) {
2ac4d1d4 551 log_debug_errno(v, "Failed to detect virtualization, ignoring: %m");
b3d75a3b
YW
552 return NULL;
553 }
554
555 if (VIRTUALIZATION_IS_VM(v))
7871c8e9 556 return "vm";
b3d75a3b 557 if (VIRTUALIZATION_IS_CONTAINER(v))
7871c8e9
LP
558 return "container";
559
b3d75a3b
YW
560 return NULL;
561}
562
563static const char* fallback_chassis_by_dmi(Context *c) {
564 unsigned t;
565 int r;
566
567 assert(c);
568
569 if (!c->device_dmi)
570 return NULL;
7871c8e9 571
b3d75a3b 572 r = device_get_sysattr_unsigned(c->device_dmi, "chassis_type", &t);
2ac4d1d4 573 if (r < 0) {
b3d75a3b
YW
574 log_debug_errno(r, "Failed to read/parse DMI chassis type, ignoring: %m");
575 return NULL;
2ac4d1d4 576 }
7871c8e9 577
219bfe38 578 /* We only list the really obvious cases here. The DMI data is unreliable enough, so let's not do any
68cdeab3
ZJS
579 * additional guesswork on top of that.
580 *
67840dbf 581 * See the SMBIOS Specification 3.5.0 section 7.4.1 for details about the values listed here:
68cdeab3 582 *
67840dbf 583 * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.5.0.pdf
7871c8e9
LP
584 */
585
219bfe38 586 switch (t) {
7871c8e9 587
67840dbf
LP
588 case 0x03: /* Desktop */
589 case 0x04: /* Low Profile Desktop */
590 case 0x06: /* Mini Tower */
591 case 0x07: /* Tower */
592 case 0x0D: /* All in one (i.e. PC built into monitor) */
593 case 0x23: /* Mini PC */
594 case 0x24: /* Stick PC */
7871c8e9
LP
595 return "desktop";
596
219bfe38
LP
597 case 0x8: /* Portable */
598 case 0x9: /* Laptop */
599 case 0xA: /* Notebook */
600 case 0xE: /* Sub Notebook */
7871c8e9 601 return "laptop";
7640a5de 602
219bfe38
LP
603 case 0xB: /* Hand Held */
604 return "handset";
605
606 case 0x11: /* Main Server Chassis */
607 case 0x1C: /* Blade */
608 case 0x1D: /* Blade Enclosure */
7871c8e9 609 return "server";
7640a5de 610
219bfe38 611 case 0x1E: /* Tablet */
7871c8e9 612 return "tablet";
b70af833
DH
613
614 case 0x1F: /* Convertible */
b4227dbb 615 case 0x20: /* Detachable */
b70af833 616 return "convertible";
2ac4d1d4 617
67840dbf
LP
618 case 0x21: /* IoT Gateway */
619 case 0x22: /* Embedded PC */
620 return "embedded";
621
2ac4d1d4
LP
622 default:
623 log_debug("Unhandled DMI chassis type 0x%02x, ignoring.", t);
b3d75a3b 624 return NULL;
7871c8e9 625 }
b3d75a3b 626}
7871c8e9 627
b3d75a3b
YW
628static const char* fallback_chassis_by_acpi(Context *c) {
629 unsigned t;
630 int r;
7640a5de 631
b3d75a3b
YW
632 assert(c);
633
634 if (!c->device_acpi)
635 return NULL;
636
637 r = device_get_sysattr_unsigned(c->device_acpi, "pm_profile", &t);
2ac4d1d4 638 if (r < 0) {
b3d75a3b
YW
639 log_debug_errno(r, "Failed read/parse ACPI PM profile, ignoring: %m");
640 return NULL;
2ac4d1d4 641 }
7640a5de 642
219bfe38
LP
643 /* We only list the really obvious cases here as the ACPI data is not really super reliable.
644 *
645 * See the ACPI 5.0 Spec Section 5.2.9.1 for details:
646 *
647 * http://www.acpi.info/DOWNLOADS/ACPIspec50.pdf
41550d40 648 */
7640a5de 649
79893116 650 switch (t) {
7640a5de 651
219bfe38
LP
652 case 1: /* Desktop */
653 case 3: /* Workstation */
654 case 6: /* Appliance PC */
7871c8e9 655 return "desktop";
7640a5de 656
219bfe38 657 case 2: /* Mobile */
7871c8e9
LP
658 return "laptop";
659
219bfe38
LP
660 case 4: /* Enterprise Server */
661 case 5: /* SOHO Server */
662 case 7: /* Performance Server */
7871c8e9 663 return "server";
f3f4f008 664
219bfe38 665 case 8: /* Tablet */
f3f4f008 666 return "tablet";
2ac4d1d4
LP
667
668 default:
669 log_debug("Unhandled ACPI PM profile 0x%02x, ignoring.", t);
b3d75a3b 670 return NULL;
7640a5de 671 }
b3d75a3b 672}
7640a5de 673
b3d75a3b
YW
674static const char* fallback_chassis_by_device_tree(Context *c) {
675 const char *type, *chassis;
676 int r;
677
678 assert(c);
679
680 if (!c->device_tree)
681 return NULL;
682
683 r = sd_device_get_sysattr_value(c->device_tree, "chassis-type", &type);
e6e6ca82
AF
684 if (r < 0) {
685 log_debug_errno(r, "Failed to read device-tree chassis type, ignoring: %m");
686 return NULL;
687 }
688
26548841 689 /* Note that the DeviceTree specification uses the very same vocabulary
e6e6ca82
AF
690 * of chassis types as we do, hence we do not need to translate these types:
691 *
692 * https://github.com/devicetree-org/devicetree-specification/blob/master/source/chapter3-devicenodes.rst */
b3d75a3b 693
e6e6ca82
AF
694 chassis = valid_chassis(type);
695 if (!chassis)
68cdeab3 696 log_debug("Invalid device-tree chassis type \"%s\", ignoring.", type);
e6e6ca82 697 return chassis;
7640a5de
LP
698}
699
b3d75a3b
YW
700static const char* fallback_chassis(Context *c) {
701 assert(c);
702
703 return
704 fallback_chassis_by_virtualization() ?:
705 fallback_chassis_by_dmi(c) ?:
706 fallback_chassis_by_acpi(c) ?:
707 fallback_chassis_by_device_tree(c);
708}
709
8c8b1800
YW
710static char* context_get_chassis(Context *c) {
711 const char *fallback;
712 char *dmi;
7871c8e9 713
66a4c743
LP
714 assert(c);
715
716 if (!isempty(c->data[PROP_CHASSIS]))
8c8b1800
YW
717 return strdup(c->data[PROP_CHASSIS]);
718
c1507748 719 if (get_dmi_property(c, "ID_CHASSIS", &dmi) >= 0)
8c8b1800
YW
720 return dmi;
721
b3d75a3b 722 fallback = fallback_chassis(c);
8c8b1800
YW
723 if (fallback)
724 return strdup(fallback);
725
726 return NULL;
727}
728
729static char* context_fallback_icon_name(Context *c) {
730 _cleanup_free_ char *chassis = NULL;
731
732 assert(c);
7871c8e9 733
8c8b1800 734 chassis = context_get_chassis(c);
7871c8e9 735 if (chassis)
b910cc72 736 return strjoin("computer-", chassis);
7871c8e9
LP
737
738 return strdup("computer");
739}
740
aa994368
LP
741static int context_update_kernel_hostname(
742 Context *c,
88a66cfb 743 const char *transient_hostname) {
aa994368 744
05c6f341 745 _cleanup_free_ char *_hn_free = NULL;
d39079fc 746 const char *hn;
60e4fb42 747 HostnameSource hns;
7d9ec609 748 int r;
7640a5de 749
66a4c743
LP
750 assert(c);
751
d39079fc 752 /* /etc/hostname has the highest preference ... */
af9c45d5
LP
753 if (c->data[PROP_STATIC_HOSTNAME_SUBSTITUTED_WILDCARDS]) {
754 hn = c->data[PROP_STATIC_HOSTNAME_SUBSTITUTED_WILDCARDS];
60e4fb42 755 hns = HOSTNAME_STATIC;
c779a442 756
38b38500 757 /* ... the transient hostname, (ie: DHCP) comes next ... */
88a66cfb
JW
758 } else if (transient_hostname) {
759 hn = transient_hostname;
60e4fb42 760 hns = HOSTNAME_TRANSIENT;
7640a5de 761
c779a442 762 /* ... and the ultimate fallback */
60e4fb42 763 } else {
05c6f341
ZJS
764 hn = _hn_free = get_default_hostname();
765 if (!hn)
766 return log_oom();
767
8770c813 768 hns = HOSTNAME_DEFAULT;
60e4fb42 769 }
c779a442 770
7d9ec609
ZJS
771 r = sethostname_idempotent(hn);
772 if (r < 0)
60e4fb42
ZJS
773 return log_error_errno(r, "Failed to set hostname: %m");
774
775 if (c->hostname_source != hns) {
776 c->hostname_source = hns;
777 r = 1;
778 }
7640a5de 779
60e4fb42
ZJS
780 if (r == 0)
781 log_debug("Hostname was already set to <%s>.", hn);
782 else {
783 log_info("Hostname set to <%s> (%s)", hn, hostname_source_to_string(hns));
784
785 hostname_update_source_hint(hn, hns);
786 }
787
efda832d 788 return r; /* 0 if no change, 1 if something was done */
7640a5de
LP
789}
790
ba12e41d
YW
791static void unset_statp(struct stat **p) {
792 if (!*p)
793 return;
794
795 **p = (struct stat) {};
796}
797
66a4c743 798static int context_write_data_static_hostname(Context *c) {
ba12e41d
YW
799 _cleanup_(unset_statp) struct stat *s = NULL;
800 int r;
801
66a4c743
LP
802 assert(c);
803
ba12e41d
YW
804 /* Make sure that if we fail here, we invalidate the cached information, since it was updated
805 * already, even if we can't make it hit the disk. */
806 s = &c->etc_hostname_stat;
807
66a4c743 808 if (isempty(c->data[PROP_STATIC_HOSTNAME])) {
0dc39dff 809 if (unlink(etc_hostname()) < 0 && errno != ENOENT)
ba12e41d
YW
810 return -errno;
811
812 TAKE_PTR(s);
7640a5de
LP
813 return 0;
814 }
536970d4 815
0dc39dff 816 r = write_string_file(etc_hostname(), c->data[PROP_STATIC_HOSTNAME], WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL);
ba12e41d
YW
817 if (r < 0)
818 return r;
819
820 TAKE_PTR(s);
821 return 0;
7640a5de
LP
822}
823
f200e8bb 824static int context_write_data_machine_info(Context *c) {
ba12e41d 825 _cleanup_(unset_statp) struct stat *s = NULL;
7640a5de
LP
826 static const char * const name[_PROP_MAX] = {
827 [PROP_PRETTY_HOSTNAME] = "PRETTY_HOSTNAME",
7871c8e9 828 [PROP_ICON_NAME] = "ICON_NAME",
799298d6
JG
829 [PROP_CHASSIS] = "CHASSIS",
830 [PROP_DEPLOYMENT] = "DEPLOYMENT",
ce0f1493 831 [PROP_LOCATION] = "LOCATION",
7640a5de 832 };
0ccad099 833 _cleanup_strv_free_ char **l = NULL;
536970d4 834 int r;
7640a5de 835
66a4c743
LP
836 assert(c);
837
ba12e41d
YW
838 /* Make sure that if we fail here, we invalidate the cached information, since it was updated
839 * already, even if we can't make it hit the disk. */
840 s = &c->etc_machine_info_stat;
841
0dc39dff 842 r = load_env_file(NULL, etc_machine_info(), &l);
7640a5de
LP
843 if (r < 0 && r != -ENOENT)
844 return r;
845
2af3cad0 846 for (HostProperty p = PROP_PRETTY_HOSTNAME; p <= PROP_LOCATION; p++) {
7640a5de
LP
847 assert(name[p]);
848
f08231fe
ZJS
849 r = strv_env_assign(&l, name[p], empty_to_null(c->data[p]));
850 if (r < 0)
851 return r;
7640a5de
LP
852 }
853
854 if (strv_isempty(l)) {
0dc39dff 855 if (unlink(etc_machine_info()) < 0 && errno != ENOENT)
ba12e41d 856 return -errno;
7640a5de 857
ba12e41d 858 TAKE_PTR(s);
7640a5de
LP
859 return 0;
860 }
861
3e5320e2
LP
862 r = write_env_file(
863 AT_FDCWD,
0dc39dff
VD
864 etc_machine_info(),
865 /* headers= */NULL,
3e5320e2
LP
866 l,
867 WRITE_ENV_FILE_LABEL);
ba12e41d
YW
868 if (r < 0)
869 return r;
870
871 TAKE_PTR(s);
872 return 0;
7640a5de
LP
873}
874
4fc7e4f3
YW
875static int property_get_hardware_property(
876 sd_bus_message *reply,
877 Context *c,
878 HostProperty prop,
c1507748 879 int (*getter)(Context *c, char **ret)) {
4fc7e4f3
YW
880
881 _cleanup_free_ char *from_dmi = NULL;
882
883 assert(reply);
884 assert(c);
79e9fb68 885 assert(IN_SET(prop, PROP_HARDWARE_VENDOR, PROP_HARDWARE_MODEL,
29a352e8 886 PROP_HARDWARE_SKU, PROP_HARDWARE_VERSION));
4fc7e4f3
YW
887 assert(getter);
888
889 context_read_machine_info(c);
890
891 if (isempty(c->data[prop]))
c1507748 892 (void) getter(c, &from_dmi);
4fc7e4f3
YW
893
894 return sd_bus_message_append(reply, "s", from_dmi ?: c->data[prop]);
895}
896
b9d80698
FB
897static int property_get_hardware_vendor(
898 sd_bus *bus,
899 const char *path,
900 const char *interface,
901 const char *property,
902 sd_bus_message *reply,
903 void *userdata,
904 sd_bus_error *error) {
b9d80698 905
0924ea2b 906 return property_get_hardware_property(reply, userdata, PROP_HARDWARE_VENDOR, get_hardware_vendor);
b9d80698
FB
907}
908
909static int property_get_hardware_model(
910 sd_bus *bus,
911 const char *path,
912 const char *interface,
913 const char *property,
914 sd_bus_message *reply,
915 void *userdata,
916 sd_bus_error *error) {
b9d80698 917
0924ea2b 918 return property_get_hardware_property(reply, userdata, PROP_HARDWARE_MODEL, get_hardware_model);
b9d80698
FB
919}
920
79e9fb68
SH
921static int property_get_hardware_sku(
922 sd_bus *bus,
923 const char *path,
924 const char *interface,
925 const char *property,
926 sd_bus_message *reply,
927 void *userdata,
928 sd_bus_error *error) {
929
930 return property_get_hardware_property(reply, userdata, PROP_HARDWARE_SKU, get_hardware_sku);
931}
932
29a352e8
SH
933static int property_get_hardware_version(
934 sd_bus *bus,
935 const char *path,
936 const char *interface,
937 const char *property,
938 sd_bus_message *reply,
939 void *userdata,
940 sd_bus_error *error) {
941
942 return property_get_hardware_property(reply, userdata, PROP_HARDWARE_VERSION, get_hardware_version);
943}
944
c52950c2
SS
945static int property_get_firmware_version(
946 sd_bus *bus,
947 const char *path,
948 const char *interface,
949 const char *property,
950 sd_bus_message *reply,
951 void *userdata,
952 sd_bus_error *error) {
953
954 _cleanup_free_ char *firmware_version = NULL;
c1507748 955 Context *c = ASSERT_PTR(userdata);
c52950c2 956
c1507748 957 (void) get_firmware_version(c, &firmware_version);
c52950c2
SS
958
959 return sd_bus_message_append(reply, "s", firmware_version);
960}
961
f233bbd6
JW
962static int property_get_firmware_vendor(
963 sd_bus *bus,
964 const char *path,
965 const char *interface,
966 const char *property,
967 sd_bus_message *reply,
968 void *userdata,
969 sd_bus_error *error) {
970
971 _cleanup_free_ char *firmware_vendor = NULL;
c1507748 972 Context *c = ASSERT_PTR(userdata);
f233bbd6 973
c1507748 974 (void) get_firmware_vendor(c, &firmware_vendor);
f233bbd6
JW
975
976 return sd_bus_message_append(reply, "s", firmware_vendor);
977}
978
ff4d26df
JW
979static int property_get_firmware_date(
980 sd_bus *bus,
981 const char *path,
982 const char *interface,
983 const char *property,
984 sd_bus_message *reply,
985 void *userdata,
986 sd_bus_error *error) {
987
ad8858c1 988 usec_t firmware_date = USEC_INFINITY;
c1507748 989 Context *c = ASSERT_PTR(userdata);
ff4d26df 990
c1507748 991 (void) get_firmware_date(c, &firmware_date);
ff4d26df 992
ad8858c1 993 return sd_bus_message_append(reply, "t", firmware_date);
ff4d26df 994}
7e638ccf
JW
995
996static int property_get_chassis_asset_tag(
997 sd_bus *bus,
998 const char *path,
999 const char *interface,
1000 const char *property,
1001 sd_bus_message *reply,
1002 void *userdata,
1003 sd_bus_error *error) {
1004
1005 _cleanup_free_ char *chassis_asset_tag = NULL;
1006 Context *c = ASSERT_PTR(userdata);
1007
1008 (void) get_chassis_asset_tag(c, &chassis_asset_tag);
1009
1010 return sd_bus_message_append(reply, "s", chassis_asset_tag);
1011}
1012
aa994368
LP
1013static int property_get_hostname(
1014 sd_bus *bus,
1015 const char *path,
1016 const char *interface,
1017 const char *property,
1018 sd_bus_message *reply,
1019 void *userdata,
1020 sd_bus_error *error) {
1021
05c6f341 1022 _cleanup_free_ char *hn = NULL;
aa994368
LP
1023 int r;
1024
05c6f341
ZJS
1025 r = gethostname_strict(&hn);
1026 if (r < 0) {
1027 if (r != -ENXIO)
1028 return r;
aa994368 1029
05c6f341
ZJS
1030 hn = get_default_hostname();
1031 if (!hn)
1032 return -ENOMEM;
1033 }
1034
1035 return sd_bus_message_append(reply, "s", hn);
aa994368
LP
1036}
1037
d7f4ad20
LP
1038static int property_get_static_hostname(
1039 sd_bus *bus,
1040 const char *path,
1041 const char *interface,
1042 const char *property,
1043 sd_bus_message *reply,
1044 void *userdata,
1045 sd_bus_error *error) {
1046
99534007 1047 Context *c = ASSERT_PTR(userdata);
d7f4ad20
LP
1048
1049 context_read_etc_hostname(c);
1050
af9c45d5 1051 return sd_bus_message_append(reply, "s", c->data[PROP_STATIC_HOSTNAME_SUBSTITUTED_WILDCARDS]);
d7f4ad20
LP
1052}
1053
8770c813 1054static int property_get_default_hostname(
05c6f341
ZJS
1055 sd_bus *bus,
1056 const char *path,
1057 const char *interface,
1058 const char *property,
1059 sd_bus_message *reply,
1060 void *userdata,
1061 sd_bus_error *error) {
1062
61d44b6b
LP
1063 _cleanup_free_ char *hn = NULL;
1064
1065 hn = get_default_hostname();
05c6f341
ZJS
1066 if (!hn)
1067 return log_oom();
1068
1069 return sd_bus_message_append(reply, "s", hn);
1070}
ce6b138c 1071
f2a434a5 1072static void context_determine_hostname_source(Context *c) {
0995accd 1073 _cleanup_free_ char *hostname = NULL;
f2a434a5
LP
1074 int r;
1075
1076 assert(c);
1077
1078 if (c->hostname_source >= 0)
1079 return;
1080
0995accd 1081 (void) gethostname_full(GET_HOSTNAME_ALLOW_LOCALHOST, &hostname);
f2a434a5 1082
af9c45d5 1083 if (streq_ptr(hostname, c->data[PROP_STATIC_HOSTNAME_SUBSTITUTED_WILDCARDS]))
f2a434a5
LP
1084 c->hostname_source = HOSTNAME_STATIC;
1085 else {
0995accd
YW
1086 _cleanup_free_ char *fallback = NULL;
1087
f2a434a5
LP
1088 /* If the hostname was not set by us, try to figure out where it came from. If we set it to
1089 * the default hostname, the file will tell us. We compare the string because it is possible
32e27670
LP
1090 * that the hostname was set by an older version that had a different fallback, in the initrd
1091 * or before we reexecuted. */
f2a434a5
LP
1092
1093 r = read_one_line_file("/run/systemd/default-hostname", &fallback);
1094 if (r < 0 && r != -ENOENT)
1095 log_warning_errno(r, "Failed to read /run/systemd/default-hostname, ignoring: %m");
1096
1097 if (streq_ptr(fallback, hostname))
1098 c->hostname_source = HOSTNAME_DEFAULT;
1099 else
1100 c->hostname_source = HOSTNAME_TRANSIENT;
1101 }
1102}
1103
60e4fb42
ZJS
1104static int property_get_hostname_source(
1105 sd_bus *bus,
1106 const char *path,
1107 const char *interface,
1108 const char *property,
1109 sd_bus_message *reply,
1110 void *userdata,
1111 sd_bus_error *error) {
1112
99534007 1113 Context *c = ASSERT_PTR(userdata);
60e4fb42
ZJS
1114
1115 context_read_etc_hostname(c);
f2a434a5 1116 context_determine_hostname_source(c);
60e4fb42
ZJS
1117
1118 return sd_bus_message_append(reply, "s", hostname_source_to_string(c->hostname_source));
1119}
1120
d7f4ad20
LP
1121static int property_get_machine_info_field(
1122 sd_bus *bus,
1123 const char *path,
1124 const char *interface,
1125 const char *property,
1126 sd_bus_message *reply,
1127 void *userdata,
1128 sd_bus_error *error) {
1129
1130 sd_bus_slot *slot;
1131 Context *c;
1132
1133 /* Acquire the context object without this property's userdata offset added. Explanation: we want
1134 * access to two pointers here: a) the main context object we cache all properties in, and b) the
1135 * pointer to the property field inside the context object that we are supposed to update and
1136 * use. The latter (b) we get in the 'userdata' function parameter, and sd-bus calculates that for us
1137 * from the 'userdata' pointer we supplied when the vtable was registered, with the offset we
1138 * specified in the vtable added on top. To get the former (a) we need the 'userdata' pointer from
1139 * the vtable registration directly, without the offset added. Hence we ask sd-bus what the slot
1140 * object is (which encapsulates the vtable registration), and then query the 'userdata' field
1141 * directly off it. */
1142 assert_se(slot = sd_bus_get_current_slot(bus));
1143 assert_se(c = sd_bus_slot_get_userdata(slot));
1144
1145 context_read_machine_info(c);
1146
1147 return sd_bus_message_append(reply, "s", *(char**) userdata);
1148}
1149
1150static int property_get_os_release_field(
1151 sd_bus *bus,
1152 const char *path,
1153 const char *interface,
1154 const char *property,
1155 sd_bus_message *reply,
1156 void *userdata,
1157 sd_bus_error *error) {
1158
1159 sd_bus_slot *slot;
1160 Context *c;
1161
1162 /* As above, acquire the current context without this property's userdata offset added. */
1163 assert_se(slot = sd_bus_get_current_slot(bus));
1164 assert_se(c = sd_bus_slot_get_userdata(slot));
1165
1166 context_read_os_release(c);
1167
1168 return sd_bus_message_append(reply, "s", *(char**) userdata);
1169}
1170
b563d5ce
LP
1171static int property_get_os_support_end(
1172 sd_bus *bus,
1173 const char *path,
1174 const char *interface,
1175 const char *property,
1176 sd_bus_message *reply,
1177 void *userdata,
1178 sd_bus_error *error) {
1179
1180 Context *c = userdata;
1181 usec_t eol = USEC_INFINITY;
1182
1183 context_read_os_release(c);
1184
1185 if (c->data[PROP_OS_SUPPORT_END])
1186 (void) os_release_support_ended(c->data[PROP_OS_SUPPORT_END], /* quiet= */ false, &eol);
1187
1188 return sd_bus_message_append(reply, "t", eol);
1189}
1190
66a4c743
LP
1191static int property_get_icon_name(
1192 sd_bus *bus,
1193 const char *path,
1194 const char *interface,
1195 const char *property,
1196 sd_bus_message *reply,
ebcf1f97
LP
1197 void *userdata,
1198 sd_bus_error *error) {
7640a5de 1199
66a4c743
LP
1200 _cleanup_free_ char *n = NULL;
1201 Context *c = userdata;
1202 const char *name;
7640a5de 1203
d7f4ad20
LP
1204 context_read_machine_info(c);
1205
66a4c743
LP
1206 if (isempty(c->data[PROP_ICON_NAME]))
1207 name = n = context_fallback_icon_name(c);
7640a5de 1208 else
66a4c743
LP
1209 name = c->data[PROP_ICON_NAME];
1210
1211 if (!name)
1212 return -ENOMEM;
7640a5de 1213
ebcf1f97 1214 return sd_bus_message_append(reply, "s", name);
7640a5de
LP
1215}
1216
66a4c743
LP
1217static int property_get_chassis(
1218 sd_bus *bus,
1219 const char *path,
1220 const char *interface,
1221 const char *property,
1222 sd_bus_message *reply,
ebcf1f97
LP
1223 void *userdata,
1224 sd_bus_error *error) {
7871c8e9 1225
8c8b1800 1226 _cleanup_free_ char *chassis = NULL;
66a4c743 1227 Context *c = userdata;
7871c8e9 1228
d7f4ad20
LP
1229 context_read_machine_info(c);
1230
8c8b1800 1231 chassis = context_get_chassis(c);
7871c8e9 1232
8c8b1800 1233 return sd_bus_message_append(reply, "s", chassis);
7871c8e9
LP
1234}
1235
72f48cd3
LP
1236static int property_get_uname_field(
1237 sd_bus *bus,
1238 const char *path,
1239 const char *interface,
1240 const char *property,
1241 sd_bus_message *reply,
1242 void *userdata,
1243 sd_bus_error *error) {
1244
1245 struct utsname u;
1246
1247 assert_se(uname(&u) >= 0);
1248
1249 return sd_bus_message_append(reply, "s", (char*) &u + PTR_TO_SIZE(userdata));
1250}
1251
5db7eb21
YW
1252static int property_get_machine_id(
1253 sd_bus *bus,
1254 const char *path,
1255 const char *interface,
1256 const char *property,
1257 sd_bus_message *reply,
1258 void *userdata,
1259 sd_bus_error *error) {
1260
1261 sd_id128_t id;
1262 int r;
1263
1264 r = sd_id128_get_machine(&id);
1265 if (r < 0)
1266 return r;
1267
1268 return bus_property_get_id128(bus, path, interface, property, reply, &id, error);
1269}
1270
1271static int property_get_boot_id(
1272 sd_bus *bus,
1273 const char *path,
1274 const char *interface,
1275 const char *property,
1276 sd_bus_message *reply,
1277 void *userdata,
1278 sd_bus_error *error) {
1279
1280 sd_id128_t id;
1281 int r;
1282
1283 r = sd_id128_get_boot(&id);
1284 if (r < 0)
1285 return r;
1286
1287 return bus_property_get_id128(bus, path, interface, property, reply, &id, error);
1288}
1289
19b8e712
LP
1290static int property_get_vsock_cid(
1291 sd_bus *bus,
1292 const char *path,
1293 const char *interface,
1294 const char *property,
1295 sd_bus_message *reply,
1296 void *userdata,
1297 sd_bus_error *error) {
1298
1299 unsigned local_cid = VMADDR_CID_ANY;
1300
1301 (void) vsock_get_local_cid(&local_cid);
1302
1303 return sd_bus_message_append(reply, "u", (uint32_t) local_cid);
1304}
1305
af9c45d5
LP
1306static int validate_and_substitute_hostname(const char *name, char **ret_substituted, sd_bus_error *error) {
1307 int r;
1308
1309 assert(ret_substituted);
1310
1311 if (!name) {
1312 *ret_substituted = NULL;
1313 return 0;
1314 }
1315
1316 _cleanup_free_ char *substituted = strdup(name);
1317 if (!substituted)
1318 return log_oom();
1319
1320 r = hostname_substitute_wildcards(substituted);
1321 if (r < 0)
1f5d8a61 1322 return log_error_errno(r, "Failed to substitute wildcards in hostname: %m");
af9c45d5
LP
1323
1324 if (!hostname_is_valid(substituted, 0))
1325 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", name);
1326
1327 *ret_substituted = TAKE_PTR(substituted);
1328 return 1;
1329}
1330
19070062 1331static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
99534007 1332 Context *c = ASSERT_PTR(userdata);
66a4c743 1333 const char *name;
aa994368 1334 int interactive, r;
d200735e 1335
19070062 1336 assert(m);
19070062 1337
66a4c743
LP
1338 r = sd_bus_message_read(m, "sb", &name, &interactive);
1339 if (r < 0)
ebcf1f97 1340 return r;
d200735e 1341
60e4fb42 1342 name = empty_to_null(name);
7640a5de 1343
60e4fb42
ZJS
1344 /* We always go through with the procedure below without comparing to the current hostname, because
1345 * we might want to adjust hostname source information even if the actual hostname is unchanged. */
7640a5de 1346
af9c45d5
LP
1347 _cleanup_free_ char *substituted = NULL;
1348 r = validate_and_substitute_hostname(name, &substituted, error);
1349 if (r < 0)
1350 return r;
7640a5de 1351
af9c45d5 1352 name = substituted;
7640a5de 1353
7b36fb9f 1354 r = bus_verify_polkit_async_full(
c529695e 1355 m,
c529695e 1356 "org.freedesktop.hostname1.set-hostname",
7b36fb9f 1357 /* details= */ NULL,
7b36fb9f 1358 /* good_user= */ UID_INVALID,
29556b75 1359 interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
c529695e
LP
1360 &c->polkit_registry,
1361 error);
66a4c743 1362 if (r < 0)
ebcf1f97 1363 return r;
66a4c743
LP
1364 if (r == 0)
1365 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7640a5de 1366
af9c45d5
LP
1367 context_read_etc_hostname(c);
1368
aa994368 1369 r = context_update_kernel_hostname(c, name);
60e4fb42 1370 if (r < 0)
1b4cd646 1371 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
60e4fb42 1372 else if (r > 0)
efda832d
ZJS
1373 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m),
1374 "/org/freedesktop/hostname1", "org.freedesktop.hostname1",
1375 "Hostname", "HostnameSource", NULL);
7640a5de 1376
df2d202e 1377 return sd_bus_reply_method_return(m, NULL);
66a4c743 1378}
7640a5de 1379
19070062 1380static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
99534007 1381 Context *c = ASSERT_PTR(userdata);
66a4c743 1382 const char *name;
af9c45d5 1383 int interactive, r;
7640a5de 1384
19070062 1385 assert(m);
19070062 1386
66a4c743
LP
1387 r = sd_bus_message_read(m, "sb", &name, &interactive);
1388 if (r < 0)
ebcf1f97 1389 return r;
7640a5de 1390
3c6f7c34 1391 name = empty_to_null(name);
7640a5de 1392
d7f4ad20
LP
1393 context_read_etc_hostname(c);
1394
66a4c743 1395 if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME]))
df2d202e 1396 return sd_bus_reply_method_return(m, NULL);
7640a5de 1397
af9c45d5
LP
1398 _cleanup_free_ char *substituted = NULL;
1399 r = validate_and_substitute_hostname(name, &substituted, error);
1400 if (r < 0)
1401 return r;
c650f207 1402
7b36fb9f 1403 r = bus_verify_polkit_async_full(
c529695e 1404 m,
c529695e 1405 "org.freedesktop.hostname1.set-static-hostname",
7b36fb9f 1406 /* details= */ NULL,
7b36fb9f 1407 /* good_user= */ UID_INVALID,
29556b75 1408 interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
c529695e
LP
1409 &c->polkit_registry,
1410 error);
66a4c743 1411 if (r < 0)
ebcf1f97 1412 return r;
66a4c743
LP
1413 if (r == 0)
1414 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7640a5de 1415
e8acf091 1416 r = free_and_strdup_warn(&c->data[PROP_STATIC_HOSTNAME], name);
c650f207
YW
1417 if (r < 0)
1418 return r;
7640a5de 1419
af9c45d5
LP
1420 free_and_replace(c->data[PROP_STATIC_HOSTNAME_SUBSTITUTED_WILDCARDS], substituted);
1421
66a4c743
LP
1422 r = context_write_data_static_hostname(c);
1423 if (r < 0) {
38b38500 1424 log_error_errno(r, "Failed to write static hostname: %m");
957991b7
YW
1425 if (ERRNO_IS_PRIVILEGE(r))
1426 return sd_bus_error_set(error, BUS_ERROR_FILE_IS_PROTECTED, "Not allowed to update /etc/hostname.");
1427 if (r == -EROFS)
1428 return sd_bus_error_set(error, BUS_ERROR_READ_ONLY_FILESYSTEM, "/etc/hostname is in a read-only filesystem.");
1b4cd646 1429 return sd_bus_error_set_errnof(error, r, "Failed to set static hostname: %m");
66a4c743 1430 }
7640a5de 1431
af9c45d5 1432 r = context_update_kernel_hostname(c, /* transient_hostname= */ NULL);
60e4fb42
ZJS
1433 if (r < 0) {
1434 log_error_errno(r, "Failed to set hostname: %m");
1435 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
1436 }
7640a5de 1437
efda832d 1438 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m),
60e4fb42
ZJS
1439 "/org/freedesktop/hostname1", "org.freedesktop.hostname1",
1440 "StaticHostname", "Hostname", "HostnameSource", NULL);
7640a5de 1441
df2d202e 1442 return sd_bus_reply_method_return(m, NULL);
66a4c743 1443}
7640a5de 1444
19070062 1445static int set_machine_info(Context *c, sd_bus_message *m, int prop, sd_bus_message_handler_t cb, sd_bus_error *error) {
102d8f81 1446 int interactive;
66a4c743
LP
1447 const char *name;
1448 int r;
1449
1450 assert(c);
66a4c743
LP
1451 assert(m);
1452
1453 r = sd_bus_message_read(m, "sb", &name, &interactive);
1454 if (r < 0)
ebcf1f97 1455 return r;
66a4c743 1456
3c6f7c34 1457 name = empty_to_null(name);
66a4c743 1458
d7f4ad20
LP
1459 context_read_machine_info(c);
1460
66a4c743 1461 if (streq_ptr(name, c->data[prop]))
df2d202e 1462 return sd_bus_reply_method_return(m, NULL);
7640a5de 1463
c650f207
YW
1464 if (!isempty(name)) {
1465 /* The icon name might ultimately be used as file
1466 * name, so better be safe than sorry */
1467
1468 if (prop == PROP_ICON_NAME && !filename_is_valid(name))
1469 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid icon name '%s'", name);
1470 if (prop == PROP_PRETTY_HOSTNAME && string_has_cc(name, NULL))
38b38500 1471 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty hostname '%s'", name);
c650f207
YW
1472 if (prop == PROP_CHASSIS && !valid_chassis(name))
1473 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid chassis '%s'", name);
1474 if (prop == PROP_DEPLOYMENT && !valid_deployment(name))
1475 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid deployment '%s'", name);
1476 if (prop == PROP_LOCATION && string_has_cc(name, NULL))
1477 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid location '%s'", name);
1478 }
1479
7b36fb9f
LP
1480 /* Since the pretty hostname should always be changed at the same time as the static one, use the
1481 * same policy action for both... */
66a4c743 1482
7b36fb9f 1483 r = bus_verify_polkit_async_full(
c529695e 1484 m,
c529695e 1485 prop == PROP_PRETTY_HOSTNAME ? "org.freedesktop.hostname1.set-static-hostname" : "org.freedesktop.hostname1.set-machine-info",
7b36fb9f 1486 /* details= */ NULL,
7b36fb9f 1487 /* good_user= */ UID_INVALID,
29556b75 1488 interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
c529695e
LP
1489 &c->polkit_registry,
1490 error);
66a4c743 1491 if (r < 0)
ebcf1f97 1492 return r;
66a4c743
LP
1493 if (r == 0)
1494 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1495
e8acf091 1496 r = free_and_strdup_warn(&c->data[prop], name);
c650f207
YW
1497 if (r < 0)
1498 return r;
7640a5de 1499
f200e8bb 1500 r = context_write_data_machine_info(c);
66a4c743 1501 if (r < 0) {
da927ba9 1502 log_error_errno(r, "Failed to write machine info: %m");
957991b7
YW
1503 if (ERRNO_IS_PRIVILEGE(r))
1504 return sd_bus_error_set(error, BUS_ERROR_FILE_IS_PROTECTED, "Not allowed to update /etc/machine-info.");
1505 if (r == -EROFS)
1506 return sd_bus_error_set(error, BUS_ERROR_READ_ONLY_FILESYSTEM, "/etc/machine-info is in a read-only filesystem.");
1b4cd646 1507 return sd_bus_error_set_errnof(error, r, "Failed to write machine info: %m");
66a4c743 1508 }
7640a5de 1509
66a4c743 1510 log_info("Changed %s to '%s'",
38b38500 1511 prop == PROP_PRETTY_HOSTNAME ? "pretty hostname" :
799298d6 1512 prop == PROP_DEPLOYMENT ? "deployment" :
ce0f1493 1513 prop == PROP_LOCATION ? "location" :
66a4c743 1514 prop == PROP_CHASSIS ? "chassis" : "icon name", strna(c->data[prop]));
7640a5de 1515
19070062
LP
1516 (void) sd_bus_emit_properties_changed(
1517 sd_bus_message_get_bus(m),
1518 "/org/freedesktop/hostname1",
1519 "org.freedesktop.hostname1",
1520 prop == PROP_PRETTY_HOSTNAME ? "PrettyHostname" :
1521 prop == PROP_DEPLOYMENT ? "Deployment" :
1522 prop == PROP_LOCATION ? "Location" :
1523 prop == PROP_CHASSIS ? "Chassis" : "IconName" , NULL);
7640a5de 1524
df2d202e 1525 return sd_bus_reply_method_return(m, NULL);
66a4c743 1526}
7640a5de 1527
19070062
LP
1528static int method_set_pretty_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1529 return set_machine_info(userdata, m, PROP_PRETTY_HOSTNAME, method_set_pretty_hostname, error);
7640a5de
LP
1530}
1531
19070062
LP
1532static int method_set_icon_name(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1533 return set_machine_info(userdata, m, PROP_ICON_NAME, method_set_icon_name, error);
66a4c743
LP
1534}
1535
19070062
LP
1536static int method_set_chassis(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1537 return set_machine_info(userdata, m, PROP_CHASSIS, method_set_chassis, error);
66a4c743
LP
1538}
1539
19070062
LP
1540static int method_set_deployment(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1541 return set_machine_info(userdata, m, PROP_DEPLOYMENT, method_set_deployment, error);
799298d6
JG
1542}
1543
19070062
LP
1544static int method_set_location(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1545 return set_machine_info(userdata, m, PROP_LOCATION, method_set_location, error);
ce0f1493
LP
1546}
1547
21e627da
YW
1548static int method_get_product_uuid(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1549 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
99534007 1550 Context *c = ASSERT_PTR(userdata);
21e627da 1551 int interactive, r;
5704cd73 1552 sd_id128_t uuid;
21e627da
YW
1553
1554 assert(m);
21e627da 1555
21e627da
YW
1556 r = sd_bus_message_read(m, "b", &interactive);
1557 if (r < 0)
1558 return r;
1559
7b36fb9f 1560 r = bus_verify_polkit_async_full(
21e627da 1561 m,
21e627da 1562 "org.freedesktop.hostname1.get-product-uuid",
7b36fb9f 1563 /* details= */ NULL,
7b36fb9f 1564 /* good_user= */ UID_INVALID,
29556b75 1565 interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
21e627da
YW
1566 &c->polkit_registry,
1567 error);
1568 if (r < 0)
1569 return r;
1570 if (r == 0)
1571 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1572
66ee2298
LP
1573 r = id128_get_product(&uuid);
1574 if (r < 0) {
1575 if (r == -EADDRNOTAVAIL)
1576 log_debug_errno(r, "DMI product UUID is all 0x00 or all 0xFF, ignoring.");
1577 else
1578 log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
1579 "Failed to read product UUID, ignoring: %m");
1580
1581 return sd_bus_error_set(error, BUS_ERROR_NO_PRODUCT_UUID,
1582 "Failed to read product UUID from firmware.");
1583 }
1584
21e627da
YW
1585 r = sd_bus_message_new_method_return(m, &reply);
1586 if (r < 0)
1587 return r;
1588
c52e295d 1589 r = sd_bus_message_append_array(reply, 'y', uuid.bytes, sizeof(uuid.bytes));
21e627da
YW
1590 if (r < 0)
1591 return r;
1592
51cc3825 1593 return sd_bus_message_send(reply);
21e627da
YW
1594}
1595
96976629 1596static int method_get_hardware_serial(sd_bus_message *m, void *userdata, sd_bus_error *error) {
96976629 1597 _cleanup_free_ char *serial = NULL;
99534007 1598 Context *c = ASSERT_PTR(userdata);
ff28d259 1599 int r;
96976629
YW
1600
1601 assert(m);
96976629 1602
96976629
YW
1603 r = bus_verify_polkit_async(
1604 m,
96976629 1605 "org.freedesktop.hostname1.get-hardware-serial",
7b36fb9f 1606 /* details= */ NULL,
96976629
YW
1607 &c->polkit_registry,
1608 error);
1609 if (r < 0)
1610 return r;
1611 if (r == 0)
1612 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1613
c1507748 1614 r = get_hardware_serial(c, &serial);
96976629 1615 if (r < 0)
171ddae1
LP
1616 return sd_bus_error_set(error, BUS_ERROR_NO_HARDWARE_SERIAL,
1617 "Failed to read hardware serial from firmware.");
96976629 1618
26d1c5b9 1619 return sd_bus_reply_method_return(m, "s", serial);
96976629
YW
1620}
1621
309a747f 1622static int build_describe_response(Context *c, bool privileged, sd_json_variant **ret) {
0a6598bb 1623 _cleanup_free_ char *hn = NULL, *dhn = NULL, *in = NULL,
f233bbd6 1624 *chassis = NULL, *vendor = NULL, *model = NULL, *serial = NULL, *firmware_version = NULL,
29a352e8 1625 *firmware_vendor = NULL, *chassis_asset_tag = NULL, *sku = NULL, *hardware_version = NULL;
db21c2ec 1626 _cleanup_strv_free_ char **os_release_pairs = NULL, **machine_info_pairs = NULL;
b563d5ce 1627 usec_t firmware_date = USEC_INFINITY, eol = USEC_INFINITY;
309a747f 1628 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
5db7eb21 1629 sd_id128_t machine_id, boot_id, product_uuid = SD_ID128_NULL;
19b8e712 1630 unsigned local_cid = VMADDR_CID_ANY;
7ecead8f
LP
1631 struct utsname u;
1632 int r;
1633
0a6598bb
LP
1634 assert(c);
1635 assert(ret);
7ecead8f
LP
1636
1637 context_read_etc_hostname(c);
1638 context_read_machine_info(c);
1639 context_read_os_release(c);
1640 context_determine_hostname_source(c);
1641
7ecead8f
LP
1642 dhn = get_default_hostname();
1643 if (!dhn)
1644 return log_oom();
1645
af9c45d5
LP
1646 r = gethostname_strict(&hn);
1647 if (r < 0 && r != -ENXIO)
1648 return log_error_errno(r, "Failed to read local host name: %m");
1649
7ecead8f
LP
1650 if (isempty(c->data[PROP_ICON_NAME]))
1651 in = context_fallback_icon_name(c);
1652
8c8b1800 1653 chassis = context_get_chassis(c);
7ecead8f
LP
1654
1655 assert_se(uname(&u) >= 0);
1656
0924ea2b 1657 if (isempty(c->data[PROP_HARDWARE_VENDOR]))
c1507748 1658 (void) get_hardware_vendor(c, &vendor);
0924ea2b 1659 if (isempty(c->data[PROP_HARDWARE_MODEL]))
c1507748 1660 (void) get_hardware_model(c, &model);
79e9fb68
SH
1661 if (isempty(c->data[PROP_HARDWARE_SKU]))
1662 (void) get_hardware_sku(c, &sku);
29a352e8
SH
1663 if (isempty(c->data[PROP_HARDWARE_VERSION]))
1664 (void) get_hardware_version(c, &hardware_version);
7ecead8f 1665
96976629
YW
1666 if (privileged) {
1667 /* The product UUID and hardware serial is only available to privileged clients */
1668 (void) id128_get_product(&product_uuid);
c1507748 1669 (void) get_hardware_serial(c, &serial);
96976629 1670 }
c1507748
YW
1671 (void) get_firmware_version(c, &firmware_version);
1672 (void) get_firmware_vendor(c, &firmware_vendor);
1673 (void) get_firmware_date(c, &firmware_date);
7e638ccf 1674 (void) get_chassis_asset_tag(c, &chassis_asset_tag);
7ecead8f 1675
b563d5ce
LP
1676 if (c->data[PROP_OS_SUPPORT_END])
1677 (void) os_release_support_ended(c->data[PROP_OS_SUPPORT_END], /* quiet= */ false, &eol);
1678
5db7eb21
YW
1679 r = sd_id128_get_machine(&machine_id);
1680 if (r < 0)
1681 return log_error_errno(r, "Failed to get machine ID: %m");
1682
1683 r = sd_id128_get_boot(&boot_id);
1684 if (r < 0)
1685 return log_error_errno(r, "Failed to get boot ID: %m");
1686
19b8e712
LP
1687 (void) vsock_get_local_cid(&local_cid);
1688
db21c2ec 1689 (void) load_os_release_pairs(/* root= */ NULL, &os_release_pairs);
0dc39dff 1690 (void) load_env_file_pairs(/* f=*/ NULL, etc_machine_info(), &machine_info_pairs);
db21c2ec 1691
be5bee2a
LP
1692 r = sd_json_buildo(
1693 &v,
af9c45d5
LP
1694 SD_JSON_BUILD_PAIR_STRING("Hostname", hn ?: dhn),
1695 SD_JSON_BUILD_PAIR_STRING("StaticHostname", c->data[PROP_STATIC_HOSTNAME_SUBSTITUTED_WILDCARDS]),
d0f6d705
JW
1696 SD_JSON_BUILD_PAIR_STRING("PrettyHostname", c->data[PROP_PRETTY_HOSTNAME]),
1697 SD_JSON_BUILD_PAIR_STRING("DefaultHostname", dhn),
1698 SD_JSON_BUILD_PAIR_STRING("HostnameSource", hostname_source_to_string(c->hostname_source)),
1699 SD_JSON_BUILD_PAIR_STRING("IconName", in ?: c->data[PROP_ICON_NAME]),
1700 SD_JSON_BUILD_PAIR_STRING("Chassis", chassis),
7e638ccf 1701 SD_JSON_BUILD_PAIR_STRING("ChassisAssetTag", chassis_asset_tag),
d0f6d705
JW
1702 SD_JSON_BUILD_PAIR_STRING("Deployment", c->data[PROP_DEPLOYMENT]),
1703 SD_JSON_BUILD_PAIR_STRING("Location", c->data[PROP_LOCATION]),
1704 SD_JSON_BUILD_PAIR_STRING("KernelName", u.sysname),
1705 SD_JSON_BUILD_PAIR_STRING("KernelRelease", u.release),
1706 SD_JSON_BUILD_PAIR_STRING("KernelVersion", u.version),
1707 SD_JSON_BUILD_PAIR_STRING("OperatingSystemPrettyName", c->data[PROP_OS_PRETTY_NAME]),
1708 SD_JSON_BUILD_PAIR_STRING("OperatingSystemCPEName", c->data[PROP_OS_CPE_NAME]),
1709 SD_JSON_BUILD_PAIR_STRING("OperatingSystemHomeURL", c->data[PROP_OS_HOME_URL]),
be5bee2a
LP
1710 JSON_BUILD_PAIR_FINITE_USEC("OperatingSystemSupportEnd", eol),
1711 SD_JSON_BUILD_PAIR("OperatingSystemReleaseData", JSON_BUILD_STRV_ENV_PAIR(os_release_pairs)),
bc60034f
LP
1712 SD_JSON_BUILD_PAIR_STRING("OperatingSystemImageID", c->data[PROP_OS_IMAGE_ID]),
1713 SD_JSON_BUILD_PAIR_STRING("OperatingSystemImageVersion", c->data[PROP_OS_IMAGE_VERSION]),
be5bee2a 1714 SD_JSON_BUILD_PAIR("MachineInformationData", JSON_BUILD_STRV_ENV_PAIR(machine_info_pairs)),
d0f6d705
JW
1715 SD_JSON_BUILD_PAIR_STRING("HardwareVendor", vendor ?: c->data[PROP_HARDWARE_VENDOR]),
1716 SD_JSON_BUILD_PAIR_STRING("HardwareModel", model ?: c->data[PROP_HARDWARE_MODEL]),
1717 SD_JSON_BUILD_PAIR_STRING("HardwareSerial", serial),
79e9fb68 1718 SD_JSON_BUILD_PAIR_STRING("HardwareSKU", sku ?: c->data[PROP_HARDWARE_SKU]),
29a352e8 1719 SD_JSON_BUILD_PAIR_STRING("HardwareVersion", hardware_version ?: c->data[PROP_HARDWARE_VERSION]),
d0f6d705
JW
1720 SD_JSON_BUILD_PAIR_STRING("FirmwareVersion", firmware_version),
1721 SD_JSON_BUILD_PAIR_STRING("FirmwareVendor", firmware_vendor),
be5bee2a
LP
1722 JSON_BUILD_PAIR_FINITE_USEC("FirmwareDate", firmware_date),
1723 SD_JSON_BUILD_PAIR_ID128("MachineID", machine_id),
1724 SD_JSON_BUILD_PAIR_ID128("BootID", boot_id),
1725 SD_JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(product_uuid), "ProductUUID", SD_JSON_BUILD_ID128(product_uuid)),
1726 SD_JSON_BUILD_PAIR_CONDITION(sd_id128_is_null(product_uuid), "ProductUUID", SD_JSON_BUILD_NULL),
1727 SD_JSON_BUILD_PAIR_CONDITION(local_cid != VMADDR_CID_ANY, "VSockCID", SD_JSON_BUILD_UNSIGNED(local_cid)),
1728 SD_JSON_BUILD_PAIR_CONDITION(local_cid == VMADDR_CID_ANY, "VSockCID", SD_JSON_BUILD_NULL));
7ecead8f
LP
1729 if (r < 0)
1730 return log_error_errno(r, "Failed to build JSON data: %m");
1731
0a6598bb
LP
1732 *ret = TAKE_PTR(v);
1733 return 0;
1734}
1735
1736static int method_describe(sd_bus_message *m, void *userdata, sd_bus_error *error) {
309a747f 1737 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
0a6598bb
LP
1738 Context *c = ASSERT_PTR(userdata);
1739 _cleanup_free_ char *text = NULL;
1740 bool privileged;
1741 int r;
1742
1743 assert(m);
1744
1745 r = bus_verify_polkit_async(
1746 m,
1747 "org.freedesktop.hostname1.get-description",
1748 /* details= */ NULL,
1749 &c->polkit_registry,
1750 error);
1751 if (r == 0)
1752 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1753
1754 /* We ignore all authentication errors here, since most data is unprivileged, the one exception being
1755 * the product ID which we'll check explicitly. */
1756 privileged = r > 0;
1757
1758 r = build_describe_response(c, privileged, &v);
1759 if (r < 0)
1760 return r;
1761
309a747f 1762 r = sd_json_variant_format(v, 0, &text);
7ecead8f
LP
1763 if (r < 0)
1764 return log_error_errno(r, "Failed to format JSON data: %m");
1765
26d1c5b9 1766 return sd_bus_reply_method_return(m, "s", text);
7ecead8f
LP
1767}
1768
66a4c743
LP
1769static const sd_bus_vtable hostname_vtable[] = {
1770 SD_BUS_VTABLE_START(0),
aa994368 1771 SD_BUS_PROPERTY("Hostname", "s", property_get_hostname, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
d7f4ad20 1772 SD_BUS_PROPERTY("StaticHostname", "s", property_get_static_hostname, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
bc60034f 1773 SD_BUS_PROPERTY("PrettyHostname", "s", property_get_machine_info_field, offsetof(Context, data[PROP_PRETTY_HOSTNAME]), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
8770c813 1774 SD_BUS_PROPERTY("DefaultHostname", "s", property_get_default_hostname, 0, SD_BUS_VTABLE_PROPERTY_CONST),
60e4fb42 1775 SD_BUS_PROPERTY("HostnameSource", "s", property_get_hostname_source, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
66a4c743
LP
1776 SD_BUS_PROPERTY("IconName", "s", property_get_icon_name, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1777 SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
bc60034f
LP
1778 SD_BUS_PROPERTY("Deployment", "s", property_get_machine_info_field, offsetof(Context, data[PROP_DEPLOYMENT]), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1779 SD_BUS_PROPERTY("Location", "s", property_get_machine_info_field, offsetof(Context, data[PROP_LOCATION]), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
72f48cd3
LP
1780 SD_BUS_PROPERTY("KernelName", "s", property_get_uname_field, offsetof(struct utsname, sysname), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
1781 SD_BUS_PROPERTY("KernelRelease", "s", property_get_uname_field, offsetof(struct utsname, release), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
1782 SD_BUS_PROPERTY("KernelVersion", "s", property_get_uname_field, offsetof(struct utsname, version), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
bc60034f
LP
1783 SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", property_get_os_release_field, offsetof(Context, data[PROP_OS_PRETTY_NAME]), SD_BUS_VTABLE_PROPERTY_CONST),
1784 SD_BUS_PROPERTY("OperatingSystemCPEName", "s", property_get_os_release_field, offsetof(Context, data[PROP_OS_CPE_NAME]), SD_BUS_VTABLE_PROPERTY_CONST),
b563d5ce 1785 SD_BUS_PROPERTY("OperatingSystemSupportEnd", "t", property_get_os_support_end, 0, SD_BUS_VTABLE_PROPERTY_CONST),
bc60034f
LP
1786 SD_BUS_PROPERTY("HomeURL", "s", property_get_os_release_field, offsetof(Context, data[PROP_OS_HOME_URL]), SD_BUS_VTABLE_PROPERTY_CONST),
1787 SD_BUS_PROPERTY("OperatingSystemImageID", "s", property_get_os_release_field, offsetof(Context, data[PROP_OS_IMAGE_ID]), SD_BUS_VTABLE_PROPERTY_CONST),
1788 SD_BUS_PROPERTY("OperatingSystemImageVersion", "s", property_get_os_release_field, offsetof(Context, data[PROP_OS_IMAGE_VERSION]), SD_BUS_VTABLE_PROPERTY_CONST),
b9d80698
FB
1789 SD_BUS_PROPERTY("HardwareVendor", "s", property_get_hardware_vendor, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1790 SD_BUS_PROPERTY("HardwareModel", "s", property_get_hardware_model, 0, SD_BUS_VTABLE_PROPERTY_CONST),
79e9fb68 1791 SD_BUS_PROPERTY("HardwareSKU", "s", property_get_hardware_sku, 0, SD_BUS_VTABLE_PROPERTY_CONST),
29a352e8 1792 SD_BUS_PROPERTY("HardwareVersion", "s", property_get_hardware_version, 0, SD_BUS_VTABLE_PROPERTY_CONST),
c52950c2 1793 SD_BUS_PROPERTY("FirmwareVersion", "s", property_get_firmware_version, 0, SD_BUS_VTABLE_PROPERTY_CONST),
f233bbd6 1794 SD_BUS_PROPERTY("FirmwareVendor", "s", property_get_firmware_vendor, 0, SD_BUS_VTABLE_PROPERTY_CONST),
ad8858c1 1795 SD_BUS_PROPERTY("FirmwareDate", "t", property_get_firmware_date, 0, SD_BUS_VTABLE_PROPERTY_CONST),
5db7eb21
YW
1796 SD_BUS_PROPERTY("MachineID", "ay", property_get_machine_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1797 SD_BUS_PROPERTY("BootID", "ay", property_get_boot_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
19b8e712 1798 SD_BUS_PROPERTY("VSockCID", "u", property_get_vsock_cid, 0, SD_BUS_VTABLE_PROPERTY_CONST),
7e638ccf 1799 SD_BUS_PROPERTY("ChassisAssetTag", "s", property_get_chassis_asset_tag, 0, SD_BUS_VTABLE_PROPERTY_CONST),
106d79be 1800
92c9f47d
SS
1801 SD_BUS_METHOD_WITH_ARGS("SetHostname",
1802 SD_BUS_ARGS("s", hostname, "b", interactive),
1803 SD_BUS_NO_RESULT,
1804 method_set_hostname,
1805 SD_BUS_VTABLE_UNPRIVILEGED),
1806 SD_BUS_METHOD_WITH_ARGS("SetStaticHostname",
1807 SD_BUS_ARGS("s", hostname, "b", interactive),
1808 SD_BUS_NO_RESULT,
1809 method_set_static_hostname,
1810 SD_BUS_VTABLE_UNPRIVILEGED),
1811 SD_BUS_METHOD_WITH_ARGS("SetPrettyHostname",
1812 SD_BUS_ARGS("s", hostname, "b", interactive),
1813 SD_BUS_NO_RESULT,
1814 method_set_pretty_hostname,
1815 SD_BUS_VTABLE_UNPRIVILEGED),
1816 SD_BUS_METHOD_WITH_ARGS("SetIconName",
1817 SD_BUS_ARGS("s", icon, "b", interactive),
1818 SD_BUS_NO_RESULT,
1819 method_set_icon_name,
1820 SD_BUS_VTABLE_UNPRIVILEGED),
1821 SD_BUS_METHOD_WITH_ARGS("SetChassis",
1822 SD_BUS_ARGS("s", chassis, "b", interactive),
1823 SD_BUS_NO_RESULT,
1824 method_set_chassis,
1825 SD_BUS_VTABLE_UNPRIVILEGED),
1826 SD_BUS_METHOD_WITH_ARGS("SetDeployment",
1827 SD_BUS_ARGS("s", deployment, "b", interactive),
1828 SD_BUS_NO_RESULT,
1829 method_set_deployment,
1830 SD_BUS_VTABLE_UNPRIVILEGED),
1831 SD_BUS_METHOD_WITH_ARGS("SetLocation",
1832 SD_BUS_ARGS("s", location, "b", interactive),
1833 SD_BUS_NO_RESULT,
1834 method_set_location,
1835 SD_BUS_VTABLE_UNPRIVILEGED),
1836 SD_BUS_METHOD_WITH_ARGS("GetProductUUID",
1837 SD_BUS_ARGS("b", interactive),
1838 SD_BUS_RESULT("ay", uuid),
1839 method_get_product_uuid,
1840 SD_BUS_VTABLE_UNPRIVILEGED),
1841 SD_BUS_METHOD_WITH_ARGS("GetHardwareSerial",
1842 SD_BUS_NO_ARGS,
1843 SD_BUS_RESULT("s", serial),
1844 method_get_hardware_serial,
1845 SD_BUS_VTABLE_UNPRIVILEGED),
7ecead8f
LP
1846 SD_BUS_METHOD_WITH_ARGS("Describe",
1847 SD_BUS_NO_ARGS,
1848 SD_BUS_RESULT("s", json),
1849 method_describe,
1850 SD_BUS_VTABLE_UNPRIVILEGED),
106d79be 1851
66a4c743
LP
1852 SD_BUS_VTABLE_END,
1853};
1854
670139db
ZJS
1855static const BusObjectImplementation manager_object = {
1856 "/org/freedesktop/hostname1",
1857 "org.freedesktop.hostname1",
1858 .vtables = BUS_VTABLES(hostname_vtable),
1859};
1860
96520e8b 1861static int connect_bus(Context *c) {
7640a5de
LP
1862 int r;
1863
66a4c743 1864 assert(c);
96520e8b
LP
1865 assert(c->event);
1866 assert(!c->bus);
d0baa06f 1867
96520e8b 1868 r = sd_bus_default_system(&c->bus);
23bbb0de
MS
1869 if (r < 0)
1870 return log_error_errno(r, "Failed to get system bus connection: %m");
d0baa06f 1871
96520e8b 1872 r = bus_add_implementation(c->bus, &manager_object, c);
23bbb0de 1873 if (r < 0)
670139db 1874 return r;
d0baa06f 1875
96520e8b 1876 r = bus_log_control_api_register(c->bus);
ac9f55ed
LP
1877 if (r < 0)
1878 return r;
1879
96520e8b 1880 r = sd_bus_request_name_async(c->bus, NULL, "org.freedesktop.hostname1", 0, NULL, NULL);
23bbb0de 1881 if (r < 0)
0c0b9306 1882 return log_error_errno(r, "Failed to request name: %m");
add10b5a 1883
96520e8b 1884 r = sd_bus_attach_event(c->bus, c->event, 0);
23bbb0de
MS
1885 if (r < 0)
1886 return log_error_errno(r, "Failed to attach bus to event loop: %m");
d0baa06f 1887
66a4c743 1888 return 0;
d0baa06f
LP
1889}
1890
25ff515b 1891static int vl_method_describe(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
0a6598bb
LP
1892 Context *c = ASSERT_PTR(userdata);
1893 bool privileged;
1894 int r;
1895
1896 assert(link);
1897 assert(parameters);
1898
8d7d2edc 1899 r = sd_varlink_dispatch(link, parameters, dispatch_table_polkit_only, /* userdata= */ NULL);
0a6598bb
LP
1900 if (r != 0)
1901 return r;
1902
b6464e80 1903 r = varlink_verify_polkit_async_full(
0a6598bb
LP
1904 link,
1905 c->bus,
1906 "org.freedesktop.hostname1.get-hardware-serial",
1907 /* details= */ NULL,
b6464e80
LP
1908 UID_INVALID,
1909 POLKIT_DONT_REPLY,
0a6598bb
LP
1910 &c->polkit_registry);
1911 if (r == 0)
1912 return 0; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1913
1914 /* We ignore all authentication errors here, since most data is unprivileged, the one exception being
1915 * the product ID which we'll check explicitly. */
1916 privileged = r > 0;
1917
309a747f 1918 _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
0a6598bb
LP
1919 r = build_describe_response(c, privileged, &v);
1920 if (r < 0)
1921 return r;
1922
25ff515b 1923 return sd_varlink_reply(link, v);
0a6598bb
LP
1924}
1925
1926static int connect_varlink(Context *c) {
1927 int r;
1928
1929 assert(c);
1930 assert(c->event);
1931 assert(!c->varlink_server);
1932
fd409ff0
ZJS
1933 r = varlink_server_new(
1934 &c->varlink_server,
1935 SD_VARLINK_SERVER_ACCOUNT_UID|SD_VARLINK_SERVER_INHERIT_USERDATA,
1936 c);
0a6598bb
LP
1937 if (r < 0)
1938 return log_error_errno(r, "Failed to allocate Varlink server: %m");
1939
c8127075
LP
1940 r = sd_varlink_server_add_interface_many(
1941 c->varlink_server,
1942 &vl_interface_io_systemd_Hostname,
1943 &vl_interface_io_systemd_service);
0a6598bb 1944 if (r < 0)
25ff515b 1945 return log_error_errno(r, "Failed to add Hostname interface to Varlink server: %m");
0a6598bb 1946
25ff515b 1947 r = sd_varlink_server_bind_method_many(
0a6598bb 1948 c->varlink_server,
c8127075
LP
1949 "io.systemd.Hostname.Describe", vl_method_describe,
1950 "io.systemd.service.Ping", varlink_method_ping,
1951 "io.systemd.service.SetLogLevel", varlink_method_set_log_level,
1952 "io.systemd.service.GetEnvironment", varlink_method_get_environment);
0a6598bb
LP
1953 if (r < 0)
1954 return log_error_errno(r, "Failed to bind Varlink method calls: %m");
1955
25ff515b 1956 r = sd_varlink_server_attach_event(c->varlink_server, c->event, SD_EVENT_PRIORITY_NORMAL);
0a6598bb
LP
1957 if (r < 0)
1958 return log_error_errno(r, "Failed to attach Varlink server to event loop: %m");
1959
25ff515b 1960 r = sd_varlink_server_listen_auto(c->varlink_server);
0a6598bb
LP
1961 if (r < 0)
1962 return log_error_errno(r, "Failed to bind to passed Varlink sockets: %m");
1963 if (r == 0) {
25ff515b 1964 r = sd_varlink_server_listen_address(c->varlink_server, "/run/systemd/io.systemd.Hostname", 0666);
0a6598bb
LP
1965 if (r < 0)
1966 return log_error_errno(r, "Failed to bind to Varlink socket: %m");
1967 }
1968
1969 return 0;
1970}
1971
ac908152
LP
1972static bool context_check_idle(void *userdata) {
1973 Context *c = ASSERT_PTR(userdata);
1974
25ff515b 1975 return sd_varlink_server_current_connections(c->varlink_server) == 0 &&
ac908152
LP
1976 hashmap_isempty(c->polkit_registry);
1977}
1978
85ae63ee 1979static int run(int argc, char *argv[]) {
60e4fb42
ZJS
1980 _cleanup_(context_destroy) Context context = {
1981 .hostname_source = _HOSTNAME_INVALID, /* appropriate value will be set later */
1982 };
d0baa06f 1983 int r;
d0baa06f 1984
d2acb93d 1985 log_setup();
7640a5de 1986
fc021a5b
ZJS
1987 r = service_parse_argv("systemd-hostnamed.service",
1988 "Manage the system hostname and related metadata.",
670139db
ZJS
1989 BUS_IMPLEMENTATIONS(&manager_object,
1990 &log_control_object),
fc021a5b
ZJS
1991 argc, argv);
1992 if (r <= 0)
1993 return r;
1994
4c12626c 1995 umask(0022);
a9ba0e32 1996
a452c807 1997 r = mac_init();
a9ba0e32
CG
1998 if (r < 0)
1999 return r;
4c12626c 2000
c1507748
YW
2001 r = context_acquire_dmi_device(&context);
2002 if (r < 0)
2003 return r;
2004
b3d75a3b
YW
2005 r = context_acquire_acpi_device(&context);
2006 if (r < 0)
2007 return r;
2008
3e91aed6
YW
2009 r = context_acquire_device_tree(&context);
2010 if (r < 0)
2011 return r;
2012
96520e8b 2013 r = sd_event_default(&context.event);
85ae63ee
YW
2014 if (r < 0)
2015 return log_error_errno(r, "Failed to allocate event loop: %m");
7640a5de 2016
96520e8b 2017 (void) sd_event_set_watchdog(context.event, true);
b22c8bfc 2018
96520e8b 2019 r = sd_event_set_signal_exit(context.event, true);
85ae63ee 2020 if (r < 0)
aefaeebe 2021 return log_error_errno(r, "Failed to install SIGINT/SIGTERM handlers: %m");
cde93897 2022
96520e8b 2023 r = connect_bus(&context);
d0baa06f 2024 if (r < 0)
85ae63ee 2025 return r;
7640a5de 2026
0a6598bb
LP
2027 r = connect_varlink(&context);
2028 if (r < 0)
2029 return r;
2030
792a8bfb 2031 r = sd_notify(false, NOTIFY_READY_MESSAGE);
9737e2c8
MY
2032 if (r < 0)
2033 log_warning_errno(r, "Failed to send readiness notification, ignoring: %m");
2034
96520e8b
LP
2035 r = bus_event_loop_with_idle(
2036 context.event,
2037 context.bus,
2038 "org.freedesktop.hostname1",
2039 DEFAULT_EXIT_USEC,
ac908152
LP
2040 context_check_idle,
2041 &context);
85ae63ee
YW
2042 if (r < 0)
2043 return log_error_errno(r, "Failed to run event loop: %m");
7640a5de 2044
85ae63ee 2045 return 0;
7640a5de 2046}
85ae63ee
YW
2047
2048DEFINE_MAIN_FUNCTION(run);