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