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