]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/hostname/hostnamed.c
hostnamed: refactor vendor/model querying a bit, reuse function
[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
61d44b6b
LP
452static int get_dmi_data(const char *database_key, const char *regular_key, char **ret) {
453 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
454 _cleanup_free_ char *b = NULL;
455 const char *s = NULL;
456 int r;
457
458 r = sd_device_new_from_syspath(&device, "/sys/class/dmi/id");
459 if (r < 0)
460 return log_debug_errno(r, "Failed to open /sys/class/dmi/id device, ignoring: %m");
461
462 if (database_key)
463 (void) sd_device_get_property_value(device, database_key, &s);
464 if (!s && regular_key)
465 (void) sd_device_get_property_value(device, regular_key, &s);
466
467 if (s) {
468 b = strdup(s);
469 if (!b)
470 return -ENOMEM;
471 }
472
473 if (ret)
474 *ret = TAKE_PTR(b);
475
476 return !!s;
477}
478
479static int get_hardware_vendor(char **ret) {
480 return get_dmi_data("ID_VENDOR_FROM_DATABASE", "ID_VENDOR", ret);
481}
482
483static int get_hardware_model(char **ret) {
484 return get_dmi_data("ID_MODEL_FROM_DATABASE", "ID_MODEL", ret);
485}
486
b9d80698
FB
487static int property_get_hardware_vendor(
488 sd_bus *bus,
489 const char *path,
490 const char *interface,
491 const char *property,
492 sd_bus_message *reply,
493 void *userdata,
494 sd_bus_error *error) {
b9d80698 495
61d44b6b 496 _cleanup_free_ char *vendor = NULL;
b9d80698 497
61d44b6b
LP
498 (void) get_hardware_vendor(&vendor);
499 return sd_bus_message_append(reply, "s", vendor);
b9d80698
FB
500}
501
502static int property_get_hardware_model(
503 sd_bus *bus,
504 const char *path,
505 const char *interface,
506 const char *property,
507 sd_bus_message *reply,
508 void *userdata,
509 sd_bus_error *error) {
b9d80698 510
61d44b6b 511 _cleanup_free_ char *model = NULL;
b9d80698 512
61d44b6b
LP
513 (void) get_hardware_model(&model);
514 return sd_bus_message_append(reply, "s", model);
b9d80698
FB
515}
516
aa994368
LP
517static int property_get_hostname(
518 sd_bus *bus,
519 const char *path,
520 const char *interface,
521 const char *property,
522 sd_bus_message *reply,
523 void *userdata,
524 sd_bus_error *error) {
525
05c6f341 526 _cleanup_free_ char *hn = NULL;
aa994368
LP
527 int r;
528
05c6f341
ZJS
529 r = gethostname_strict(&hn);
530 if (r < 0) {
531 if (r != -ENXIO)
532 return r;
aa994368 533
05c6f341
ZJS
534 hn = get_default_hostname();
535 if (!hn)
536 return -ENOMEM;
537 }
538
539 return sd_bus_message_append(reply, "s", hn);
aa994368
LP
540}
541
d7f4ad20
LP
542static int property_get_static_hostname(
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 Context *c = userdata;
552 assert(c);
553
554 context_read_etc_hostname(c);
555
556 return sd_bus_message_append(reply, "s", c->data[PROP_STATIC_HOSTNAME]);
557}
558
8770c813 559static int property_get_default_hostname(
05c6f341
ZJS
560 sd_bus *bus,
561 const char *path,
562 const char *interface,
563 const char *property,
564 sd_bus_message *reply,
565 void *userdata,
566 sd_bus_error *error) {
567
61d44b6b
LP
568 _cleanup_free_ char *hn = NULL;
569
570 hn = get_default_hostname();
05c6f341
ZJS
571 if (!hn)
572 return log_oom();
573
574 return sd_bus_message_append(reply, "s", hn);
575}
ce6b138c 576
60e4fb42
ZJS
577static int property_get_hostname_source(
578 sd_bus *bus,
579 const char *path,
580 const char *interface,
581 const char *property,
582 sd_bus_message *reply,
583 void *userdata,
584 sd_bus_error *error) {
585
586 Context *c = userdata;
587 int r;
588 assert(c);
589
590 context_read_etc_hostname(c);
591
592 if (c->hostname_source < 0) {
593 char hostname[HOST_NAME_MAX + 1] = {};
594 _cleanup_free_ char *fallback = NULL;
595
596 (void) get_hostname_filtered(hostname);
597
598 if (streq_ptr(hostname, c->data[PROP_STATIC_HOSTNAME]))
599 c->hostname_source = HOSTNAME_STATIC;
600
601 else {
602 /* If the hostname was not set by us, try to figure out where it came from. If we set
8770c813 603 * it to the default hostname, the file will tell us. We compare the string because
60e4fb42
ZJS
604 * it is possible that the hostname was set by an older version that had a different
605 * fallback, in the initramfs or before we reexecuted. */
606
8770c813 607 r = read_one_line_file("/run/systemd/default-hostname", &fallback);
60e4fb42 608 if (r < 0 && r != -ENOENT)
8770c813 609 log_warning_errno(r, "Failed to read /run/systemd/default-hostname, ignoring: %m");
60e4fb42
ZJS
610
611 if (streq_ptr(fallback, hostname))
8770c813 612 c->hostname_source = HOSTNAME_DEFAULT;
60e4fb42
ZJS
613 else
614 c->hostname_source = HOSTNAME_TRANSIENT;
615 }
616 }
617
618 return sd_bus_message_append(reply, "s", hostname_source_to_string(c->hostname_source));
619}
620
d7f4ad20
LP
621static int property_get_machine_info_field(
622 sd_bus *bus,
623 const char *path,
624 const char *interface,
625 const char *property,
626 sd_bus_message *reply,
627 void *userdata,
628 sd_bus_error *error) {
629
630 sd_bus_slot *slot;
631 Context *c;
632
633 /* Acquire the context object without this property's userdata offset added. Explanation: we want
634 * access to two pointers here: a) the main context object we cache all properties in, and b) the
635 * pointer to the property field inside the context object that we are supposed to update and
636 * use. The latter (b) we get in the 'userdata' function parameter, and sd-bus calculates that for us
637 * from the 'userdata' pointer we supplied when the vtable was registered, with the offset we
638 * specified in the vtable added on top. To get the former (a) we need the 'userdata' pointer from
639 * the vtable registration directly, without the offset added. Hence we ask sd-bus what the slot
640 * object is (which encapsulates the vtable registration), and then query the 'userdata' field
641 * directly off it. */
642 assert_se(slot = sd_bus_get_current_slot(bus));
643 assert_se(c = sd_bus_slot_get_userdata(slot));
644
645 context_read_machine_info(c);
646
647 return sd_bus_message_append(reply, "s", *(char**) userdata);
648}
649
650static int property_get_os_release_field(
651 sd_bus *bus,
652 const char *path,
653 const char *interface,
654 const char *property,
655 sd_bus_message *reply,
656 void *userdata,
657 sd_bus_error *error) {
658
659 sd_bus_slot *slot;
660 Context *c;
661
662 /* As above, acquire the current context without this property's userdata offset added. */
663 assert_se(slot = sd_bus_get_current_slot(bus));
664 assert_se(c = sd_bus_slot_get_userdata(slot));
665
666 context_read_os_release(c);
667
668 return sd_bus_message_append(reply, "s", *(char**) userdata);
669}
670
66a4c743
LP
671static int property_get_icon_name(
672 sd_bus *bus,
673 const char *path,
674 const char *interface,
675 const char *property,
676 sd_bus_message *reply,
ebcf1f97
LP
677 void *userdata,
678 sd_bus_error *error) {
7640a5de 679
66a4c743
LP
680 _cleanup_free_ char *n = NULL;
681 Context *c = userdata;
682 const char *name;
7640a5de 683
d7f4ad20
LP
684 context_read_machine_info(c);
685
66a4c743
LP
686 if (isempty(c->data[PROP_ICON_NAME]))
687 name = n = context_fallback_icon_name(c);
7640a5de 688 else
66a4c743
LP
689 name = c->data[PROP_ICON_NAME];
690
691 if (!name)
692 return -ENOMEM;
7640a5de 693
ebcf1f97 694 return sd_bus_message_append(reply, "s", name);
7640a5de
LP
695}
696
66a4c743
LP
697static int property_get_chassis(
698 sd_bus *bus,
699 const char *path,
700 const char *interface,
701 const char *property,
702 sd_bus_message *reply,
ebcf1f97
LP
703 void *userdata,
704 sd_bus_error *error) {
7871c8e9 705
66a4c743
LP
706 Context *c = userdata;
707 const char *name;
7871c8e9 708
d7f4ad20
LP
709 context_read_machine_info(c);
710
66a4c743 711 if (isempty(c->data[PROP_CHASSIS]))
7871c8e9
LP
712 name = fallback_chassis();
713 else
66a4c743 714 name = c->data[PROP_CHASSIS];
7871c8e9 715
ebcf1f97 716 return sd_bus_message_append(reply, "s", name);
7871c8e9
LP
717}
718
72f48cd3
LP
719static int property_get_uname_field(
720 sd_bus *bus,
721 const char *path,
722 const char *interface,
723 const char *property,
724 sd_bus_message *reply,
725 void *userdata,
726 sd_bus_error *error) {
727
728 struct utsname u;
729
730 assert_se(uname(&u) >= 0);
731
732 return sd_bus_message_append(reply, "s", (char*) &u + PTR_TO_SIZE(userdata));
733}
734
19070062 735static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
66a4c743
LP
736 Context *c = userdata;
737 const char *name;
aa994368 738 int interactive, r;
d200735e 739
19070062
LP
740 assert(m);
741 assert(c);
742
66a4c743
LP
743 r = sd_bus_message_read(m, "sb", &name, &interactive);
744 if (r < 0)
ebcf1f97 745 return r;
d200735e 746
60e4fb42 747 name = empty_to_null(name);
7640a5de 748
60e4fb42
ZJS
749 /* We always go through with the procedure below without comparing to the current hostname, because
750 * we might want to adjust hostname source information even if the actual hostname is unchanged. */
7640a5de 751
f190ac48 752 if (name && !hostname_is_valid(name, 0))
ebcf1f97 753 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", name);
7640a5de 754
60e4fb42 755 context_read_etc_hostname(c);
7640a5de 756
c529695e
LP
757 r = bus_verify_polkit_async(
758 m,
759 CAP_SYS_ADMIN,
760 "org.freedesktop.hostname1.set-hostname",
403ed0e5 761 NULL,
c529695e
LP
762 interactive,
763 UID_INVALID,
764 &c->polkit_registry,
765 error);
66a4c743 766 if (r < 0)
ebcf1f97 767 return r;
66a4c743
LP
768 if (r == 0)
769 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7640a5de 770
aa994368 771 r = context_update_kernel_hostname(c, name);
60e4fb42 772 if (r < 0)
1b4cd646 773 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
60e4fb42 774 else if (r > 0)
efda832d
ZJS
775 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m),
776 "/org/freedesktop/hostname1", "org.freedesktop.hostname1",
777 "Hostname", "HostnameSource", NULL);
7640a5de 778
df2d202e 779 return sd_bus_reply_method_return(m, NULL);
66a4c743 780}
7640a5de 781
19070062 782static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
66a4c743
LP
783 Context *c = userdata;
784 const char *name;
102d8f81 785 int interactive;
66a4c743 786 int r;
7640a5de 787
19070062
LP
788 assert(m);
789 assert(c);
790
66a4c743
LP
791 r = sd_bus_message_read(m, "sb", &name, &interactive);
792 if (r < 0)
ebcf1f97 793 return r;
7640a5de 794
3c6f7c34 795 name = empty_to_null(name);
7640a5de 796
d7f4ad20
LP
797 context_read_etc_hostname(c);
798
66a4c743 799 if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME]))
df2d202e 800 return sd_bus_reply_method_return(m, NULL);
7640a5de 801
60e4fb42 802 if (name && !hostname_is_valid(name, 0))
c650f207
YW
803 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name);
804
c529695e
LP
805 r = bus_verify_polkit_async(
806 m,
807 CAP_SYS_ADMIN,
808 "org.freedesktop.hostname1.set-static-hostname",
403ed0e5 809 NULL,
c529695e
LP
810 interactive,
811 UID_INVALID,
812 &c->polkit_registry,
813 error);
66a4c743 814 if (r < 0)
ebcf1f97 815 return r;
66a4c743
LP
816 if (r == 0)
817 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7640a5de 818
e8acf091 819 r = free_and_strdup_warn(&c->data[PROP_STATIC_HOSTNAME], name);
c650f207
YW
820 if (r < 0)
821 return r;
7640a5de 822
66a4c743
LP
823 r = context_write_data_static_hostname(c);
824 if (r < 0) {
38b38500 825 log_error_errno(r, "Failed to write static hostname: %m");
957991b7
YW
826 if (ERRNO_IS_PRIVILEGE(r))
827 return sd_bus_error_set(error, BUS_ERROR_FILE_IS_PROTECTED, "Not allowed to update /etc/hostname.");
828 if (r == -EROFS)
829 return sd_bus_error_set(error, BUS_ERROR_READ_ONLY_FILESYSTEM, "/etc/hostname is in a read-only filesystem.");
1b4cd646 830 return sd_bus_error_set_errnof(error, r, "Failed to set static hostname: %m");
66a4c743 831 }
7640a5de 832
60e4fb42
ZJS
833 r = context_update_kernel_hostname(c, NULL);
834 if (r < 0) {
835 log_error_errno(r, "Failed to set hostname: %m");
836 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
837 }
7640a5de 838
efda832d 839 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m),
60e4fb42
ZJS
840 "/org/freedesktop/hostname1", "org.freedesktop.hostname1",
841 "StaticHostname", "Hostname", "HostnameSource", NULL);
7640a5de 842
df2d202e 843 return sd_bus_reply_method_return(m, NULL);
66a4c743 844}
7640a5de 845
19070062 846static int set_machine_info(Context *c, sd_bus_message *m, int prop, sd_bus_message_handler_t cb, sd_bus_error *error) {
102d8f81 847 int interactive;
66a4c743
LP
848 const char *name;
849 int r;
850
851 assert(c);
66a4c743
LP
852 assert(m);
853
854 r = sd_bus_message_read(m, "sb", &name, &interactive);
855 if (r < 0)
ebcf1f97 856 return r;
66a4c743 857
3c6f7c34 858 name = empty_to_null(name);
66a4c743 859
d7f4ad20
LP
860 context_read_machine_info(c);
861
66a4c743 862 if (streq_ptr(name, c->data[prop]))
df2d202e 863 return sd_bus_reply_method_return(m, NULL);
7640a5de 864
c650f207
YW
865 if (!isempty(name)) {
866 /* The icon name might ultimately be used as file
867 * name, so better be safe than sorry */
868
869 if (prop == PROP_ICON_NAME && !filename_is_valid(name))
870 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid icon name '%s'", name);
871 if (prop == PROP_PRETTY_HOSTNAME && string_has_cc(name, NULL))
38b38500 872 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty hostname '%s'", name);
c650f207
YW
873 if (prop == PROP_CHASSIS && !valid_chassis(name))
874 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid chassis '%s'", name);
875 if (prop == PROP_DEPLOYMENT && !valid_deployment(name))
876 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid deployment '%s'", name);
877 if (prop == PROP_LOCATION && string_has_cc(name, NULL))
878 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid location '%s'", name);
879 }
880
66a4c743
LP
881 /* Since the pretty hostname should always be changed at the
882 * same time as the static one, use the same policy action for
883 * both... */
884
c529695e
LP
885 r = bus_verify_polkit_async(
886 m,
887 CAP_SYS_ADMIN,
888 prop == PROP_PRETTY_HOSTNAME ? "org.freedesktop.hostname1.set-static-hostname" : "org.freedesktop.hostname1.set-machine-info",
403ed0e5 889 NULL,
c529695e
LP
890 interactive,
891 UID_INVALID,
892 &c->polkit_registry,
893 error);
66a4c743 894 if (r < 0)
ebcf1f97 895 return r;
66a4c743
LP
896 if (r == 0)
897 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
898
e8acf091 899 r = free_and_strdup_warn(&c->data[prop], name);
c650f207
YW
900 if (r < 0)
901 return r;
7640a5de 902
f200e8bb 903 r = context_write_data_machine_info(c);
66a4c743 904 if (r < 0) {
da927ba9 905 log_error_errno(r, "Failed to write machine info: %m");
957991b7
YW
906 if (ERRNO_IS_PRIVILEGE(r))
907 return sd_bus_error_set(error, BUS_ERROR_FILE_IS_PROTECTED, "Not allowed to update /etc/machine-info.");
908 if (r == -EROFS)
909 return sd_bus_error_set(error, BUS_ERROR_READ_ONLY_FILESYSTEM, "/etc/machine-info is in a read-only filesystem.");
1b4cd646 910 return sd_bus_error_set_errnof(error, r, "Failed to write machine info: %m");
66a4c743 911 }
7640a5de 912
66a4c743 913 log_info("Changed %s to '%s'",
38b38500 914 prop == PROP_PRETTY_HOSTNAME ? "pretty hostname" :
799298d6 915 prop == PROP_DEPLOYMENT ? "deployment" :
ce0f1493 916 prop == PROP_LOCATION ? "location" :
66a4c743 917 prop == PROP_CHASSIS ? "chassis" : "icon name", strna(c->data[prop]));
7640a5de 918
19070062
LP
919 (void) sd_bus_emit_properties_changed(
920 sd_bus_message_get_bus(m),
921 "/org/freedesktop/hostname1",
922 "org.freedesktop.hostname1",
923 prop == PROP_PRETTY_HOSTNAME ? "PrettyHostname" :
924 prop == PROP_DEPLOYMENT ? "Deployment" :
925 prop == PROP_LOCATION ? "Location" :
926 prop == PROP_CHASSIS ? "Chassis" : "IconName" , NULL);
7640a5de 927
df2d202e 928 return sd_bus_reply_method_return(m, NULL);
66a4c743 929}
7640a5de 930
19070062
LP
931static int method_set_pretty_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
932 return set_machine_info(userdata, m, PROP_PRETTY_HOSTNAME, method_set_pretty_hostname, error);
7640a5de
LP
933}
934
19070062
LP
935static int method_set_icon_name(sd_bus_message *m, void *userdata, sd_bus_error *error) {
936 return set_machine_info(userdata, m, PROP_ICON_NAME, method_set_icon_name, error);
66a4c743
LP
937}
938
19070062
LP
939static int method_set_chassis(sd_bus_message *m, void *userdata, sd_bus_error *error) {
940 return set_machine_info(userdata, m, PROP_CHASSIS, method_set_chassis, error);
66a4c743
LP
941}
942
19070062
LP
943static int method_set_deployment(sd_bus_message *m, void *userdata, sd_bus_error *error) {
944 return set_machine_info(userdata, m, PROP_DEPLOYMENT, method_set_deployment, error);
799298d6
JG
945}
946
19070062
LP
947static int method_set_location(sd_bus_message *m, void *userdata, sd_bus_error *error) {
948 return set_machine_info(userdata, m, PROP_LOCATION, method_set_location, error);
ce0f1493
LP
949}
950
21e627da
YW
951static int method_get_product_uuid(sd_bus_message *m, void *userdata, sd_bus_error *error) {
952 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
953 Context *c = userdata;
954 int interactive, r;
5704cd73 955 sd_id128_t uuid;
21e627da
YW
956
957 assert(m);
958 assert(c);
959
21e627da
YW
960 r = sd_bus_message_read(m, "b", &interactive);
961 if (r < 0)
962 return r;
963
964 r = bus_verify_polkit_async(
965 m,
966 CAP_SYS_ADMIN,
967 "org.freedesktop.hostname1.get-product-uuid",
968 NULL,
969 interactive,
970 UID_INVALID,
971 &c->polkit_registry,
972 error);
973 if (r < 0)
974 return r;
975 if (r == 0)
976 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
977
66ee2298
LP
978 r = id128_get_product(&uuid);
979 if (r < 0) {
980 if (r == -EADDRNOTAVAIL)
981 log_debug_errno(r, "DMI product UUID is all 0x00 or all 0xFF, ignoring.");
982 else
983 log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
984 "Failed to read product UUID, ignoring: %m");
985
986 return sd_bus_error_set(error, BUS_ERROR_NO_PRODUCT_UUID,
987 "Failed to read product UUID from firmware.");
988 }
989
21e627da
YW
990 r = sd_bus_message_new_method_return(m, &reply);
991 if (r < 0)
992 return r;
993
c52e295d 994 r = sd_bus_message_append_array(reply, 'y', uuid.bytes, sizeof(uuid.bytes));
21e627da
YW
995 if (r < 0)
996 return r;
997
998 return sd_bus_send(NULL, reply, NULL);
999}
1000
66a4c743
LP
1001static const sd_bus_vtable hostname_vtable[] = {
1002 SD_BUS_VTABLE_START(0),
aa994368 1003 SD_BUS_PROPERTY("Hostname", "s", property_get_hostname, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
d7f4ad20
LP
1004 SD_BUS_PROPERTY("StaticHostname", "s", property_get_static_hostname, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1005 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 1006 SD_BUS_PROPERTY("DefaultHostname", "s", property_get_default_hostname, 0, SD_BUS_VTABLE_PROPERTY_CONST),
60e4fb42 1007 SD_BUS_PROPERTY("HostnameSource", "s", property_get_hostname_source, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
66a4c743
LP
1008 SD_BUS_PROPERTY("IconName", "s", property_get_icon_name, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1009 SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
d7f4ad20
LP
1010 SD_BUS_PROPERTY("Deployment", "s", property_get_machine_info_field, offsetof(Context, data) + sizeof(char*) * PROP_DEPLOYMENT, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1011 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
1012 SD_BUS_PROPERTY("KernelName", "s", property_get_uname_field, offsetof(struct utsname, sysname), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
1013 SD_BUS_PROPERTY("KernelRelease", "s", property_get_uname_field, offsetof(struct utsname, release), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
1014 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
1015 SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", property_get_os_release_field, offsetof(Context, data) + sizeof(char*) * PROP_OS_PRETTY_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
1016 SD_BUS_PROPERTY("OperatingSystemCPEName", "s", property_get_os_release_field, offsetof(Context, data) + sizeof(char*) * PROP_OS_CPE_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
1017 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
1018 SD_BUS_PROPERTY("HardwareVendor", "s", property_get_hardware_vendor, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1019 SD_BUS_PROPERTY("HardwareModel", "s", property_get_hardware_model, 0, SD_BUS_VTABLE_PROPERTY_CONST),
106d79be
ZJS
1020
1021 SD_BUS_METHOD_WITH_NAMES("SetHostname",
1022 "sb",
1023 SD_BUS_PARAM(hostname)
1024 SD_BUS_PARAM(interactive),
1025 NULL,,
1026 method_set_hostname,
1027 SD_BUS_VTABLE_UNPRIVILEGED),
1028 SD_BUS_METHOD_WITH_NAMES("SetStaticHostname",
1029 "sb",
1030 SD_BUS_PARAM(hostname)
1031 SD_BUS_PARAM(interactive),
1032 NULL,,
1033 method_set_static_hostname,
1034 SD_BUS_VTABLE_UNPRIVILEGED),
1035 SD_BUS_METHOD_WITH_NAMES("SetPrettyHostname",
1036 "sb",
1037 SD_BUS_PARAM(hostname)
1038 SD_BUS_PARAM(interactive),
1039 NULL,,
1040 method_set_pretty_hostname,
1041 SD_BUS_VTABLE_UNPRIVILEGED),
1042 SD_BUS_METHOD_WITH_NAMES("SetIconName",
1043 "sb",
1044 SD_BUS_PARAM(icon)
1045 SD_BUS_PARAM(interactive),
1046 NULL,,
1047 method_set_icon_name,
1048 SD_BUS_VTABLE_UNPRIVILEGED),
1049 SD_BUS_METHOD_WITH_NAMES("SetChassis",
1050 "sb",
1051 SD_BUS_PARAM(chassis)
1052 SD_BUS_PARAM(interactive),
1053 NULL,,
1054 method_set_chassis,
1055 SD_BUS_VTABLE_UNPRIVILEGED),
1056 SD_BUS_METHOD_WITH_NAMES("SetDeployment",
1057 "sb",
1058 SD_BUS_PARAM(deployment)
1059 SD_BUS_PARAM(interactive),
1060 NULL,,
1061 method_set_deployment,
1062 SD_BUS_VTABLE_UNPRIVILEGED),
1063 SD_BUS_METHOD_WITH_NAMES("SetLocation",
1064 "sb",
1065 SD_BUS_PARAM(location)
1066 SD_BUS_PARAM(interactive),
1067 NULL,,
1068 method_set_location,
1069 SD_BUS_VTABLE_UNPRIVILEGED),
1070 SD_BUS_METHOD_WITH_NAMES("GetProductUUID",
1071 "b",
1072 SD_BUS_PARAM(interactive),
1073 "ay",
1074 SD_BUS_PARAM(uuid),
1075 method_get_product_uuid,
1076 SD_BUS_VTABLE_UNPRIVILEGED),
1077
66a4c743
LP
1078 SD_BUS_VTABLE_END,
1079};
1080
670139db
ZJS
1081static const BusObjectImplementation manager_object = {
1082 "/org/freedesktop/hostname1",
1083 "org.freedesktop.hostname1",
1084 .vtables = BUS_VTABLES(hostname_vtable),
1085};
1086
2ac4d1d4 1087static int connect_bus(Context *c, sd_event *event, sd_bus **ret) {
4afd3348 1088 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
7640a5de
LP
1089 int r;
1090
66a4c743
LP
1091 assert(c);
1092 assert(event);
2ac4d1d4 1093 assert(ret);
d0baa06f 1094
76b54375 1095 r = sd_bus_default_system(&bus);
23bbb0de
MS
1096 if (r < 0)
1097 return log_error_errno(r, "Failed to get system bus connection: %m");
d0baa06f 1098
670139db 1099 r = bus_add_implementation(bus, &manager_object, c);
23bbb0de 1100 if (r < 0)
670139db 1101 return r;
d0baa06f 1102
ac9f55ed
LP
1103 r = bus_log_control_api_register(bus);
1104 if (r < 0)
1105 return r;
1106
0c0b9306 1107 r = sd_bus_request_name_async(bus, NULL, "org.freedesktop.hostname1", 0, NULL, NULL);
23bbb0de 1108 if (r < 0)
0c0b9306 1109 return log_error_errno(r, "Failed to request name: %m");
add10b5a 1110
66a4c743 1111 r = sd_bus_attach_event(bus, event, 0);
23bbb0de
MS
1112 if (r < 0)
1113 return log_error_errno(r, "Failed to attach bus to event loop: %m");
d0baa06f 1114
2ac4d1d4 1115 *ret = TAKE_PTR(bus);
66a4c743 1116 return 0;
d0baa06f
LP
1117}
1118
85ae63ee 1119static int run(int argc, char *argv[]) {
60e4fb42
ZJS
1120 _cleanup_(context_destroy) Context context = {
1121 .hostname_source = _HOSTNAME_INVALID, /* appropriate value will be set later */
1122 };
4afd3348
LP
1123 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
1124 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
d0baa06f 1125 int r;
d0baa06f 1126
d2acb93d 1127 log_setup();
7640a5de 1128
fc021a5b
ZJS
1129 r = service_parse_argv("systemd-hostnamed.service",
1130 "Manage the system hostname and related metadata.",
670139db
ZJS
1131 BUS_IMPLEMENTATIONS(&manager_object,
1132 &log_control_object),
fc021a5b
ZJS
1133 argc, argv);
1134 if (r <= 0)
1135 return r;
1136
4c12626c 1137 umask(0022);
a9ba0e32
CG
1138
1139 r = mac_selinux_init();
1140 if (r < 0)
1141 return r;
4c12626c 1142
b22c8bfc
YW
1143 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
1144
afc6adb5 1145 r = sd_event_default(&event);
85ae63ee
YW
1146 if (r < 0)
1147 return log_error_errno(r, "Failed to allocate event loop: %m");
7640a5de 1148
b22c8bfc
YW
1149 (void) sd_event_set_watchdog(event, true);
1150
1151 r = sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
85ae63ee
YW
1152 if (r < 0)
1153 return log_error_errno(r, "Failed to install SIGINT handler: %m");
b22c8bfc
YW
1154
1155 r = sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
85ae63ee
YW
1156 if (r < 0)
1157 return log_error_errno(r, "Failed to install SIGTERM handler: %m");
cde93897 1158
66a4c743 1159 r = connect_bus(&context, event, &bus);
d0baa06f 1160 if (r < 0)
85ae63ee 1161 return r;
7640a5de 1162
37224a5f 1163 r = bus_event_loop_with_idle(event, bus, "org.freedesktop.hostname1", DEFAULT_EXIT_USEC, NULL, NULL);
85ae63ee
YW
1164 if (r < 0)
1165 return log_error_errno(r, "Failed to run event loop: %m");
7640a5de 1166
85ae63ee 1167 return 0;
7640a5de 1168}
85ae63ee
YW
1169
1170DEFINE_MAIN_FUNCTION(run);