/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2011 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "alloc-util.h"
+#include "bus-common-errors.h"
#include "bus-util.h"
#include "def.h"
#include "env-util.h"
#include "fileio-label.h"
+#include "fileio.h"
#include "hostname-util.h"
+#include "id128-util.h"
+#include "main-func.h"
+#include "os-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "selinux-util.h"
+#include "signal-util.h"
#include "strv.h"
#include "user-util.h"
#include "util.h"
PROP_KERNEL_VERSION,
PROP_OS_PRETTY_NAME,
PROP_OS_CPE_NAME,
+ PROP_HOME_URL,
_PROP_MAX
};
typedef struct Context {
char *data[_PROP_MAX];
Hashmap *polkit_registry;
+ sd_id128_t uuid;
+ bool has_uuid;
} Context;
static void context_reset(Context *c) {
c->data[p] = mfree(c->data[p]);
}
-static void context_free(Context *c) {
+static void context_clear(Context *c) {
assert(c);
context_reset(c);
if (!c->data[PROP_HOSTNAME])
return -ENOMEM;
- r = read_hostname_config("/etc/hostname", &c->data[PROP_STATIC_HOSTNAME]);
+ r = read_etc_hostname(NULL, &c->data[PROP_STATIC_HOSTNAME]);
if (r < 0 && r != -ENOENT)
return r;
- r = parse_env_file("/etc/machine-info", NEWLINE,
+ r = parse_env_file(NULL, "/etc/machine-info",
"PRETTY_HOSTNAME", &c->data[PROP_PRETTY_HOSTNAME],
"ICON_NAME", &c->data[PROP_ICON_NAME],
"CHASSIS", &c->data[PROP_CHASSIS],
"DEPLOYMENT", &c->data[PROP_DEPLOYMENT],
- "LOCATION", &c->data[PROP_LOCATION],
- NULL);
+ "LOCATION", &c->data[PROP_LOCATION]);
if (r < 0 && r != -ENOENT)
return r;
- r = parse_env_file("/etc/os-release", NEWLINE,
- "PRETTY_NAME", &c->data[PROP_OS_PRETTY_NAME],
- "CPE_NAME", &c->data[PROP_OS_CPE_NAME],
- NULL);
- if (r == -ENOENT)
- r = parse_env_file("/usr/lib/os-release", NEWLINE,
- "PRETTY_NAME", &c->data[PROP_OS_PRETTY_NAME],
- "CPE_NAME", &c->data[PROP_OS_CPE_NAME],
- NULL);
-
+ r = parse_os_release(NULL,
+ "PRETTY_NAME", &c->data[PROP_OS_PRETTY_NAME],
+ "CPE_NAME", &c->data[PROP_OS_CPE_NAME],
+ "HOME_URL", &c->data[PROP_HOME_URL],
+ NULL);
if (r < 0 && r != -ENOENT)
return r;
+ r = id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, &c->uuid);
+ if (r < 0)
+ log_info_errno(r, "Failed to read product UUID, ignoring: %m");
+ c->has_uuid = (r >= 0);
+
return 0;
}
return strdup("computer");
}
-
static bool hostname_is_useful(const char *hn) {
return !isempty(hn) && !is_localhost(hn);
}
assert(c);
- r = load_env_file(NULL, "/etc/machine-info", NULL, &l);
+ r = load_env_file(NULL, "/etc/machine-info", &l);
if (r < 0 && r != -ENOENT)
return r;
if (!u)
return -ENOMEM;
- strv_free(l);
- l = u;
+ strv_free_and_replace(l, u);
}
if (strv_isempty(l)) {
Context *c = userdata;
const char *name;
int interactive;
- char *h;
int r;
assert(m);
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
- h = strdup(name);
- if (!h)
- return -ENOMEM;
-
- free(c->data[PROP_HOSTNAME]);
- c->data[PROP_HOSTNAME] = h;
+ r = free_and_strdup(&c->data[PROP_HOSTNAME], name);
+ if (r < 0)
+ return r;
r = context_update_kernel_hostname(c);
if (r < 0) {
if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME]))
return sd_bus_reply_method_return(m, NULL);
+ if (!isempty(name) && !hostname_is_valid(name, false))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name);
+
r = bus_verify_polkit_async(
m,
CAP_SYS_ADMIN,
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
- if (isempty(name))
- c->data[PROP_STATIC_HOSTNAME] = mfree(c->data[PROP_STATIC_HOSTNAME]);
- else {
- char *h;
-
- if (!hostname_is_valid(name, false))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name);
-
- h = strdup(name);
- if (!h)
- return -ENOMEM;
-
- free(c->data[PROP_STATIC_HOSTNAME]);
- c->data[PROP_STATIC_HOSTNAME] = h;
- }
+ r = free_and_strdup(&c->data[PROP_STATIC_HOSTNAME], name);
+ if (r < 0)
+ return r;
r = context_update_kernel_hostname(c);
if (r < 0) {
if (streq_ptr(name, c->data[prop]))
return sd_bus_reply_method_return(m, NULL);
+ if (!isempty(name)) {
+ /* The icon name might ultimately be used as file
+ * name, so better be safe than sorry */
+
+ if (prop == PROP_ICON_NAME && !filename_is_valid(name))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid icon name '%s'", name);
+ if (prop == PROP_PRETTY_HOSTNAME && string_has_cc(name, NULL))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty host name '%s'", name);
+ if (prop == PROP_CHASSIS && !valid_chassis(name))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid chassis '%s'", name);
+ if (prop == PROP_DEPLOYMENT && !valid_deployment(name))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid deployment '%s'", name);
+ if (prop == PROP_LOCATION && string_has_cc(name, NULL))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid location '%s'", name);
+ }
+
/* Since the pretty hostname should always be changed at the
* same time as the static one, use the same policy action for
* both... */
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
- if (isempty(name))
- c->data[prop] = mfree(c->data[prop]);
- else {
- char *h;
-
- /* The icon name might ultimately be used as file
- * name, so better be safe than sorry */
-
- if (prop == PROP_ICON_NAME && !filename_is_valid(name))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid icon name '%s'", name);
- if (prop == PROP_PRETTY_HOSTNAME && string_has_cc(name, NULL))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty host name '%s'", name);
- if (prop == PROP_CHASSIS && !valid_chassis(name))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid chassis '%s'", name);
- if (prop == PROP_DEPLOYMENT && !valid_deployment(name))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid deployment '%s'", name);
- if (prop == PROP_LOCATION && string_has_cc(name, NULL))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid location '%s'", name);
-
- h = strdup(name);
- if (!h)
- return -ENOMEM;
-
- free(c->data[prop]);
- c->data[prop] = h;
- }
+ r = free_and_strdup(&c->data[prop], name);
+ if (r < 0)
+ return r;
r = context_write_data_machine_info(c);
if (r < 0) {
return set_machine_info(userdata, m, PROP_LOCATION, method_set_location, error);
}
+static int method_get_product_uuid(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ Context *c = userdata;
+ int interactive, r;
+
+ assert(m);
+ assert(c);
+
+ if (!c->has_uuid)
+ return sd_bus_error_set(error, BUS_ERROR_NO_PRODUCT_UUID, "Failed to read product UUID from /sys/class/dmi/id/product_uuid");
+
+ r = sd_bus_message_read(m, "b", &interactive);
+ if (r < 0)
+ return r;
+
+ r = bus_verify_polkit_async(
+ m,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.hostname1.get-product-uuid",
+ NULL,
+ interactive,
+ UID_INVALID,
+ &c->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
+ r = sd_bus_message_new_method_return(m, &reply);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append_array(reply, 'y', &c->uuid, sizeof(c->uuid));
+ if (r < 0)
+ return r;
+
+ return sd_bus_send(NULL, reply, NULL);
+}
+
static const sd_bus_vtable hostname_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Hostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("KernelVersion", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_VERSION, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_PRETTY_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OperatingSystemCPEName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_CPE_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("HomeURL", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_HOME_URL, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD("SetHostname", "sb", NULL, method_set_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetStaticHostname", "sb", NULL, method_set_static_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetPrettyHostname", "sb", NULL, method_set_pretty_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetChassis", "sb", NULL, method_set_chassis, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetDeployment", "sb", NULL, method_set_deployment, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetLocation", "sb", NULL, method_set_location, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("GetProductUUID", "b", "ay", method_get_product_uuid, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END,
};
if (r < 0)
return log_error_errno(r, "Failed to register object: %m");
- r = sd_bus_request_name(bus, "org.freedesktop.hostname1", 0);
+ r = sd_bus_request_name_async(bus, NULL, "org.freedesktop.hostname1", 0, NULL, NULL);
if (r < 0)
- return log_error_errno(r, "Failed to register name: %m");
+ return log_error_errno(r, "Failed to request name: %m");
r = sd_bus_attach_event(bus, event, 0);
if (r < 0)
return log_error_errno(r, "Failed to attach bus to event loop: %m");
- *_bus = bus;
- bus = NULL;
+ *_bus = TAKE_PTR(bus);
return 0;
}
-int main(int argc, char *argv[]) {
- Context context = {};
+static int run(int argc, char *argv[]) {
+ _cleanup_(context_clear) Context context = {};
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r;
- log_set_target(LOG_TARGET_AUTO);
- log_parse_environment();
- log_open();
+ log_setup_service();
umask(0022);
mac_selinux_init();
if (argc != 1) {
log_error("This program takes no arguments.");
- r = -EINVAL;
- goto finish;
+ return -EINVAL;
}
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
+
r = sd_event_default(&event);
- if (r < 0) {
- log_error_errno(r, "Failed to allocate event loop: %m");
- goto finish;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate event loop: %m");
+
+ (void) sd_event_set_watchdog(event, true);
- sd_event_set_watchdog(event, true);
+ r = sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to install SIGINT handler: %m");
+
+ r = sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to install SIGTERM handler: %m");
r = connect_bus(&context, event, &bus);
if (r < 0)
- goto finish;
+ return r;
r = context_read_data(&context);
- if (r < 0) {
- log_error_errno(r, "Failed to read hostname and machine information: %m");
- goto finish;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to read hostname and machine information: %m");
r = bus_event_loop_with_idle(event, bus, "org.freedesktop.hostname1", DEFAULT_EXIT_USEC, NULL, NULL);
- if (r < 0) {
- log_error_errno(r, "Failed to run event loop: %m");
- goto finish;
- }
-
-finish:
- context_free(&context);
+ if (r < 0)
+ return log_error_errno(r, "Failed to run event loop: %m");
- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+ return 0;
}
+
+DEFINE_MAIN_FUNCTION(run);