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