From 00c36f274b43e5386b42160c8ce07aea0cf15fc3 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sat, 31 Dec 2011 06:59:04 +0100 Subject: hostnamed: move sources to subdirectory --- Makefile.am | 52 ++-- po/.gitignore | 1 + po/POTFILES.skip | 2 +- src/hostname/hostnamed.c | 623 +++++++++++++++++++++++++++++++++++++++++++++++ src/hostnamed.c | 623 ----------------------------------------------- 5 files changed, 651 insertions(+), 650 deletions(-) create mode 100644 src/hostname/hostnamed.c delete mode 100644 src/hostnamed.c diff --git a/Makefile.am b/Makefile.am index cc28e2abb5..c6a25a78e1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -202,11 +202,6 @@ rootlibexec_PROGRAMS += \ systemd-binfmt endif -if ENABLE_HOSTNAMED -rootlibexec_PROGRAMS += \ - systemd-hostnamed -endif - systemgenerator_PROGRAMS = \ systemd-getty-generator @@ -428,11 +423,6 @@ nodist_systemunit_DATA += \ units/systemd-binfmt.service endif -if ENABLE_HOSTNAMED -nodist_systemunit_DATA += \ - units/systemd-hostnamed.service -endif - dist_userunit_DATA = \ units/user/default.target \ units/user/exit.target @@ -492,11 +482,6 @@ EXTRA_DIST += \ units/systemd-binfmt.service.in endif -if ENABLE_HOSTNAMED -EXTRA_DIST += \ - units/systemd-hostnamed.service.in -endif - if TARGET_FEDORA dist_systemunit_DATA += \ units/fedora/prefdm.service \ @@ -1100,8 +1085,10 @@ dist_pkgdata_DATA = \ dist_noinst_SCRIPT = \ src/generate-kbd-model-map +# ------------------------------------------------------------------------------ +if ENABLE_HOSTNAMED systemd_hostnamed_SOURCES = \ - src/hostnamed.c \ + src/hostname/hostnamed.c \ src/dbus-common.c \ src/polkit.c @@ -1114,6 +1101,29 @@ systemd_hostnamed_LDADD = \ libsystemd-daemon.la \ $(DBUS_LIBS) +rootlibexec_PROGRAMS += \ + systemd-hostnamed + +nodist_systemunit_DATA += \ + units/systemd-hostnamed.service + +org.freedesktop.hostname1.xml: systemd-hostnamed + $(AM_V_GEN)$(LIBTOOL) --mode=execute $(OBJCOPY) -O binary -j introspect.hostname1 $< $@.tmp && \ + $(STRINGS) $@.tmp | $(AWK) -f $(srcdir)/introspect.awk | \ + $(DBUS_PREPROCESS) -o $@ - && rm $@.tmp + +hostnamed-install-data-hook: + ( cd $(DESTDIR)$(systemunitdir) && \ + rm -f dbus-org.freedesktop.hostname1.service && \ + $(LN_S) systemd-hostnamed.service dbus-org.freedesktop.hostname1.service ) + +INSTALL_DATA_HOOKS += \ + hostnamed-install-data-hook + +EXTRA_DIST += \ + units/systemd-hostnamed.service.in +endif + # ------------------------------------------------------------------------------ if ENABLE_LOCALED systemd_localed_SOURCES = \ @@ -2040,11 +2050,6 @@ org.freedesktop.systemd1.%.xml: systemd $(STRINGS) $@.tmp | $(AWK) -f $(srcdir)/introspect.awk | \ $(DBUS_PREPROCESS) -o $@ - && rm $@.tmp -org.freedesktop.hostname1.xml: systemd-hostnamed - $(AM_V_GEN)$(LIBTOOL) --mode=execute $(OBJCOPY) -O binary -j introspect.hostname1 $< $@.tmp && \ - $(STRINGS) $@.tmp | $(AWK) -f $(srcdir)/introspect.awk | \ - $(DBUS_PREPROCESS) -o $@ - && rm $@.tmp - CLEANFILES += \ $(dbusinterface_DATA) @@ -2195,11 +2200,6 @@ if ENABLE_BINFMT proc-sys-fs-binfmt_misc.automount && \ $(LN_S) ../systemd-binfmt.service systemd-binfmt.service && \ $(LN_S) ../proc-sys-fs-binfmt_misc.automount proc-sys-fs-binfmt_misc.automount ) -endif -if ENABLE_HOSTNAMED - ( cd $(DESTDIR)$(systemunitdir) && \ - rm -f dbus-org.freedesktop.hostname1.service && \ - $(LN_S) systemd-hostnamed.service dbus-org.freedesktop.hostname1.service ) endif ( cd $(DESTDIR)$(systemunitdir)/basic.target.wants && \ rm -f systemd-tmpfiles-clean.timer && \ diff --git a/po/.gitignore b/po/.gitignore index ee1215654d..1fa8d3fd56 100644 --- a/po/.gitignore +++ b/po/.gitignore @@ -2,3 +2,4 @@ POTFILES Makefile.in.in .intltool-merge-cache Makefile +systemd.pot diff --git a/po/POTFILES.skip b/po/POTFILES.skip index 10d61410fe..5a5d027493 100644 --- a/po/POTFILES.skip +++ b/po/POTFILES.skip @@ -11,7 +11,7 @@ src/dbus-swap.c src/dbus-target.c src/dbus-timer.c src/dbus-unit.c -src/hostnamed.c +src/hostname/hostnamed.c src/locale/localed.c src/org.freedesktop.systemd1.policy.in.in src/timedate/timedated.c diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c new file mode 100644 index 0000000000..f3b2c94173 --- /dev/null +++ b/src/hostname/hostnamed.c @@ -0,0 +1,623 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + 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 General Public License as published by + the Free Software Foundation; either version 2 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with systemd; If not, see . +***/ + +#include + +#include +#include +#include +#include + +#include "util.h" +#include "strv.h" +#include "dbus-common.h" +#include "polkit.h" +#include "def.h" +#include "virt.h" + +#define INTERFACE \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" + +#define INTROSPECTION \ + DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ + "\n" \ + INTERFACE \ + BUS_PROPERTIES_INTERFACE \ + BUS_INTROSPECTABLE_INTERFACE \ + BUS_PEER_INTERFACE \ + "\n" + +#define INTERFACES_LIST \ + BUS_GENERIC_INTERFACES_LIST \ + "org.freedesktop.hostname1\0" + +const char hostname_interface[] _introspect_("hostname1") = INTERFACE; + +enum { + PROP_HOSTNAME, + PROP_STATIC_HOSTNAME, + PROP_PRETTY_HOSTNAME, + PROP_ICON_NAME, + _PROP_MAX +}; + +static char *data[_PROP_MAX] = { + NULL, + NULL, + NULL, + NULL +}; + +static usec_t remain_until = 0; + +static void free_data(void) { + int p; + + for (p = 0; p < _PROP_MAX; p++) { + free(data[p]); + data[p] = NULL; + } +} + +static int read_data(void) { + int r; + + free_data(); + + data[PROP_HOSTNAME] = gethostname_malloc(); + if (!data[PROP_HOSTNAME]) + return -ENOMEM; + + r = read_one_line_file("/etc/hostname", &data[PROP_STATIC_HOSTNAME]); + if (r < 0 && r != -ENOENT) + return r; + + r = parse_env_file("/etc/machine-info", NEWLINE, + "PRETTY_HOSTNAME", &data[PROP_PRETTY_HOSTNAME], + "ICON_NAME", &data[PROP_ICON_NAME], + NULL); + if (r < 0 && r != -ENOENT) + return r; + + return 0; +} + +static bool check_nss(void) { + + void *dl; + + if ((dl = dlopen("libnss_myhostname.so.2", RTLD_LAZY))) { + dlclose(dl); + return true; + } + + return false; +} + +static const char* fallback_icon_name(void) { + +#if defined(__i386__) || defined(__x86_64__) + int r; + char *type; + unsigned t; +#endif + + if (detect_virtualization(NULL) > 0) + return "computer-vm"; + +#if defined(__i386__) || defined(__x86_64__) + r = read_one_line_file("/sys/class/dmi/id/chassis_type", &type); + if (r < 0) + return NULL; + + r = safe_atou(type, &t); + free(type); + + if (r < 0) + return NULL; + + /* We only list the really obvious cases here. The DMI data is + unreliable enough, so let's not do any additional guesswork + on top of that. + + See the SMBIOS Specification 2.7.1 section 7.4.1 for + details about the values listed here: + + http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.1.pdf + */ + + switch (t) { + + case 0x3: + case 0x4: + case 0x6: + case 0x7: + return "computer-desktop"; + + case 0x9: + case 0xA: + case 0xE: + return "computer-laptop"; + + case 0x11: + case 0x1C: + return "computer-server"; + } + +#endif + return NULL; +} + +static int write_data_hostname(void) { + const char *hn; + + if (isempty(data[PROP_HOSTNAME])) + hn = "localhost"; + else + hn = data[PROP_HOSTNAME]; + + if (sethostname(hn, strlen(hn)) < 0) + return -errno; + + return 0; +} + +static int write_data_static_hostname(void) { + + if (isempty(data[PROP_STATIC_HOSTNAME])) { + + if (unlink("/etc/hostname") < 0) + return errno == ENOENT ? 0 : -errno; + + return 0; + } + + return write_one_line_file_atomic("/etc/hostname", data[PROP_STATIC_HOSTNAME]); +} + +static int write_data_other(void) { + + static const char * const name[_PROP_MAX] = { + [PROP_PRETTY_HOSTNAME] = "PRETTY_HOSTNAME", + [PROP_ICON_NAME] = "ICON_NAME" + }; + + char **l = NULL; + int r, p; + + r = load_env_file("/etc/machine-info", &l); + if (r < 0 && r != -ENOENT) + return r; + + for (p = 2; p < _PROP_MAX; p++) { + char *t, **u; + + assert(name[p]); + + if (isempty(data[p])) { + strv_env_unset(l, name[p]); + continue; + } + + if (asprintf(&t, "%s=%s", name[p], strempty(data[p])) < 0) { + strv_free(l); + return -ENOMEM; + } + + u = strv_env_set(l, t); + free(t); + strv_free(l); + + if (!u) + return -ENOMEM; + l = u; + } + + if (strv_isempty(l)) { + + if (unlink("/etc/machine-info") < 0) + return errno == ENOENT ? 0 : -errno; + + return 0; + } + + r = write_env_file("/etc/machine-info", l); + strv_free(l); + + return r; +} + +static int bus_hostname_append_icon_name(DBusMessageIter *i, const char *property, void *userdata) { + const char *name; + + assert(i); + assert(property); + + if (isempty(data[PROP_ICON_NAME])) + name = fallback_icon_name(); + else + name = data[PROP_ICON_NAME]; + + return bus_property_append_string(i, property, (void*) name); +} + +static DBusHandlerResult hostname_message_handler( + DBusConnection *connection, + DBusMessage *message, + void *userdata) { + + const BusProperty properties[] = { + { "org.freedesktop.hostname1", "Hostname", bus_property_append_string, "s", data[PROP_HOSTNAME]}, + { "org.freedesktop.hostname1", "StaticHostname", bus_property_append_string, "s", data[PROP_STATIC_HOSTNAME]}, + { "org.freedesktop.hostname1", "PrettyHostname", bus_property_append_string, "s", data[PROP_PRETTY_HOSTNAME]}, + { "org.freedesktop.hostname1", "IconName", bus_hostname_append_icon_name, "s", data[PROP_ICON_NAME]}, + { NULL, NULL, NULL, NULL, NULL } + }; + + DBusMessage *reply = NULL, *changed = NULL; + DBusError error; + int r; + + assert(connection); + assert(message); + + dbus_error_init(&error); + + if (dbus_message_is_method_call(message, "org.freedesktop.hostname1", "SetHostname")) { + const char *name; + dbus_bool_t interactive; + + if (!dbus_message_get_args( + message, + &error, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_BOOLEAN, &interactive, + DBUS_TYPE_INVALID)) + return bus_send_error_reply(connection, message, &error, -EINVAL); + + if (isempty(name)) + name = data[PROP_STATIC_HOSTNAME]; + + if (isempty(name)) + name = "localhost"; + + if (!hostname_is_valid(name)) + return bus_send_error_reply(connection, message, NULL, -EINVAL); + + if (!streq_ptr(name, data[PROP_HOSTNAME])) { + char *h; + + r = verify_polkit(connection, message, "org.freedesktop.hostname1.set-hostname", interactive, &error); + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); + + h = strdup(name); + if (!h) + goto oom; + + free(data[PROP_HOSTNAME]); + data[PROP_HOSTNAME] = h; + + r = write_data_hostname(); + if (r < 0) { + log_error("Failed to set host name: %s", strerror(-r)); + return bus_send_error_reply(connection, message, NULL, r); + } + + log_info("Changed host name to '%s'", strempty(data[PROP_HOSTNAME])); + + changed = bus_properties_changed_new( + "/org/freedesktop/hostname1", + "org.freedesktop.hostname1", + "Hostname\0"); + if (!changed) + goto oom; + } + + } else if (dbus_message_is_method_call(message, "org.freedesktop.hostname1", "SetStaticHostname")) { + const char *name; + dbus_bool_t interactive; + + if (!dbus_message_get_args( + message, + &error, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_BOOLEAN, &interactive, + DBUS_TYPE_INVALID)) + return bus_send_error_reply(connection, message, &error, -EINVAL); + + if (isempty(name)) + name = NULL; + + if (!streq_ptr(name, data[PROP_STATIC_HOSTNAME])) { + + r = verify_polkit(connection, message, "org.freedesktop.hostname1.set-static-hostname", interactive, &error); + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); + + if (isempty(name)) { + free(data[PROP_STATIC_HOSTNAME]); + data[PROP_STATIC_HOSTNAME] = NULL; + } else { + char *h; + + if (!hostname_is_valid(name)) + return bus_send_error_reply(connection, message, NULL, -EINVAL); + + h = strdup(name); + if (!h) + goto oom; + + free(data[PROP_STATIC_HOSTNAME]); + data[PROP_STATIC_HOSTNAME] = h; + } + + r = write_data_static_hostname(); + if (r < 0) { + log_error("Failed to write static host name: %s", strerror(-r)); + return bus_send_error_reply(connection, message, NULL, r); + } + + log_info("Changed static host name to '%s'", strempty(data[PROP_STATIC_HOSTNAME])); + + changed = bus_properties_changed_new( + "/org/freedesktop/hostname1", + "org.freedesktop.hostname1", + "StaticHostname\0"); + if (!changed) + goto oom; + } + + } else if (dbus_message_is_method_call(message, "org.freedesktop.hostname1", "SetPrettyHostname") || + dbus_message_is_method_call(message, "org.freedesktop.hostname1", "SetIconName")) { + + const char *name; + dbus_bool_t interactive; + int k; + + if (!dbus_message_get_args( + message, + &error, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_BOOLEAN, &interactive, + DBUS_TYPE_INVALID)) + return bus_send_error_reply(connection, message, &error, -EINVAL); + + if (isempty(name)) + name = NULL; + + k = streq(dbus_message_get_member(message), "SetPrettyHostname") ? PROP_PRETTY_HOSTNAME : PROP_ICON_NAME; + + if (!streq_ptr(name, data[k])) { + + /* Since the pretty hostname should always be + * changed at the same time as the static one, + * use the same policy action for both... */ + + r = verify_polkit(connection, message, k == PROP_PRETTY_HOSTNAME ? + "org.freedesktop.hostname1.set-static-hostname" : + "org.freedesktop.hostname1.set-machine-info", interactive, &error); + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); + + if (isempty(name)) { + free(data[k]); + data[k] = NULL; + } else { + char *h; + + h = strdup(name); + if (!h) + goto oom; + + free(data[k]); + data[k] = h; + } + + r = write_data_other(); + if (r < 0) { + log_error("Failed to write machine info: %s", strerror(-r)); + return bus_send_error_reply(connection, message, NULL, r); + } + + log_info("Changed %s to '%s'", k == PROP_PRETTY_HOSTNAME ? "pretty host name" : "icon name", strempty(data[k])); + + changed = bus_properties_changed_new( + "/org/freedesktop/hostname1", + "org.freedesktop.hostname1", + k == PROP_PRETTY_HOSTNAME ? "PrettyHostname\0" : "IconName\0"); + if (!changed) + goto oom; + } + + } else + return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties); + + if (!(reply = dbus_message_new_method_return(message))) + goto oom; + + if (!dbus_connection_send(connection, reply, NULL)) + goto oom; + + dbus_message_unref(reply); + reply = NULL; + + if (changed) { + + if (!dbus_connection_send(connection, changed, NULL)) + goto oom; + + dbus_message_unref(changed); + } + + return DBUS_HANDLER_RESULT_HANDLED; + +oom: + if (reply) + dbus_message_unref(reply); + + if (changed) + dbus_message_unref(changed); + + dbus_error_free(&error); + + return DBUS_HANDLER_RESULT_NEED_MEMORY; +} + +static int connect_bus(DBusConnection **_bus) { + static const DBusObjectPathVTable hostname_vtable = { + .message_function = hostname_message_handler + }; + DBusError error; + DBusConnection *bus = NULL; + int r; + + assert(_bus); + + dbus_error_init(&error); + + bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error); + if (!bus) { + log_error("Failed to get system D-Bus connection: %s", bus_error_message(&error)); + r = -ECONNREFUSED; + goto fail; + } + + dbus_connection_set_exit_on_disconnect(bus, FALSE); + + if (!dbus_connection_register_object_path(bus, "/org/freedesktop/hostname1", &hostname_vtable, NULL) || + !dbus_connection_add_filter(bus, bus_exit_idle_filter, &remain_until, NULL)) { + log_error("Not enough memory"); + r = -ENOMEM; + goto fail; + } + + r = dbus_bus_request_name(bus, "org.freedesktop.hostname1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error); + if (dbus_error_is_set(&error)) { + log_error("Failed to register name on bus: %s", bus_error_message(&error)); + r = -EEXIST; + goto fail; + } + + if (r != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { + log_error("Failed to acquire name."); + r = -EEXIST; + goto fail; + } + + if (_bus) + *_bus = bus; + + return 0; + +fail: + dbus_connection_close(bus); + dbus_connection_unref(bus); + + dbus_error_free(&error); + + return r; +} + +int main(int argc, char *argv[]) { + int r; + DBusConnection *bus = NULL; + bool exiting = false; + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + umask(0022); + + if (argc == 2 && streq(argv[1], "--introspect")) { + fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE + "\n", stdout); + fputs(hostname_interface, stdout); + fputs("\n", stdout); + return 0; + } + + if (argc != 1) { + log_error("This program takes no arguments."); + r = -EINVAL; + goto finish; + } + + if (!check_nss()) + log_warning("Warning: nss-myhostname is not installed. Changing the local hostname might make it unresolveable. Please install nss-myhostname!"); + + r = read_data(); + if (r < 0) { + log_error("Failed to read hostname data: %s", strerror(-r)); + goto finish; + } + + r = connect_bus(&bus); + if (r < 0) + goto finish; + + remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC; + for (;;) { + + if (!dbus_connection_read_write_dispatch(bus, exiting ? -1 : (int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC))) + break; + + if (!exiting && remain_until < now(CLOCK_MONOTONIC)) { + exiting = true; + bus_async_unregister_and_exit(bus, "org.freedesktop.hostname1"); + } + } + + r = 0; + +finish: + free_data(); + + if (bus) { + dbus_connection_flush(bus); + dbus_connection_close(bus); + dbus_connection_unref(bus); + } + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/hostnamed.c b/src/hostnamed.c deleted file mode 100644 index f3b2c94173..0000000000 --- a/src/hostnamed.c +++ /dev/null @@ -1,623 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 General Public License as published by - the Free Software Foundation; either version 2 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 - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with systemd; If not, see . -***/ - -#include - -#include -#include -#include -#include - -#include "util.h" -#include "strv.h" -#include "dbus-common.h" -#include "polkit.h" -#include "def.h" -#include "virt.h" - -#define INTERFACE \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "\n" \ - INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - BUS_PEER_INTERFACE \ - "\n" - -#define INTERFACES_LIST \ - BUS_GENERIC_INTERFACES_LIST \ - "org.freedesktop.hostname1\0" - -const char hostname_interface[] _introspect_("hostname1") = INTERFACE; - -enum { - PROP_HOSTNAME, - PROP_STATIC_HOSTNAME, - PROP_PRETTY_HOSTNAME, - PROP_ICON_NAME, - _PROP_MAX -}; - -static char *data[_PROP_MAX] = { - NULL, - NULL, - NULL, - NULL -}; - -static usec_t remain_until = 0; - -static void free_data(void) { - int p; - - for (p = 0; p < _PROP_MAX; p++) { - free(data[p]); - data[p] = NULL; - } -} - -static int read_data(void) { - int r; - - free_data(); - - data[PROP_HOSTNAME] = gethostname_malloc(); - if (!data[PROP_HOSTNAME]) - return -ENOMEM; - - r = read_one_line_file("/etc/hostname", &data[PROP_STATIC_HOSTNAME]); - if (r < 0 && r != -ENOENT) - return r; - - r = parse_env_file("/etc/machine-info", NEWLINE, - "PRETTY_HOSTNAME", &data[PROP_PRETTY_HOSTNAME], - "ICON_NAME", &data[PROP_ICON_NAME], - NULL); - if (r < 0 && r != -ENOENT) - return r; - - return 0; -} - -static bool check_nss(void) { - - void *dl; - - if ((dl = dlopen("libnss_myhostname.so.2", RTLD_LAZY))) { - dlclose(dl); - return true; - } - - return false; -} - -static const char* fallback_icon_name(void) { - -#if defined(__i386__) || defined(__x86_64__) - int r; - char *type; - unsigned t; -#endif - - if (detect_virtualization(NULL) > 0) - return "computer-vm"; - -#if defined(__i386__) || defined(__x86_64__) - r = read_one_line_file("/sys/class/dmi/id/chassis_type", &type); - if (r < 0) - return NULL; - - r = safe_atou(type, &t); - free(type); - - if (r < 0) - return NULL; - - /* We only list the really obvious cases here. The DMI data is - unreliable enough, so let's not do any additional guesswork - on top of that. - - See the SMBIOS Specification 2.7.1 section 7.4.1 for - details about the values listed here: - - http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.1.pdf - */ - - switch (t) { - - case 0x3: - case 0x4: - case 0x6: - case 0x7: - return "computer-desktop"; - - case 0x9: - case 0xA: - case 0xE: - return "computer-laptop"; - - case 0x11: - case 0x1C: - return "computer-server"; - } - -#endif - return NULL; -} - -static int write_data_hostname(void) { - const char *hn; - - if (isempty(data[PROP_HOSTNAME])) - hn = "localhost"; - else - hn = data[PROP_HOSTNAME]; - - if (sethostname(hn, strlen(hn)) < 0) - return -errno; - - return 0; -} - -static int write_data_static_hostname(void) { - - if (isempty(data[PROP_STATIC_HOSTNAME])) { - - if (unlink("/etc/hostname") < 0) - return errno == ENOENT ? 0 : -errno; - - return 0; - } - - return write_one_line_file_atomic("/etc/hostname", data[PROP_STATIC_HOSTNAME]); -} - -static int write_data_other(void) { - - static const char * const name[_PROP_MAX] = { - [PROP_PRETTY_HOSTNAME] = "PRETTY_HOSTNAME", - [PROP_ICON_NAME] = "ICON_NAME" - }; - - char **l = NULL; - int r, p; - - r = load_env_file("/etc/machine-info", &l); - if (r < 0 && r != -ENOENT) - return r; - - for (p = 2; p < _PROP_MAX; p++) { - char *t, **u; - - assert(name[p]); - - if (isempty(data[p])) { - strv_env_unset(l, name[p]); - continue; - } - - if (asprintf(&t, "%s=%s", name[p], strempty(data[p])) < 0) { - strv_free(l); - return -ENOMEM; - } - - u = strv_env_set(l, t); - free(t); - strv_free(l); - - if (!u) - return -ENOMEM; - l = u; - } - - if (strv_isempty(l)) { - - if (unlink("/etc/machine-info") < 0) - return errno == ENOENT ? 0 : -errno; - - return 0; - } - - r = write_env_file("/etc/machine-info", l); - strv_free(l); - - return r; -} - -static int bus_hostname_append_icon_name(DBusMessageIter *i, const char *property, void *userdata) { - const char *name; - - assert(i); - assert(property); - - if (isempty(data[PROP_ICON_NAME])) - name = fallback_icon_name(); - else - name = data[PROP_ICON_NAME]; - - return bus_property_append_string(i, property, (void*) name); -} - -static DBusHandlerResult hostname_message_handler( - DBusConnection *connection, - DBusMessage *message, - void *userdata) { - - const BusProperty properties[] = { - { "org.freedesktop.hostname1", "Hostname", bus_property_append_string, "s", data[PROP_HOSTNAME]}, - { "org.freedesktop.hostname1", "StaticHostname", bus_property_append_string, "s", data[PROP_STATIC_HOSTNAME]}, - { "org.freedesktop.hostname1", "PrettyHostname", bus_property_append_string, "s", data[PROP_PRETTY_HOSTNAME]}, - { "org.freedesktop.hostname1", "IconName", bus_hostname_append_icon_name, "s", data[PROP_ICON_NAME]}, - { NULL, NULL, NULL, NULL, NULL } - }; - - DBusMessage *reply = NULL, *changed = NULL; - DBusError error; - int r; - - assert(connection); - assert(message); - - dbus_error_init(&error); - - if (dbus_message_is_method_call(message, "org.freedesktop.hostname1", "SetHostname")) { - const char *name; - dbus_bool_t interactive; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_BOOLEAN, &interactive, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (isempty(name)) - name = data[PROP_STATIC_HOSTNAME]; - - if (isempty(name)) - name = "localhost"; - - if (!hostname_is_valid(name)) - return bus_send_error_reply(connection, message, NULL, -EINVAL); - - if (!streq_ptr(name, data[PROP_HOSTNAME])) { - char *h; - - r = verify_polkit(connection, message, "org.freedesktop.hostname1.set-hostname", interactive, &error); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - h = strdup(name); - if (!h) - goto oom; - - free(data[PROP_HOSTNAME]); - data[PROP_HOSTNAME] = h; - - r = write_data_hostname(); - if (r < 0) { - log_error("Failed to set host name: %s", strerror(-r)); - return bus_send_error_reply(connection, message, NULL, r); - } - - log_info("Changed host name to '%s'", strempty(data[PROP_HOSTNAME])); - - changed = bus_properties_changed_new( - "/org/freedesktop/hostname1", - "org.freedesktop.hostname1", - "Hostname\0"); - if (!changed) - goto oom; - } - - } else if (dbus_message_is_method_call(message, "org.freedesktop.hostname1", "SetStaticHostname")) { - const char *name; - dbus_bool_t interactive; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_BOOLEAN, &interactive, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (isempty(name)) - name = NULL; - - if (!streq_ptr(name, data[PROP_STATIC_HOSTNAME])) { - - r = verify_polkit(connection, message, "org.freedesktop.hostname1.set-static-hostname", interactive, &error); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - if (isempty(name)) { - free(data[PROP_STATIC_HOSTNAME]); - data[PROP_STATIC_HOSTNAME] = NULL; - } else { - char *h; - - if (!hostname_is_valid(name)) - return bus_send_error_reply(connection, message, NULL, -EINVAL); - - h = strdup(name); - if (!h) - goto oom; - - free(data[PROP_STATIC_HOSTNAME]); - data[PROP_STATIC_HOSTNAME] = h; - } - - r = write_data_static_hostname(); - if (r < 0) { - log_error("Failed to write static host name: %s", strerror(-r)); - return bus_send_error_reply(connection, message, NULL, r); - } - - log_info("Changed static host name to '%s'", strempty(data[PROP_STATIC_HOSTNAME])); - - changed = bus_properties_changed_new( - "/org/freedesktop/hostname1", - "org.freedesktop.hostname1", - "StaticHostname\0"); - if (!changed) - goto oom; - } - - } else if (dbus_message_is_method_call(message, "org.freedesktop.hostname1", "SetPrettyHostname") || - dbus_message_is_method_call(message, "org.freedesktop.hostname1", "SetIconName")) { - - const char *name; - dbus_bool_t interactive; - int k; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_BOOLEAN, &interactive, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (isempty(name)) - name = NULL; - - k = streq(dbus_message_get_member(message), "SetPrettyHostname") ? PROP_PRETTY_HOSTNAME : PROP_ICON_NAME; - - if (!streq_ptr(name, data[k])) { - - /* Since the pretty hostname should always be - * changed at the same time as the static one, - * use the same policy action for both... */ - - r = verify_polkit(connection, message, k == PROP_PRETTY_HOSTNAME ? - "org.freedesktop.hostname1.set-static-hostname" : - "org.freedesktop.hostname1.set-machine-info", interactive, &error); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - if (isempty(name)) { - free(data[k]); - data[k] = NULL; - } else { - char *h; - - h = strdup(name); - if (!h) - goto oom; - - free(data[k]); - data[k] = h; - } - - r = write_data_other(); - if (r < 0) { - log_error("Failed to write machine info: %s", strerror(-r)); - return bus_send_error_reply(connection, message, NULL, r); - } - - log_info("Changed %s to '%s'", k == PROP_PRETTY_HOSTNAME ? "pretty host name" : "icon name", strempty(data[k])); - - changed = bus_properties_changed_new( - "/org/freedesktop/hostname1", - "org.freedesktop.hostname1", - k == PROP_PRETTY_HOSTNAME ? "PrettyHostname\0" : "IconName\0"); - if (!changed) - goto oom; - } - - } else - return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties); - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - if (!dbus_connection_send(connection, reply, NULL)) - goto oom; - - dbus_message_unref(reply); - reply = NULL; - - if (changed) { - - if (!dbus_connection_send(connection, changed, NULL)) - goto oom; - - dbus_message_unref(changed); - } - - return DBUS_HANDLER_RESULT_HANDLED; - -oom: - if (reply) - dbus_message_unref(reply); - - if (changed) - dbus_message_unref(changed); - - dbus_error_free(&error); - - return DBUS_HANDLER_RESULT_NEED_MEMORY; -} - -static int connect_bus(DBusConnection **_bus) { - static const DBusObjectPathVTable hostname_vtable = { - .message_function = hostname_message_handler - }; - DBusError error; - DBusConnection *bus = NULL; - int r; - - assert(_bus); - - dbus_error_init(&error); - - bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error); - if (!bus) { - log_error("Failed to get system D-Bus connection: %s", bus_error_message(&error)); - r = -ECONNREFUSED; - goto fail; - } - - dbus_connection_set_exit_on_disconnect(bus, FALSE); - - if (!dbus_connection_register_object_path(bus, "/org/freedesktop/hostname1", &hostname_vtable, NULL) || - !dbus_connection_add_filter(bus, bus_exit_idle_filter, &remain_until, NULL)) { - log_error("Not enough memory"); - r = -ENOMEM; - goto fail; - } - - r = dbus_bus_request_name(bus, "org.freedesktop.hostname1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error); - if (dbus_error_is_set(&error)) { - log_error("Failed to register name on bus: %s", bus_error_message(&error)); - r = -EEXIST; - goto fail; - } - - if (r != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { - log_error("Failed to acquire name."); - r = -EEXIST; - goto fail; - } - - if (_bus) - *_bus = bus; - - return 0; - -fail: - dbus_connection_close(bus); - dbus_connection_unref(bus); - - dbus_error_free(&error); - - return r; -} - -int main(int argc, char *argv[]) { - int r; - DBusConnection *bus = NULL; - bool exiting = false; - - log_set_target(LOG_TARGET_AUTO); - log_parse_environment(); - log_open(); - - umask(0022); - - if (argc == 2 && streq(argv[1], "--introspect")) { - fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE - "\n", stdout); - fputs(hostname_interface, stdout); - fputs("\n", stdout); - return 0; - } - - if (argc != 1) { - log_error("This program takes no arguments."); - r = -EINVAL; - goto finish; - } - - if (!check_nss()) - log_warning("Warning: nss-myhostname is not installed. Changing the local hostname might make it unresolveable. Please install nss-myhostname!"); - - r = read_data(); - if (r < 0) { - log_error("Failed to read hostname data: %s", strerror(-r)); - goto finish; - } - - r = connect_bus(&bus); - if (r < 0) - goto finish; - - remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC; - for (;;) { - - if (!dbus_connection_read_write_dispatch(bus, exiting ? -1 : (int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC))) - break; - - if (!exiting && remain_until < now(CLOCK_MONOTONIC)) { - exiting = true; - bus_async_unregister_and_exit(bus, "org.freedesktop.hostname1"); - } - } - - r = 0; - -finish: - free_data(); - - if (bus) { - dbus_connection_flush(bus); - dbus_connection_close(bus); - dbus_connection_unref(bus); - } - - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -} -- cgit v1.2.3