chiark / gitweb /
68c5715b0e1cc1ed7ab6df2cd510a7407c844d6b
[elogind.git] / src / 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 General Public License as published by
10   the Free Software Foundation; either version 2 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   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <dbus/dbus.h>
23
24 #include <errno.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <dlfcn.h>
28
29 #include "util.h"
30 #include "strv.h"
31 #include "dbus-common.h"
32
33 #define INTROSPECTION                                                   \
34         DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
35         "<node>\n"                                                      \
36         " <interface name=\"org.freedesktop.hostname1\">\n"             \
37         "  <property name=\"Hostname\" type=\"s\" access=\"read\"/>\n"  \
38         "  <property name=\"StaticHostname\" type=\"s\" access=\"read\"/>\n" \
39         "  <property name=\"PrettyHostname\" type=\"s\" access=\"read\"/>\n" \
40         "  <property name=\"IconName\" type=\"s\" access=\"read\"/>\n"  \
41         "  <method name=\"SetHostname\">\n"                             \
42         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
43         "   <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
44         "  </method>\n"                                                 \
45         "  <method name=\"SetStaticHostname\">\n"                       \
46         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
47         "   <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
48         "  </method>\n"                                                 \
49         "  <method name=\"SetPrettyHostname\">\n"                       \
50         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
51         "   <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
52         "  </method>\n"                                                 \
53         "  <method name=\"SetIconName\">\n"                             \
54         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
55         "   <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
56         "  </method>\n"                                                 \
57         " </interface>\n"                                               \
58         BUS_PROPERTIES_INTERFACE                                        \
59         BUS_INTROSPECTABLE_INTERFACE                                    \
60         BUS_PEER_INTERFACE                                              \
61         "</node>\n"
62
63 #define INTERFACES_LIST                         \
64         BUS_GENERIC_INTERFACES_LIST             \
65         "org.freedesktop.hostname1\0"
66
67 enum {
68         PROP_HOSTNAME,
69         PROP_STATIC_HOSTNAME,
70         PROP_PRETTY_HOSTNAME,
71         PROP_ICON_NAME,
72         _PROP_MAX
73 };
74
75 static char *data[_PROP_MAX] = {
76         NULL,
77         NULL,
78         NULL,
79         NULL
80 };
81
82 static void free_data(void) {
83         int p;
84
85         for (p = 0; p < _PROP_MAX; p++) {
86                 free(data[p]);
87                 data[p] = NULL;
88         }
89 }
90
91 static int read_data(void) {
92         int r;
93
94         free_data();
95
96         data[PROP_HOSTNAME] = gethostname_malloc();
97         if (!data[PROP_HOSTNAME])
98                 return -ENOMEM;
99
100         r = read_one_line_file("/etc/hostname", &data[PROP_STATIC_HOSTNAME]);
101         if (r < 0 && r != -ENOENT)
102                 return r;
103
104         r = parse_env_file("/etc/machine-info", NEWLINE,
105                            "PRETTY_HOSTNAME", &data[PROP_PRETTY_HOSTNAME],
106                            "ICON_NAME", &data[PROP_ICON_NAME],
107                            NULL);
108         if (r < 0 && r != -ENOENT)
109                 return r;
110
111         return 0;
112 }
113
114 static bool check_nss(void) {
115
116         void *dl;
117
118         if ((dl = dlopen("libnss_myhostname.so.2", RTLD_LAZY))) {
119                 dlclose(dl);
120                 return true;
121         }
122
123         return false;
124 }
125
126 static const char* fallback_icon_name(void) {
127
128 #if defined(__i386__) || defined(__x86_64__)
129         int r;
130         char *type;
131         unsigned t;
132 #endif
133
134         if (detect_virtualization(NULL) > 0)
135                 return "computer-vm";
136
137 #if defined(__i386__) || defined(__x86_64__)
138         r = read_one_line_file("/sys/class/dmi/id/chassis_type", &type);
139         if (r < 0)
140                 return NULL;
141
142         r = safe_atou(type, &t);
143         free(type);
144
145         if (r < 0)
146                 return NULL;
147
148         /* We only list the really obvious cases here. The DMI data is
149            unreliable enough, so let's not do any additional guesswork
150            on top of that.
151
152            See the SMBIOS Specification 2.7.1 section 7.4.1 for
153            details about the values listed here:
154
155            http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.1.pdf
156          */
157
158         switch (t) {
159
160         case 0x3:
161         case 0x4:
162         case 0x6:
163         case 0x7:
164                 return "computer-desktop";
165
166         case 0x9:
167         case 0xA:
168         case 0xE:
169                 return "computer-laptop";
170
171         case 0x11:
172         case 0x1C:
173                 return "computer-server";
174         }
175
176 #endif
177         return NULL;
178 }
179
180 static int write_data_hostname(void) {
181         const char *hn;
182
183         if (isempty(data[PROP_HOSTNAME]))
184                 hn = "localhost";
185         else
186                 hn = data[PROP_HOSTNAME];
187
188         if (sethostname(hn, strlen(hn)) < 0)
189                 return -errno;
190
191         return 0;
192 }
193
194 static int write_data_static_hostname(void) {
195
196         if (isempty(data[PROP_STATIC_HOSTNAME])) {
197
198                 if (unlink("/etc/hostname") < 0)
199                         return errno == ENOENT ? 0 : -errno;
200
201                 return 0;
202         }
203
204         return write_one_line_file_atomic("/etc/hostname", data[PROP_STATIC_HOSTNAME]);
205 }
206
207 static int write_data_other(void) {
208
209         static const char * const name[_PROP_MAX] = {
210                 [PROP_PRETTY_HOSTNAME] = "PRETTY_HOSTNAME",
211                 [PROP_ICON_NAME] = "ICON_NAME"
212         };
213
214         char **l = NULL;
215         int r, p;
216
217         r = load_env_file("/etc/machine-info", &l);
218         if (r < 0 && r != -ENOENT)
219                 return r;
220
221         for (p = 2; p < _PROP_MAX; p++) {
222                 char *t, **u;
223
224                 assert(name[p]);
225
226                 if (isempty(data[p]))  {
227                         l = strv_env_unset(l, name[p]);
228                         continue;
229                 }
230
231                 if (asprintf(&t, "%s=%s", name[p], strempty(data[p])) < 0) {
232                         strv_free(l);
233                         return -ENOMEM;
234                 }
235
236                 u = strv_env_set(l, t);
237                 free(t);
238                 strv_free(l);
239
240                 if (!u)
241                         return -ENOMEM;
242                 l = u;
243         }
244
245         if (strv_isempty(l)) {
246
247                 if (unlink("/etc/machine-info") < 0)
248                         return errno == ENOENT ? 0 : -errno;
249
250                 return 0;
251         }
252
253         r = write_env_file("/etc/machine-info", l);
254         strv_free(l);
255
256         return r;
257 }
258
259 /* This mimics dbus_bus_get_unix_user() */
260 static pid_t get_unix_process_id(
261                 DBusConnection *connection,
262                 const char *name,
263                 DBusError *error) {
264
265         DBusMessage *m = NULL, *reply = NULL;
266         uint32_t pid = 0;
267
268         m = dbus_message_new_method_call(
269                         DBUS_SERVICE_DBUS,
270                         DBUS_PATH_DBUS,
271                         DBUS_INTERFACE_DBUS,
272                         "GetConnectionUnixProcessID");
273         if (!m) {
274                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
275                 goto finish;
276         }
277
278         if (!dbus_message_append_args(
279                             m,
280                             DBUS_TYPE_STRING, &name,
281                             DBUS_TYPE_INVALID)) {
282                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
283                 goto finish;
284         }
285
286         reply = dbus_connection_send_with_reply_and_block(connection, m, -1, error);
287         if (!reply)
288                 goto finish;
289
290         if (dbus_set_error_from_message(error, reply))
291                 goto finish;
292
293         if (!dbus_message_get_args(
294                             reply, error,
295                             DBUS_TYPE_UINT32, &pid,
296                             DBUS_TYPE_INVALID))
297                 goto finish;
298
299 finish:
300         if (m)
301                 dbus_message_unref(m);
302
303         if (reply)
304                 dbus_message_unref(reply);
305
306         return (pid_t) pid;
307 }
308
309 static int verify_polkit(
310                 DBusConnection *c,
311                 DBusMessage *request,
312                 const char *action,
313                 bool interactive,
314                 DBusError *error) {
315
316         DBusMessage *m = NULL, *reply = NULL;
317         const char *unix_process = "unix-process", *pid = "pid", *starttime = "start-time", *cancel_id = "";
318         const char *sender;
319         uint32_t flags = interactive ? 1 : 0;
320         pid_t pid_raw;
321         uint32_t pid_u32;
322         unsigned long long starttime_raw;
323         uint64_t starttime_u64;
324         DBusMessageIter iter_msg, iter_struct, iter_array, iter_dict, iter_variant;
325         int r;
326         dbus_bool_t authorized = FALSE;
327
328         assert(c);
329         assert(request);
330
331         sender = dbus_message_get_sender(request);
332         if (!sender)
333                 return -EINVAL;
334
335         pid_raw = get_unix_process_id(c, sender, error);
336         if (pid_raw == 0)
337                 return -EINVAL;
338
339         r = get_starttime_of_pid(pid_raw, &starttime_raw);
340         if (r < 0)
341                 return r;
342
343         m = dbus_message_new_method_call(
344                         "org.freedesktop.PolicyKit1",
345                         "/org/freedesktop/PolicyKit1/Authority",
346                         "org.freedesktop.PolicyKit1.Authority",
347                         "CheckAuthorization");
348         if (!m)
349                 return -ENOMEM;
350
351         dbus_message_iter_init_append(m, &iter_msg);
352
353         pid_u32 = (uint32_t) pid_raw;
354         starttime_u64 = (uint64_t) starttime_raw;
355
356         if (!dbus_message_iter_open_container(&iter_msg, DBUS_TYPE_STRUCT, NULL, &iter_struct) ||
357             !dbus_message_iter_append_basic(&iter_struct, DBUS_TYPE_STRING, &unix_process) ||
358             !dbus_message_iter_open_container(&iter_struct, DBUS_TYPE_ARRAY, "{sv}", &iter_array) ||
359             !dbus_message_iter_open_container(&iter_array, DBUS_TYPE_DICT_ENTRY, NULL, &iter_dict) ||
360             !dbus_message_iter_append_basic(&iter_dict, DBUS_TYPE_STRING, &pid) ||
361             !dbus_message_iter_open_container(&iter_dict, DBUS_TYPE_VARIANT, "u", &iter_variant) ||
362             !dbus_message_iter_append_basic(&iter_variant, DBUS_TYPE_UINT32, &pid_u32) ||
363             !dbus_message_iter_close_container(&iter_dict, &iter_variant) ||
364             !dbus_message_iter_close_container(&iter_array, &iter_dict) ||
365             !dbus_message_iter_open_container(&iter_array, DBUS_TYPE_DICT_ENTRY, NULL, &iter_dict) ||
366             !dbus_message_iter_append_basic(&iter_dict, DBUS_TYPE_STRING, &starttime) ||
367             !dbus_message_iter_open_container(&iter_dict, DBUS_TYPE_VARIANT, "t", &iter_variant) ||
368             !dbus_message_iter_append_basic(&iter_variant, DBUS_TYPE_UINT64, &starttime_u64) ||
369             !dbus_message_iter_close_container(&iter_dict, &iter_variant) ||
370             !dbus_message_iter_close_container(&iter_array, &iter_dict) ||
371             !dbus_message_iter_close_container(&iter_struct, &iter_array) ||
372             !dbus_message_iter_close_container(&iter_msg, &iter_struct) ||
373             !dbus_message_iter_append_basic(&iter_msg, DBUS_TYPE_STRING, &action) ||
374             !dbus_message_iter_open_container(&iter_msg, DBUS_TYPE_ARRAY, "{ss}", &iter_array) ||
375             !dbus_message_iter_close_container(&iter_msg, &iter_array) ||
376             !dbus_message_iter_append_basic(&iter_msg, DBUS_TYPE_UINT32, &flags) ||
377             !dbus_message_iter_append_basic(&iter_msg, DBUS_TYPE_STRING, &cancel_id)) {
378                 r = -ENOMEM;
379                 goto finish;
380         }
381
382         reply = dbus_connection_send_with_reply_and_block(c, m, -1, error);
383         if (!reply) {
384                 r = -EIO;
385                 goto finish;
386         }
387
388         if (dbus_set_error_from_message(error, reply)) {
389                 r = -EIO;
390                 goto finish;
391         }
392
393         if (!dbus_message_iter_init(reply, &iter_msg) ||
394             dbus_message_iter_get_arg_type(&iter_msg) != DBUS_TYPE_STRUCT) {
395                 r = -EIO;
396                 goto finish;
397         }
398
399         dbus_message_iter_recurse(&iter_msg, &iter_struct);
400
401         if (dbus_message_iter_get_arg_type(&iter_struct) != DBUS_TYPE_BOOLEAN) {
402                 r = -EIO;
403                 goto finish;
404         }
405
406         dbus_message_iter_get_basic(&iter_struct, &authorized);
407
408         r = authorized ? 0 : -EPERM;
409
410 finish:
411
412         if (m)
413                 dbus_message_unref(m);
414
415         if (reply)
416                 dbus_message_unref(reply);
417
418         return r;
419 }
420
421 static int bus_hostname_append_icon_name(DBusMessageIter *i, const char *property, void *userdata) {
422         const char *name;
423
424         assert(i);
425         assert(property);
426
427         if (isempty(data[PROP_ICON_NAME]))
428                 name = fallback_icon_name();
429         else
430                 name = data[PROP_ICON_NAME];
431
432         return bus_property_append_string(i, property, (void*) name);
433 }
434
435 static DBusHandlerResult hostname_message_handler(
436                 DBusConnection *connection,
437                 DBusMessage *message,
438                 void *userdata) {
439
440         const BusProperty properties[] = {
441                 { "org.freedesktop.hostname1", "Hostname",       bus_property_append_string,    "s", data[PROP_HOSTNAME]},
442                 { "org.freedesktop.hostname1", "StaticHostname", bus_property_append_string,    "s", data[PROP_STATIC_HOSTNAME]},
443                 { "org.freedesktop.hostname1", "PrettyHostname", bus_property_append_string,    "s", data[PROP_PRETTY_HOSTNAME]},
444                 { "org.freedesktop.hostname1", "IconName",       bus_hostname_append_icon_name, "s", data[PROP_ICON_NAME]},
445                 { NULL, NULL, NULL, NULL, NULL }
446         };
447
448         DBusMessage *reply = NULL, *changed = NULL;
449         DBusError error;
450         int r;
451
452         assert(connection);
453         assert(message);
454
455         dbus_error_init(&error);
456
457         if (dbus_message_is_method_call(message, "org.freedesktop.hostname1", "SetHostname")) {
458                 const char *name;
459                 dbus_bool_t interactive;
460
461                 if (!dbus_message_get_args(
462                                     message,
463                                     &error,
464                                     DBUS_TYPE_STRING, &name,
465                                     DBUS_TYPE_BOOLEAN, &interactive,
466                                     DBUS_TYPE_INVALID))
467                         return bus_send_error_reply(connection, message, &error, -EINVAL);
468
469                 if (isempty(name))
470                         name = data[PROP_STATIC_HOSTNAME];
471
472                 if (isempty(name))
473                         name = "localhost";
474
475                 if (!hostname_is_valid(name))
476                         return bus_send_error_reply(connection, message, NULL, -EINVAL);
477
478                 if (!streq_ptr(name, data[PROP_HOSTNAME])) {
479                         char *h;
480
481                         r = verify_polkit(connection, message, "org.freedesktop.hostname1.set-hostname", interactive, &error);
482                         if (r < 0)
483                                 return bus_send_error_reply(connection, message, &error, r);
484
485                         h = strdup(name);
486                         if (!h)
487                                 goto oom;
488
489                         free(data[PROP_HOSTNAME]);
490                         data[PROP_HOSTNAME] = h;
491
492                         r = write_data_hostname();
493                         if (r < 0) {
494                                 log_error("Failed to set host name: %s", strerror(-r));
495                                 return bus_send_error_reply(connection, message, NULL, r);
496                         }
497
498                         log_info("Changed host name to '%s'", strempty(data[PROP_HOSTNAME]));
499
500                         changed = bus_properties_changed_new(
501                                         "/org/freedesktop/hostname1",
502                                         "org.freedesktop.hostname1",
503                                         "Hostname\0");
504                         if (!changed)
505                                 goto oom;
506                 }
507
508         } else if (dbus_message_is_method_call(message, "org.freedesktop.hostname1", "SetStaticHostname")) {
509                 const char *name;
510                 dbus_bool_t interactive;
511
512                 if (!dbus_message_get_args(
513                                     message,
514                                     &error,
515                                     DBUS_TYPE_STRING, &name,
516                                     DBUS_TYPE_BOOLEAN, &interactive,
517                                     DBUS_TYPE_INVALID))
518                         return bus_send_error_reply(connection, message, &error, -EINVAL);
519
520                 if (isempty(name))
521                         name = NULL;
522
523                 if (!streq_ptr(name, data[PROP_STATIC_HOSTNAME])) {
524
525                         r = verify_polkit(connection, message, "org.freedesktop.hostname1.set-static-hostname", interactive, &error);
526                         if (r < 0)
527                                 return bus_send_error_reply(connection, message, &error, r);
528
529                         if (isempty(name)) {
530                                 free(data[PROP_STATIC_HOSTNAME]);
531                                 data[PROP_STATIC_HOSTNAME] = NULL;
532                         } else {
533                                 char *h;
534
535                                 if (!hostname_is_valid(name))
536                                         return bus_send_error_reply(connection, message, NULL, -EINVAL);
537
538                                 h = strdup(name);
539                                 if (!h)
540                                         goto oom;
541
542                                 free(data[PROP_STATIC_HOSTNAME]);
543                                 data[PROP_STATIC_HOSTNAME] = h;
544                         }
545
546                         r = write_data_static_hostname();
547                         if (r < 0) {
548                                 log_error("Failed to write static host name: %s", strerror(-r));
549                                 return bus_send_error_reply(connection, message, NULL, r);
550                         }
551
552                         log_info("Changed static host name to '%s'", strempty(data[PROP_HOSTNAME]));
553
554                         changed = bus_properties_changed_new(
555                                         "/org/freedesktop/hostname1",
556                                         "org.freedesktop.hostname1",
557                                         "StaticHostname\0");
558                         if (!changed)
559                                 goto oom;
560                 }
561
562         } else if (dbus_message_is_method_call(message, "org.freedesktop.hostname1", "SetPrettyHostname") ||
563                    dbus_message_is_method_call(message, "org.freedesktop.hostname1", "SetIconName")) {
564
565                 const char *name;
566                 dbus_bool_t interactive;
567                 int k;
568
569                 if (!dbus_message_get_args(
570                                     message,
571                                     &error,
572                                     DBUS_TYPE_STRING, &name,
573                                     DBUS_TYPE_BOOLEAN, &interactive,
574                                     DBUS_TYPE_INVALID))
575                         return bus_send_error_reply(connection, message, &error, -EINVAL);
576
577                 if (isempty(name))
578                         name = NULL;
579
580                 k = streq(dbus_message_get_member(message), "SetPrettyHostname") ? PROP_PRETTY_HOSTNAME : PROP_ICON_NAME;
581
582                 if (!streq_ptr(name, data[k])) {
583
584                         /* Since the pretty hostname should always be
585                          * changed at the same time as the static one,
586                          * use the same policy action for both... */
587
588                         r = verify_polkit(connection, message, k == PROP_PRETTY_HOSTNAME ?
589                                           "org.freedesktop.hostname1.set-static-hostname" :
590                                           "org.freedesktop.hostname1.set-machine-info", interactive, &error);
591                         if (r < 0)
592                                 return bus_send_error_reply(connection, message, &error, r);
593
594                         if (isempty(name)) {
595                                 free(data[k]);
596                                 data[k] = NULL;
597                         } else {
598                                 char *h;
599
600                                 h = strdup(name);
601                                 if (!h)
602                                         goto oom;
603
604                                 free(data[k]);
605                                 data[k] = h;
606                         }
607
608                         r = write_data_other();
609                         if (r < 0) {
610                                 log_error("Failed to write machine info: %s", strerror(-r));
611                                 return bus_send_error_reply(connection, message, NULL, r);
612                         }
613
614                         log_info("Changed %s to '%s'", k == PROP_PRETTY_HOSTNAME ? "pretty host name" : "icon name", strempty(data[k]));
615
616                         changed = bus_properties_changed_new(
617                                         "/org/freedesktop/hostname1",
618                                         "org.freedesktop.hostname1",
619                                         k == PROP_PRETTY_HOSTNAME ? "PrettyHostname\0" : "IconName\0");
620                         if (!changed)
621                                 goto oom;
622                 }
623
624         } else
625                 return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
626
627         if (!(reply = dbus_message_new_method_return(message)))
628                 goto oom;
629
630         if (!dbus_connection_send(connection, reply, NULL))
631                 goto oom;
632
633         dbus_message_unref(reply);
634         reply = NULL;
635
636         if (changed) {
637
638                 if (!dbus_connection_send(connection, changed, NULL))
639                         goto oom;
640
641                 dbus_message_unref(changed);
642         }
643
644         return DBUS_HANDLER_RESULT_HANDLED;
645
646 oom:
647         if (reply)
648                 dbus_message_unref(reply);
649
650         if (changed)
651                 dbus_message_unref(changed);
652
653         dbus_error_free(&error);
654
655         return DBUS_HANDLER_RESULT_NEED_MEMORY;
656 }
657
658 static int connect_bus(DBusConnection **_bus) {
659         static const DBusObjectPathVTable hostname_vtable = {
660                 .message_function = hostname_message_handler
661         };
662         DBusError error;
663         DBusConnection *bus = NULL;
664         int r;
665
666         assert(_bus);
667
668         dbus_error_init(&error);
669
670         bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
671         if (!bus) {
672                 log_error("Failed to get system D-Bus connection: %s", error.message);
673                 r = -ECONNREFUSED;
674                 goto fail;
675         }
676
677         if (!dbus_connection_register_object_path(bus, "/org/freedesktop/hostname1", &hostname_vtable, NULL)) {
678                 log_error("Not enough memory");
679                 r = -ENOMEM;
680                 goto fail;
681         }
682
683         if (dbus_bus_request_name(bus, "org.freedesktop.hostname1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error) < 0) {
684                 log_error("Failed to register name on bus: %s", error.message);
685                 r = -EEXIST;
686                 goto fail;
687         }
688
689         if (_bus)
690                 *_bus = bus;
691
692         return 0;
693
694 fail:
695         dbus_connection_close(bus);
696         dbus_connection_unref(bus);
697
698         dbus_error_free(&error);
699
700         return r;
701 }
702
703 int main(int argc, char *argv[]) {
704         int r;
705         DBusConnection *bus = NULL;
706
707         log_set_target(LOG_TARGET_AUTO);
708         log_parse_environment();
709         log_open();
710
711         if (argc != 1) {
712                 log_error("This program takes no arguments.");
713                 r = -EINVAL;
714                 goto finish;
715         }
716
717         if (!check_nss())
718                 log_warning("Warning: nss-myhostname is not installed. Changing the local hostname might make it unresolveable. Please install nss-myhostname!");
719
720         umask(0022);
721
722         r = read_data();
723         if (r < 0) {
724                 log_error("Failed to read hostname data: %s", strerror(-r));
725                 goto finish;
726         }
727
728         r = connect_bus(&bus);
729         if (r < 0)
730                 goto finish;
731
732         while (dbus_connection_read_write_dispatch(bus, -1))
733                 ;
734
735         r = 0;
736
737 finish:
738         free_data();
739
740         if (bus) {
741                 dbus_connection_flush(bus);
742                 dbus_connection_close(bus);
743                 dbus_connection_unref(bus);
744         }
745
746         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
747 }