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