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