]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/hostname/hostnamed.c
rules: drop weird spaces
[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;
310 r = safe_atou(month, &m);
311 if (r < 0)
312 return r;
313 if (m < 1 || m > 12)
314 return -EINVAL;
315 m -= 1;
316
317 r = safe_atou(day, &d);
318 if (r < 0)
319 return r;
320 if (d < 1 || d > 31)
321 return -EINVAL;
322
323 r = safe_atou(year, &y);
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
ba12e41d
YW
659 r = write_env_file_label("/etc/machine-info", l);
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
19070062 998static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
99534007 999 Context *c = ASSERT_PTR(userdata);
66a4c743 1000 const char *name;
aa994368 1001 int interactive, r;
d200735e 1002
19070062 1003 assert(m);
19070062 1004
66a4c743
LP
1005 r = sd_bus_message_read(m, "sb", &name, &interactive);
1006 if (r < 0)
ebcf1f97 1007 return r;
d200735e 1008
60e4fb42 1009 name = empty_to_null(name);
7640a5de 1010
60e4fb42
ZJS
1011 /* We always go through with the procedure below without comparing to the current hostname, because
1012 * we might want to adjust hostname source information even if the actual hostname is unchanged. */
7640a5de 1013
f190ac48 1014 if (name && !hostname_is_valid(name, 0))
ebcf1f97 1015 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", name);
7640a5de 1016
60e4fb42 1017 context_read_etc_hostname(c);
7640a5de 1018
c529695e
LP
1019 r = bus_verify_polkit_async(
1020 m,
1021 CAP_SYS_ADMIN,
1022 "org.freedesktop.hostname1.set-hostname",
403ed0e5 1023 NULL,
c529695e
LP
1024 interactive,
1025 UID_INVALID,
1026 &c->polkit_registry,
1027 error);
66a4c743 1028 if (r < 0)
ebcf1f97 1029 return r;
66a4c743
LP
1030 if (r == 0)
1031 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7640a5de 1032
aa994368 1033 r = context_update_kernel_hostname(c, name);
60e4fb42 1034 if (r < 0)
1b4cd646 1035 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
60e4fb42 1036 else if (r > 0)
efda832d
ZJS
1037 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m),
1038 "/org/freedesktop/hostname1", "org.freedesktop.hostname1",
1039 "Hostname", "HostnameSource", NULL);
7640a5de 1040
df2d202e 1041 return sd_bus_reply_method_return(m, NULL);
66a4c743 1042}
7640a5de 1043
19070062 1044static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
99534007 1045 Context *c = ASSERT_PTR(userdata);
66a4c743 1046 const char *name;
102d8f81 1047 int interactive;
66a4c743 1048 int r;
7640a5de 1049
19070062 1050 assert(m);
19070062 1051
66a4c743
LP
1052 r = sd_bus_message_read(m, "sb", &name, &interactive);
1053 if (r < 0)
ebcf1f97 1054 return r;
7640a5de 1055
3c6f7c34 1056 name = empty_to_null(name);
7640a5de 1057
d7f4ad20
LP
1058 context_read_etc_hostname(c);
1059
66a4c743 1060 if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME]))
df2d202e 1061 return sd_bus_reply_method_return(m, NULL);
7640a5de 1062
60e4fb42 1063 if (name && !hostname_is_valid(name, 0))
c650f207
YW
1064 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name);
1065
c529695e
LP
1066 r = bus_verify_polkit_async(
1067 m,
1068 CAP_SYS_ADMIN,
1069 "org.freedesktop.hostname1.set-static-hostname",
403ed0e5 1070 NULL,
c529695e
LP
1071 interactive,
1072 UID_INVALID,
1073 &c->polkit_registry,
1074 error);
66a4c743 1075 if (r < 0)
ebcf1f97 1076 return r;
66a4c743
LP
1077 if (r == 0)
1078 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7640a5de 1079
e8acf091 1080 r = free_and_strdup_warn(&c->data[PROP_STATIC_HOSTNAME], name);
c650f207
YW
1081 if (r < 0)
1082 return r;
7640a5de 1083
66a4c743
LP
1084 r = context_write_data_static_hostname(c);
1085 if (r < 0) {
38b38500 1086 log_error_errno(r, "Failed to write static hostname: %m");
957991b7
YW
1087 if (ERRNO_IS_PRIVILEGE(r))
1088 return sd_bus_error_set(error, BUS_ERROR_FILE_IS_PROTECTED, "Not allowed to update /etc/hostname.");
1089 if (r == -EROFS)
1090 return sd_bus_error_set(error, BUS_ERROR_READ_ONLY_FILESYSTEM, "/etc/hostname is in a read-only filesystem.");
1b4cd646 1091 return sd_bus_error_set_errnof(error, r, "Failed to set static hostname: %m");
66a4c743 1092 }
7640a5de 1093
60e4fb42
ZJS
1094 r = context_update_kernel_hostname(c, NULL);
1095 if (r < 0) {
1096 log_error_errno(r, "Failed to set hostname: %m");
1097 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
1098 }
7640a5de 1099
efda832d 1100 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m),
60e4fb42
ZJS
1101 "/org/freedesktop/hostname1", "org.freedesktop.hostname1",
1102 "StaticHostname", "Hostname", "HostnameSource", NULL);
7640a5de 1103
df2d202e 1104 return sd_bus_reply_method_return(m, NULL);
66a4c743 1105}
7640a5de 1106
19070062 1107static int set_machine_info(Context *c, sd_bus_message *m, int prop, sd_bus_message_handler_t cb, sd_bus_error *error) {
102d8f81 1108 int interactive;
66a4c743
LP
1109 const char *name;
1110 int r;
1111
1112 assert(c);
66a4c743
LP
1113 assert(m);
1114
1115 r = sd_bus_message_read(m, "sb", &name, &interactive);
1116 if (r < 0)
ebcf1f97 1117 return r;
66a4c743 1118
3c6f7c34 1119 name = empty_to_null(name);
66a4c743 1120
d7f4ad20
LP
1121 context_read_machine_info(c);
1122
66a4c743 1123 if (streq_ptr(name, c->data[prop]))
df2d202e 1124 return sd_bus_reply_method_return(m, NULL);
7640a5de 1125
c650f207
YW
1126 if (!isempty(name)) {
1127 /* The icon name might ultimately be used as file
1128 * name, so better be safe than sorry */
1129
1130 if (prop == PROP_ICON_NAME && !filename_is_valid(name))
1131 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid icon name '%s'", name);
1132 if (prop == PROP_PRETTY_HOSTNAME && string_has_cc(name, NULL))
38b38500 1133 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty hostname '%s'", name);
c650f207
YW
1134 if (prop == PROP_CHASSIS && !valid_chassis(name))
1135 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid chassis '%s'", name);
1136 if (prop == PROP_DEPLOYMENT && !valid_deployment(name))
1137 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid deployment '%s'", name);
1138 if (prop == PROP_LOCATION && string_has_cc(name, NULL))
1139 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid location '%s'", name);
1140 }
1141
66a4c743
LP
1142 /* Since the pretty hostname should always be changed at the
1143 * same time as the static one, use the same policy action for
1144 * both... */
1145
c529695e
LP
1146 r = bus_verify_polkit_async(
1147 m,
1148 CAP_SYS_ADMIN,
1149 prop == PROP_PRETTY_HOSTNAME ? "org.freedesktop.hostname1.set-static-hostname" : "org.freedesktop.hostname1.set-machine-info",
403ed0e5 1150 NULL,
c529695e
LP
1151 interactive,
1152 UID_INVALID,
1153 &c->polkit_registry,
1154 error);
66a4c743 1155 if (r < 0)
ebcf1f97 1156 return r;
66a4c743
LP
1157 if (r == 0)
1158 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1159
e8acf091 1160 r = free_and_strdup_warn(&c->data[prop], name);
c650f207
YW
1161 if (r < 0)
1162 return r;
7640a5de 1163
f200e8bb 1164 r = context_write_data_machine_info(c);
66a4c743 1165 if (r < 0) {
da927ba9 1166 log_error_errno(r, "Failed to write machine info: %m");
957991b7
YW
1167 if (ERRNO_IS_PRIVILEGE(r))
1168 return sd_bus_error_set(error, BUS_ERROR_FILE_IS_PROTECTED, "Not allowed to update /etc/machine-info.");
1169 if (r == -EROFS)
1170 return sd_bus_error_set(error, BUS_ERROR_READ_ONLY_FILESYSTEM, "/etc/machine-info is in a read-only filesystem.");
1b4cd646 1171 return sd_bus_error_set_errnof(error, r, "Failed to write machine info: %m");
66a4c743 1172 }
7640a5de 1173
66a4c743 1174 log_info("Changed %s to '%s'",
38b38500 1175 prop == PROP_PRETTY_HOSTNAME ? "pretty hostname" :
799298d6 1176 prop == PROP_DEPLOYMENT ? "deployment" :
ce0f1493 1177 prop == PROP_LOCATION ? "location" :
66a4c743 1178 prop == PROP_CHASSIS ? "chassis" : "icon name", strna(c->data[prop]));
7640a5de 1179
19070062
LP
1180 (void) sd_bus_emit_properties_changed(
1181 sd_bus_message_get_bus(m),
1182 "/org/freedesktop/hostname1",
1183 "org.freedesktop.hostname1",
1184 prop == PROP_PRETTY_HOSTNAME ? "PrettyHostname" :
1185 prop == PROP_DEPLOYMENT ? "Deployment" :
1186 prop == PROP_LOCATION ? "Location" :
1187 prop == PROP_CHASSIS ? "Chassis" : "IconName" , NULL);
7640a5de 1188
df2d202e 1189 return sd_bus_reply_method_return(m, NULL);
66a4c743 1190}
7640a5de 1191
19070062
LP
1192static int method_set_pretty_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1193 return set_machine_info(userdata, m, PROP_PRETTY_HOSTNAME, method_set_pretty_hostname, error);
7640a5de
LP
1194}
1195
19070062
LP
1196static int method_set_icon_name(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1197 return set_machine_info(userdata, m, PROP_ICON_NAME, method_set_icon_name, error);
66a4c743
LP
1198}
1199
19070062
LP
1200static int method_set_chassis(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1201 return set_machine_info(userdata, m, PROP_CHASSIS, method_set_chassis, error);
66a4c743
LP
1202}
1203
19070062
LP
1204static int method_set_deployment(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1205 return set_machine_info(userdata, m, PROP_DEPLOYMENT, method_set_deployment, error);
799298d6
JG
1206}
1207
19070062
LP
1208static int method_set_location(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1209 return set_machine_info(userdata, m, PROP_LOCATION, method_set_location, error);
ce0f1493
LP
1210}
1211
21e627da
YW
1212static int method_get_product_uuid(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1213 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
99534007 1214 Context *c = ASSERT_PTR(userdata);
21e627da 1215 int interactive, r;
5704cd73 1216 sd_id128_t uuid;
21e627da
YW
1217
1218 assert(m);
21e627da 1219
21e627da
YW
1220 r = sd_bus_message_read(m, "b", &interactive);
1221 if (r < 0)
1222 return r;
1223
1224 r = bus_verify_polkit_async(
1225 m,
1226 CAP_SYS_ADMIN,
1227 "org.freedesktop.hostname1.get-product-uuid",
1228 NULL,
1229 interactive,
1230 UID_INVALID,
1231 &c->polkit_registry,
1232 error);
1233 if (r < 0)
1234 return r;
1235 if (r == 0)
1236 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1237
66ee2298
LP
1238 r = id128_get_product(&uuid);
1239 if (r < 0) {
1240 if (r == -EADDRNOTAVAIL)
1241 log_debug_errno(r, "DMI product UUID is all 0x00 or all 0xFF, ignoring.");
1242 else
1243 log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
1244 "Failed to read product UUID, ignoring: %m");
1245
1246 return sd_bus_error_set(error, BUS_ERROR_NO_PRODUCT_UUID,
1247 "Failed to read product UUID from firmware.");
1248 }
1249
21e627da
YW
1250 r = sd_bus_message_new_method_return(m, &reply);
1251 if (r < 0)
1252 return r;
1253
c52e295d 1254 r = sd_bus_message_append_array(reply, 'y', uuid.bytes, sizeof(uuid.bytes));
21e627da
YW
1255 if (r < 0)
1256 return r;
1257
1258 return sd_bus_send(NULL, reply, NULL);
1259}
1260
96976629
YW
1261static int method_get_hardware_serial(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1262 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1263 _cleanup_free_ char *serial = NULL;
99534007 1264 Context *c = ASSERT_PTR(userdata);
ff28d259 1265 int r;
96976629
YW
1266
1267 assert(m);
96976629 1268
96976629
YW
1269 r = bus_verify_polkit_async(
1270 m,
1271 CAP_SYS_ADMIN,
1272 "org.freedesktop.hostname1.get-hardware-serial",
1273 NULL,
ff28d259 1274 false,
96976629
YW
1275 UID_INVALID,
1276 &c->polkit_registry,
1277 error);
1278 if (r < 0)
1279 return r;
1280 if (r == 0)
1281 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1282
1283 r = get_hardware_serial(&serial);
1284 if (r < 0)
1285 return r;
1286
1287 r = sd_bus_message_new_method_return(m, &reply);
1288 if (r < 0)
1289 return r;
1290
1291 r = sd_bus_message_append(reply, "s", serial);
1292 if (r < 0)
1293 return r;
1294
1295 return sd_bus_send(NULL, reply, NULL);
1296}
1297
7ecead8f 1298static int method_describe(sd_bus_message *m, void *userdata, sd_bus_error *error) {
96976629 1299 _cleanup_free_ char *hn = NULL, *dhn = NULL, *in = NULL, *text = NULL,
f233bbd6 1300 *chassis = NULL, *vendor = NULL, *model = NULL, *serial = NULL, *firmware_version = NULL,
ad8858c1 1301 *firmware_vendor = NULL;
b563d5ce 1302 usec_t firmware_date = USEC_INFINITY, eol = USEC_INFINITY;
7ecead8f
LP
1303 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1304 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
1305 sd_id128_t product_uuid = SD_ID128_NULL;
99534007 1306 Context *c = ASSERT_PTR(userdata);
7ecead8f
LP
1307 bool privileged;
1308 struct utsname u;
1309 int r;
1310
1311 assert(m);
7ecead8f
LP
1312
1313 r = bus_verify_polkit_async(
1314 m,
1315 CAP_SYS_ADMIN,
96976629 1316 "org.freedesktop.hostname1.get-description",
7ecead8f
LP
1317 NULL,
1318 false,
1319 UID_INVALID,
1320 &c->polkit_registry,
1321 NULL);
1322 if (r == 0)
1323 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1324
1325 /* We ignore all authentication errors here, since most data is unprivileged, the one exception being
1326 * the product ID which we'll check explicitly. */
1327 privileged = r > 0;
1328
1329 context_read_etc_hostname(c);
1330 context_read_machine_info(c);
1331 context_read_os_release(c);
1332 context_determine_hostname_source(c);
1333
1334 r = gethostname_strict(&hn);
1335 if (r < 0) {
1336 if (r != -ENXIO)
1337 return log_error_errno(r, "Failed to read local host name: %m");
1338
1339 hn = get_default_hostname();
1340 if (!hn)
1341 return log_oom();
1342 }
1343
1344 dhn = get_default_hostname();
1345 if (!dhn)
1346 return log_oom();
1347
1348 if (isempty(c->data[PROP_ICON_NAME]))
1349 in = context_fallback_icon_name(c);
1350
8c8b1800 1351 chassis = context_get_chassis(c);
7ecead8f
LP
1352
1353 assert_se(uname(&u) >= 0);
1354
0924ea2b 1355 if (isempty(c->data[PROP_HARDWARE_VENDOR]))
4fc7e4f3 1356 (void) get_hardware_vendor(&vendor);
0924ea2b 1357 if (isempty(c->data[PROP_HARDWARE_MODEL]))
4fc7e4f3 1358 (void) get_hardware_model(&model);
7ecead8f 1359
96976629
YW
1360 if (privileged) {
1361 /* The product UUID and hardware serial is only available to privileged clients */
1362 (void) id128_get_product(&product_uuid);
1363 (void) get_hardware_serial(&serial);
1364 }
c52950c2 1365 (void) get_firmware_version(&firmware_version);
f233bbd6 1366 (void) get_firmware_vendor(&firmware_vendor);
ff4d26df 1367 (void) get_firmware_date(&firmware_date);
7ecead8f 1368
b563d5ce
LP
1369 if (c->data[PROP_OS_SUPPORT_END])
1370 (void) os_release_support_ended(c->data[PROP_OS_SUPPORT_END], /* quiet= */ false, &eol);
1371
7ecead8f
LP
1372 r = json_build(&v, JSON_BUILD_OBJECT(
1373 JSON_BUILD_PAIR("Hostname", JSON_BUILD_STRING(hn)),
1374 JSON_BUILD_PAIR("StaticHostname", JSON_BUILD_STRING(c->data[PROP_STATIC_HOSTNAME])),
1375 JSON_BUILD_PAIR("PrettyHostname", JSON_BUILD_STRING(c->data[PROP_PRETTY_HOSTNAME])),
1376 JSON_BUILD_PAIR("DefaultHostname", JSON_BUILD_STRING(dhn)),
1377 JSON_BUILD_PAIR("HostnameSource", JSON_BUILD_STRING(hostname_source_to_string(c->hostname_source))),
1378 JSON_BUILD_PAIR("IconName", JSON_BUILD_STRING(in ?: c->data[PROP_ICON_NAME])),
8c8b1800 1379 JSON_BUILD_PAIR("Chassis", JSON_BUILD_STRING(chassis)),
7ecead8f
LP
1380 JSON_BUILD_PAIR("Deployment", JSON_BUILD_STRING(c->data[PROP_DEPLOYMENT])),
1381 JSON_BUILD_PAIR("Location", JSON_BUILD_STRING(c->data[PROP_LOCATION])),
1382 JSON_BUILD_PAIR("KernelName", JSON_BUILD_STRING(u.sysname)),
1383 JSON_BUILD_PAIR("KernelRelease", JSON_BUILD_STRING(u.release)),
1384 JSON_BUILD_PAIR("KernelVersion", JSON_BUILD_STRING(u.version)),
1385 JSON_BUILD_PAIR("OperatingSystemPrettyName", JSON_BUILD_STRING(c->data[PROP_OS_PRETTY_NAME])),
1386 JSON_BUILD_PAIR("OperatingSystemCPEName", JSON_BUILD_STRING(c->data[PROP_OS_CPE_NAME])),
1387 JSON_BUILD_PAIR("OperatingSystemHomeURL", JSON_BUILD_STRING(c->data[PROP_OS_HOME_URL])),
b563d5ce 1388 JSON_BUILD_PAIR_FINITE_USEC("OperatingSystemSupportEnd", eol),
0924ea2b
LP
1389 JSON_BUILD_PAIR("HardwareVendor", JSON_BUILD_STRING(vendor ?: c->data[PROP_HARDWARE_VENDOR])),
1390 JSON_BUILD_PAIR("HardwareModel", JSON_BUILD_STRING(model ?: c->data[PROP_HARDWARE_MODEL])),
96976629 1391 JSON_BUILD_PAIR("HardwareSerial", JSON_BUILD_STRING(serial)),
c52950c2 1392 JSON_BUILD_PAIR("FirmwareVersion", JSON_BUILD_STRING(firmware_version)),
f233bbd6 1393 JSON_BUILD_PAIR("FirmwareVendor", JSON_BUILD_STRING(firmware_vendor)),
ad8858c1 1394 JSON_BUILD_PAIR_FINITE_USEC("FirmwareDate", firmware_date),
7ecead8f
LP
1395 JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(product_uuid), "ProductUUID", JSON_BUILD_ID128(product_uuid)),
1396 JSON_BUILD_PAIR_CONDITION(sd_id128_is_null(product_uuid), "ProductUUID", JSON_BUILD_NULL)));
1397
1398 if (r < 0)
1399 return log_error_errno(r, "Failed to build JSON data: %m");
1400
1401 r = json_variant_format(v, 0, &text);
1402 if (r < 0)
1403 return log_error_errno(r, "Failed to format JSON data: %m");
1404
1405 r = sd_bus_message_new_method_return(m, &reply);
1406 if (r < 0)
1407 return r;
1408
1409 r = sd_bus_message_append(reply, "s", text);
1410 if (r < 0)
1411 return r;
1412
1413 return sd_bus_send(NULL, reply, NULL);
1414}
1415
66a4c743
LP
1416static const sd_bus_vtable hostname_vtable[] = {
1417 SD_BUS_VTABLE_START(0),
aa994368 1418 SD_BUS_PROPERTY("Hostname", "s", property_get_hostname, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
d7f4ad20
LP
1419 SD_BUS_PROPERTY("StaticHostname", "s", property_get_static_hostname, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1420 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 1421 SD_BUS_PROPERTY("DefaultHostname", "s", property_get_default_hostname, 0, SD_BUS_VTABLE_PROPERTY_CONST),
60e4fb42 1422 SD_BUS_PROPERTY("HostnameSource", "s", property_get_hostname_source, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
66a4c743
LP
1423 SD_BUS_PROPERTY("IconName", "s", property_get_icon_name, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1424 SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
d7f4ad20
LP
1425 SD_BUS_PROPERTY("Deployment", "s", property_get_machine_info_field, offsetof(Context, data) + sizeof(char*) * PROP_DEPLOYMENT, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1426 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
1427 SD_BUS_PROPERTY("KernelName", "s", property_get_uname_field, offsetof(struct utsname, sysname), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
1428 SD_BUS_PROPERTY("KernelRelease", "s", property_get_uname_field, offsetof(struct utsname, release), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
1429 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
1430 SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", property_get_os_release_field, offsetof(Context, data) + sizeof(char*) * PROP_OS_PRETTY_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
1431 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 1432 SD_BUS_PROPERTY("OperatingSystemSupportEnd", "t", property_get_os_support_end, 0, SD_BUS_VTABLE_PROPERTY_CONST),
d7f4ad20 1433 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
1434 SD_BUS_PROPERTY("HardwareVendor", "s", property_get_hardware_vendor, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1435 SD_BUS_PROPERTY("HardwareModel", "s", property_get_hardware_model, 0, SD_BUS_VTABLE_PROPERTY_CONST),
c52950c2 1436 SD_BUS_PROPERTY("FirmwareVersion", "s", property_get_firmware_version, 0, SD_BUS_VTABLE_PROPERTY_CONST),
f233bbd6 1437 SD_BUS_PROPERTY("FirmwareVendor", "s", property_get_firmware_vendor, 0, SD_BUS_VTABLE_PROPERTY_CONST),
ad8858c1 1438 SD_BUS_PROPERTY("FirmwareDate", "t", property_get_firmware_date, 0, SD_BUS_VTABLE_PROPERTY_CONST),
106d79be 1439
92c9f47d
SS
1440 SD_BUS_METHOD_WITH_ARGS("SetHostname",
1441 SD_BUS_ARGS("s", hostname, "b", interactive),
1442 SD_BUS_NO_RESULT,
1443 method_set_hostname,
1444 SD_BUS_VTABLE_UNPRIVILEGED),
1445 SD_BUS_METHOD_WITH_ARGS("SetStaticHostname",
1446 SD_BUS_ARGS("s", hostname, "b", interactive),
1447 SD_BUS_NO_RESULT,
1448 method_set_static_hostname,
1449 SD_BUS_VTABLE_UNPRIVILEGED),
1450 SD_BUS_METHOD_WITH_ARGS("SetPrettyHostname",
1451 SD_BUS_ARGS("s", hostname, "b", interactive),
1452 SD_BUS_NO_RESULT,
1453 method_set_pretty_hostname,
1454 SD_BUS_VTABLE_UNPRIVILEGED),
1455 SD_BUS_METHOD_WITH_ARGS("SetIconName",
1456 SD_BUS_ARGS("s", icon, "b", interactive),
1457 SD_BUS_NO_RESULT,
1458 method_set_icon_name,
1459 SD_BUS_VTABLE_UNPRIVILEGED),
1460 SD_BUS_METHOD_WITH_ARGS("SetChassis",
1461 SD_BUS_ARGS("s", chassis, "b", interactive),
1462 SD_BUS_NO_RESULT,
1463 method_set_chassis,
1464 SD_BUS_VTABLE_UNPRIVILEGED),
1465 SD_BUS_METHOD_WITH_ARGS("SetDeployment",
1466 SD_BUS_ARGS("s", deployment, "b", interactive),
1467 SD_BUS_NO_RESULT,
1468 method_set_deployment,
1469 SD_BUS_VTABLE_UNPRIVILEGED),
1470 SD_BUS_METHOD_WITH_ARGS("SetLocation",
1471 SD_BUS_ARGS("s", location, "b", interactive),
1472 SD_BUS_NO_RESULT,
1473 method_set_location,
1474 SD_BUS_VTABLE_UNPRIVILEGED),
1475 SD_BUS_METHOD_WITH_ARGS("GetProductUUID",
1476 SD_BUS_ARGS("b", interactive),
1477 SD_BUS_RESULT("ay", uuid),
1478 method_get_product_uuid,
1479 SD_BUS_VTABLE_UNPRIVILEGED),
1480 SD_BUS_METHOD_WITH_ARGS("GetHardwareSerial",
1481 SD_BUS_NO_ARGS,
1482 SD_BUS_RESULT("s", serial),
1483 method_get_hardware_serial,
1484 SD_BUS_VTABLE_UNPRIVILEGED),
7ecead8f
LP
1485 SD_BUS_METHOD_WITH_ARGS("Describe",
1486 SD_BUS_NO_ARGS,
1487 SD_BUS_RESULT("s", json),
1488 method_describe,
1489 SD_BUS_VTABLE_UNPRIVILEGED),
106d79be 1490
66a4c743
LP
1491 SD_BUS_VTABLE_END,
1492};
1493
670139db
ZJS
1494static const BusObjectImplementation manager_object = {
1495 "/org/freedesktop/hostname1",
1496 "org.freedesktop.hostname1",
1497 .vtables = BUS_VTABLES(hostname_vtable),
1498};
1499
2ac4d1d4 1500static int connect_bus(Context *c, sd_event *event, sd_bus **ret) {
4afd3348 1501 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
7640a5de
LP
1502 int r;
1503
66a4c743
LP
1504 assert(c);
1505 assert(event);
2ac4d1d4 1506 assert(ret);
d0baa06f 1507
76b54375 1508 r = sd_bus_default_system(&bus);
23bbb0de
MS
1509 if (r < 0)
1510 return log_error_errno(r, "Failed to get system bus connection: %m");
d0baa06f 1511
670139db 1512 r = bus_add_implementation(bus, &manager_object, c);
23bbb0de 1513 if (r < 0)
670139db 1514 return r;
d0baa06f 1515
ac9f55ed
LP
1516 r = bus_log_control_api_register(bus);
1517 if (r < 0)
1518 return r;
1519
0c0b9306 1520 r = sd_bus_request_name_async(bus, NULL, "org.freedesktop.hostname1", 0, NULL, NULL);
23bbb0de 1521 if (r < 0)
0c0b9306 1522 return log_error_errno(r, "Failed to request name: %m");
add10b5a 1523
66a4c743 1524 r = sd_bus_attach_event(bus, event, 0);
23bbb0de
MS
1525 if (r < 0)
1526 return log_error_errno(r, "Failed to attach bus to event loop: %m");
d0baa06f 1527
2ac4d1d4 1528 *ret = TAKE_PTR(bus);
66a4c743 1529 return 0;
d0baa06f
LP
1530}
1531
85ae63ee 1532static int run(int argc, char *argv[]) {
60e4fb42
ZJS
1533 _cleanup_(context_destroy) Context context = {
1534 .hostname_source = _HOSTNAME_INVALID, /* appropriate value will be set later */
1535 };
4afd3348
LP
1536 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
1537 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
d0baa06f 1538 int r;
d0baa06f 1539
d2acb93d 1540 log_setup();
7640a5de 1541
fc021a5b
ZJS
1542 r = service_parse_argv("systemd-hostnamed.service",
1543 "Manage the system hostname and related metadata.",
670139db
ZJS
1544 BUS_IMPLEMENTATIONS(&manager_object,
1545 &log_control_object),
fc021a5b
ZJS
1546 argc, argv);
1547 if (r <= 0)
1548 return r;
1549
4c12626c 1550 umask(0022);
a9ba0e32 1551
a452c807 1552 r = mac_init();
a9ba0e32
CG
1553 if (r < 0)
1554 return r;
4c12626c 1555
b22c8bfc
YW
1556 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
1557
afc6adb5 1558 r = sd_event_default(&event);
85ae63ee
YW
1559 if (r < 0)
1560 return log_error_errno(r, "Failed to allocate event loop: %m");
7640a5de 1561
b22c8bfc
YW
1562 (void) sd_event_set_watchdog(event, true);
1563
1564 r = sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
85ae63ee
YW
1565 if (r < 0)
1566 return log_error_errno(r, "Failed to install SIGINT handler: %m");
b22c8bfc
YW
1567
1568 r = sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
85ae63ee
YW
1569 if (r < 0)
1570 return log_error_errno(r, "Failed to install SIGTERM handler: %m");
cde93897 1571
66a4c743 1572 r = connect_bus(&context, event, &bus);
d0baa06f 1573 if (r < 0)
85ae63ee 1574 return r;
7640a5de 1575
37224a5f 1576 r = bus_event_loop_with_idle(event, bus, "org.freedesktop.hostname1", DEFAULT_EXIT_USEC, NULL, NULL);
85ae63ee
YW
1577 if (r < 0)
1578 return log_error_errno(r, "Failed to run event loop: %m");
7640a5de 1579
85ae63ee 1580 return 0;
7640a5de 1581}
85ae63ee
YW
1582
1583DEFINE_MAIN_FUNCTION(run);