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