]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/hostname/hostnamed.c
28fc628742a8f074f33eeea9784f476f8897309a
[thirdparty/systemd.git] / src / hostname / hostnamed.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2011 Lennart Poettering
6 ***/
7
8 #include <errno.h>
9 #include <string.h>
10 #include <sys/utsname.h>
11 #include <unistd.h>
12
13 #include "alloc-util.h"
14 #include "bus-util.h"
15 #include "def.h"
16 #include "env-util.h"
17 #include "fileio-label.h"
18 #include "hostname-util.h"
19 #include "os-util.h"
20 #include "parse-util.h"
21 #include "path-util.h"
22 #include "selinux-util.h"
23 #include "strv.h"
24 #include "user-util.h"
25 #include "util.h"
26 #include "virt.h"
27
28 #define VALID_DEPLOYMENT_CHARS (DIGITS LETTERS "-.:")
29
30 enum {
31 PROP_HOSTNAME,
32 PROP_STATIC_HOSTNAME,
33 PROP_PRETTY_HOSTNAME,
34 PROP_ICON_NAME,
35 PROP_CHASSIS,
36 PROP_DEPLOYMENT,
37 PROP_LOCATION,
38 PROP_KERNEL_NAME,
39 PROP_KERNEL_RELEASE,
40 PROP_KERNEL_VERSION,
41 PROP_OS_PRETTY_NAME,
42 PROP_OS_CPE_NAME,
43 PROP_HOME_URL,
44 _PROP_MAX
45 };
46
47 typedef struct Context {
48 char *data[_PROP_MAX];
49 Hashmap *polkit_registry;
50 } Context;
51
52 static void context_reset(Context *c) {
53 int p;
54
55 assert(c);
56
57 for (p = 0; p < _PROP_MAX; p++)
58 c->data[p] = mfree(c->data[p]);
59 }
60
61 static void context_free(Context *c) {
62 assert(c);
63
64 context_reset(c);
65 bus_verify_polkit_async_registry_free(c->polkit_registry);
66 }
67
68 static int context_read_data(Context *c) {
69 int r;
70 struct utsname u;
71
72 assert(c);
73
74 context_reset(c);
75
76 assert_se(uname(&u) >= 0);
77 c->data[PROP_KERNEL_NAME] = strdup(u.sysname);
78 c->data[PROP_KERNEL_RELEASE] = strdup(u.release);
79 c->data[PROP_KERNEL_VERSION] = strdup(u.version);
80 if (!c->data[PROP_KERNEL_NAME] || !c->data[PROP_KERNEL_RELEASE] ||
81 !c->data[PROP_KERNEL_VERSION])
82 return -ENOMEM;
83
84 c->data[PROP_HOSTNAME] = gethostname_malloc();
85 if (!c->data[PROP_HOSTNAME])
86 return -ENOMEM;
87
88 r = read_etc_hostname(NULL, &c->data[PROP_STATIC_HOSTNAME]);
89 if (r < 0 && r != -ENOENT)
90 return r;
91
92 r = parse_env_file(NULL, "/etc/machine-info", NEWLINE,
93 "PRETTY_HOSTNAME", &c->data[PROP_PRETTY_HOSTNAME],
94 "ICON_NAME", &c->data[PROP_ICON_NAME],
95 "CHASSIS", &c->data[PROP_CHASSIS],
96 "DEPLOYMENT", &c->data[PROP_DEPLOYMENT],
97 "LOCATION", &c->data[PROP_LOCATION],
98 NULL);
99 if (r < 0 && r != -ENOENT)
100 return r;
101
102 r = parse_os_release(NULL,
103 "PRETTY_NAME", &c->data[PROP_OS_PRETTY_NAME],
104 "CPE_NAME", &c->data[PROP_OS_CPE_NAME],
105 "HOME_URL", &c->data[PROP_HOME_URL],
106 NULL);
107 if (r < 0 && r != -ENOENT)
108 return r;
109
110 return 0;
111 }
112
113 static bool valid_chassis(const char *chassis) {
114 assert(chassis);
115
116 return nulstr_contains(
117 "vm\0"
118 "container\0"
119 "desktop\0"
120 "laptop\0"
121 "convertible\0"
122 "server\0"
123 "tablet\0"
124 "handset\0"
125 "watch\0"
126 "embedded\0",
127 chassis);
128 }
129
130 static bool valid_deployment(const char *deployment) {
131 assert(deployment);
132
133 return in_charset(deployment, VALID_DEPLOYMENT_CHARS);
134 }
135
136 static const char* fallback_chassis(void) {
137 char *type;
138 unsigned t;
139 int v, r;
140
141 v = detect_virtualization();
142 if (VIRTUALIZATION_IS_VM(v))
143 return "vm";
144 if (VIRTUALIZATION_IS_CONTAINER(v))
145 return "container";
146
147 r = read_one_line_file("/sys/class/dmi/id/chassis_type", &type);
148 if (r < 0)
149 goto try_acpi;
150
151 r = safe_atou(type, &t);
152 free(type);
153 if (r < 0)
154 goto try_acpi;
155
156 /* We only list the really obvious cases here. The DMI data is unreliable enough, so let's not do any
157 additional guesswork on top of that.
158
159 See the SMBIOS Specification 3.0 section 7.4.1 for details about the values listed here:
160
161 https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.0.0.pdf
162 */
163
164 switch (t) {
165
166 case 0x3: /* Desktop */
167 case 0x4: /* Low Profile Desktop */
168 case 0x6: /* Mini Tower */
169 case 0x7: /* Tower */
170 return "desktop";
171
172 case 0x8: /* Portable */
173 case 0x9: /* Laptop */
174 case 0xA: /* Notebook */
175 case 0xE: /* Sub Notebook */
176 return "laptop";
177
178 case 0xB: /* Hand Held */
179 return "handset";
180
181 case 0x11: /* Main Server Chassis */
182 case 0x1C: /* Blade */
183 case 0x1D: /* Blade Enclosure */
184 return "server";
185
186 case 0x1E: /* Tablet */
187 return "tablet";
188
189 case 0x1F: /* Convertible */
190 case 0x20: /* Detachable */
191 return "convertible";
192 }
193
194 try_acpi:
195 r = read_one_line_file("/sys/firmware/acpi/pm_profile", &type);
196 if (r < 0)
197 return NULL;
198
199 r = safe_atou(type, &t);
200 free(type);
201 if (r < 0)
202 return NULL;
203
204 /* We only list the really obvious cases here as the ACPI data is not really super reliable.
205 *
206 * See the ACPI 5.0 Spec Section 5.2.9.1 for details:
207 *
208 * http://www.acpi.info/DOWNLOADS/ACPIspec50.pdf
209 */
210
211 switch(t) {
212
213 case 1: /* Desktop */
214 case 3: /* Workstation */
215 case 6: /* Appliance PC */
216 return "desktop";
217
218 case 2: /* Mobile */
219 return "laptop";
220
221 case 4: /* Enterprise Server */
222 case 5: /* SOHO Server */
223 case 7: /* Performance Server */
224 return "server";
225
226 case 8: /* Tablet */
227 return "tablet";
228 }
229
230 return NULL;
231 }
232
233 static char* context_fallback_icon_name(Context *c) {
234 const char *chassis;
235
236 assert(c);
237
238 if (!isempty(c->data[PROP_CHASSIS]))
239 return strappend("computer-", c->data[PROP_CHASSIS]);
240
241 chassis = fallback_chassis();
242 if (chassis)
243 return strappend("computer-", chassis);
244
245 return strdup("computer");
246 }
247
248 static bool hostname_is_useful(const char *hn) {
249 return !isempty(hn) && !is_localhost(hn);
250 }
251
252 static int context_update_kernel_hostname(Context *c) {
253 const char *static_hn;
254 const char *hn;
255
256 assert(c);
257
258 static_hn = c->data[PROP_STATIC_HOSTNAME];
259
260 /* /etc/hostname with something other than "localhost"
261 * has the highest preference ... */
262 if (hostname_is_useful(static_hn))
263 hn = static_hn;
264
265 /* ... the transient host name, (ie: DHCP) comes next ... */
266 else if (!isempty(c->data[PROP_HOSTNAME]))
267 hn = c->data[PROP_HOSTNAME];
268
269 /* ... fallback to static "localhost.*" ignored above ... */
270 else if (!isempty(static_hn))
271 hn = static_hn;
272
273 /* ... and the ultimate fallback */
274 else
275 hn = FALLBACK_HOSTNAME;
276
277 if (sethostname_idempotent(hn) < 0)
278 return -errno;
279
280 return 0;
281 }
282
283 static int context_write_data_static_hostname(Context *c) {
284
285 assert(c);
286
287 if (isempty(c->data[PROP_STATIC_HOSTNAME])) {
288
289 if (unlink("/etc/hostname") < 0)
290 return errno == ENOENT ? 0 : -errno;
291
292 return 0;
293 }
294 return write_string_file_atomic_label("/etc/hostname", c->data[PROP_STATIC_HOSTNAME]);
295 }
296
297 static int context_write_data_machine_info(Context *c) {
298
299 static const char * const name[_PROP_MAX] = {
300 [PROP_PRETTY_HOSTNAME] = "PRETTY_HOSTNAME",
301 [PROP_ICON_NAME] = "ICON_NAME",
302 [PROP_CHASSIS] = "CHASSIS",
303 [PROP_DEPLOYMENT] = "DEPLOYMENT",
304 [PROP_LOCATION] = "LOCATION",
305 };
306
307 _cleanup_strv_free_ char **l = NULL;
308 int r, p;
309
310 assert(c);
311
312 r = load_env_file(NULL, "/etc/machine-info", NULL, &l);
313 if (r < 0 && r != -ENOENT)
314 return r;
315
316 for (p = PROP_PRETTY_HOSTNAME; p <= PROP_LOCATION; p++) {
317 _cleanup_free_ char *t = NULL;
318 char **u;
319
320 assert(name[p]);
321
322 if (isempty(c->data[p])) {
323 strv_env_unset(l, name[p]);
324 continue;
325 }
326
327 t = strjoin(name[p], "=", c->data[p]);
328 if (!t)
329 return -ENOMEM;
330
331 u = strv_env_set(l, t);
332 if (!u)
333 return -ENOMEM;
334
335 strv_free_and_replace(l, u);
336 }
337
338 if (strv_isempty(l)) {
339 if (unlink("/etc/machine-info") < 0)
340 return errno == ENOENT ? 0 : -errno;
341
342 return 0;
343 }
344
345 return write_env_file_label("/etc/machine-info", l);
346 }
347
348 static int property_get_icon_name(
349 sd_bus *bus,
350 const char *path,
351 const char *interface,
352 const char *property,
353 sd_bus_message *reply,
354 void *userdata,
355 sd_bus_error *error) {
356
357 _cleanup_free_ char *n = NULL;
358 Context *c = userdata;
359 const char *name;
360
361 if (isempty(c->data[PROP_ICON_NAME]))
362 name = n = context_fallback_icon_name(c);
363 else
364 name = c->data[PROP_ICON_NAME];
365
366 if (!name)
367 return -ENOMEM;
368
369 return sd_bus_message_append(reply, "s", name);
370 }
371
372 static int property_get_chassis(
373 sd_bus *bus,
374 const char *path,
375 const char *interface,
376 const char *property,
377 sd_bus_message *reply,
378 void *userdata,
379 sd_bus_error *error) {
380
381 Context *c = userdata;
382 const char *name;
383
384 if (isempty(c->data[PROP_CHASSIS]))
385 name = fallback_chassis();
386 else
387 name = c->data[PROP_CHASSIS];
388
389 return sd_bus_message_append(reply, "s", name);
390 }
391
392 static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
393 Context *c = userdata;
394 const char *name;
395 int interactive;
396 int r;
397
398 assert(m);
399 assert(c);
400
401 r = sd_bus_message_read(m, "sb", &name, &interactive);
402 if (r < 0)
403 return r;
404
405 if (isempty(name))
406 name = c->data[PROP_STATIC_HOSTNAME];
407
408 if (isempty(name))
409 name = FALLBACK_HOSTNAME;
410
411 if (!hostname_is_valid(name, false))
412 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", name);
413
414 if (streq_ptr(name, c->data[PROP_HOSTNAME]))
415 return sd_bus_reply_method_return(m, NULL);
416
417 r = bus_verify_polkit_async(
418 m,
419 CAP_SYS_ADMIN,
420 "org.freedesktop.hostname1.set-hostname",
421 NULL,
422 interactive,
423 UID_INVALID,
424 &c->polkit_registry,
425 error);
426 if (r < 0)
427 return r;
428 if (r == 0)
429 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
430
431 r = free_and_strdup(&c->data[PROP_HOSTNAME], name);
432 if (r < 0)
433 return r;
434
435 r = context_update_kernel_hostname(c);
436 if (r < 0) {
437 log_error_errno(r, "Failed to set host name: %m");
438 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
439 }
440
441 log_info("Changed host name to '%s'", strna(c->data[PROP_HOSTNAME]));
442
443 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "Hostname", NULL);
444
445 return sd_bus_reply_method_return(m, NULL);
446 }
447
448 static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
449 Context *c = userdata;
450 const char *name;
451 int interactive;
452 int r;
453
454 assert(m);
455 assert(c);
456
457 r = sd_bus_message_read(m, "sb", &name, &interactive);
458 if (r < 0)
459 return r;
460
461 name = empty_to_null(name);
462
463 if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME]))
464 return sd_bus_reply_method_return(m, NULL);
465
466 if (!isempty(name) && !hostname_is_valid(name, false))
467 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name);
468
469 r = bus_verify_polkit_async(
470 m,
471 CAP_SYS_ADMIN,
472 "org.freedesktop.hostname1.set-static-hostname",
473 NULL,
474 interactive,
475 UID_INVALID,
476 &c->polkit_registry,
477 error);
478 if (r < 0)
479 return r;
480 if (r == 0)
481 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
482
483 r = free_and_strdup(&c->data[PROP_STATIC_HOSTNAME], name);
484 if (r < 0)
485 return r;
486
487 r = context_update_kernel_hostname(c);
488 if (r < 0) {
489 log_error_errno(r, "Failed to set host name: %m");
490 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
491 }
492
493 r = context_write_data_static_hostname(c);
494 if (r < 0) {
495 log_error_errno(r, "Failed to write static host name: %m");
496 return sd_bus_error_set_errnof(error, r, "Failed to set static hostname: %m");
497 }
498
499 log_info("Changed static host name to '%s'", strna(c->data[PROP_STATIC_HOSTNAME]));
500
501 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "StaticHostname", NULL);
502
503 return sd_bus_reply_method_return(m, NULL);
504 }
505
506 static int set_machine_info(Context *c, sd_bus_message *m, int prop, sd_bus_message_handler_t cb, sd_bus_error *error) {
507 int interactive;
508 const char *name;
509 int r;
510
511 assert(c);
512 assert(m);
513
514 r = sd_bus_message_read(m, "sb", &name, &interactive);
515 if (r < 0)
516 return r;
517
518 name = empty_to_null(name);
519
520 if (streq_ptr(name, c->data[prop]))
521 return sd_bus_reply_method_return(m, NULL);
522
523 if (!isempty(name)) {
524 /* The icon name might ultimately be used as file
525 * name, so better be safe than sorry */
526
527 if (prop == PROP_ICON_NAME && !filename_is_valid(name))
528 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid icon name '%s'", name);
529 if (prop == PROP_PRETTY_HOSTNAME && string_has_cc(name, NULL))
530 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty host name '%s'", name);
531 if (prop == PROP_CHASSIS && !valid_chassis(name))
532 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid chassis '%s'", name);
533 if (prop == PROP_DEPLOYMENT && !valid_deployment(name))
534 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid deployment '%s'", name);
535 if (prop == PROP_LOCATION && string_has_cc(name, NULL))
536 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid location '%s'", name);
537 }
538
539 /* Since the pretty hostname should always be changed at the
540 * same time as the static one, use the same policy action for
541 * both... */
542
543 r = bus_verify_polkit_async(
544 m,
545 CAP_SYS_ADMIN,
546 prop == PROP_PRETTY_HOSTNAME ? "org.freedesktop.hostname1.set-static-hostname" : "org.freedesktop.hostname1.set-machine-info",
547 NULL,
548 interactive,
549 UID_INVALID,
550 &c->polkit_registry,
551 error);
552 if (r < 0)
553 return r;
554 if (r == 0)
555 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
556
557 r = free_and_strdup(&c->data[prop], name);
558 if (r < 0)
559 return r;
560
561 r = context_write_data_machine_info(c);
562 if (r < 0) {
563 log_error_errno(r, "Failed to write machine info: %m");
564 return sd_bus_error_set_errnof(error, r, "Failed to write machine info: %m");
565 }
566
567 log_info("Changed %s to '%s'",
568 prop == PROP_PRETTY_HOSTNAME ? "pretty host name" :
569 prop == PROP_DEPLOYMENT ? "deployment" :
570 prop == PROP_LOCATION ? "location" :
571 prop == PROP_CHASSIS ? "chassis" : "icon name", strna(c->data[prop]));
572
573 (void) sd_bus_emit_properties_changed(
574 sd_bus_message_get_bus(m),
575 "/org/freedesktop/hostname1",
576 "org.freedesktop.hostname1",
577 prop == PROP_PRETTY_HOSTNAME ? "PrettyHostname" :
578 prop == PROP_DEPLOYMENT ? "Deployment" :
579 prop == PROP_LOCATION ? "Location" :
580 prop == PROP_CHASSIS ? "Chassis" : "IconName" , NULL);
581
582 return sd_bus_reply_method_return(m, NULL);
583 }
584
585 static int method_set_pretty_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
586 return set_machine_info(userdata, m, PROP_PRETTY_HOSTNAME, method_set_pretty_hostname, error);
587 }
588
589 static int method_set_icon_name(sd_bus_message *m, void *userdata, sd_bus_error *error) {
590 return set_machine_info(userdata, m, PROP_ICON_NAME, method_set_icon_name, error);
591 }
592
593 static int method_set_chassis(sd_bus_message *m, void *userdata, sd_bus_error *error) {
594 return set_machine_info(userdata, m, PROP_CHASSIS, method_set_chassis, error);
595 }
596
597 static int method_set_deployment(sd_bus_message *m, void *userdata, sd_bus_error *error) {
598 return set_machine_info(userdata, m, PROP_DEPLOYMENT, method_set_deployment, error);
599 }
600
601 static int method_set_location(sd_bus_message *m, void *userdata, sd_bus_error *error) {
602 return set_machine_info(userdata, m, PROP_LOCATION, method_set_location, error);
603 }
604
605 static const sd_bus_vtable hostname_vtable[] = {
606 SD_BUS_VTABLE_START(0),
607 SD_BUS_PROPERTY("Hostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
608 SD_BUS_PROPERTY("StaticHostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_STATIC_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
609 SD_BUS_PROPERTY("PrettyHostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_PRETTY_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
610 SD_BUS_PROPERTY("IconName", "s", property_get_icon_name, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
611 SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
612 SD_BUS_PROPERTY("Deployment", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_DEPLOYMENT, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
613 SD_BUS_PROPERTY("Location", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_LOCATION, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
614 SD_BUS_PROPERTY("KernelName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
615 SD_BUS_PROPERTY("KernelRelease", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_RELEASE, SD_BUS_VTABLE_PROPERTY_CONST),
616 SD_BUS_PROPERTY("KernelVersion", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_VERSION, SD_BUS_VTABLE_PROPERTY_CONST),
617 SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_PRETTY_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
618 SD_BUS_PROPERTY("OperatingSystemCPEName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_CPE_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
619 SD_BUS_PROPERTY("HomeURL", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_HOME_URL, SD_BUS_VTABLE_PROPERTY_CONST),
620 SD_BUS_METHOD("SetHostname", "sb", NULL, method_set_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
621 SD_BUS_METHOD("SetStaticHostname", "sb", NULL, method_set_static_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
622 SD_BUS_METHOD("SetPrettyHostname", "sb", NULL, method_set_pretty_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
623 SD_BUS_METHOD("SetIconName", "sb", NULL, method_set_icon_name, SD_BUS_VTABLE_UNPRIVILEGED),
624 SD_BUS_METHOD("SetChassis", "sb", NULL, method_set_chassis, SD_BUS_VTABLE_UNPRIVILEGED),
625 SD_BUS_METHOD("SetDeployment", "sb", NULL, method_set_deployment, SD_BUS_VTABLE_UNPRIVILEGED),
626 SD_BUS_METHOD("SetLocation", "sb", NULL, method_set_location, SD_BUS_VTABLE_UNPRIVILEGED),
627 SD_BUS_VTABLE_END,
628 };
629
630 static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
631 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
632 int r;
633
634 assert(c);
635 assert(event);
636 assert(_bus);
637
638 r = sd_bus_default_system(&bus);
639 if (r < 0)
640 return log_error_errno(r, "Failed to get system bus connection: %m");
641
642 r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", hostname_vtable, c);
643 if (r < 0)
644 return log_error_errno(r, "Failed to register object: %m");
645
646 r = sd_bus_request_name_async(bus, NULL, "org.freedesktop.hostname1", 0, NULL, NULL);
647 if (r < 0)
648 return log_error_errno(r, "Failed to request name: %m");
649
650 r = sd_bus_attach_event(bus, event, 0);
651 if (r < 0)
652 return log_error_errno(r, "Failed to attach bus to event loop: %m");
653
654 *_bus = TAKE_PTR(bus);
655
656 return 0;
657 }
658
659 int main(int argc, char *argv[]) {
660 Context context = {};
661 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
662 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
663 int r;
664
665 log_set_target(LOG_TARGET_AUTO);
666 log_parse_environment();
667 log_open();
668
669 umask(0022);
670 mac_selinux_init();
671
672 if (argc != 1) {
673 log_error("This program takes no arguments.");
674 r = -EINVAL;
675 goto finish;
676 }
677
678 r = sd_event_default(&event);
679 if (r < 0) {
680 log_error_errno(r, "Failed to allocate event loop: %m");
681 goto finish;
682 }
683
684 sd_event_set_watchdog(event, true);
685
686 r = connect_bus(&context, event, &bus);
687 if (r < 0)
688 goto finish;
689
690 r = context_read_data(&context);
691 if (r < 0) {
692 log_error_errno(r, "Failed to read hostname and machine information: %m");
693 goto finish;
694 }
695
696 r = bus_event_loop_with_idle(event, bus, "org.freedesktop.hostname1", DEFAULT_EXIT_USEC, NULL, NULL);
697 if (r < 0) {
698 log_error_errno(r, "Failed to run event loop: %m");
699 goto finish;
700 }
701
702 finish:
703 context_free(&context);
704
705 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
706 }