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