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