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