1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
4 #include <sys/utsname.h>
9 #include "alloc-util.h"
10 #include "bus-common-errors.h"
11 #include "bus-get-properties.h"
12 #include "bus-log-control-api.h"
13 #include "bus-polkit.h"
15 #include "env-file-label.h"
18 #include "fileio-label.h"
20 #include "hostname-setup.h"
21 #include "hostname-util.h"
22 #include "id128-util.h"
24 #include "main-func.h"
25 #include "missing_capability.h"
26 #include "nscd-flush.h"
27 #include "nulstr-util.h"
29 #include "parse-util.h"
30 #include "path-util.h"
31 #include "sd-device.h"
32 #include "selinux-util.h"
33 #include "service-util.h"
34 #include "signal-util.h"
35 #include "stat-util.h"
36 #include "string-table.h"
38 #include "user-util.h"
42 #define VALID_DEPLOYMENT_CHARS (DIGITS LETTERS "-.:")
44 /* Properties we cache are indexed by an enum, to make invalidation easy and systematic (as we can iterate
45 * through them all, and they are uniformly strings). */
47 /* Read from /etc/hostname */
50 /* Read from /etc/machine-info */
57 /* Read from /etc/os-release (or /usr/lib/os-release) */
62 _PROP_INVALID
= -EINVAL
,
65 typedef struct Context
{
66 char *data
[_PROP_MAX
];
68 HostnameSource hostname_source
;
70 struct stat etc_hostname_stat
;
71 struct stat etc_os_release_stat
;
72 struct stat etc_machine_info_stat
;
74 Hashmap
*polkit_registry
;
77 static void context_reset(Context
*c
, uint64_t mask
) {
80 for (int p
= 0; p
< _PROP_MAX
; p
++) {
81 if (!FLAGS_SET(mask
, UINT64_C(1) << p
))
84 c
->data
[p
] = mfree(c
->data
[p
]);
88 static void context_destroy(Context
*c
) {
91 context_reset(c
, UINT64_MAX
);
92 bus_verify_polkit_async_registry_free(c
->polkit_registry
);
95 static void context_read_etc_hostname(Context
*c
) {
96 struct stat current_stat
= {};
101 if (stat("/etc/hostname", ¤t_stat
) >= 0 &&
102 stat_inode_unmodified(&c
->etc_hostname_stat
, ¤t_stat
))
105 context_reset(c
, UINT64_C(1) << PROP_STATIC_HOSTNAME
);
107 r
= read_etc_hostname(NULL
, &c
->data
[PROP_STATIC_HOSTNAME
]);
108 if (r
< 0 && r
!= -ENOENT
)
109 log_warning_errno(r
, "Failed to read /etc/hostname, ignoring: %m");
111 c
->etc_hostname_stat
= current_stat
;
114 static void context_read_machine_info(Context
*c
) {
115 struct stat current_stat
= {};
120 if (stat("/etc/machine-info", ¤t_stat
) >= 0 &&
121 stat_inode_unmodified(&c
->etc_machine_info_stat
, ¤t_stat
))
125 (UINT64_C(1) << PROP_PRETTY_HOSTNAME
) |
126 (UINT64_C(1) << PROP_ICON_NAME
) |
127 (UINT64_C(1) << PROP_CHASSIS
) |
128 (UINT64_C(1) << PROP_DEPLOYMENT
) |
129 (UINT64_C(1) << PROP_LOCATION
));
131 r
= parse_env_file(NULL
, "/etc/machine-info",
132 "PRETTY_HOSTNAME", &c
->data
[PROP_PRETTY_HOSTNAME
],
133 "ICON_NAME", &c
->data
[PROP_ICON_NAME
],
134 "CHASSIS", &c
->data
[PROP_CHASSIS
],
135 "DEPLOYMENT", &c
->data
[PROP_DEPLOYMENT
],
136 "LOCATION", &c
->data
[PROP_LOCATION
]);
137 if (r
< 0 && r
!= -ENOENT
)
138 log_warning_errno(r
, "Failed to read /etc/machine-info, ignoring: %m");
140 c
->etc_machine_info_stat
= current_stat
;
143 static void context_read_os_release(Context
*c
) {
144 struct stat current_stat
= {};
149 if ((stat("/etc/os-release", ¤t_stat
) >= 0 ||
150 stat("/usr/lib/os-release", ¤t_stat
) >= 0) &&
151 stat_inode_unmodified(&c
->etc_os_release_stat
, ¤t_stat
))
155 (UINT64_C(1) << PROP_OS_PRETTY_NAME
) |
156 (UINT64_C(1) << PROP_OS_CPE_NAME
) |
157 (UINT64_C(1) << PROP_OS_HOME_URL
));
159 r
= parse_os_release(NULL
,
160 "PRETTY_NAME", &c
->data
[PROP_OS_PRETTY_NAME
],
161 "CPE_NAME", &c
->data
[PROP_OS_CPE_NAME
],
162 "HOME_URL", &c
->data
[PROP_OS_HOME_URL
]);
163 if (r
< 0 && r
!= -ENOENT
)
164 log_warning_errno(r
, "Failed to read os-release file, ignoring: %m");
166 c
->etc_os_release_stat
= current_stat
;
169 static const char* valid_chassis(const char *chassis
) {
186 static bool valid_deployment(const char *deployment
) {
189 return in_charset(deployment
, VALID_DEPLOYMENT_CHARS
);
192 static const char* fallback_chassis(void) {
194 _cleanup_free_
char *type
= NULL
;
198 v
= detect_virtualization();
200 log_debug_errno(v
, "Failed to detect virtualization, ignoring: %m");
201 else if (VIRTUALIZATION_IS_VM(v
))
203 else if (VIRTUALIZATION_IS_CONTAINER(v
))
206 r
= read_one_line_file("/sys/class/dmi/id/chassis_type", &type
);
208 log_debug_errno(r
, "Failed to read DMI chassis type, ignoring: %m");
212 r
= safe_atou(type
, &t
);
214 log_debug_errno(r
, "Failed to parse DMI chassis type \"%s\", ignoring: %m", type
);
218 /* We only list the really obvious cases here. The DMI data is unreliable enough, so let's not do any
219 * additional guesswork on top of that.
221 * See the SMBIOS Specification 3.0 section 7.4.1 for details about the values listed here:
223 * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.0.0.pdf
228 case 0x3: /* Desktop */
229 case 0x4: /* Low Profile Desktop */
230 case 0x6: /* Mini Tower */
231 case 0x7: /* Tower */
232 case 0xD: /* All in one (i.e. PC built into monitor) */
235 case 0x8: /* Portable */
236 case 0x9: /* Laptop */
237 case 0xA: /* Notebook */
238 case 0xE: /* Sub Notebook */
241 case 0xB: /* Hand Held */
244 case 0x11: /* Main Server Chassis */
245 case 0x1C: /* Blade */
246 case 0x1D: /* Blade Enclosure */
249 case 0x1E: /* Tablet */
252 case 0x1F: /* Convertible */
253 case 0x20: /* Detachable */
254 return "convertible";
257 log_debug("Unhandled DMI chassis type 0x%02x, ignoring.", t
);
262 r
= read_one_line_file("/sys/firmware/acpi/pm_profile", &type
);
264 log_debug_errno(r
, "Failed read ACPI PM profile, ignoring: %m");
268 r
= safe_atou(type
, &t
);
270 log_debug_errno(r
, "Failed parse ACPI PM profile \"%s\", ignoring: %m", type
);
274 /* We only list the really obvious cases here as the ACPI data is not really super reliable.
276 * See the ACPI 5.0 Spec Section 5.2.9.1 for details:
278 * http://www.acpi.info/DOWNLOADS/ACPIspec50.pdf
283 case 1: /* Desktop */
284 case 3: /* Workstation */
285 case 6: /* Appliance PC */
291 case 4: /* Enterprise Server */
292 case 5: /* SOHO Server */
293 case 7: /* Performance Server */
300 log_debug("Unhandled ACPI PM profile 0x%02x, ignoring.", t
);
305 r
= read_one_line_file("/proc/device-tree/chassis-type", &type
);
307 log_debug_errno(r
, "Failed to read device-tree chassis type, ignoring: %m");
311 /* Note that the Devicetree specification uses the very same vocabulary
312 * of chassis types as we do, hence we do not need to translate these types:
314 * https://github.com/devicetree-org/devicetree-specification/blob/master/source/chapter3-devicenodes.rst */
315 chassis
= valid_chassis(type
);
317 log_debug("Invalid device-tree chassis type \"%s\", ignoring.", type
);
321 static char* context_fallback_icon_name(Context
*c
) {
326 if (!isempty(c
->data
[PROP_CHASSIS
]))
327 return strjoin("computer-", c
->data
[PROP_CHASSIS
]);
329 chassis
= fallback_chassis();
331 return strjoin("computer-", chassis
);
333 return strdup("computer");
336 static int context_update_kernel_hostname(
338 const char *transient_hn
) {
340 _cleanup_free_
char *_hn_free
= NULL
;
347 /* /etc/hostname has the highest preference ... */
348 if (c
->data
[PROP_STATIC_HOSTNAME
]) {
349 hn
= c
->data
[PROP_STATIC_HOSTNAME
];
350 hns
= HOSTNAME_STATIC
;
352 /* ... the transient hostname, (ie: DHCP) comes next ... */
353 } else if (transient_hn
) {
355 hns
= HOSTNAME_TRANSIENT
;
357 /* ... and the ultimate fallback */
359 hn
= _hn_free
= get_default_hostname();
363 hns
= HOSTNAME_DEFAULT
;
366 r
= sethostname_idempotent(hn
);
368 return log_error_errno(r
, "Failed to set hostname: %m");
370 if (c
->hostname_source
!= hns
) {
371 c
->hostname_source
= hns
;
375 (void) nscd_flush_cache(STRV_MAKE("hosts"));
378 log_debug("Hostname was already set to <%s>.", hn
);
380 log_info("Hostname set to <%s> (%s)", hn
, hostname_source_to_string(hns
));
382 hostname_update_source_hint(hn
, hns
);
385 return r
; /* 0 if no change, 1 if something was done */
388 static void unset_statp(struct stat
**p
) {
392 **p
= (struct stat
) {};
395 static int context_write_data_static_hostname(Context
*c
) {
396 _cleanup_(unset_statp
) struct stat
*s
= NULL
;
401 /* Make sure that if we fail here, we invalidate the cached information, since it was updated
402 * already, even if we can't make it hit the disk. */
403 s
= &c
->etc_hostname_stat
;
405 if (isempty(c
->data
[PROP_STATIC_HOSTNAME
])) {
406 if (unlink("/etc/hostname") < 0 && errno
!= ENOENT
)
413 r
= write_string_file_atomic_label("/etc/hostname", c
->data
[PROP_STATIC_HOSTNAME
]);
421 static int context_write_data_machine_info(Context
*c
) {
422 _cleanup_(unset_statp
) struct stat
*s
= NULL
;
423 static const char * const name
[_PROP_MAX
] = {
424 [PROP_PRETTY_HOSTNAME
] = "PRETTY_HOSTNAME",
425 [PROP_ICON_NAME
] = "ICON_NAME",
426 [PROP_CHASSIS
] = "CHASSIS",
427 [PROP_DEPLOYMENT
] = "DEPLOYMENT",
428 [PROP_LOCATION
] = "LOCATION",
430 _cleanup_strv_free_
char **l
= NULL
;
435 /* Make sure that if we fail here, we invalidate the cached information, since it was updated
436 * already, even if we can't make it hit the disk. */
437 s
= &c
->etc_machine_info_stat
;
439 r
= load_env_file(NULL
, "/etc/machine-info", &l
);
440 if (r
< 0 && r
!= -ENOENT
)
443 for (int p
= PROP_PRETTY_HOSTNAME
; p
<= PROP_LOCATION
; p
++) {
446 r
= strv_env_assign(&l
, name
[p
], empty_to_null(c
->data
[p
]));
451 if (strv_isempty(l
)) {
452 if (unlink("/etc/machine-info") < 0 && errno
!= ENOENT
)
459 r
= write_env_file_label("/etc/machine-info", l
);
467 static int get_dmi_data(const char *database_key
, const char *regular_key
, char **ret
) {
468 _cleanup_(sd_device_unrefp
) sd_device
*device
= NULL
;
469 _cleanup_free_
char *b
= NULL
;
470 const char *s
= NULL
;
473 r
= sd_device_new_from_syspath(&device
, "/sys/class/dmi/id");
475 return log_debug_errno(r
, "Failed to open /sys/class/dmi/id device, ignoring: %m");
478 (void) sd_device_get_property_value(device
, database_key
, &s
);
479 if (!s
&& regular_key
)
480 (void) sd_device_get_property_value(device
, regular_key
, &s
);
494 static int get_hardware_vendor(char **ret
) {
495 return get_dmi_data("ID_VENDOR_FROM_DATABASE", "ID_VENDOR", ret
);
498 static int get_hardware_model(char **ret
) {
499 return get_dmi_data("ID_MODEL_FROM_DATABASE", "ID_MODEL", ret
);
502 static int property_get_hardware_vendor(
505 const char *interface
,
506 const char *property
,
507 sd_bus_message
*reply
,
509 sd_bus_error
*error
) {
511 _cleanup_free_
char *vendor
= NULL
;
513 (void) get_hardware_vendor(&vendor
);
514 return sd_bus_message_append(reply
, "s", vendor
);
517 static int property_get_hardware_model(
520 const char *interface
,
521 const char *property
,
522 sd_bus_message
*reply
,
524 sd_bus_error
*error
) {
526 _cleanup_free_
char *model
= NULL
;
528 (void) get_hardware_model(&model
);
529 return sd_bus_message_append(reply
, "s", model
);
532 static int property_get_hostname(
535 const char *interface
,
536 const char *property
,
537 sd_bus_message
*reply
,
539 sd_bus_error
*error
) {
541 _cleanup_free_
char *hn
= NULL
;
544 r
= gethostname_strict(&hn
);
549 hn
= get_default_hostname();
554 return sd_bus_message_append(reply
, "s", hn
);
557 static int property_get_static_hostname(
560 const char *interface
,
561 const char *property
,
562 sd_bus_message
*reply
,
564 sd_bus_error
*error
) {
566 Context
*c
= userdata
;
569 context_read_etc_hostname(c
);
571 return sd_bus_message_append(reply
, "s", c
->data
[PROP_STATIC_HOSTNAME
]);
574 static int property_get_default_hostname(
577 const char *interface
,
578 const char *property
,
579 sd_bus_message
*reply
,
581 sd_bus_error
*error
) {
583 _cleanup_free_
char *hn
= NULL
;
585 hn
= get_default_hostname();
589 return sd_bus_message_append(reply
, "s", hn
);
592 static void context_determine_hostname_source(Context
*c
) {
593 _cleanup_free_
char *hostname
= NULL
;
598 if (c
->hostname_source
>= 0)
601 (void) gethostname_full(GET_HOSTNAME_ALLOW_LOCALHOST
, &hostname
);
603 if (streq_ptr(hostname
, c
->data
[PROP_STATIC_HOSTNAME
]))
604 c
->hostname_source
= HOSTNAME_STATIC
;
606 _cleanup_free_
char *fallback
= NULL
;
608 /* If the hostname was not set by us, try to figure out where it came from. If we set it to
609 * the default hostname, the file will tell us. We compare the string because it is possible
610 * that the hostname was set by an older version that had a different fallback, in the
611 * initramfs or before we reexecuted. */
613 r
= read_one_line_file("/run/systemd/default-hostname", &fallback
);
614 if (r
< 0 && r
!= -ENOENT
)
615 log_warning_errno(r
, "Failed to read /run/systemd/default-hostname, ignoring: %m");
617 if (streq_ptr(fallback
, hostname
))
618 c
->hostname_source
= HOSTNAME_DEFAULT
;
620 c
->hostname_source
= HOSTNAME_TRANSIENT
;
624 static int property_get_hostname_source(
627 const char *interface
,
628 const char *property
,
629 sd_bus_message
*reply
,
631 sd_bus_error
*error
) {
633 Context
*c
= userdata
;
636 context_read_etc_hostname(c
);
637 context_determine_hostname_source(c
);
639 return sd_bus_message_append(reply
, "s", hostname_source_to_string(c
->hostname_source
));
642 static int property_get_machine_info_field(
645 const char *interface
,
646 const char *property
,
647 sd_bus_message
*reply
,
649 sd_bus_error
*error
) {
654 /* Acquire the context object without this property's userdata offset added. Explanation: we want
655 * access to two pointers here: a) the main context object we cache all properties in, and b) the
656 * pointer to the property field inside the context object that we are supposed to update and
657 * use. The latter (b) we get in the 'userdata' function parameter, and sd-bus calculates that for us
658 * from the 'userdata' pointer we supplied when the vtable was registered, with the offset we
659 * specified in the vtable added on top. To get the former (a) we need the 'userdata' pointer from
660 * the vtable registration directly, without the offset added. Hence we ask sd-bus what the slot
661 * object is (which encapsulates the vtable registration), and then query the 'userdata' field
662 * directly off it. */
663 assert_se(slot
= sd_bus_get_current_slot(bus
));
664 assert_se(c
= sd_bus_slot_get_userdata(slot
));
666 context_read_machine_info(c
);
668 return sd_bus_message_append(reply
, "s", *(char**) userdata
);
671 static int property_get_os_release_field(
674 const char *interface
,
675 const char *property
,
676 sd_bus_message
*reply
,
678 sd_bus_error
*error
) {
683 /* As above, acquire the current context without this property's userdata offset added. */
684 assert_se(slot
= sd_bus_get_current_slot(bus
));
685 assert_se(c
= sd_bus_slot_get_userdata(slot
));
687 context_read_os_release(c
);
689 return sd_bus_message_append(reply
, "s", *(char**) userdata
);
692 static int property_get_icon_name(
695 const char *interface
,
696 const char *property
,
697 sd_bus_message
*reply
,
699 sd_bus_error
*error
) {
701 _cleanup_free_
char *n
= NULL
;
702 Context
*c
= userdata
;
705 context_read_machine_info(c
);
707 if (isempty(c
->data
[PROP_ICON_NAME
]))
708 name
= n
= context_fallback_icon_name(c
);
710 name
= c
->data
[PROP_ICON_NAME
];
715 return sd_bus_message_append(reply
, "s", name
);
718 static int property_get_chassis(
721 const char *interface
,
722 const char *property
,
723 sd_bus_message
*reply
,
725 sd_bus_error
*error
) {
727 Context
*c
= userdata
;
730 context_read_machine_info(c
);
732 if (isempty(c
->data
[PROP_CHASSIS
]))
733 name
= fallback_chassis();
735 name
= c
->data
[PROP_CHASSIS
];
737 return sd_bus_message_append(reply
, "s", name
);
740 static int property_get_uname_field(
743 const char *interface
,
744 const char *property
,
745 sd_bus_message
*reply
,
747 sd_bus_error
*error
) {
751 assert_se(uname(&u
) >= 0);
753 return sd_bus_message_append(reply
, "s", (char*) &u
+ PTR_TO_SIZE(userdata
));
756 static int method_set_hostname(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
757 Context
*c
= userdata
;
764 r
= sd_bus_message_read(m
, "sb", &name
, &interactive
);
768 name
= empty_to_null(name
);
770 /* We always go through with the procedure below without comparing to the current hostname, because
771 * we might want to adjust hostname source information even if the actual hostname is unchanged. */
773 if (name
&& !hostname_is_valid(name
, 0))
774 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid hostname '%s'", name
);
776 context_read_etc_hostname(c
);
778 r
= bus_verify_polkit_async(
781 "org.freedesktop.hostname1.set-hostname",
790 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
792 r
= context_update_kernel_hostname(c
, name
);
794 return sd_bus_error_set_errnof(error
, r
, "Failed to set hostname: %m");
796 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m
),
797 "/org/freedesktop/hostname1", "org.freedesktop.hostname1",
798 "Hostname", "HostnameSource", NULL
);
800 return sd_bus_reply_method_return(m
, NULL
);
803 static int method_set_static_hostname(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
804 Context
*c
= userdata
;
812 r
= sd_bus_message_read(m
, "sb", &name
, &interactive
);
816 name
= empty_to_null(name
);
818 context_read_etc_hostname(c
);
820 if (streq_ptr(name
, c
->data
[PROP_STATIC_HOSTNAME
]))
821 return sd_bus_reply_method_return(m
, NULL
);
823 if (name
&& !hostname_is_valid(name
, 0))
824 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid static hostname '%s'", name
);
826 r
= bus_verify_polkit_async(
829 "org.freedesktop.hostname1.set-static-hostname",
838 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
840 r
= free_and_strdup_warn(&c
->data
[PROP_STATIC_HOSTNAME
], name
);
844 r
= context_write_data_static_hostname(c
);
846 log_error_errno(r
, "Failed to write static hostname: %m");
847 if (ERRNO_IS_PRIVILEGE(r
))
848 return sd_bus_error_set(error
, BUS_ERROR_FILE_IS_PROTECTED
, "Not allowed to update /etc/hostname.");
850 return sd_bus_error_set(error
, BUS_ERROR_READ_ONLY_FILESYSTEM
, "/etc/hostname is in a read-only filesystem.");
851 return sd_bus_error_set_errnof(error
, r
, "Failed to set static hostname: %m");
854 r
= context_update_kernel_hostname(c
, NULL
);
856 log_error_errno(r
, "Failed to set hostname: %m");
857 return sd_bus_error_set_errnof(error
, r
, "Failed to set hostname: %m");
860 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m
),
861 "/org/freedesktop/hostname1", "org.freedesktop.hostname1",
862 "StaticHostname", "Hostname", "HostnameSource", NULL
);
864 return sd_bus_reply_method_return(m
, NULL
);
867 static int set_machine_info(Context
*c
, sd_bus_message
*m
, int prop
, sd_bus_message_handler_t cb
, sd_bus_error
*error
) {
875 r
= sd_bus_message_read(m
, "sb", &name
, &interactive
);
879 name
= empty_to_null(name
);
881 context_read_machine_info(c
);
883 if (streq_ptr(name
, c
->data
[prop
]))
884 return sd_bus_reply_method_return(m
, NULL
);
886 if (!isempty(name
)) {
887 /* The icon name might ultimately be used as file
888 * name, so better be safe than sorry */
890 if (prop
== PROP_ICON_NAME
&& !filename_is_valid(name
))
891 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid icon name '%s'", name
);
892 if (prop
== PROP_PRETTY_HOSTNAME
&& string_has_cc(name
, NULL
))
893 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid pretty hostname '%s'", name
);
894 if (prop
== PROP_CHASSIS
&& !valid_chassis(name
))
895 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid chassis '%s'", name
);
896 if (prop
== PROP_DEPLOYMENT
&& !valid_deployment(name
))
897 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid deployment '%s'", name
);
898 if (prop
== PROP_LOCATION
&& string_has_cc(name
, NULL
))
899 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid location '%s'", name
);
902 /* Since the pretty hostname should always be changed at the
903 * same time as the static one, use the same policy action for
906 r
= bus_verify_polkit_async(
909 prop
== PROP_PRETTY_HOSTNAME
? "org.freedesktop.hostname1.set-static-hostname" : "org.freedesktop.hostname1.set-machine-info",
918 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
920 r
= free_and_strdup_warn(&c
->data
[prop
], name
);
924 r
= context_write_data_machine_info(c
);
926 log_error_errno(r
, "Failed to write machine info: %m");
927 if (ERRNO_IS_PRIVILEGE(r
))
928 return sd_bus_error_set(error
, BUS_ERROR_FILE_IS_PROTECTED
, "Not allowed to update /etc/machine-info.");
930 return sd_bus_error_set(error
, BUS_ERROR_READ_ONLY_FILESYSTEM
, "/etc/machine-info is in a read-only filesystem.");
931 return sd_bus_error_set_errnof(error
, r
, "Failed to write machine info: %m");
934 log_info("Changed %s to '%s'",
935 prop
== PROP_PRETTY_HOSTNAME
? "pretty hostname" :
936 prop
== PROP_DEPLOYMENT
? "deployment" :
937 prop
== PROP_LOCATION
? "location" :
938 prop
== PROP_CHASSIS
? "chassis" : "icon name", strna(c
->data
[prop
]));
940 (void) sd_bus_emit_properties_changed(
941 sd_bus_message_get_bus(m
),
942 "/org/freedesktop/hostname1",
943 "org.freedesktop.hostname1",
944 prop
== PROP_PRETTY_HOSTNAME
? "PrettyHostname" :
945 prop
== PROP_DEPLOYMENT
? "Deployment" :
946 prop
== PROP_LOCATION
? "Location" :
947 prop
== PROP_CHASSIS
? "Chassis" : "IconName" , NULL
);
949 return sd_bus_reply_method_return(m
, NULL
);
952 static int method_set_pretty_hostname(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
953 return set_machine_info(userdata
, m
, PROP_PRETTY_HOSTNAME
, method_set_pretty_hostname
, error
);
956 static int method_set_icon_name(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
957 return set_machine_info(userdata
, m
, PROP_ICON_NAME
, method_set_icon_name
, error
);
960 static int method_set_chassis(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
961 return set_machine_info(userdata
, m
, PROP_CHASSIS
, method_set_chassis
, error
);
964 static int method_set_deployment(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
965 return set_machine_info(userdata
, m
, PROP_DEPLOYMENT
, method_set_deployment
, error
);
968 static int method_set_location(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
969 return set_machine_info(userdata
, m
, PROP_LOCATION
, method_set_location
, error
);
972 static int method_get_product_uuid(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
973 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
974 Context
*c
= userdata
;
981 r
= sd_bus_message_read(m
, "b", &interactive
);
985 r
= bus_verify_polkit_async(
988 "org.freedesktop.hostname1.get-product-uuid",
997 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
999 r
= id128_get_product(&uuid
);
1001 if (r
== -EADDRNOTAVAIL
)
1002 log_debug_errno(r
, "DMI product UUID is all 0x00 or all 0xFF, ignoring.");
1004 log_full_errno(r
== -ENOENT
? LOG_DEBUG
: LOG_WARNING
, r
,
1005 "Failed to read product UUID, ignoring: %m");
1007 return sd_bus_error_set(error
, BUS_ERROR_NO_PRODUCT_UUID
,
1008 "Failed to read product UUID from firmware.");
1011 r
= sd_bus_message_new_method_return(m
, &reply
);
1015 r
= sd_bus_message_append_array(reply
, 'y', uuid
.bytes
, sizeof(uuid
.bytes
));
1019 return sd_bus_send(NULL
, reply
, NULL
);
1022 static int method_describe(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
1023 _cleanup_free_
char *hn
= NULL
, *dhn
= NULL
, *in
= NULL
, *text
= NULL
, *vendor
= NULL
, *model
= NULL
;
1024 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1025 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
1026 sd_id128_t product_uuid
= SD_ID128_NULL
;
1027 const char *chassis
= NULL
;
1028 Context
*c
= userdata
;
1036 r
= bus_verify_polkit_async(
1039 "org.freedesktop.hostname1.get-product-uuid",
1043 &c
->polkit_registry
,
1046 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1048 /* We ignore all authentication errors here, since most data is unprivileged, the one exception being
1049 * the product ID which we'll check explicitly. */
1052 context_read_etc_hostname(c
);
1053 context_read_machine_info(c
);
1054 context_read_os_release(c
);
1055 context_determine_hostname_source(c
);
1057 r
= gethostname_strict(&hn
);
1060 return log_error_errno(r
, "Failed to read local host name: %m");
1062 hn
= get_default_hostname();
1067 dhn
= get_default_hostname();
1071 if (isempty(c
->data
[PROP_ICON_NAME
]))
1072 in
= context_fallback_icon_name(c
);
1074 if (isempty(c
->data
[PROP_CHASSIS
]))
1075 chassis
= fallback_chassis();
1077 assert_se(uname(&u
) >= 0);
1079 (void) get_hardware_vendor(&vendor
);
1080 (void) get_hardware_model(&model
);
1082 if (privileged
) /* The product UUID is only available to privileged clients */
1083 id128_get_product(&product_uuid
);
1085 r
= json_build(&v
, JSON_BUILD_OBJECT(
1086 JSON_BUILD_PAIR("Hostname", JSON_BUILD_STRING(hn
)),
1087 JSON_BUILD_PAIR("StaticHostname", JSON_BUILD_STRING(c
->data
[PROP_STATIC_HOSTNAME
])),
1088 JSON_BUILD_PAIR("PrettyHostname", JSON_BUILD_STRING(c
->data
[PROP_PRETTY_HOSTNAME
])),
1089 JSON_BUILD_PAIR("DefaultHostname", JSON_BUILD_STRING(dhn
)),
1090 JSON_BUILD_PAIR("HostnameSource", JSON_BUILD_STRING(hostname_source_to_string(c
->hostname_source
))),
1091 JSON_BUILD_PAIR("IconName", JSON_BUILD_STRING(in
?: c
->data
[PROP_ICON_NAME
])),
1092 JSON_BUILD_PAIR("Chassis", JSON_BUILD_STRING(chassis
?: c
->data
[PROP_CHASSIS
])),
1093 JSON_BUILD_PAIR("Deployment", JSON_BUILD_STRING(c
->data
[PROP_DEPLOYMENT
])),
1094 JSON_BUILD_PAIR("Location", JSON_BUILD_STRING(c
->data
[PROP_LOCATION
])),
1095 JSON_BUILD_PAIR("KernelName", JSON_BUILD_STRING(u
.sysname
)),
1096 JSON_BUILD_PAIR("KernelRelease", JSON_BUILD_STRING(u
.release
)),
1097 JSON_BUILD_PAIR("KernelVersion", JSON_BUILD_STRING(u
.version
)),
1098 JSON_BUILD_PAIR("OperatingSystemPrettyName", JSON_BUILD_STRING(c
->data
[PROP_OS_PRETTY_NAME
])),
1099 JSON_BUILD_PAIR("OperatingSystemCPEName", JSON_BUILD_STRING(c
->data
[PROP_OS_CPE_NAME
])),
1100 JSON_BUILD_PAIR("OperatingSystemHomeURL", JSON_BUILD_STRING(c
->data
[PROP_OS_HOME_URL
])),
1101 JSON_BUILD_PAIR("HardwareVendor", JSON_BUILD_STRING(vendor
)),
1102 JSON_BUILD_PAIR("HardwareModel", JSON_BUILD_STRING(model
)),
1103 JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(product_uuid
), "ProductUUID", JSON_BUILD_ID128(product_uuid
)),
1104 JSON_BUILD_PAIR_CONDITION(sd_id128_is_null(product_uuid
), "ProductUUID", JSON_BUILD_NULL
)));
1107 return log_error_errno(r
, "Failed to build JSON data: %m");
1109 r
= json_variant_format(v
, 0, &text
);
1111 return log_error_errno(r
, "Failed to format JSON data: %m");
1113 r
= sd_bus_message_new_method_return(m
, &reply
);
1117 r
= sd_bus_message_append(reply
, "s", text
);
1121 return sd_bus_send(NULL
, reply
, NULL
);
1124 static const sd_bus_vtable hostname_vtable
[] = {
1125 SD_BUS_VTABLE_START(0),
1126 SD_BUS_PROPERTY("Hostname", "s", property_get_hostname
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
1127 SD_BUS_PROPERTY("StaticHostname", "s", property_get_static_hostname
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
1128 SD_BUS_PROPERTY("PrettyHostname", "s", property_get_machine_info_field
, offsetof(Context
, data
) + sizeof(char*) * PROP_PRETTY_HOSTNAME
, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
1129 SD_BUS_PROPERTY("DefaultHostname", "s", property_get_default_hostname
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
1130 SD_BUS_PROPERTY("HostnameSource", "s", property_get_hostname_source
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
1131 SD_BUS_PROPERTY("IconName", "s", property_get_icon_name
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
1132 SD_BUS_PROPERTY("Chassis", "s", property_get_chassis
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
1133 SD_BUS_PROPERTY("Deployment", "s", property_get_machine_info_field
, offsetof(Context
, data
) + sizeof(char*) * PROP_DEPLOYMENT
, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
1134 SD_BUS_PROPERTY("Location", "s", property_get_machine_info_field
, offsetof(Context
, data
) + sizeof(char*) * PROP_LOCATION
, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
1135 SD_BUS_PROPERTY("KernelName", "s", property_get_uname_field
, offsetof(struct utsname
, sysname
), SD_BUS_VTABLE_ABSOLUTE_OFFSET
|SD_BUS_VTABLE_PROPERTY_CONST
),
1136 SD_BUS_PROPERTY("KernelRelease", "s", property_get_uname_field
, offsetof(struct utsname
, release
), SD_BUS_VTABLE_ABSOLUTE_OFFSET
|SD_BUS_VTABLE_PROPERTY_CONST
),
1137 SD_BUS_PROPERTY("KernelVersion", "s", property_get_uname_field
, offsetof(struct utsname
, version
), SD_BUS_VTABLE_ABSOLUTE_OFFSET
|SD_BUS_VTABLE_PROPERTY_CONST
),
1138 SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", property_get_os_release_field
, offsetof(Context
, data
) + sizeof(char*) * PROP_OS_PRETTY_NAME
, SD_BUS_VTABLE_PROPERTY_CONST
),
1139 SD_BUS_PROPERTY("OperatingSystemCPEName", "s", property_get_os_release_field
, offsetof(Context
, data
) + sizeof(char*) * PROP_OS_CPE_NAME
, SD_BUS_VTABLE_PROPERTY_CONST
),
1140 SD_BUS_PROPERTY("HomeURL", "s", property_get_os_release_field
, offsetof(Context
, data
) + sizeof(char*) * PROP_OS_HOME_URL
, SD_BUS_VTABLE_PROPERTY_CONST
),
1141 SD_BUS_PROPERTY("HardwareVendor", "s", property_get_hardware_vendor
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
1142 SD_BUS_PROPERTY("HardwareModel", "s", property_get_hardware_model
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
1144 SD_BUS_METHOD_WITH_NAMES("SetHostname",
1146 SD_BUS_PARAM(hostname
)
1147 SD_BUS_PARAM(interactive
),
1149 method_set_hostname
,
1150 SD_BUS_VTABLE_UNPRIVILEGED
),
1151 SD_BUS_METHOD_WITH_NAMES("SetStaticHostname",
1153 SD_BUS_PARAM(hostname
)
1154 SD_BUS_PARAM(interactive
),
1156 method_set_static_hostname
,
1157 SD_BUS_VTABLE_UNPRIVILEGED
),
1158 SD_BUS_METHOD_WITH_NAMES("SetPrettyHostname",
1160 SD_BUS_PARAM(hostname
)
1161 SD_BUS_PARAM(interactive
),
1163 method_set_pretty_hostname
,
1164 SD_BUS_VTABLE_UNPRIVILEGED
),
1165 SD_BUS_METHOD_WITH_NAMES("SetIconName",
1168 SD_BUS_PARAM(interactive
),
1170 method_set_icon_name
,
1171 SD_BUS_VTABLE_UNPRIVILEGED
),
1172 SD_BUS_METHOD_WITH_NAMES("SetChassis",
1174 SD_BUS_PARAM(chassis
)
1175 SD_BUS_PARAM(interactive
),
1178 SD_BUS_VTABLE_UNPRIVILEGED
),
1179 SD_BUS_METHOD_WITH_NAMES("SetDeployment",
1181 SD_BUS_PARAM(deployment
)
1182 SD_BUS_PARAM(interactive
),
1184 method_set_deployment
,
1185 SD_BUS_VTABLE_UNPRIVILEGED
),
1186 SD_BUS_METHOD_WITH_NAMES("SetLocation",
1188 SD_BUS_PARAM(location
)
1189 SD_BUS_PARAM(interactive
),
1191 method_set_location
,
1192 SD_BUS_VTABLE_UNPRIVILEGED
),
1193 SD_BUS_METHOD_WITH_NAMES("GetProductUUID",
1195 SD_BUS_PARAM(interactive
),
1198 method_get_product_uuid
,
1199 SD_BUS_VTABLE_UNPRIVILEGED
),
1200 SD_BUS_METHOD_WITH_ARGS("Describe",
1202 SD_BUS_RESULT("s", json
),
1204 SD_BUS_VTABLE_UNPRIVILEGED
),
1209 static const BusObjectImplementation manager_object
= {
1210 "/org/freedesktop/hostname1",
1211 "org.freedesktop.hostname1",
1212 .vtables
= BUS_VTABLES(hostname_vtable
),
1215 static int connect_bus(Context
*c
, sd_event
*event
, sd_bus
**ret
) {
1216 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1223 r
= sd_bus_default_system(&bus
);
1225 return log_error_errno(r
, "Failed to get system bus connection: %m");
1227 r
= bus_add_implementation(bus
, &manager_object
, c
);
1231 r
= bus_log_control_api_register(bus
);
1235 r
= sd_bus_request_name_async(bus
, NULL
, "org.freedesktop.hostname1", 0, NULL
, NULL
);
1237 return log_error_errno(r
, "Failed to request name: %m");
1239 r
= sd_bus_attach_event(bus
, event
, 0);
1241 return log_error_errno(r
, "Failed to attach bus to event loop: %m");
1243 *ret
= TAKE_PTR(bus
);
1247 static int run(int argc
, char *argv
[]) {
1248 _cleanup_(context_destroy
) Context context
= {
1249 .hostname_source
= _HOSTNAME_INVALID
, /* appropriate value will be set later */
1251 _cleanup_(sd_event_unrefp
) sd_event
*event
= NULL
;
1252 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1257 r
= service_parse_argv("systemd-hostnamed.service",
1258 "Manage the system hostname and related metadata.",
1259 BUS_IMPLEMENTATIONS(&manager_object
,
1260 &log_control_object
),
1267 r
= mac_selinux_init();
1271 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGTERM
, SIGINT
, -1) >= 0);
1273 r
= sd_event_default(&event
);
1275 return log_error_errno(r
, "Failed to allocate event loop: %m");
1277 (void) sd_event_set_watchdog(event
, true);
1279 r
= sd_event_add_signal(event
, NULL
, SIGINT
, NULL
, NULL
);
1281 return log_error_errno(r
, "Failed to install SIGINT handler: %m");
1283 r
= sd_event_add_signal(event
, NULL
, SIGTERM
, NULL
, NULL
);
1285 return log_error_errno(r
, "Failed to install SIGTERM handler: %m");
1287 r
= connect_bus(&context
, event
, &bus
);
1291 r
= bus_event_loop_with_idle(event
, bus
, "org.freedesktop.hostname1", DEFAULT_EXIT_USEC
, NULL
, NULL
);
1293 return log_error_errno(r
, "Failed to run event loop: %m");
1298 DEFINE_MAIN_FUNCTION(run
);