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