]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/hostname/hostnamed.c
hostnamed: drop unused enums
[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"
ad740100 14#include "def.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"
85ae63ee 23#include "main-func.h"
36dd5ffd 24#include "missing_capability.h"
7782e0a0 25#include "nscd-flush.h"
d8b4d14d 26#include "nulstr-util.h"
d58ad743 27#include "os-util.h"
6bedfcbb 28#include "parse-util.h"
bb15fafe 29#include "path-util.h"
b9d80698 30#include "sd-device.h"
6bedfcbb 31#include "selinux-util.h"
fc021a5b 32#include "service-util.h"
b22c8bfc 33#include "signal-util.h"
d7f4ad20 34#include "stat-util.h"
60e4fb42 35#include "string-table.h"
6bedfcbb 36#include "strv.h"
ee104e11 37#include "user-util.h"
6bedfcbb
LP
38#include "util.h"
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). */
7640a5de 45enum {
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,
d7f4ad20
LP
55
56 /* Read from /etc/os-release (or /usr/lib/os-release) */
44c32988
DH
57 PROP_OS_PRETTY_NAME,
58 PROP_OS_CPE_NAME,
d7f4ad20
LP
59 PROP_OS_HOME_URL,
60 _PROP_MAX,
2d93c20e 61 _PROP_INVALID = -EINVAL,
7640a5de
LP
62};
63
66a4c743
LP
64typedef struct Context {
65 char *data[_PROP_MAX];
d7f4ad20 66
60e4fb42
ZJS
67 HostnameSource hostname_source;
68
d7f4ad20
LP
69 struct stat etc_hostname_stat;
70 struct stat etc_os_release_stat;
71 struct stat etc_machine_info_stat;
72
66a4c743
LP
73 Hashmap *polkit_registry;
74} Context;
ad740100 75
d7f4ad20 76static void context_reset(Context *c, uint64_t mask) {
66a4c743
LP
77 assert(c);
78
536970d4 79 for (int p = 0; p < _PROP_MAX; p++) {
d7f4ad20
LP
80 if (!FLAGS_SET(mask, UINT64_C(1) << p))
81 continue;
82
a1e58e8e 83 c->data[p] = mfree(c->data[p]);
d7f4ad20 84 }
7640a5de
LP
85}
86
cfb9433d 87static void context_destroy(Context *c) {
66a4c743
LP
88 assert(c);
89
d7f4ad20 90 context_reset(c, UINT64_MAX);
36e34057 91 bus_verify_polkit_async_registry_free(c->polkit_registry);
66a4c743
LP
92}
93
d7f4ad20
LP
94static void context_read_etc_hostname(Context *c) {
95 struct stat current_stat = {};
7640a5de
LP
96 int r;
97
66a4c743
LP
98 assert(c);
99
d7f4ad20
LP
100 if (stat("/etc/hostname", &current_stat) >= 0 &&
101 stat_inode_unmodified(&c->etc_hostname_stat, &current_stat))
102 return;
103
104 context_reset(c, UINT64_C(1) << PROP_STATIC_HOSTNAME);
7640a5de 105
f35cb39e 106 r = read_etc_hostname(NULL, &c->data[PROP_STATIC_HOSTNAME]);
7640a5de 107 if (r < 0 && r != -ENOENT)
d7f4ad20
LP
108 log_warning_errno(r, "Failed to read /etc/hostname, ignoring: %m");
109
110 c->etc_hostname_stat = current_stat;
111}
112
113static void context_read_machine_info(Context *c) {
114 struct stat current_stat = {};
115 int r;
116
117 assert(c);
118
119 if (stat("/etc/machine-info", &current_stat) >= 0 &&
120 stat_inode_unmodified(&c->etc_machine_info_stat, &current_stat))
121 return;
122
123 context_reset(c,
124 (UINT64_C(1) << PROP_PRETTY_HOSTNAME) |
125 (UINT64_C(1) << PROP_ICON_NAME) |
126 (UINT64_C(1) << PROP_CHASSIS) |
127 (UINT64_C(1) << PROP_DEPLOYMENT) |
128 (UINT64_C(1) << PROP_LOCATION));
7640a5de 129
aa8fbc74 130 r = parse_env_file(NULL, "/etc/machine-info",
66a4c743
LP
131 "PRETTY_HOSTNAME", &c->data[PROP_PRETTY_HOSTNAME],
132 "ICON_NAME", &c->data[PROP_ICON_NAME],
133 "CHASSIS", &c->data[PROP_CHASSIS],
799298d6 134 "DEPLOYMENT", &c->data[PROP_DEPLOYMENT],
13df9c39 135 "LOCATION", &c->data[PROP_LOCATION]);
7640a5de 136 if (r < 0 && r != -ENOENT)
d7f4ad20
LP
137 log_warning_errno(r, "Failed to read /etc/machine-info, ignoring: %m");
138
139 c->etc_machine_info_stat = current_stat;
140}
141
142static void context_read_os_release(Context *c) {
143 struct stat current_stat = {};
144 int r;
145
146 assert(c);
147
148 if ((stat("/etc/os-release", &current_stat) >= 0 ||
149 stat("/usr/lib/os-release", &current_stat) >= 0) &&
150 stat_inode_unmodified(&c->etc_os_release_stat, &current_stat))
151 return;
152
153 context_reset(c,
154 (UINT64_C(1) << PROP_OS_PRETTY_NAME) |
155 (UINT64_C(1) << PROP_OS_CPE_NAME) |
156 (UINT64_C(1) << PROP_OS_HOME_URL));
7640a5de 157
d58ad743
LP
158 r = parse_os_release(NULL,
159 "PRETTY_NAME", &c->data[PROP_OS_PRETTY_NAME],
160 "CPE_NAME", &c->data[PROP_OS_CPE_NAME],
209c1470 161 "HOME_URL", &c->data[PROP_OS_HOME_URL]);
44c32988 162 if (r < 0 && r != -ENOENT)
d7f4ad20 163 log_warning_errno(r, "Failed to read os-release file, ignoring: %m");
44c32988 164
d7f4ad20 165 c->etc_os_release_stat = current_stat;
7640a5de
LP
166}
167
7871c8e9 168static bool valid_chassis(const char *chassis) {
7871c8e9
LP
169 assert(chassis);
170
171 return nulstr_contains(
172 "vm\0"
173 "container\0"
174 "desktop\0"
175 "laptop\0"
34b52450 176 "convertible\0"
7871c8e9
LP
177 "server\0"
178 "tablet\0"
c49e59c1 179 "handset\0"
25fa306e
LP
180 "watch\0"
181 "embedded\0",
7871c8e9
LP
182 chassis);
183}
184
799298d6
JG
185static bool valid_deployment(const char *deployment) {
186 assert(deployment);
187
c2142cf1 188 return in_charset(deployment, VALID_DEPLOYMENT_CHARS);
799298d6
JG
189}
190
7871c8e9 191static const char* fallback_chassis(void) {
7640a5de
LP
192 char *type;
193 unsigned t;
219bfe38 194 int v, r;
7871c8e9 195
75f86906 196 v = detect_virtualization();
2ac4d1d4
LP
197 if (v < 0)
198 log_debug_errno(v, "Failed to detect virtualization, ignoring: %m");
199 else if (VIRTUALIZATION_IS_VM(v))
7871c8e9 200 return "vm";
2ac4d1d4 201 else if (VIRTUALIZATION_IS_CONTAINER(v))
7871c8e9
LP
202 return "container";
203
219bfe38 204 r = read_one_line_file("/sys/class/dmi/id/chassis_type", &type);
2ac4d1d4
LP
205 if (r < 0) {
206 log_debug_errno(v, "Failed to read DMI chassis type, ignoring: %m");
219bfe38 207 goto try_acpi;
2ac4d1d4 208 }
7871c8e9
LP
209
210 r = safe_atou(type, &t);
211 free(type);
2ac4d1d4
LP
212 if (r < 0) {
213 log_debug_errno(v, "Failed to parse DMI chassis type, ignoring: %m");
219bfe38 214 goto try_acpi;
2ac4d1d4 215 }
7871c8e9 216
219bfe38
LP
217 /* We only list the really obvious cases here. The DMI data is unreliable enough, so let's not do any
218 additional guesswork on top of that.
219
220 See the SMBIOS Specification 3.0 section 7.4.1 for details about the values listed here:
221
222 https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.0.0.pdf
7871c8e9
LP
223 */
224
219bfe38 225 switch (t) {
7871c8e9 226
219bfe38
LP
227 case 0x3: /* Desktop */
228 case 0x4: /* Low Profile Desktop */
229 case 0x6: /* Mini Tower */
230 case 0x7: /* Tower */
7c5c59d4 231 case 0xD: /* All in one (i.e. PC built into monitor) */
7871c8e9
LP
232 return "desktop";
233
219bfe38
LP
234 case 0x8: /* Portable */
235 case 0x9: /* Laptop */
236 case 0xA: /* Notebook */
237 case 0xE: /* Sub Notebook */
7871c8e9 238 return "laptop";
7640a5de 239
219bfe38
LP
240 case 0xB: /* Hand Held */
241 return "handset";
242
243 case 0x11: /* Main Server Chassis */
244 case 0x1C: /* Blade */
245 case 0x1D: /* Blade Enclosure */
7871c8e9 246 return "server";
7640a5de 247
219bfe38 248 case 0x1E: /* Tablet */
7871c8e9 249 return "tablet";
b70af833
DH
250
251 case 0x1F: /* Convertible */
b4227dbb 252 case 0x20: /* Detachable */
b70af833 253 return "convertible";
2ac4d1d4
LP
254
255 default:
256 log_debug("Unhandled DMI chassis type 0x%02x, ignoring.", t);
7871c8e9
LP
257 }
258
219bfe38
LP
259try_acpi:
260 r = read_one_line_file("/sys/firmware/acpi/pm_profile", &type);
2ac4d1d4
LP
261 if (r < 0) {
262 log_debug_errno(v, "Failed read ACPI PM profile, ignoring: %m");
7640a5de 263 return NULL;
2ac4d1d4 264 }
7640a5de
LP
265
266 r = safe_atou(type, &t);
267 free(type);
2ac4d1d4
LP
268 if (r < 0) {
269 log_debug_errno(v, "Failed parse ACPI PM profile, ignoring: %m");
7640a5de 270 return NULL;
2ac4d1d4 271 }
7640a5de 272
219bfe38
LP
273 /* We only list the really obvious cases here as the ACPI data is not really super reliable.
274 *
275 * See the ACPI 5.0 Spec Section 5.2.9.1 for details:
276 *
277 * http://www.acpi.info/DOWNLOADS/ACPIspec50.pdf
41550d40 278 */
7640a5de 279
219bfe38 280 switch(t) {
7640a5de 281
219bfe38
LP
282 case 1: /* Desktop */
283 case 3: /* Workstation */
284 case 6: /* Appliance PC */
7871c8e9 285 return "desktop";
7640a5de 286
219bfe38 287 case 2: /* Mobile */
7871c8e9
LP
288 return "laptop";
289
219bfe38
LP
290 case 4: /* Enterprise Server */
291 case 5: /* SOHO Server */
292 case 7: /* Performance Server */
7871c8e9 293 return "server";
f3f4f008 294
219bfe38 295 case 8: /* Tablet */
f3f4f008 296 return "tablet";
2ac4d1d4
LP
297
298 default:
299 log_debug("Unhandled ACPI PM profile 0x%02x, ignoring.", t);
7640a5de
LP
300 }
301
7640a5de
LP
302 return NULL;
303}
304
66a4c743 305static char* context_fallback_icon_name(Context *c) {
7871c8e9
LP
306 const char *chassis;
307
66a4c743
LP
308 assert(c);
309
310 if (!isempty(c->data[PROP_CHASSIS]))
b910cc72 311 return strjoin("computer-", c->data[PROP_CHASSIS]);
7871c8e9
LP
312
313 chassis = fallback_chassis();
314 if (chassis)
b910cc72 315 return strjoin("computer-", chassis);
7871c8e9
LP
316
317 return strdup("computer");
318}
319
aa994368
LP
320static int context_update_kernel_hostname(
321 Context *c,
322 const char *transient_hn) {
323
05c6f341 324 _cleanup_free_ char *_hn_free = NULL;
d39079fc 325 const char *hn;
60e4fb42 326 HostnameSource hns;
7d9ec609 327 int r;
7640a5de 328
66a4c743
LP
329 assert(c);
330
d39079fc 331 /* /etc/hostname has the highest preference ... */
60e4fb42 332 if (c->data[PROP_STATIC_HOSTNAME]) {
d39079fc 333 hn = c->data[PROP_STATIC_HOSTNAME];
60e4fb42 334 hns = HOSTNAME_STATIC;
c779a442 335
38b38500 336 /* ... the transient hostname, (ie: DHCP) comes next ... */
60e4fb42 337 } else if (transient_hn) {
aa994368 338 hn = transient_hn;
60e4fb42 339 hns = HOSTNAME_TRANSIENT;
7640a5de 340
c779a442 341 /* ... and the ultimate fallback */
60e4fb42 342 } else {
05c6f341
ZJS
343 hn = _hn_free = get_default_hostname();
344 if (!hn)
345 return log_oom();
346
8770c813 347 hns = HOSTNAME_DEFAULT;
60e4fb42 348 }
c779a442 349
7d9ec609
ZJS
350 r = sethostname_idempotent(hn);
351 if (r < 0)
60e4fb42
ZJS
352 return log_error_errno(r, "Failed to set hostname: %m");
353
354 if (c->hostname_source != hns) {
355 c->hostname_source = hns;
356 r = 1;
357 }
7640a5de 358
7782e0a0 359 (void) nscd_flush_cache(STRV_MAKE("hosts"));
60e4fb42
ZJS
360
361 if (r == 0)
362 log_debug("Hostname was already set to <%s>.", hn);
363 else {
364 log_info("Hostname set to <%s> (%s)", hn, hostname_source_to_string(hns));
365
366 hostname_update_source_hint(hn, hns);
367 }
368
efda832d 369 return r; /* 0 if no change, 1 if something was done */
7640a5de
LP
370}
371
ba12e41d
YW
372static void unset_statp(struct stat **p) {
373 if (!*p)
374 return;
375
376 **p = (struct stat) {};
377}
378
66a4c743 379static int context_write_data_static_hostname(Context *c) {
ba12e41d
YW
380 _cleanup_(unset_statp) struct stat *s = NULL;
381 int r;
382
66a4c743
LP
383 assert(c);
384
ba12e41d
YW
385 /* Make sure that if we fail here, we invalidate the cached information, since it was updated
386 * already, even if we can't make it hit the disk. */
387 s = &c->etc_hostname_stat;
388
66a4c743 389 if (isempty(c->data[PROP_STATIC_HOSTNAME])) {
ba12e41d
YW
390 if (unlink("/etc/hostname") < 0 && errno != ENOENT)
391 return -errno;
392
393 TAKE_PTR(s);
7640a5de
LP
394 return 0;
395 }
536970d4 396
ba12e41d
YW
397 r = write_string_file_atomic_label("/etc/hostname", c->data[PROP_STATIC_HOSTNAME]);
398 if (r < 0)
399 return r;
400
401 TAKE_PTR(s);
402 return 0;
7640a5de
LP
403}
404
f200e8bb 405static int context_write_data_machine_info(Context *c) {
ba12e41d 406 _cleanup_(unset_statp) struct stat *s = NULL;
7640a5de
LP
407 static const char * const name[_PROP_MAX] = {
408 [PROP_PRETTY_HOSTNAME] = "PRETTY_HOSTNAME",
7871c8e9 409 [PROP_ICON_NAME] = "ICON_NAME",
799298d6
JG
410 [PROP_CHASSIS] = "CHASSIS",
411 [PROP_DEPLOYMENT] = "DEPLOYMENT",
ce0f1493 412 [PROP_LOCATION] = "LOCATION",
7640a5de 413 };
0ccad099 414 _cleanup_strv_free_ char **l = NULL;
536970d4 415 int r;
7640a5de 416
66a4c743
LP
417 assert(c);
418
ba12e41d
YW
419 /* Make sure that if we fail here, we invalidate the cached information, since it was updated
420 * already, even if we can't make it hit the disk. */
421 s = &c->etc_machine_info_stat;
422
aa8fbc74 423 r = load_env_file(NULL, "/etc/machine-info", &l);
7640a5de
LP
424 if (r < 0 && r != -ENOENT)
425 return r;
426
536970d4 427 for (int p = PROP_PRETTY_HOSTNAME; p <= PROP_LOCATION; p++) {
7640a5de
LP
428 assert(name[p]);
429
f08231fe
ZJS
430 r = strv_env_assign(&l, name[p], empty_to_null(c->data[p]));
431 if (r < 0)
432 return r;
7640a5de
LP
433 }
434
435 if (strv_isempty(l)) {
ba12e41d
YW
436 if (unlink("/etc/machine-info") < 0 && errno != ENOENT)
437 return -errno;
7640a5de 438
ba12e41d 439 TAKE_PTR(s);
7640a5de
LP
440 return 0;
441 }
442
ba12e41d
YW
443 r = write_env_file_label("/etc/machine-info", l);
444 if (r < 0)
445 return r;
446
447 TAKE_PTR(s);
448 return 0;
7640a5de
LP
449}
450
61d44b6b
LP
451static int get_dmi_data(const char *database_key, const char *regular_key, char **ret) {
452 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
453 _cleanup_free_ char *b = NULL;
454 const char *s = NULL;
455 int r;
456
457 r = sd_device_new_from_syspath(&device, "/sys/class/dmi/id");
458 if (r < 0)
459 return log_debug_errno(r, "Failed to open /sys/class/dmi/id device, ignoring: %m");
460
461 if (database_key)
462 (void) sd_device_get_property_value(device, database_key, &s);
463 if (!s && regular_key)
464 (void) sd_device_get_property_value(device, regular_key, &s);
465
466 if (s) {
467 b = strdup(s);
468 if (!b)
469 return -ENOMEM;
470 }
471
472 if (ret)
473 *ret = TAKE_PTR(b);
474
475 return !!s;
476}
477
478static int get_hardware_vendor(char **ret) {
479 return get_dmi_data("ID_VENDOR_FROM_DATABASE", "ID_VENDOR", ret);
480}
481
482static int get_hardware_model(char **ret) {
483 return get_dmi_data("ID_MODEL_FROM_DATABASE", "ID_MODEL", ret);
484}
485
b9d80698
FB
486static int property_get_hardware_vendor(
487 sd_bus *bus,
488 const char *path,
489 const char *interface,
490 const char *property,
491 sd_bus_message *reply,
492 void *userdata,
493 sd_bus_error *error) {
b9d80698 494
61d44b6b 495 _cleanup_free_ char *vendor = NULL;
b9d80698 496
61d44b6b
LP
497 (void) get_hardware_vendor(&vendor);
498 return sd_bus_message_append(reply, "s", vendor);
b9d80698
FB
499}
500
501static int property_get_hardware_model(
502 sd_bus *bus,
503 const char *path,
504 const char *interface,
505 const char *property,
506 sd_bus_message *reply,
507 void *userdata,
508 sd_bus_error *error) {
b9d80698 509
61d44b6b 510 _cleanup_free_ char *model = NULL;
b9d80698 511
61d44b6b
LP
512 (void) get_hardware_model(&model);
513 return sd_bus_message_append(reply, "s", model);
b9d80698
FB
514}
515
aa994368
LP
516static int property_get_hostname(
517 sd_bus *bus,
518 const char *path,
519 const char *interface,
520 const char *property,
521 sd_bus_message *reply,
522 void *userdata,
523 sd_bus_error *error) {
524
05c6f341 525 _cleanup_free_ char *hn = NULL;
aa994368
LP
526 int r;
527
05c6f341
ZJS
528 r = gethostname_strict(&hn);
529 if (r < 0) {
530 if (r != -ENXIO)
531 return r;
aa994368 532
05c6f341
ZJS
533 hn = get_default_hostname();
534 if (!hn)
535 return -ENOMEM;
536 }
537
538 return sd_bus_message_append(reply, "s", hn);
aa994368
LP
539}
540
d7f4ad20
LP
541static int property_get_static_hostname(
542 sd_bus *bus,
543 const char *path,
544 const char *interface,
545 const char *property,
546 sd_bus_message *reply,
547 void *userdata,
548 sd_bus_error *error) {
549
550 Context *c = userdata;
551 assert(c);
552
553 context_read_etc_hostname(c);
554
555 return sd_bus_message_append(reply, "s", c->data[PROP_STATIC_HOSTNAME]);
556}
557
8770c813 558static int property_get_default_hostname(
05c6f341
ZJS
559 sd_bus *bus,
560 const char *path,
561 const char *interface,
562 const char *property,
563 sd_bus_message *reply,
564 void *userdata,
565 sd_bus_error *error) {
566
61d44b6b
LP
567 _cleanup_free_ char *hn = NULL;
568
569 hn = get_default_hostname();
05c6f341
ZJS
570 if (!hn)
571 return log_oom();
572
573 return sd_bus_message_append(reply, "s", hn);
574}
ce6b138c 575
f2a434a5
LP
576static void context_determine_hostname_source(Context *c) {
577 char hostname[HOST_NAME_MAX + 1] = {};
578 _cleanup_free_ char *fallback = NULL;
579 int r;
580
581 assert(c);
582
583 if (c->hostname_source >= 0)
584 return;
585
586 (void) get_hostname_filtered(hostname);
587
588 if (streq_ptr(hostname, c->data[PROP_STATIC_HOSTNAME]))
589 c->hostname_source = HOSTNAME_STATIC;
590 else {
591 /* If the hostname was not set by us, try to figure out where it came from. If we set it to
592 * the default hostname, the file will tell us. We compare the string because it is possible
593 * that the hostname was set by an older version that had a different fallback, in the
594 * initramfs or before we reexecuted. */
595
596 r = read_one_line_file("/run/systemd/default-hostname", &fallback);
597 if (r < 0 && r != -ENOENT)
598 log_warning_errno(r, "Failed to read /run/systemd/default-hostname, ignoring: %m");
599
600 if (streq_ptr(fallback, hostname))
601 c->hostname_source = HOSTNAME_DEFAULT;
602 else
603 c->hostname_source = HOSTNAME_TRANSIENT;
604 }
605}
606
60e4fb42
ZJS
607static int property_get_hostname_source(
608 sd_bus *bus,
609 const char *path,
610 const char *interface,
611 const char *property,
612 sd_bus_message *reply,
613 void *userdata,
614 sd_bus_error *error) {
615
616 Context *c = userdata;
60e4fb42
ZJS
617 assert(c);
618
619 context_read_etc_hostname(c);
f2a434a5 620 context_determine_hostname_source(c);
60e4fb42
ZJS
621
622 return sd_bus_message_append(reply, "s", hostname_source_to_string(c->hostname_source));
623}
624
d7f4ad20
LP
625static int property_get_machine_info_field(
626 sd_bus *bus,
627 const char *path,
628 const char *interface,
629 const char *property,
630 sd_bus_message *reply,
631 void *userdata,
632 sd_bus_error *error) {
633
634 sd_bus_slot *slot;
635 Context *c;
636
637 /* Acquire the context object without this property's userdata offset added. Explanation: we want
638 * access to two pointers here: a) the main context object we cache all properties in, and b) the
639 * pointer to the property field inside the context object that we are supposed to update and
640 * use. The latter (b) we get in the 'userdata' function parameter, and sd-bus calculates that for us
641 * from the 'userdata' pointer we supplied when the vtable was registered, with the offset we
642 * specified in the vtable added on top. To get the former (a) we need the 'userdata' pointer from
643 * the vtable registration directly, without the offset added. Hence we ask sd-bus what the slot
644 * object is (which encapsulates the vtable registration), and then query the 'userdata' field
645 * directly off it. */
646 assert_se(slot = sd_bus_get_current_slot(bus));
647 assert_se(c = sd_bus_slot_get_userdata(slot));
648
649 context_read_machine_info(c);
650
651 return sd_bus_message_append(reply, "s", *(char**) userdata);
652}
653
654static int property_get_os_release_field(
655 sd_bus *bus,
656 const char *path,
657 const char *interface,
658 const char *property,
659 sd_bus_message *reply,
660 void *userdata,
661 sd_bus_error *error) {
662
663 sd_bus_slot *slot;
664 Context *c;
665
666 /* As above, acquire the current context without this property's userdata offset added. */
667 assert_se(slot = sd_bus_get_current_slot(bus));
668 assert_se(c = sd_bus_slot_get_userdata(slot));
669
670 context_read_os_release(c);
671
672 return sd_bus_message_append(reply, "s", *(char**) userdata);
673}
674
66a4c743
LP
675static int property_get_icon_name(
676 sd_bus *bus,
677 const char *path,
678 const char *interface,
679 const char *property,
680 sd_bus_message *reply,
ebcf1f97
LP
681 void *userdata,
682 sd_bus_error *error) {
7640a5de 683
66a4c743
LP
684 _cleanup_free_ char *n = NULL;
685 Context *c = userdata;
686 const char *name;
7640a5de 687
d7f4ad20
LP
688 context_read_machine_info(c);
689
66a4c743
LP
690 if (isempty(c->data[PROP_ICON_NAME]))
691 name = n = context_fallback_icon_name(c);
7640a5de 692 else
66a4c743
LP
693 name = c->data[PROP_ICON_NAME];
694
695 if (!name)
696 return -ENOMEM;
7640a5de 697
ebcf1f97 698 return sd_bus_message_append(reply, "s", name);
7640a5de
LP
699}
700
66a4c743
LP
701static int property_get_chassis(
702 sd_bus *bus,
703 const char *path,
704 const char *interface,
705 const char *property,
706 sd_bus_message *reply,
ebcf1f97
LP
707 void *userdata,
708 sd_bus_error *error) {
7871c8e9 709
66a4c743
LP
710 Context *c = userdata;
711 const char *name;
7871c8e9 712
d7f4ad20
LP
713 context_read_machine_info(c);
714
66a4c743 715 if (isempty(c->data[PROP_CHASSIS]))
7871c8e9
LP
716 name = fallback_chassis();
717 else
66a4c743 718 name = c->data[PROP_CHASSIS];
7871c8e9 719
ebcf1f97 720 return sd_bus_message_append(reply, "s", name);
7871c8e9
LP
721}
722
72f48cd3
LP
723static int property_get_uname_field(
724 sd_bus *bus,
725 const char *path,
726 const char *interface,
727 const char *property,
728 sd_bus_message *reply,
729 void *userdata,
730 sd_bus_error *error) {
731
732 struct utsname u;
733
734 assert_se(uname(&u) >= 0);
735
736 return sd_bus_message_append(reply, "s", (char*) &u + PTR_TO_SIZE(userdata));
737}
738
19070062 739static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
66a4c743
LP
740 Context *c = userdata;
741 const char *name;
aa994368 742 int interactive, r;
d200735e 743
19070062
LP
744 assert(m);
745 assert(c);
746
66a4c743
LP
747 r = sd_bus_message_read(m, "sb", &name, &interactive);
748 if (r < 0)
ebcf1f97 749 return r;
d200735e 750
60e4fb42 751 name = empty_to_null(name);
7640a5de 752
60e4fb42
ZJS
753 /* We always go through with the procedure below without comparing to the current hostname, because
754 * we might want to adjust hostname source information even if the actual hostname is unchanged. */
7640a5de 755
f190ac48 756 if (name && !hostname_is_valid(name, 0))
ebcf1f97 757 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", name);
7640a5de 758
60e4fb42 759 context_read_etc_hostname(c);
7640a5de 760
c529695e
LP
761 r = bus_verify_polkit_async(
762 m,
763 CAP_SYS_ADMIN,
764 "org.freedesktop.hostname1.set-hostname",
403ed0e5 765 NULL,
c529695e
LP
766 interactive,
767 UID_INVALID,
768 &c->polkit_registry,
769 error);
66a4c743 770 if (r < 0)
ebcf1f97 771 return r;
66a4c743
LP
772 if (r == 0)
773 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7640a5de 774
aa994368 775 r = context_update_kernel_hostname(c, name);
60e4fb42 776 if (r < 0)
1b4cd646 777 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
60e4fb42 778 else if (r > 0)
efda832d
ZJS
779 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m),
780 "/org/freedesktop/hostname1", "org.freedesktop.hostname1",
781 "Hostname", "HostnameSource", NULL);
7640a5de 782
df2d202e 783 return sd_bus_reply_method_return(m, NULL);
66a4c743 784}
7640a5de 785
19070062 786static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
66a4c743
LP
787 Context *c = userdata;
788 const char *name;
102d8f81 789 int interactive;
66a4c743 790 int r;
7640a5de 791
19070062
LP
792 assert(m);
793 assert(c);
794
66a4c743
LP
795 r = sd_bus_message_read(m, "sb", &name, &interactive);
796 if (r < 0)
ebcf1f97 797 return r;
7640a5de 798
3c6f7c34 799 name = empty_to_null(name);
7640a5de 800
d7f4ad20
LP
801 context_read_etc_hostname(c);
802
66a4c743 803 if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME]))
df2d202e 804 return sd_bus_reply_method_return(m, NULL);
7640a5de 805
60e4fb42 806 if (name && !hostname_is_valid(name, 0))
c650f207
YW
807 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name);
808
c529695e
LP
809 r = bus_verify_polkit_async(
810 m,
811 CAP_SYS_ADMIN,
812 "org.freedesktop.hostname1.set-static-hostname",
403ed0e5 813 NULL,
c529695e
LP
814 interactive,
815 UID_INVALID,
816 &c->polkit_registry,
817 error);
66a4c743 818 if (r < 0)
ebcf1f97 819 return r;
66a4c743
LP
820 if (r == 0)
821 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7640a5de 822
e8acf091 823 r = free_and_strdup_warn(&c->data[PROP_STATIC_HOSTNAME], name);
c650f207
YW
824 if (r < 0)
825 return r;
7640a5de 826
66a4c743
LP
827 r = context_write_data_static_hostname(c);
828 if (r < 0) {
38b38500 829 log_error_errno(r, "Failed to write static hostname: %m");
957991b7
YW
830 if (ERRNO_IS_PRIVILEGE(r))
831 return sd_bus_error_set(error, BUS_ERROR_FILE_IS_PROTECTED, "Not allowed to update /etc/hostname.");
832 if (r == -EROFS)
833 return sd_bus_error_set(error, BUS_ERROR_READ_ONLY_FILESYSTEM, "/etc/hostname is in a read-only filesystem.");
1b4cd646 834 return sd_bus_error_set_errnof(error, r, "Failed to set static hostname: %m");
66a4c743 835 }
7640a5de 836
60e4fb42
ZJS
837 r = context_update_kernel_hostname(c, NULL);
838 if (r < 0) {
839 log_error_errno(r, "Failed to set hostname: %m");
840 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
841 }
7640a5de 842
efda832d 843 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m),
60e4fb42
ZJS
844 "/org/freedesktop/hostname1", "org.freedesktop.hostname1",
845 "StaticHostname", "Hostname", "HostnameSource", NULL);
7640a5de 846
df2d202e 847 return sd_bus_reply_method_return(m, NULL);
66a4c743 848}
7640a5de 849
19070062 850static int set_machine_info(Context *c, sd_bus_message *m, int prop, sd_bus_message_handler_t cb, sd_bus_error *error) {
102d8f81 851 int interactive;
66a4c743
LP
852 const char *name;
853 int r;
854
855 assert(c);
66a4c743
LP
856 assert(m);
857
858 r = sd_bus_message_read(m, "sb", &name, &interactive);
859 if (r < 0)
ebcf1f97 860 return r;
66a4c743 861
3c6f7c34 862 name = empty_to_null(name);
66a4c743 863
d7f4ad20
LP
864 context_read_machine_info(c);
865
66a4c743 866 if (streq_ptr(name, c->data[prop]))
df2d202e 867 return sd_bus_reply_method_return(m, NULL);
7640a5de 868
c650f207
YW
869 if (!isempty(name)) {
870 /* The icon name might ultimately be used as file
871 * name, so better be safe than sorry */
872
873 if (prop == PROP_ICON_NAME && !filename_is_valid(name))
874 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid icon name '%s'", name);
875 if (prop == PROP_PRETTY_HOSTNAME && string_has_cc(name, NULL))
38b38500 876 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty hostname '%s'", name);
c650f207
YW
877 if (prop == PROP_CHASSIS && !valid_chassis(name))
878 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid chassis '%s'", name);
879 if (prop == PROP_DEPLOYMENT && !valid_deployment(name))
880 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid deployment '%s'", name);
881 if (prop == PROP_LOCATION && string_has_cc(name, NULL))
882 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid location '%s'", name);
883 }
884
66a4c743
LP
885 /* Since the pretty hostname should always be changed at the
886 * same time as the static one, use the same policy action for
887 * both... */
888
c529695e
LP
889 r = bus_verify_polkit_async(
890 m,
891 CAP_SYS_ADMIN,
892 prop == PROP_PRETTY_HOSTNAME ? "org.freedesktop.hostname1.set-static-hostname" : "org.freedesktop.hostname1.set-machine-info",
403ed0e5 893 NULL,
c529695e
LP
894 interactive,
895 UID_INVALID,
896 &c->polkit_registry,
897 error);
66a4c743 898 if (r < 0)
ebcf1f97 899 return r;
66a4c743
LP
900 if (r == 0)
901 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
902
e8acf091 903 r = free_and_strdup_warn(&c->data[prop], name);
c650f207
YW
904 if (r < 0)
905 return r;
7640a5de 906
f200e8bb 907 r = context_write_data_machine_info(c);
66a4c743 908 if (r < 0) {
da927ba9 909 log_error_errno(r, "Failed to write machine info: %m");
957991b7
YW
910 if (ERRNO_IS_PRIVILEGE(r))
911 return sd_bus_error_set(error, BUS_ERROR_FILE_IS_PROTECTED, "Not allowed to update /etc/machine-info.");
912 if (r == -EROFS)
913 return sd_bus_error_set(error, BUS_ERROR_READ_ONLY_FILESYSTEM, "/etc/machine-info is in a read-only filesystem.");
1b4cd646 914 return sd_bus_error_set_errnof(error, r, "Failed to write machine info: %m");
66a4c743 915 }
7640a5de 916
66a4c743 917 log_info("Changed %s to '%s'",
38b38500 918 prop == PROP_PRETTY_HOSTNAME ? "pretty hostname" :
799298d6 919 prop == PROP_DEPLOYMENT ? "deployment" :
ce0f1493 920 prop == PROP_LOCATION ? "location" :
66a4c743 921 prop == PROP_CHASSIS ? "chassis" : "icon name", strna(c->data[prop]));
7640a5de 922
19070062
LP
923 (void) sd_bus_emit_properties_changed(
924 sd_bus_message_get_bus(m),
925 "/org/freedesktop/hostname1",
926 "org.freedesktop.hostname1",
927 prop == PROP_PRETTY_HOSTNAME ? "PrettyHostname" :
928 prop == PROP_DEPLOYMENT ? "Deployment" :
929 prop == PROP_LOCATION ? "Location" :
930 prop == PROP_CHASSIS ? "Chassis" : "IconName" , NULL);
7640a5de 931
df2d202e 932 return sd_bus_reply_method_return(m, NULL);
66a4c743 933}
7640a5de 934
19070062
LP
935static int method_set_pretty_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
936 return set_machine_info(userdata, m, PROP_PRETTY_HOSTNAME, method_set_pretty_hostname, error);
7640a5de
LP
937}
938
19070062
LP
939static int method_set_icon_name(sd_bus_message *m, void *userdata, sd_bus_error *error) {
940 return set_machine_info(userdata, m, PROP_ICON_NAME, method_set_icon_name, error);
66a4c743
LP
941}
942
19070062
LP
943static int method_set_chassis(sd_bus_message *m, void *userdata, sd_bus_error *error) {
944 return set_machine_info(userdata, m, PROP_CHASSIS, method_set_chassis, error);
66a4c743
LP
945}
946
19070062
LP
947static int method_set_deployment(sd_bus_message *m, void *userdata, sd_bus_error *error) {
948 return set_machine_info(userdata, m, PROP_DEPLOYMENT, method_set_deployment, error);
799298d6
JG
949}
950
19070062
LP
951static int method_set_location(sd_bus_message *m, void *userdata, sd_bus_error *error) {
952 return set_machine_info(userdata, m, PROP_LOCATION, method_set_location, error);
ce0f1493
LP
953}
954
21e627da
YW
955static int method_get_product_uuid(sd_bus_message *m, void *userdata, sd_bus_error *error) {
956 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
957 Context *c = userdata;
958 int interactive, r;
5704cd73 959 sd_id128_t uuid;
21e627da
YW
960
961 assert(m);
962 assert(c);
963
21e627da
YW
964 r = sd_bus_message_read(m, "b", &interactive);
965 if (r < 0)
966 return r;
967
968 r = bus_verify_polkit_async(
969 m,
970 CAP_SYS_ADMIN,
971 "org.freedesktop.hostname1.get-product-uuid",
972 NULL,
973 interactive,
974 UID_INVALID,
975 &c->polkit_registry,
976 error);
977 if (r < 0)
978 return r;
979 if (r == 0)
980 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
981
66ee2298
LP
982 r = id128_get_product(&uuid);
983 if (r < 0) {
984 if (r == -EADDRNOTAVAIL)
985 log_debug_errno(r, "DMI product UUID is all 0x00 or all 0xFF, ignoring.");
986 else
987 log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
988 "Failed to read product UUID, ignoring: %m");
989
990 return sd_bus_error_set(error, BUS_ERROR_NO_PRODUCT_UUID,
991 "Failed to read product UUID from firmware.");
992 }
993
21e627da
YW
994 r = sd_bus_message_new_method_return(m, &reply);
995 if (r < 0)
996 return r;
997
c52e295d 998 r = sd_bus_message_append_array(reply, 'y', uuid.bytes, sizeof(uuid.bytes));
21e627da
YW
999 if (r < 0)
1000 return r;
1001
1002 return sd_bus_send(NULL, reply, NULL);
1003}
1004
66a4c743
LP
1005static const sd_bus_vtable hostname_vtable[] = {
1006 SD_BUS_VTABLE_START(0),
aa994368 1007 SD_BUS_PROPERTY("Hostname", "s", property_get_hostname, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
d7f4ad20
LP
1008 SD_BUS_PROPERTY("StaticHostname", "s", property_get_static_hostname, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1009 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 1010 SD_BUS_PROPERTY("DefaultHostname", "s", property_get_default_hostname, 0, SD_BUS_VTABLE_PROPERTY_CONST),
60e4fb42 1011 SD_BUS_PROPERTY("HostnameSource", "s", property_get_hostname_source, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
66a4c743
LP
1012 SD_BUS_PROPERTY("IconName", "s", property_get_icon_name, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1013 SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
d7f4ad20
LP
1014 SD_BUS_PROPERTY("Deployment", "s", property_get_machine_info_field, offsetof(Context, data) + sizeof(char*) * PROP_DEPLOYMENT, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1015 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
1016 SD_BUS_PROPERTY("KernelName", "s", property_get_uname_field, offsetof(struct utsname, sysname), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
1017 SD_BUS_PROPERTY("KernelRelease", "s", property_get_uname_field, offsetof(struct utsname, release), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
1018 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
1019 SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", property_get_os_release_field, offsetof(Context, data) + sizeof(char*) * PROP_OS_PRETTY_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
1020 SD_BUS_PROPERTY("OperatingSystemCPEName", "s", property_get_os_release_field, offsetof(Context, data) + sizeof(char*) * PROP_OS_CPE_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
1021 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
1022 SD_BUS_PROPERTY("HardwareVendor", "s", property_get_hardware_vendor, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1023 SD_BUS_PROPERTY("HardwareModel", "s", property_get_hardware_model, 0, SD_BUS_VTABLE_PROPERTY_CONST),
106d79be
ZJS
1024
1025 SD_BUS_METHOD_WITH_NAMES("SetHostname",
1026 "sb",
1027 SD_BUS_PARAM(hostname)
1028 SD_BUS_PARAM(interactive),
1029 NULL,,
1030 method_set_hostname,
1031 SD_BUS_VTABLE_UNPRIVILEGED),
1032 SD_BUS_METHOD_WITH_NAMES("SetStaticHostname",
1033 "sb",
1034 SD_BUS_PARAM(hostname)
1035 SD_BUS_PARAM(interactive),
1036 NULL,,
1037 method_set_static_hostname,
1038 SD_BUS_VTABLE_UNPRIVILEGED),
1039 SD_BUS_METHOD_WITH_NAMES("SetPrettyHostname",
1040 "sb",
1041 SD_BUS_PARAM(hostname)
1042 SD_BUS_PARAM(interactive),
1043 NULL,,
1044 method_set_pretty_hostname,
1045 SD_BUS_VTABLE_UNPRIVILEGED),
1046 SD_BUS_METHOD_WITH_NAMES("SetIconName",
1047 "sb",
1048 SD_BUS_PARAM(icon)
1049 SD_BUS_PARAM(interactive),
1050 NULL,,
1051 method_set_icon_name,
1052 SD_BUS_VTABLE_UNPRIVILEGED),
1053 SD_BUS_METHOD_WITH_NAMES("SetChassis",
1054 "sb",
1055 SD_BUS_PARAM(chassis)
1056 SD_BUS_PARAM(interactive),
1057 NULL,,
1058 method_set_chassis,
1059 SD_BUS_VTABLE_UNPRIVILEGED),
1060 SD_BUS_METHOD_WITH_NAMES("SetDeployment",
1061 "sb",
1062 SD_BUS_PARAM(deployment)
1063 SD_BUS_PARAM(interactive),
1064 NULL,,
1065 method_set_deployment,
1066 SD_BUS_VTABLE_UNPRIVILEGED),
1067 SD_BUS_METHOD_WITH_NAMES("SetLocation",
1068 "sb",
1069 SD_BUS_PARAM(location)
1070 SD_BUS_PARAM(interactive),
1071 NULL,,
1072 method_set_location,
1073 SD_BUS_VTABLE_UNPRIVILEGED),
1074 SD_BUS_METHOD_WITH_NAMES("GetProductUUID",
1075 "b",
1076 SD_BUS_PARAM(interactive),
1077 "ay",
1078 SD_BUS_PARAM(uuid),
1079 method_get_product_uuid,
1080 SD_BUS_VTABLE_UNPRIVILEGED),
1081
66a4c743
LP
1082 SD_BUS_VTABLE_END,
1083};
1084
670139db
ZJS
1085static const BusObjectImplementation manager_object = {
1086 "/org/freedesktop/hostname1",
1087 "org.freedesktop.hostname1",
1088 .vtables = BUS_VTABLES(hostname_vtable),
1089};
1090
2ac4d1d4 1091static int connect_bus(Context *c, sd_event *event, sd_bus **ret) {
4afd3348 1092 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
7640a5de
LP
1093 int r;
1094
66a4c743
LP
1095 assert(c);
1096 assert(event);
2ac4d1d4 1097 assert(ret);
d0baa06f 1098
76b54375 1099 r = sd_bus_default_system(&bus);
23bbb0de
MS
1100 if (r < 0)
1101 return log_error_errno(r, "Failed to get system bus connection: %m");
d0baa06f 1102
670139db 1103 r = bus_add_implementation(bus, &manager_object, c);
23bbb0de 1104 if (r < 0)
670139db 1105 return r;
d0baa06f 1106
ac9f55ed
LP
1107 r = bus_log_control_api_register(bus);
1108 if (r < 0)
1109 return r;
1110
0c0b9306 1111 r = sd_bus_request_name_async(bus, NULL, "org.freedesktop.hostname1", 0, NULL, NULL);
23bbb0de 1112 if (r < 0)
0c0b9306 1113 return log_error_errno(r, "Failed to request name: %m");
add10b5a 1114
66a4c743 1115 r = sd_bus_attach_event(bus, event, 0);
23bbb0de
MS
1116 if (r < 0)
1117 return log_error_errno(r, "Failed to attach bus to event loop: %m");
d0baa06f 1118
2ac4d1d4 1119 *ret = TAKE_PTR(bus);
66a4c743 1120 return 0;
d0baa06f
LP
1121}
1122
85ae63ee 1123static int run(int argc, char *argv[]) {
60e4fb42
ZJS
1124 _cleanup_(context_destroy) Context context = {
1125 .hostname_source = _HOSTNAME_INVALID, /* appropriate value will be set later */
1126 };
4afd3348
LP
1127 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
1128 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
d0baa06f 1129 int r;
d0baa06f 1130
d2acb93d 1131 log_setup();
7640a5de 1132
fc021a5b
ZJS
1133 r = service_parse_argv("systemd-hostnamed.service",
1134 "Manage the system hostname and related metadata.",
670139db
ZJS
1135 BUS_IMPLEMENTATIONS(&manager_object,
1136 &log_control_object),
fc021a5b
ZJS
1137 argc, argv);
1138 if (r <= 0)
1139 return r;
1140
4c12626c 1141 umask(0022);
a9ba0e32
CG
1142
1143 r = mac_selinux_init();
1144 if (r < 0)
1145 return r;
4c12626c 1146
b22c8bfc
YW
1147 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
1148
afc6adb5 1149 r = sd_event_default(&event);
85ae63ee
YW
1150 if (r < 0)
1151 return log_error_errno(r, "Failed to allocate event loop: %m");
7640a5de 1152
b22c8bfc
YW
1153 (void) sd_event_set_watchdog(event, true);
1154
1155 r = sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
85ae63ee
YW
1156 if (r < 0)
1157 return log_error_errno(r, "Failed to install SIGINT handler: %m");
b22c8bfc
YW
1158
1159 r = sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
85ae63ee
YW
1160 if (r < 0)
1161 return log_error_errno(r, "Failed to install SIGTERM handler: %m");
cde93897 1162
66a4c743 1163 r = connect_bus(&context, event, &bus);
d0baa06f 1164 if (r < 0)
85ae63ee 1165 return r;
7640a5de 1166
37224a5f 1167 r = bus_event_loop_with_idle(event, bus, "org.freedesktop.hostname1", DEFAULT_EXIT_USEC, NULL, NULL);
85ae63ee
YW
1168 if (r < 0)
1169 return log_error_errno(r, "Failed to run event loop: %m");
7640a5de 1170
85ae63ee 1171 return 0;
7640a5de 1172}
85ae63ee
YW
1173
1174DEFINE_MAIN_FUNCTION(run);