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-util.h"
21 #include "id128-util.h"
22 #include "main-func.h"
23 #include "missing_capability.h"
24 #include "nscd-flush.h"
25 #include "nulstr-util.h"
27 #include "parse-util.h"
28 #include "path-util.h"
29 #include "selinux-util.h"
30 #include "service-util.h"
31 #include "signal-util.h"
32 #include "stat-util.h"
34 #include "user-util.h"
38 #define VALID_DEPLOYMENT_CHARS (DIGITS LETTERS "-.:")
41 /* Read from /etc/hostname */
44 /* Read from /etc/machine-info */
51 /* Read from /etc/os-release (or /usr/lib/os-release) */
59 typedef struct Context
{
60 char *data
[_PROP_MAX
];
62 struct stat etc_hostname_stat
;
63 struct stat etc_os_release_stat
;
64 struct stat etc_machine_info_stat
;
66 Hashmap
*polkit_registry
;
69 static void context_reset(Context
*c
, uint64_t mask
) {
74 for (p
= 0; p
< _PROP_MAX
; p
++) {
75 if (!FLAGS_SET(mask
, UINT64_C(1) << p
))
78 c
->data
[p
] = mfree(c
->data
[p
]);
82 static void context_destroy(Context
*c
) {
85 context_reset(c
, UINT64_MAX
);
86 bus_verify_polkit_async_registry_free(c
->polkit_registry
);
89 static void context_read_etc_hostname(Context
*c
) {
90 struct stat current_stat
= {};
95 if (stat("/etc/hostname", ¤t_stat
) >= 0 &&
96 stat_inode_unmodified(&c
->etc_hostname_stat
, ¤t_stat
))
99 context_reset(c
, UINT64_C(1) << PROP_STATIC_HOSTNAME
);
101 r
= read_etc_hostname(NULL
, &c
->data
[PROP_STATIC_HOSTNAME
]);
102 if (r
< 0 && r
!= -ENOENT
)
103 log_warning_errno(r
, "Failed to read /etc/hostname, ignoring: %m");
105 c
->etc_hostname_stat
= current_stat
;
108 static void context_read_machine_info(Context
*c
) {
109 struct stat current_stat
= {};
114 if (stat("/etc/machine-info", ¤t_stat
) >= 0 &&
115 stat_inode_unmodified(&c
->etc_machine_info_stat
, ¤t_stat
))
119 (UINT64_C(1) << PROP_PRETTY_HOSTNAME
) |
120 (UINT64_C(1) << PROP_ICON_NAME
) |
121 (UINT64_C(1) << PROP_CHASSIS
) |
122 (UINT64_C(1) << PROP_DEPLOYMENT
) |
123 (UINT64_C(1) << PROP_LOCATION
));
125 r
= parse_env_file(NULL
, "/etc/machine-info",
126 "PRETTY_HOSTNAME", &c
->data
[PROP_PRETTY_HOSTNAME
],
127 "ICON_NAME", &c
->data
[PROP_ICON_NAME
],
128 "CHASSIS", &c
->data
[PROP_CHASSIS
],
129 "DEPLOYMENT", &c
->data
[PROP_DEPLOYMENT
],
130 "LOCATION", &c
->data
[PROP_LOCATION
]);
131 if (r
< 0 && r
!= -ENOENT
)
132 log_warning_errno(r
, "Failed to read /etc/machine-info, ignoring: %m");
134 c
->etc_machine_info_stat
= current_stat
;
137 static void context_read_os_release(Context
*c
) {
138 struct stat current_stat
= {};
143 if ((stat("/etc/os-release", ¤t_stat
) >= 0 ||
144 stat("/usr/lib/os-release", ¤t_stat
) >= 0) &&
145 stat_inode_unmodified(&c
->etc_os_release_stat
, ¤t_stat
))
149 (UINT64_C(1) << PROP_OS_PRETTY_NAME
) |
150 (UINT64_C(1) << PROP_OS_CPE_NAME
) |
151 (UINT64_C(1) << PROP_OS_HOME_URL
));
153 r
= parse_os_release(NULL
,
154 "PRETTY_NAME", &c
->data
[PROP_OS_PRETTY_NAME
],
155 "CPE_NAME", &c
->data
[PROP_OS_CPE_NAME
],
156 "HOME_URL", &c
->data
[PROP_OS_HOME_URL
],
158 if (r
< 0 && r
!= -ENOENT
)
159 log_warning_errno(r
, "Failed to read os-release file, ignoring: %m");
161 c
->etc_os_release_stat
= current_stat
;
164 static bool valid_chassis(const char *chassis
) {
167 return nulstr_contains(
181 static bool valid_deployment(const char *deployment
) {
184 return in_charset(deployment
, VALID_DEPLOYMENT_CHARS
);
187 static const char* fallback_chassis(void) {
192 v
= detect_virtualization();
194 log_debug_errno(v
, "Failed to detect virtualization, ignoring: %m");
195 else if (VIRTUALIZATION_IS_VM(v
))
197 else if (VIRTUALIZATION_IS_CONTAINER(v
))
200 r
= read_one_line_file("/sys/class/dmi/id/chassis_type", &type
);
202 log_debug_errno(v
, "Failed to read DMI chassis type, ignoring: %m");
206 r
= safe_atou(type
, &t
);
209 log_debug_errno(v
, "Failed to parse DMI chassis type, ignoring: %m");
213 /* We only list the really obvious cases here. The DMI data is unreliable enough, so let's not do any
214 additional guesswork on top of that.
216 See the SMBIOS Specification 3.0 section 7.4.1 for details about the values listed here:
218 https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.0.0.pdf
223 case 0x3: /* Desktop */
224 case 0x4: /* Low Profile Desktop */
225 case 0x6: /* Mini Tower */
226 case 0x7: /* Tower */
227 case 0xD: /* All in one (i.e. PC built into monitor) */
230 case 0x8: /* Portable */
231 case 0x9: /* Laptop */
232 case 0xA: /* Notebook */
233 case 0xE: /* Sub Notebook */
236 case 0xB: /* Hand Held */
239 case 0x11: /* Main Server Chassis */
240 case 0x1C: /* Blade */
241 case 0x1D: /* Blade Enclosure */
244 case 0x1E: /* Tablet */
247 case 0x1F: /* Convertible */
248 case 0x20: /* Detachable */
249 return "convertible";
252 log_debug("Unhandled DMI chassis type 0x%02x, ignoring.", t
);
256 r
= read_one_line_file("/sys/firmware/acpi/pm_profile", &type
);
258 log_debug_errno(v
, "Failed read ACPI PM profile, ignoring: %m");
262 r
= safe_atou(type
, &t
);
265 log_debug_errno(v
, "Failed parse ACPI PM profile, ignoring: %m");
269 /* We only list the really obvious cases here as the ACPI data is not really super reliable.
271 * See the ACPI 5.0 Spec Section 5.2.9.1 for details:
273 * http://www.acpi.info/DOWNLOADS/ACPIspec50.pdf
278 case 1: /* Desktop */
279 case 3: /* Workstation */
280 case 6: /* Appliance PC */
286 case 4: /* Enterprise Server */
287 case 5: /* SOHO Server */
288 case 7: /* Performance Server */
295 log_debug("Unhandled ACPI PM profile 0x%02x, ignoring.", t
);
301 static char* context_fallback_icon_name(Context
*c
) {
306 if (!isempty(c
->data
[PROP_CHASSIS
]))
307 return strjoin("computer-", c
->data
[PROP_CHASSIS
]);
309 chassis
= fallback_chassis();
311 return strjoin("computer-", chassis
);
313 return strdup("computer");
316 static bool hostname_is_useful(const char *hn
) {
317 return !isempty(hn
) && !is_localhost(hn
);
320 static int context_update_kernel_hostname(
322 const char *transient_hn
) {
324 const char *static_hn
, *hn
;
330 /* If no transient hostname is passed in, then let's check what is currently set. */
331 assert_se(uname(&u
) >= 0);
333 isempty(u
.nodename
) || streq(u
.nodename
, "(none)") ? NULL
: u
.nodename
;
336 static_hn
= c
->data
[PROP_STATIC_HOSTNAME
];
338 /* /etc/hostname with something other than "localhost"
339 * has the highest preference ... */
340 if (hostname_is_useful(static_hn
))
343 /* ... the transient hostname, (ie: DHCP) comes next ... */
344 else if (!isempty(transient_hn
))
347 /* ... fallback to static "localhost.*" ignored above ... */
348 else if (!isempty(static_hn
))
351 /* ... and the ultimate fallback */
353 hn
= FALLBACK_HOSTNAME
;
355 if (sethostname_idempotent(hn
) < 0)
358 (void) nscd_flush_cache(STRV_MAKE("hosts"));
363 static int context_write_data_static_hostname(Context
*c
) {
366 if (isempty(c
->data
[PROP_STATIC_HOSTNAME
])) {
368 if (unlink("/etc/hostname") < 0)
369 return errno
== ENOENT
? 0 : -errno
;
373 return write_string_file_atomic_label("/etc/hostname", c
->data
[PROP_STATIC_HOSTNAME
]);
376 static int context_write_data_machine_info(Context
*c
) {
378 static const char * const name
[_PROP_MAX
] = {
379 [PROP_PRETTY_HOSTNAME
] = "PRETTY_HOSTNAME",
380 [PROP_ICON_NAME
] = "ICON_NAME",
381 [PROP_CHASSIS
] = "CHASSIS",
382 [PROP_DEPLOYMENT
] = "DEPLOYMENT",
383 [PROP_LOCATION
] = "LOCATION",
386 _cleanup_strv_free_
char **l
= NULL
;
391 r
= load_env_file(NULL
, "/etc/machine-info", &l
);
392 if (r
< 0 && r
!= -ENOENT
)
395 for (p
= PROP_PRETTY_HOSTNAME
; p
<= PROP_LOCATION
; p
++) {
396 _cleanup_free_
char *t
= NULL
;
401 if (isempty(c
->data
[p
])) {
402 strv_env_unset(l
, name
[p
]);
406 t
= strjoin(name
[p
], "=", c
->data
[p
]);
410 u
= strv_env_set(l
, t
);
414 strv_free_and_replace(l
, u
);
417 if (strv_isempty(l
)) {
418 if (unlink("/etc/machine-info") < 0)
419 return errno
== ENOENT
? 0 : -errno
;
424 return write_env_file_label("/etc/machine-info", l
);
427 static int property_get_hostname(
430 const char *interface
,
431 const char *property
,
432 sd_bus_message
*reply
,
434 sd_bus_error
*error
) {
436 _cleanup_free_
char *current
= NULL
;
439 r
= gethostname_strict(¤t
);
441 return sd_bus_message_append(reply
, "s", FALLBACK_HOSTNAME
);
445 return sd_bus_message_append(reply
, "s", current
);
448 static int property_get_static_hostname(
451 const char *interface
,
452 const char *property
,
453 sd_bus_message
*reply
,
455 sd_bus_error
*error
) {
457 Context
*c
= userdata
;
460 context_read_etc_hostname(c
);
462 return sd_bus_message_append(reply
, "s", c
->data
[PROP_STATIC_HOSTNAME
]);
465 static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_fallback_hostname
, "s", FALLBACK_HOSTNAME
);
467 static int property_get_machine_info_field(
470 const char *interface
,
471 const char *property
,
472 sd_bus_message
*reply
,
474 sd_bus_error
*error
) {
479 /* Acquire the context object without this property's userdata offset added. Explanation: we want
480 * access to two pointers here: a) the main context object we cache all properties in, and b) the
481 * pointer to the property field inside the context object that we are supposed to update and
482 * use. The latter (b) we get in the 'userdata' function parameter, and sd-bus calculates that for us
483 * from the 'userdata' pointer we supplied when the vtable was registered, with the offset we
484 * specified in the vtable added on top. To get the former (a) we need the 'userdata' pointer from
485 * the vtable registration directly, without the offset added. Hence we ask sd-bus what the slot
486 * object is (which encapsulates the vtable registration), and then query the 'userdata' field
487 * directly off it. */
488 assert_se(slot
= sd_bus_get_current_slot(bus
));
489 assert_se(c
= sd_bus_slot_get_userdata(slot
));
491 context_read_machine_info(c
);
493 return sd_bus_message_append(reply
, "s", *(char**) userdata
);
496 static int property_get_os_release_field(
499 const char *interface
,
500 const char *property
,
501 sd_bus_message
*reply
,
503 sd_bus_error
*error
) {
508 /* As above, acquire the current context without this property's userdata offset added. */
509 assert_se(slot
= sd_bus_get_current_slot(bus
));
510 assert_se(c
= sd_bus_slot_get_userdata(slot
));
512 context_read_os_release(c
);
514 return sd_bus_message_append(reply
, "s", *(char**) userdata
);
517 static int property_get_icon_name(
520 const char *interface
,
521 const char *property
,
522 sd_bus_message
*reply
,
524 sd_bus_error
*error
) {
526 _cleanup_free_
char *n
= NULL
;
527 Context
*c
= userdata
;
530 context_read_machine_info(c
);
532 if (isempty(c
->data
[PROP_ICON_NAME
]))
533 name
= n
= context_fallback_icon_name(c
);
535 name
= c
->data
[PROP_ICON_NAME
];
540 return sd_bus_message_append(reply
, "s", name
);
543 static int property_get_chassis(
546 const char *interface
,
547 const char *property
,
548 sd_bus_message
*reply
,
550 sd_bus_error
*error
) {
552 Context
*c
= userdata
;
555 context_read_machine_info(c
);
557 if (isempty(c
->data
[PROP_CHASSIS
]))
558 name
= fallback_chassis();
560 name
= c
->data
[PROP_CHASSIS
];
562 return sd_bus_message_append(reply
, "s", name
);
565 static int property_get_uname_field(
568 const char *interface
,
569 const char *property
,
570 sd_bus_message
*reply
,
572 sd_bus_error
*error
) {
576 assert_se(uname(&u
) >= 0);
578 return sd_bus_message_append(reply
, "s", (char*) &u
+ PTR_TO_SIZE(userdata
));
581 static int method_set_hostname(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
582 Context
*c
= userdata
;
590 r
= sd_bus_message_read(m
, "sb", &name
, &interactive
);
594 context_read_etc_hostname(c
);
597 name
= c
->data
[PROP_STATIC_HOSTNAME
];
600 name
= FALLBACK_HOSTNAME
;
602 if (!hostname_is_valid(name
, 0))
603 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid hostname '%s'", name
);
605 assert_se(uname(&u
) >= 0);
606 if (streq_ptr(name
, u
.nodename
))
607 return sd_bus_reply_method_return(m
, NULL
);
609 r
= bus_verify_polkit_async(
612 "org.freedesktop.hostname1.set-hostname",
621 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
623 r
= context_update_kernel_hostname(c
, name
);
625 log_error_errno(r
, "Failed to set hostname: %m");
626 return sd_bus_error_set_errnof(error
, r
, "Failed to set hostname: %m");
629 log_info("Changed hostname to '%s'", name
);
631 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m
), "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "Hostname", NULL
);
633 return sd_bus_reply_method_return(m
, NULL
);
636 static int method_set_static_hostname(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
637 Context
*c
= userdata
;
645 r
= sd_bus_message_read(m
, "sb", &name
, &interactive
);
649 name
= empty_to_null(name
);
651 context_read_etc_hostname(c
);
653 if (streq_ptr(name
, c
->data
[PROP_STATIC_HOSTNAME
]))
654 return sd_bus_reply_method_return(m
, NULL
);
656 if (!isempty(name
) && !hostname_is_valid(name
, 0))
657 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid static hostname '%s'", name
);
659 r
= bus_verify_polkit_async(
662 "org.freedesktop.hostname1.set-static-hostname",
671 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
673 r
= free_and_strdup(&c
->data
[PROP_STATIC_HOSTNAME
], name
);
677 r
= context_update_kernel_hostname(c
, NULL
);
679 log_error_errno(r
, "Failed to set hostname: %m");
680 return sd_bus_error_set_errnof(error
, r
, "Failed to set hostname: %m");
683 r
= context_write_data_static_hostname(c
);
685 log_error_errno(r
, "Failed to write static hostname: %m");
686 return sd_bus_error_set_errnof(error
, r
, "Failed to set static hostname: %m");
689 log_info("Changed static hostname to '%s'", strna(c
->data
[PROP_STATIC_HOSTNAME
]));
691 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m
), "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "StaticHostname", NULL
);
693 return sd_bus_reply_method_return(m
, NULL
);
696 static int set_machine_info(Context
*c
, sd_bus_message
*m
, int prop
, sd_bus_message_handler_t cb
, sd_bus_error
*error
) {
704 r
= sd_bus_message_read(m
, "sb", &name
, &interactive
);
708 name
= empty_to_null(name
);
710 context_read_machine_info(c
);
712 if (streq_ptr(name
, c
->data
[prop
]))
713 return sd_bus_reply_method_return(m
, NULL
);
715 if (!isempty(name
)) {
716 /* The icon name might ultimately be used as file
717 * name, so better be safe than sorry */
719 if (prop
== PROP_ICON_NAME
&& !filename_is_valid(name
))
720 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid icon name '%s'", name
);
721 if (prop
== PROP_PRETTY_HOSTNAME
&& string_has_cc(name
, NULL
))
722 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid pretty hostname '%s'", name
);
723 if (prop
== PROP_CHASSIS
&& !valid_chassis(name
))
724 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid chassis '%s'", name
);
725 if (prop
== PROP_DEPLOYMENT
&& !valid_deployment(name
))
726 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid deployment '%s'", name
);
727 if (prop
== PROP_LOCATION
&& string_has_cc(name
, NULL
))
728 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid location '%s'", name
);
731 /* Since the pretty hostname should always be changed at the
732 * same time as the static one, use the same policy action for
735 r
= bus_verify_polkit_async(
738 prop
== PROP_PRETTY_HOSTNAME
? "org.freedesktop.hostname1.set-static-hostname" : "org.freedesktop.hostname1.set-machine-info",
747 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
749 r
= free_and_strdup(&c
->data
[prop
], name
);
753 r
= context_write_data_machine_info(c
);
755 log_error_errno(r
, "Failed to write machine info: %m");
756 return sd_bus_error_set_errnof(error
, r
, "Failed to write machine info: %m");
759 log_info("Changed %s to '%s'",
760 prop
== PROP_PRETTY_HOSTNAME
? "pretty hostname" :
761 prop
== PROP_DEPLOYMENT
? "deployment" :
762 prop
== PROP_LOCATION
? "location" :
763 prop
== PROP_CHASSIS
? "chassis" : "icon name", strna(c
->data
[prop
]));
765 (void) sd_bus_emit_properties_changed(
766 sd_bus_message_get_bus(m
),
767 "/org/freedesktop/hostname1",
768 "org.freedesktop.hostname1",
769 prop
== PROP_PRETTY_HOSTNAME
? "PrettyHostname" :
770 prop
== PROP_DEPLOYMENT
? "Deployment" :
771 prop
== PROP_LOCATION
? "Location" :
772 prop
== PROP_CHASSIS
? "Chassis" : "IconName" , NULL
);
774 return sd_bus_reply_method_return(m
, NULL
);
777 static int method_set_pretty_hostname(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
778 return set_machine_info(userdata
, m
, PROP_PRETTY_HOSTNAME
, method_set_pretty_hostname
, error
);
781 static int method_set_icon_name(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
782 return set_machine_info(userdata
, m
, PROP_ICON_NAME
, method_set_icon_name
, error
);
785 static int method_set_chassis(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
786 return set_machine_info(userdata
, m
, PROP_CHASSIS
, method_set_chassis
, error
);
789 static int method_set_deployment(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
790 return set_machine_info(userdata
, m
, PROP_DEPLOYMENT
, method_set_deployment
, error
);
793 static int method_set_location(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
794 return set_machine_info(userdata
, m
, PROP_LOCATION
, method_set_location
, error
);
797 static int method_get_product_uuid(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
798 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
799 Context
*c
= userdata
;
800 bool has_uuid
= false;
807 r
= id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID
, &uuid
);
809 r
= id128_read("/sys/firmware/devicetree/base/vm,uuid", ID128_UUID
, &uuid
);
811 log_full_errno(r
== -ENOENT
? LOG_DEBUG
: LOG_WARNING
, r
,
812 "Failed to read product UUID, ignoring: %m");
813 else if (sd_id128_is_null(uuid
) || sd_id128_is_allf(uuid
))
814 log_debug("DMI product UUID " SD_ID128_FORMAT_STR
" is all 0x00 or all 0xFF, ignoring.", SD_ID128_FORMAT_VAL(uuid
));
819 return sd_bus_error_set(error
, BUS_ERROR_NO_PRODUCT_UUID
,
820 "Failed to read product UUID from firmware.");
822 r
= sd_bus_message_read(m
, "b", &interactive
);
826 r
= bus_verify_polkit_async(
829 "org.freedesktop.hostname1.get-product-uuid",
838 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
840 r
= sd_bus_message_new_method_return(m
, &reply
);
844 r
= sd_bus_message_append_array(reply
, 'y', &uuid
, sizeof(uuid
));
848 return sd_bus_send(NULL
, reply
, NULL
);
851 static const sd_bus_vtable hostname_vtable
[] = {
852 SD_BUS_VTABLE_START(0),
853 SD_BUS_PROPERTY("Hostname", "s", property_get_hostname
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
854 SD_BUS_PROPERTY("StaticHostname", "s", property_get_static_hostname
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
855 SD_BUS_PROPERTY("PrettyHostname", "s", property_get_machine_info_field
, offsetof(Context
, data
) + sizeof(char*) * PROP_PRETTY_HOSTNAME
, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
856 SD_BUS_PROPERTY("FallbackHostname", "s", property_get_fallback_hostname
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
857 SD_BUS_PROPERTY("IconName", "s", property_get_icon_name
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
858 SD_BUS_PROPERTY("Chassis", "s", property_get_chassis
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
859 SD_BUS_PROPERTY("Deployment", "s", property_get_machine_info_field
, offsetof(Context
, data
) + sizeof(char*) * PROP_DEPLOYMENT
, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
860 SD_BUS_PROPERTY("Location", "s", property_get_machine_info_field
, offsetof(Context
, data
) + sizeof(char*) * PROP_LOCATION
, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
861 SD_BUS_PROPERTY("KernelName", "s", property_get_uname_field
, offsetof(struct utsname
, sysname
), SD_BUS_VTABLE_ABSOLUTE_OFFSET
|SD_BUS_VTABLE_PROPERTY_CONST
),
862 SD_BUS_PROPERTY("KernelRelease", "s", property_get_uname_field
, offsetof(struct utsname
, release
), SD_BUS_VTABLE_ABSOLUTE_OFFSET
|SD_BUS_VTABLE_PROPERTY_CONST
),
863 SD_BUS_PROPERTY("KernelVersion", "s", property_get_uname_field
, offsetof(struct utsname
, version
), SD_BUS_VTABLE_ABSOLUTE_OFFSET
|SD_BUS_VTABLE_PROPERTY_CONST
),
864 SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", property_get_os_release_field
, offsetof(Context
, data
) + sizeof(char*) * PROP_OS_PRETTY_NAME
, SD_BUS_VTABLE_PROPERTY_CONST
),
865 SD_BUS_PROPERTY("OperatingSystemCPEName", "s", property_get_os_release_field
, offsetof(Context
, data
) + sizeof(char*) * PROP_OS_CPE_NAME
, SD_BUS_VTABLE_PROPERTY_CONST
),
866 SD_BUS_PROPERTY("HomeURL", "s", property_get_os_release_field
, offsetof(Context
, data
) + sizeof(char*) * PROP_OS_HOME_URL
, SD_BUS_VTABLE_PROPERTY_CONST
),
868 SD_BUS_METHOD_WITH_NAMES("SetHostname",
870 SD_BUS_PARAM(hostname
)
871 SD_BUS_PARAM(interactive
),
874 SD_BUS_VTABLE_UNPRIVILEGED
),
875 SD_BUS_METHOD_WITH_NAMES("SetStaticHostname",
877 SD_BUS_PARAM(hostname
)
878 SD_BUS_PARAM(interactive
),
880 method_set_static_hostname
,
881 SD_BUS_VTABLE_UNPRIVILEGED
),
882 SD_BUS_METHOD_WITH_NAMES("SetPrettyHostname",
884 SD_BUS_PARAM(hostname
)
885 SD_BUS_PARAM(interactive
),
887 method_set_pretty_hostname
,
888 SD_BUS_VTABLE_UNPRIVILEGED
),
889 SD_BUS_METHOD_WITH_NAMES("SetIconName",
892 SD_BUS_PARAM(interactive
),
894 method_set_icon_name
,
895 SD_BUS_VTABLE_UNPRIVILEGED
),
896 SD_BUS_METHOD_WITH_NAMES("SetChassis",
898 SD_BUS_PARAM(chassis
)
899 SD_BUS_PARAM(interactive
),
902 SD_BUS_VTABLE_UNPRIVILEGED
),
903 SD_BUS_METHOD_WITH_NAMES("SetDeployment",
905 SD_BUS_PARAM(deployment
)
906 SD_BUS_PARAM(interactive
),
908 method_set_deployment
,
909 SD_BUS_VTABLE_UNPRIVILEGED
),
910 SD_BUS_METHOD_WITH_NAMES("SetLocation",
912 SD_BUS_PARAM(location
)
913 SD_BUS_PARAM(interactive
),
916 SD_BUS_VTABLE_UNPRIVILEGED
),
917 SD_BUS_METHOD_WITH_NAMES("GetProductUUID",
919 SD_BUS_PARAM(interactive
),
922 method_get_product_uuid
,
923 SD_BUS_VTABLE_UNPRIVILEGED
),
928 static const BusObjectImplementation manager_object
= {
929 "/org/freedesktop/hostname1",
930 "org.freedesktop.hostname1",
931 .vtables
= BUS_VTABLES(hostname_vtable
),
934 static int connect_bus(Context
*c
, sd_event
*event
, sd_bus
**ret
) {
935 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
942 r
= sd_bus_default_system(&bus
);
944 return log_error_errno(r
, "Failed to get system bus connection: %m");
946 r
= bus_add_implementation(bus
, &manager_object
, c
);
950 r
= bus_log_control_api_register(bus
);
954 r
= sd_bus_request_name_async(bus
, NULL
, "org.freedesktop.hostname1", 0, NULL
, NULL
);
956 return log_error_errno(r
, "Failed to request name: %m");
958 r
= sd_bus_attach_event(bus
, event
, 0);
960 return log_error_errno(r
, "Failed to attach bus to event loop: %m");
962 *ret
= TAKE_PTR(bus
);
966 static int run(int argc
, char *argv
[]) {
967 _cleanup_(context_destroy
) Context context
= {};
968 _cleanup_(sd_event_unrefp
) sd_event
*event
= NULL
;
969 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
974 r
= service_parse_argv("systemd-hostnamed.service",
975 "Manage the system hostname and related metadata.",
976 BUS_IMPLEMENTATIONS(&manager_object
,
977 &log_control_object
),
984 r
= mac_selinux_init();
988 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGTERM
, SIGINT
, -1) >= 0);
990 r
= sd_event_default(&event
);
992 return log_error_errno(r
, "Failed to allocate event loop: %m");
994 (void) sd_event_set_watchdog(event
, true);
996 r
= sd_event_add_signal(event
, NULL
, SIGINT
, NULL
, NULL
);
998 return log_error_errno(r
, "Failed to install SIGINT handler: %m");
1000 r
= sd_event_add_signal(event
, NULL
, SIGTERM
, NULL
, NULL
);
1002 return log_error_errno(r
, "Failed to install SIGTERM handler: %m");
1004 r
= connect_bus(&context
, event
, &bus
);
1008 r
= bus_event_loop_with_idle(event
, bus
, "org.freedesktop.hostname1", DEFAULT_EXIT_USEC
, NULL
, NULL
);
1010 return log_error_errno(r
, "Failed to run event loop: %m");
1015 DEFINE_MAIN_FUNCTION(run
);