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