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