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