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