diff options
Diffstat (limited to 'src/hostnamed.c')
-rw-r--r-- | src/hostnamed.c | 388 |
1 files changed, 388 insertions, 0 deletions
diff --git a/src/hostnamed.c b/src/hostnamed.c new file mode 100644 index 0000000..f0c2357 --- /dev/null +++ b/src/hostnamed.c @@ -0,0 +1,388 @@ +/* + Copyright 2012 Alexandre Rostovtsev + + This program 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. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <dbus/dbus-protocol.h> +#include <glib.h> +#include <gio/gio.h> +#include <polkit/polkit.h> + +#include "hostnamed.h" +#include "hostnamed-generated.h" +#include "bus-utils.h" +#include "shell-utils.h" + +#include "config.h" + +#define QUOTE(macro) #macro +#define STR(macro) QUOTE(macro) + +guint bus_id = 0; +gboolean read_only = FALSE; + +static OpenrcSettingsdHostnamedHostname1 *hostname1 = NULL; + +static gchar hostname[HOST_NAME_MAX + 1]; +static gchar *static_hostname = NULL; +static gchar *pretty_hostname = NULL; +static gchar *icon_name = NULL; + +static gboolean +hostname_is_valid (const gchar *name) +{ + if (name == NULL) + return FALSE; + + return g_regex_match_simple ("^[a-zA-Z0-9_.-]{1," STR(HOST_NAME_MAX) "}$", + name, G_REGEX_MULTILINE, 0); +} + +static void +guess_icon_name () +{ + /* TODO: detect virtualization by reading rc_sys */ + +#if defined(__i386__) || defined(__x86_64__) + /* + Taken with a few minor changes from systemd's hostnamed + + 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 + */ + gchar *contents; + + if (g_file_get_contents ("/sys/class/dmi/id/chassis_type", &contents, NULL, NULL)) { + switch (g_ascii_strtoull (contents, NULL, 10)) { + case 0x3: + case 0x4: + case 0x5: + case 0x6: + case 0x7: + icon_name = g_strdup ("computer-desktop"); + return; + case 0x9: + case 0xA: + case 0xE: + icon_name = g_strdup ("computer-laptop"); + return; + case 0x11: + case 0x17: + case 0x1C: + case 0x1D: + icon_name = g_strdup ("computer-server"); + return; + } + } +#endif + icon_name = g_strdup ("computer"); +} + +static gboolean +on_handle_set_hostname (OpenrcSettingsdHostnamedHostname1 *hostname1, + GDBusMethodInvocation *invocation, + const gchar *name, + const gboolean user_interaction, + gpointer user_data) +{ + GError *err = NULL; + + if (read_only) { + g_dbus_method_invocation_return_dbus_error (invocation, + DBUS_ERROR_NOT_SUPPORTED, + "openrc-settingsd hostnamed is in read-only mode"); + goto end; + } + + if (!check_polkit (g_dbus_method_invocation_get_sender (invocation), "org.freedesktop.hostname1.set-hostname", user_interaction, &err)) { + g_dbus_method_invocation_return_gerror (invocation, err); + goto end; + } + + /* Don't allow an empty or invalid hostname */ + if (!hostname_is_valid (name)) { + name = hostname; + if (!hostname_is_valid (name)) + name = "localhost"; + } + if (sethostname (name, strlen(name))) { + int errsv = errno; + g_dbus_method_invocation_return_dbus_error (invocation, + DBUS_ERROR_FAILED, + strerror (errsv)); + } + g_strlcpy (hostname, name, HOST_NAME_MAX + 1); + openrc_settingsd_hostnamed_hostname1_complete_set_hostname (hostname1, invocation); + openrc_settingsd_hostnamed_hostname1_set_hostname (hostname1, hostname); + + end: + return TRUE; +} + +static gboolean +on_handle_set_static_hostname (OpenrcSettingsdHostnamedHostname1 *hostname1, + GDBusMethodInvocation *invocation, + const gchar *name, + const gboolean user_interaction, + gpointer user_data) +{ + ShellUtilsTrivial *confd_file = NULL; + GError *err = NULL; + + if (read_only) { + g_dbus_method_invocation_return_dbus_error (invocation, + DBUS_ERROR_NOT_SUPPORTED, + "openrc-settingsd hostnamed is in read-only mode"); + goto end; + } + + if (!check_polkit (g_dbus_method_invocation_get_sender (invocation), "org.freedesktop.hostname1.set-static-hostname", user_interaction, &err)) { + g_dbus_method_invocation_return_gerror (invocation, err); + goto end; + } + + /* Don't allow an empty or invalid hostname */ + if (!hostname_is_valid (name)) + name = "localhost"; + + confd_file = shell_utils_trivial_new (SYSCONFDIR "/conf.d/hostname", &err); + if (confd_file == NULL) { + g_dbus_method_invocation_return_gerror (invocation, err); + goto end; + } + + if (!shell_utils_trivial_set_variable (confd_file, "hostname", name, FALSE) && + !shell_utils_trivial_set_variable (confd_file, "HOSTNAME", name, FALSE) && + !shell_utils_trivial_set_variable (confd_file, "hostname", name, TRUE)) + { + g_dbus_method_invocation_return_dbus_error (invocation, + DBUS_ERROR_FAILED, + "Failed to set static hostname in " SYSCONFDIR "/conf.d/hostname"); + goto end; + } + + if (!shell_utils_trivial_save (confd_file, &err)) { + g_dbus_method_invocation_return_gerror (invocation, err); + goto end; + } + + g_free (static_hostname); + static_hostname = g_strdup (name); + openrc_settingsd_hostnamed_hostname1_complete_set_static_hostname (hostname1, invocation); + openrc_settingsd_hostnamed_hostname1_set_static_hostname (hostname1, static_hostname); + + end: + shell_utils_trivial_free (confd_file); + if (err != NULL) + g_error_free (err); + + return TRUE; /* Always return TRUE to indicate signal has been handled */ +} + +static gboolean +on_handle_set_machine_info (OpenrcSettingsdHostnamedHostname1 *hostname1, + GDBusMethodInvocation *invocation, + const gchar *name, + const gboolean user_interaction, + gpointer user_data) +{ + ShellUtilsTrivial *confd_file = NULL; + GError *err = NULL; + gboolean is_pretty_hostname = GPOINTER_TO_INT(user_data); + + if (read_only) { + g_dbus_method_invocation_return_dbus_error (invocation, + DBUS_ERROR_NOT_SUPPORTED, + "openrc-settingsd hostnamed is in read-only mode"); + goto end; + } + + if (!check_polkit (g_dbus_method_invocation_get_sender (invocation), "org.freedesktop.hostname1.set-machine-info", user_interaction, &err)) { + g_dbus_method_invocation_return_gerror (invocation, err); + goto end; + } + + /* Don't allow a null pretty hostname */ + if (name == NULL) + name = ""; + + confd_file = shell_utils_trivial_new (SYSCONFDIR "/machine-info", &err); + if (confd_file == NULL) { + g_dbus_method_invocation_return_gerror (invocation, err); + goto end; + } + + if ((is_pretty_hostname && !shell_utils_trivial_set_variable (confd_file, "PRETTY_HOSTNAME", name, TRUE)) || + (!is_pretty_hostname && !shell_utils_trivial_set_variable (confd_file, "ICON_NAME", name, TRUE))) + { + g_dbus_method_invocation_return_dbus_error (invocation, + DBUS_ERROR_FAILED, + "Failed to value in " SYSCONFDIR "/machine-info"); + goto end; + } + + if (!shell_utils_trivial_save (confd_file, &err)) { + g_dbus_method_invocation_return_gerror (invocation, err); + goto end; + } + + if (is_pretty_hostname) { + g_free (pretty_hostname); + pretty_hostname = g_strdup (name); + openrc_settingsd_hostnamed_hostname1_complete_set_pretty_hostname (hostname1, invocation); + openrc_settingsd_hostnamed_hostname1_set_pretty_hostname (hostname1, pretty_hostname); + } else { + g_free (icon_name); + icon_name = g_strdup (name); + openrc_settingsd_hostnamed_hostname1_complete_set_icon_name (hostname1, invocation); + openrc_settingsd_hostnamed_hostname1_set_icon_name (hostname1, icon_name); + } + + end: + shell_utils_trivial_free (confd_file); + if (err != NULL) + g_error_free (err); + + return TRUE; /* Always return TRUE to indicate signal has been handled */ +} + +static void +on_bus_acquired (GDBusConnection *connection, + const gchar *bus_name, + gpointer user_data) +{ + gchar *name; + GError *err = NULL; + +#ifdef OPENRC_SETTINGSD_DEBUG + g_debug ("Acquired a message bus connection"); +#endif + + hostname1 = openrc_settingsd_hostnamed_hostname1_skeleton_new (); + + openrc_settingsd_hostnamed_hostname1_set_hostname (hostname1, hostname); + openrc_settingsd_hostnamed_hostname1_set_static_hostname (hostname1, static_hostname); + openrc_settingsd_hostnamed_hostname1_set_pretty_hostname (hostname1, pretty_hostname); + openrc_settingsd_hostnamed_hostname1_set_icon_name (hostname1, icon_name); + + g_signal_connect (hostname1, "handle-set-hostname", G_CALLBACK (on_handle_set_hostname), NULL); + g_signal_connect (hostname1, "handle-set-static-hostname", G_CALLBACK (on_handle_set_static_hostname), NULL); + g_signal_connect (hostname1, "handle-set-pretty-hostname", G_CALLBACK (on_handle_set_machine_info), GINT_TO_POINTER(TRUE)); + g_signal_connect (hostname1, "handle-set-icon-name", G_CALLBACK (on_handle_set_machine_info), GINT_TO_POINTER(FALSE)); + + if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (hostname1), + connection, + "/org/freedesktop/hostname1", + &err)) { + if (err != NULL) { + g_printerr ("Failed to export interface on /org/freedesktop/hostname1: %s\n", err->message); + g_error_free (err); + } + } +} + +static void +on_name_acquired (GDBusConnection *connection, + const gchar *bus_name, + gpointer user_data) +{ +#ifdef OPENRC_SETTINGSD_DEBUG + g_debug ("Acquired the name %s", bus_name); +#endif +} + +static void +on_name_lost (GDBusConnection *connection, + const gchar *bus_name, + gpointer user_data) +{ + if (connection == NULL) + g_printerr ("Failed to acquire a dbus connection\n"); + else + g_printerr ("Failed to acquire dbus name %s\n", bus_name); + exit(-1); +} + +/* Public functions */ + +void +hostnamed_init (gboolean _read_only) +{ + GError *err = NULL; + + memset (hostname, 0, HOST_NAME_MAX + 1); + if (gethostname (hostname, HOST_NAME_MAX)) { + perror (NULL); + hostname[0] = 0; + } + + static_hostname = shell_utils_source_var (SYSCONFDIR "/conf.d/hostname", "${hostname-${HOSTNAME-localhost}}", &err); + if (err != NULL) { + g_debug ("%s", err->message); + g_error_free (err); + err = NULL; + } + pretty_hostname = shell_utils_source_var (SYSCONFDIR "/machine-info", "${PRETTY_HOSTNAME}", &err); + if (pretty_hostname == NULL) + pretty_hostname = g_strdup (""); + if (err != NULL) { + g_debug ("%s", err->message); + g_error_free (err); + err = NULL; + } + icon_name = shell_utils_source_var (SYSCONFDIR "/machine-info", "${ICON_NAME}", &err); + if (icon_name == NULL) + icon_name = g_strdup (""); + if (err != NULL) { + g_debug ("%s", err->message); + g_error_free (err); + err = NULL; + } + + if (icon_name == NULL || strlen (icon_name) == 0) + guess_icon_name (); + + read_only = _read_only; + + bus_id = g_bus_own_name (G_BUS_TYPE_SYSTEM, + "org.freedesktop.hostname1", + G_BUS_NAME_OWNER_FLAGS_NONE, + on_bus_acquired, + on_name_acquired, + on_name_lost, + NULL, + NULL); +} + +void +hostnamed_destroy (void) +{ + g_bus_unown_name (bus_id); + bus_id = 0; + read_only = FALSE; + memset (hostname, 0, HOST_NAME_MAX + 1); + g_free (static_hostname); + g_free (pretty_hostname); + g_free (icon_name); +}
\ No newline at end of file |