merge: branch 'bg/hostname-bgo740409'

- move all hostname-related functions from plugins to the core
- allow to specify the method used to load and store the hostname at
  build time
- add hostnamed support
- remove unused setting plugins

https://bugzilla.gnome.org/show_bug.cgi?id=740409
This commit is contained in:
Beniamino Galvani 2015-06-12 16:06:12 +02:00
commit 135999c2ec
30 changed files with 424 additions and 2493 deletions

View file

@ -40,7 +40,6 @@ DISTCHECK_CONFIGURE_FLAGS = \
--with-udev-dir=$$dc_install_base/lib/udev \
--with-wext=no \
--enable-ifcfg-rh \
--enable-ifcfg-suse \
--enable-ifupdown \
--enable-ifnet

View file

@ -85,7 +85,7 @@ AC_SUBST(nmrundir, "$runstatedir/$PACKAGE", [NetworkManager runtime state direct
# Alternative configuration plugins
AC_ARG_ENABLE(config-plugin-ibft, AS_HELP_STRING([--enable-config-plugin-ibft], [enable ibft configuration plugin]))
AC_ARG_ENABLE(ifcfg-rh, AS_HELP_STRING([--enable-ifcfg-rh], [enable ifcfg-rh configuration plugin (Fedora/RHEL)]))
AC_ARG_ENABLE(ifcfg-suse, AS_HELP_STRING([--enable-ifcfg-suse], [enable ifcfg-suse configuration plugin (SUSE)]))
AC_ARG_ENABLE(ifcfg-suse, AS_HELP_STRING([--enable-ifcfg-suse], [enable ifcfg-suse configuration plugin (SUSE) (deprecated)]))
AC_ARG_ENABLE(ifupdown, AS_HELP_STRING([--enable-ifupdown], [enable ifupdown configuration plugin (Debian/Ubuntu)]))
AC_ARG_ENABLE(ifnet, AS_HELP_STRING([--enable-ifnet], [enable ifnet configuration plugin (Gentoo)]))
# Default alternative plugins by distribution
@ -105,7 +105,6 @@ AS_IF([test -z "$enable_config_plugin_ibft"], enable_config_plugin_ibft="yes")
# Create automake conditionals
AM_CONDITIONAL(CONFIG_PLUGIN_IBFT, test "$enable_config_plugin_ibft" = "yes")
AM_CONDITIONAL(CONFIG_PLUGIN_IFCFG_RH, test "$enable_ifcfg_rh" = "yes")
AM_CONDITIONAL(CONFIG_PLUGIN_IFCFG_SUSE, test "$enable_ifcfg_suse" = "yes")
AM_CONDITIONAL(CONFIG_PLUGIN_IFUPDOWN, test "$enable_ifupdown" = "yes")
AM_CONDITIONAL(CONFIG_PLUGIN_IFNET, test "$enable_ifnet" = "yes")
@ -113,12 +112,18 @@ AC_ARG_WITH(config-plugins-default, AS_HELP_STRING([--with-config-plugins-defaul
if test -z "$config_plugins_default" -o "$config_plugins_default" = no; then
config_plugins_default=''
test "$enable_ifcfg_rh" = "yes" && config_plugins_default="$config_plugins_default,ifcfg-rh"
test "$enable_ifcfg_suse" = "yes" && config_plugins_default="$config_plugins_default,ifcfg-suse"
test "$enable_ifupdown" = "yes" && config_plugins_default="$config_plugins_default,ifupdown"
test "$enable_ifnet" = "yes" && config_plugins_default="$config_plugins_default,ifnet"
test "$enable_config_plugin_ibft" = "yes" && config_plugins_default="$config_plugins_default,ibft"
config_plugins_default="${config_plugins_default#,}"
fi
test "$enable_ifcfg_rh" = "yes" && distro_plugins="$distro_plugins,ifcfg-rh"
test "$enable_ifcfg_suse" = "yes" && distro_plugins="$distro_plugins,ifcfg-suse"
test "$enable_ifupdown" = "yes" && distro_plugins="$distro_plugins,ifupdown"
test "$enable_ifnet" = "yes" && distro_plugins="$distro_plugins,ifnet"
distro_plugins="${distro_plugins#,}"
AC_DEFINE_UNQUOTED(CONFIG_PLUGINS_DEFAULT, "$config_plugins_default", [Default configuration option for main.plugins setting])
if test "$enable_ifcfg_rh" = "yes"; then
@ -347,6 +352,24 @@ fi
PKG_CHECK_MODULES(SYSTEMD_200, [systemd >= 200], [have_systemd_200=yes],[have_systemd_200=no])
AM_CONDITIONAL(HAVE_SYSTEMD_200, test "${have_systemd_200}" = "yes")
# Hostname persist mode
AC_ARG_WITH(hostname-persist, AS_HELP_STRING([--with-hostname-persist=default|suse|gentoo],
[Hostname persist method]))
AS_IF([test "$with_hostname_persist" = "suse"], hostname_persist=suse)
AS_IF([test "$with_hostname_persist" = "gentoo"], hostname_persist=gentoo)
AS_IF([test "$with_hostname_persist" = "default"], hostname_persist=default)
# if the method was not explicitly set, try to guess it from the enabled plugins
AS_IF([test -z "$hostname_persist" -a "$distro_plugins" = "ifcfg-suse"], hostname_persist=suse)
AS_IF([test -z "$hostname_persist" -a "$distro_plugins" = "ifnet"], hostname_persist=gentoo)
AS_IF([test -z "$hostname_persist"], hostname_persist=default)
if test "$hostname_persist" = suse; then
AC_DEFINE(HOSTNAME_PERSIST_SUSE, 1, [Enable SuSE hostname persist method])
elif test "$hostname_persist" = gentoo; then
AC_DEFINE(HOSTNAME_PERSIST_GENTOO, 1, [Enable Gentoo hostname persist method])
fi
# Session tracking support
AC_ARG_WITH(systemd-logind, AS_HELP_STRING([--with-systemd-logind=yes|no],
[Support systemd session tracking]))
@ -954,11 +977,9 @@ src/settings/plugins/ifcfg-rh/tests/Makefile
src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile
src/settings/plugins/ibft/Makefile
src/settings/plugins/ibft/tests/Makefile
src/settings/plugins/ifcfg-suse/Makefile
src/settings/plugins/keyfile/Makefile
src/settings/plugins/keyfile/tests/Makefile
src/settings/plugins/keyfile/tests/keyfiles/Makefile
src/settings/plugins/example/Makefile
src/platform/Makefile
src/platform/tests/Makefile
src/rdisc/Makefile
@ -1063,6 +1084,7 @@ else
fi
echo " polkit agent: ${enable_polkit_agent}"
echo " selinux: $have_selinux"
echo " hostname persist: ${hostname_persist}"
echo
echo "Features:"
@ -1078,7 +1100,6 @@ echo
echo "Configuration plugins (main.plugins=${config_plugins_default})"
echo " ibft: ${enable_config_plugin_ibft}"
echo " ifcfg-rh: ${enable_ifcfg_rh}"
echo " ifcfg-suse: ${enable_ifcfg_suse}"
echo " ifupdown: ${enable_ifupdown}"
echo " ifnet: ${enable_ifnet}"
echo

View file

@ -313,7 +313,10 @@ no-auto-default=*
<variablelist>
<varlistentry>
<term><varname>hostname</varname></term>
<listitem><para>Set a persistent hostname.</para></listitem>
<listitem><para>This key is deprecated and has no effect
since the hostname is now stored in /etc/hostname or other
system configuration files according to build options.
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>unmanaged-devices</varname></term>
@ -619,12 +622,9 @@ ipv6.ip6-privacy=1
<term><varname>ifcfg-suse</varname></term>
<listitem>
<para>
This plugin is only provided for simple backward
compatibility with SUSE and OpenSUSE configuration. Most
setups should be using the <literal>keyfile</literal>
plugin instead. The <literal>ifcfg-suse</literal> plugin
supports reading Ethernet and Wi-Fi connections, but does
not support saving any connection types.
This plugin is deprecated and its selection has no effect.
The <literal>keyfile</literal> plugin should be used
instead.
</para>
</listitem>
</varlistentry>

View file

@ -406,6 +406,7 @@ AM_CPPFLAGS += \
$(LIBNL_CFLAGS) \
$(LIBNDP_CFLAGS) \
$(LIBSOUP_CFLAGS) \
$(SELINUX_CFLAGS) \
$(SYSTEMD_LOGIN_CFLAGS) \
$(SYSTEMD_NM_CFLAGS) \
\
@ -450,6 +451,10 @@ if WITH_LIBSOUP
libNetworkManager_la_LIBADD += $(LIBSOUP_LIBS)
endif
if HAVE_SELINUX
libNetworkManager_la_LIBADD += $(SELINUX_LIBS)
endif
NetworkManager_LDFLAGS = -rdynamic
######################

View file

@ -34,6 +34,10 @@
#include <dbus/dbus.h>
#include <dbus/dbus-glib-lowlevel.h>
#if HAVE_SELINUX
#include <selinux/selinux.h>
#endif
#include "gsystem-local-alloc.h"
#include <nm-dbus-interface.h>
#include <nm-connection.h>
@ -94,6 +98,24 @@ EXPORT(nm_settings_connection_replace_settings)
EXPORT(nm_settings_connection_replace_and_commit)
/* END LINKER CRACKROCK */
#define HOSTNAMED_SERVICE_NAME "org.freedesktop.hostname1"
#define HOSTNAMED_SERVICE_PATH "/org/freedesktop/hostname1"
#define HOSTNAMED_SERVICE_INTERFACE "org.freedesktop.hostname1"
#define HOSTNAME_FILE_DEFAULT "/etc/hostname"
#define HOSTNAME_FILE_SUSE "/etc/HOSTNAME"
#define HOSTNAME_FILE_GENTOO "/etc/conf.d/hostname"
#define IFCFG_DIR SYSCONFDIR "/sysconfig/network"
#define CONF_DHCP IFCFG_DIR "/dhcp"
#if defined(HOSTNAME_PERSIST_SUSE)
#define HOSTNAME_FILE HOSTNAME_FILE_SUSE
#elif defined(HOSTNAME_PERSIST_GENTOO)
#define HOSTNAME_FILE HOSTNAME_FILE_GENTOO
#else
#define HOSTNAME_FILE HOSTNAME_FILE_DEFAULT
#endif
static void claim_connection (NMSettings *self,
NMSettingsConnection *connection);
@ -152,6 +174,16 @@ typedef struct {
GSList *get_connections_cache;
gboolean startup_complete;
struct {
char *value;
char *file;
GFileMonitor *monitor;
GFileMonitor *dhcp_monitor;
guint monitor_id;
guint dhcp_monitor_id;
GDBusProxy *hostnamed_proxy;
} hostname;
} NMSettingsPrivate;
#define NM_SETTINGS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTINGS, NMSettingsPrivate))
@ -497,7 +529,7 @@ get_plugin (NMSettings *self, guint32 capability)
g_return_val_if_fail (self != NULL, NULL);
/* Do any of the plugins support setting the hostname? */
/* Do any of the plugins support the given capability? */
for (iter = priv->plugins; iter; iter = iter->next) {
NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE;
@ -509,30 +541,94 @@ get_plugin (NMSettings *self, guint32 capability)
return NULL;
}
#if defined(HOSTNAME_PERSIST_GENTOO)
static gchar *
read_hostname_gentoo (const char *path)
{
gchar *contents = NULL, *result = NULL, *tmp;
gchar **all_lines = NULL;
guint line_num, i;
if (!g_file_get_contents (path, &contents, NULL, NULL))
return NULL;
all_lines = g_strsplit (contents, "\n", 0);
line_num = g_strv_length (all_lines);
for (i = 0; i < line_num; i++) {
g_strstrip (all_lines[i]);
if (all_lines[i][0] == '#' || all_lines[i][0] == '\0')
continue;
if (g_str_has_prefix (all_lines[i], "hostname=")) {
tmp = &all_lines[i][STRLEN ("hostname=")];
result = g_shell_unquote (tmp, NULL);
break;
}
}
g_strfreev (all_lines);
g_free (contents);
return result;
}
#endif
#if defined(HOSTNAME_PERSIST_SUSE)
static gboolean
hostname_is_dynamic (void)
{
GIOChannel *channel;
char *str = NULL;
gboolean dynamic = FALSE;
channel = g_io_channel_new_file (CONF_DHCP, "r", NULL);
if (!channel)
return dynamic;
while (g_io_channel_read_line (channel, &str, NULL, NULL, NULL) != G_IO_STATUS_EOF) {
if (str) {
g_strstrip (str);
if (g_str_has_prefix (str, "DHCLIENT_SET_HOSTNAME="))
dynamic = strcmp (&str[STRLEN ("DHCLIENT_SET_HOSTNAME=")], "\"yes\"") == 0;
g_free (str);
}
}
g_io_channel_shutdown (channel, FALSE, NULL);
g_io_channel_unref (channel);
return dynamic;
}
#endif
/* Returns an allocated string which the caller owns and must eventually free */
char *
nm_settings_get_hostname (NMSettings *self)
{
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
GSList *iter;
char *hostname = NULL;
/* Hostname returned is the hostname returned from the first plugin
* that provides one.
*/
for (iter = priv->plugins; iter; iter = iter->next) {
NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE;
g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, &caps, NULL);
if (caps & NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME) {
g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME, &hostname, NULL);
if (hostname && strlen (hostname))
return hostname;
g_free (hostname);
}
if (priv->hostname.hostnamed_proxy) {
hostname = g_strdup (priv->hostname.value);
goto out;
}
return NULL;
#if defined(HOSTNAME_PERSIST_GENTOO)
hostname = read_hostname_gentoo (priv->hostname.file);
#else
#if defined(HOSTNAME_PERSIST_SUSE)
if (priv->hostname.dhcp_monitor_id && hostname_is_dynamic ())
return NULL;
#endif
if (g_file_get_contents (priv->hostname.file, &hostname, NULL, NULL))
g_strchomp (hostname);
#endif /* HOSTNAME_PERSIST_GENTOO */
out:
if (hostname && !hostname[0]) {
g_free (hostname);
hostname = NULL;
}
return hostname;
}
static gboolean
@ -595,14 +691,6 @@ unrecognized_specs_changed (NMSystemConfigInterface *config,
nm_system_config_interface_get_unrecognized_specs);
}
static void
hostname_changed (NMSystemConfigInterface *config,
GParamSpec *pspec,
gpointer user_data)
{
g_object_notify (G_OBJECT (user_data), NM_SETTINGS_HOSTNAME);
}
static void
add_plugin (NMSettings *self, NMSystemConfigInterface *plugin)
{
@ -616,9 +704,6 @@ add_plugin (NMSettings *self, NMSystemConfigInterface *plugin)
priv = NM_SETTINGS_GET_PRIVATE (self);
priv->plugins = g_slist_append (priv->plugins, g_object_ref (plugin));
g_signal_connect (plugin, "notify::"NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME, G_CALLBACK (hostname_changed), self);
nm_system_config_interface_init (plugin, NULL);
g_object_get (G_OBJECT (plugin),
@ -695,6 +780,11 @@ load_plugins (NMSettings *self, const char **plugins, GError **error)
continue;
}
if (!strcmp (pname, "ifcfg-suse")) {
LOG (LOGL_WARN, "skipping deprecated plugin ifcfg-suse");
continue;
}
obj = find_plugin (list, pname);
if (obj)
continue;
@ -1442,6 +1532,73 @@ impl_settings_reload_connections (NMSettings *self,
dbus_g_method_return (context, TRUE);
}
static gboolean
write_hostname (NMSettingsPrivate *priv, const char *hostname)
{
char *hostname_eol;
gboolean ret;
gs_free_error GError *error = NULL;
const char *file = priv->hostname.file;
gs_unref_variant GVariant *var = NULL;
#if HAVE_SELINUX
security_context_t se_ctx_prev = NULL, se_ctx = NULL;
struct stat file_stat = { .st_mode = 0 };
mode_t st_mode = 0;
#endif
if (priv->hostname.hostnamed_proxy) {
var = g_dbus_proxy_call_sync (priv->hostname.hostnamed_proxy,
"SetStaticHostname",
g_variant_new ("(sb)", hostname, FALSE),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&error);
if (error)
nm_log_warn (LOGD_SETTINGS, "Could not set hostname: %s", error->message);
return !error;
}
#if HAVE_SELINUX
/* Get default context for hostname file and set it for fscreate */
if (stat (file, &file_stat) == 0)
st_mode = file_stat.st_mode;
matchpathcon (file, st_mode, &se_ctx);
matchpathcon_fini ();
getfscreatecon (&se_ctx_prev);
setfscreatecon (se_ctx);
#endif
#if defined (HOSTNAME_PERSIST_GENTOO)
hostname_eol = g_strdup_printf ("#Generated by NetworkManager\n"
"hostname=\"%s\"\n", hostname);
#else
hostname_eol = g_strdup_printf ("%s\n", hostname);
#endif
/* FIXME: g_file_set_contents() writes first to a temporary file
* and renames it atomically. We should hack g_file_set_contents()
* to set the SELINUX labels before renaming the file. */
ret = g_file_set_contents (file, hostname_eol, -1, &error);
#if HAVE_SELINUX
/* Restore previous context and cleanup */
setfscreatecon (se_ctx_prev);
freecon (se_ctx);
freecon (se_ctx_prev);
#endif
g_free (hostname_eol);
if (!ret) {
nm_log_warn (LOGD_SETTINGS, "Could not save hostname to %s: %s", file, error->message);
return FALSE;
}
return TRUE;
}
static void
pk_hostname_cb (NMAuthChain *chain,
GError *chain_error,
@ -1452,7 +1609,6 @@ pk_hostname_cb (NMAuthChain *chain,
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
NMAuthCallResult result;
GError *error = NULL;
GSList *iter;
const char *hostname;
g_assert (context);
@ -1472,21 +1628,12 @@ pk_hostname_cb (NMAuthChain *chain,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
"Insufficient privileges.");
} else {
/* Set the hostname in all plugins */
hostname = nm_auth_chain_get_data (chain, "hostname");
for (iter = priv->plugins; iter; iter = iter->next) {
NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE;
/* error will be cleared if any plugin supports saving the hostname */
if (!write_hostname (priv, hostname)) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_FAILED,
"Saving the hostname failed.");
g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, &caps, NULL);
if (caps & NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME) {
g_object_set (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME, hostname, NULL);
g_clear_error (&error);
}
}
}
@ -1543,14 +1690,6 @@ impl_settings_save_hostname (NMSettings *self,
goto done;
}
/* Do any of the plugins support setting the hostname? */
if (!get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME)) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_NOT_SUPPORTED,
"None of the registered plugins support setting the hostname.");
goto done;
}
chain = nm_auth_chain_new_context (context, pk_hostname_cb, self);
if (!chain) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
@ -1569,6 +1708,37 @@ done:
g_clear_error (&error);
}
static void
hostname_maybe_changed (NMSettings *settings)
{
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (settings);
char *new_hostname;
new_hostname = nm_settings_get_hostname (settings);
if ( (new_hostname && !priv->hostname.value)
|| (!new_hostname && priv->hostname.value)
|| (priv->hostname.value && new_hostname && strcmp (priv->hostname.value, new_hostname))) {
nm_log_info (LOGD_SETTINGS, "hostname changed from '%s' to '%s'",
priv->hostname.value, new_hostname);
g_free (priv->hostname.value);
priv->hostname.value = new_hostname;
g_object_notify (G_OBJECT (settings), NM_SETTINGS_HOSTNAME);
} else
g_free (new_hostname);
}
static void
hostname_file_changed_cb (GFileMonitor *monitor,
GFile *file,
GFile *other_file,
GFileMonitorEvent event_type,
gpointer user_data)
{
hostname_maybe_changed (user_data);
}
static gboolean
have_connection_for_device (NMSettings *self, NMDevice *device)
{
@ -1867,11 +2037,79 @@ nm_settings_get_startup_complete (NMSettings *self)
/***************************************************************/
static void
hostnamed_properties_changed (GDBusProxy *proxy,
GVariant *changed_properties,
char **invalidated_properties,
gpointer user_data)
{
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (user_data);
GVariant *v_hostname;
const char *hostname;
v_hostname = g_dbus_proxy_get_cached_property (priv->hostname.hostnamed_proxy,
"StaticHostname");
if (!v_hostname)
return;
hostname = g_variant_get_string (v_hostname, NULL);
if (g_strcmp0 (priv->hostname.value, hostname) != 0) {
nm_log_info (LOGD_SETTINGS, "hostname changed from '%s' to '%s'",
priv->hostname.value, hostname);
g_free (priv->hostname.value);
priv->hostname.value = g_strdup (hostname);
g_object_notify (G_OBJECT (user_data), NM_SETTINGS_HOSTNAME);
}
g_variant_unref (v_hostname);
}
static void
setup_hostname_file_monitors (NMSettings *self)
{
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
GFileMonitor *monitor;
GFile *file;
priv->hostname.file = HOSTNAME_FILE;
priv->hostname.value = nm_settings_get_hostname (self);
/* monitor changes to hostname file */
file = g_file_new_for_path (priv->hostname.file);
monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
g_object_unref (file);
if (monitor) {
priv->hostname.monitor_id = g_signal_connect (monitor, "changed",
G_CALLBACK (hostname_file_changed_cb),
self);
priv->hostname.monitor = monitor;
}
#if defined (HOSTNAME_PERSIST_SUSE)
/* monitor changes to dhcp file to know whether the hostname is valid */
file = g_file_new_for_path (CONF_DHCP);
monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
g_object_unref (file);
if (monitor) {
priv->hostname.dhcp_monitor_id = g_signal_connect (monitor, "changed",
G_CALLBACK (hostname_file_changed_cb),
self);
priv->hostname.dhcp_monitor = monitor;
}
#endif
hostname_maybe_changed (self);
}
NMSettings *
nm_settings_new (GError **error)
{
NMSettings *self;
NMSettingsPrivate *priv;
GDBusProxy *proxy;
GVariant *variant;
GError *local_error = NULL;
self = g_object_new (NM_TYPE_SETTINGS, NULL);
@ -1889,6 +2127,31 @@ nm_settings_new (GError **error)
load_connections (self);
check_startup_complete (self);
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, 0, NULL,
HOSTNAMED_SERVICE_NAME, HOSTNAMED_SERVICE_PATH,
HOSTNAMED_SERVICE_INTERFACE, NULL, &local_error);
if (proxy) {
variant = g_dbus_proxy_get_cached_property (proxy, "StaticHostname");
if (variant) {
nm_log_info (LOGD_SETTINGS, "hostname: using hostnamed");
priv->hostname.hostnamed_proxy = proxy;
g_signal_connect (proxy, "g-properties-changed",
G_CALLBACK (hostnamed_properties_changed), self);
hostnamed_properties_changed (proxy, NULL, NULL, self);
g_variant_unref (variant);
} else {
nm_log_info (LOGD_SETTINGS, "hostname: couldn't get property from hostnamed");
g_object_unref (proxy);
}
} else {
nm_log_info (LOGD_SETTINGS, "hostname: hostnamed not used as proxy creation failed with: %s",
local_error->message);
g_clear_error (&local_error);
}
if (!priv->hostname.hostnamed_proxy)
setup_hostname_file_monitors (self);
nm_dbus_manager_register_object (priv->dbus_mgr, NM_DBUS_PATH_SETTINGS, self);
return self;
}
@ -1932,6 +2195,32 @@ dispose (GObject *object)
g_object_unref (priv->agent_mgr);
if (priv->hostname.hostnamed_proxy) {
g_signal_handlers_disconnect_by_func (priv->hostname.hostnamed_proxy,
G_CALLBACK (hostnamed_properties_changed),
self);
g_clear_object (&priv->hostname.hostnamed_proxy);
}
if (priv->hostname.monitor) {
if (priv->hostname.monitor_id)
g_signal_handler_disconnect (priv->hostname.monitor, priv->hostname.monitor_id);
g_file_monitor_cancel (priv->hostname.monitor);
g_clear_object (&priv->hostname.monitor);
}
if (priv->hostname.dhcp_monitor) {
if (priv->hostname.dhcp_monitor_id)
g_signal_handler_disconnect (priv->hostname.dhcp_monitor,
priv->hostname.dhcp_monitor_id);
g_file_monitor_cancel (priv->hostname.dhcp_monitor);
g_clear_object (&priv->hostname.dhcp_monitor);
}
g_clear_pointer (&priv->hostname.value, g_free);
G_OBJECT_CLASS (nm_settings_parent_class)->dispose (object);
}
@ -2001,7 +2290,7 @@ static void
nm_settings_class_init (NMSettingsClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
g_type_class_add_private (class, sizeof (NMSettingsPrivate));
/* virtual methods */

View file

@ -52,19 +52,11 @@ interface_init (gpointer g_iface)
(g_iface,
g_param_spec_uint (NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, "", "",
NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE,
( NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS
| NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME),
NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS,
NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_interface_install_property
(g_iface,
g_param_spec_string (NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME, "", "",
NULL,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
/* Signals */
g_signal_new (NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED,
iface_type,

View file

@ -43,7 +43,6 @@ GObject * nm_system_config_factory (void);
#define NM_SYSTEM_CONFIG_INTERFACE_NAME "name"
#define NM_SYSTEM_CONFIG_INTERFACE_INFO "info"
#define NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES "capabilities"
#define NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME "hostname"
#define NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED "unmanaged-specs-changed"
#define NM_SYSTEM_CONFIG_INTERFACE_UNRECOGNIZED_SPECS_CHANGED "unrecognized-specs-changed"
@ -52,7 +51,6 @@ GObject * nm_system_config_factory (void);
typedef enum {
NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE = 0x00000000,
NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS = 0x00000001,
NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME = 0x00000002
/* When adding more capabilities, be sure to update the "Capabilities"
* property max value in nm-system-config-interface.c.
@ -65,7 +63,6 @@ typedef enum {
NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME = NM_SYSTEM_CONFIG_INTERFACE_PROP_FIRST,
NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO,
NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES,
NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME,
} NMSystemConfigInterfaceProp;

View file

@ -1,4 +1,4 @@
SUBDIRS=keyfile example
SUBDIRS=keyfile
@GNOME_CODE_COVERAGE_RULES@
@ -10,10 +10,6 @@ if CONFIG_PLUGIN_IFCFG_RH
SUBDIRS+=ifcfg-rh
endif
if CONFIG_PLUGIN_IFCFG_SUSE
SUBDIRS+=ifcfg-suse
endif
if CONFIG_PLUGIN_IFUPDOWN
SUBDIRS+=ifupdown
endif

View file

@ -3,12 +3,11 @@ Plugins generally have three components:
1) plugin object: manages the individual "connections", which are
just objects wrapped around on-disk config data. The plugin handles requests
to add new connections via the NM D-Bus API, and also watches config
directories for changes to configuration data. It also handles reading and
writing the persistent hostname, if the plugin supports hostnames. Plugins
implement the NMSystemConfigInterface interface. See plugin.c.
directories for changes to configuration data. Plugins implement the
NMSystemConfigInterface interface. See plugin.c.
2) "connections": subclasses of NMSettingsConnection. They handle updates to
configuration data, deletion, etc. See NMExampleConnection.c.
configuration data, deletion, etc. See NMKeyfileConnection.
3) reader/writer code: typically a separate static library that gets linked
into the main plugin shared object, so they can be unit tested separately
@ -27,9 +26,8 @@ entry points into the plugin: nm_system_config_factory() and
the NMSystemConfigInterface methods.
The plugin also emits various signals (defined by NMSystemConfigInterface)
which NetworkManager listens for. These include persistent hostname changes
(if something modified the file in which the persistent hostname is stored)
and notifications of new connections if they were created via changes to
the on-disk files. The "connection" objects can also emit signals
(defined by the NMSettingsConnection and NMConnection superclasses) when the
connections' backing storage gets changed or deleted.
which NetworkManager listens for. These include notifications of new
connections if they were created via changes to the on-disk files. The
"connection" objects can also emit signals (defined by the NMSettingsConnection
and NMConnection superclasses) when the connections' backing storage gets
changed or deleted.

View file

@ -1,32 +0,0 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/src \
-I$(top_srcdir)/src/settings \
-I$(top_srcdir)/include \
-I$(top_srcdir)/libnm-core \
-I$(top_builddir)/libnm-core \
-DG_LOG_DOMAIN=\""NetworkManager-example"\" \
-DNETWORKMANAGER_COMPILATION \
-DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
$(GLIB_CFLAGS) \
$(DBUS_CFLAGS) \
-DNMCONFDIR=\"$(nmconfdir)\"
# 'noinst' here because this is an example plugin we don't want to install
noinst_LTLIBRARIES = libnm-settings-plugin-example.la
# The actual plugins typically pull reader.c and writer.c out into
# their own static library so that unit tests can use them without
# having to build the entire plugin. But since this is a simple
# plugin we don't do that yet.
libnm_settings_plugin_example_la_SOURCES = \
nm-example-connection.c \
nm-example-connection.h \
plugin.c \
plugin.h \
common.h \
reader.c \
writer.c
libnm_settings_plugin_example_la_LDFLAGS = -module -avoid-version

View file

@ -1,45 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager system settings service
*
* 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* (C) Copyright 2012 Red Hat, Inc.
*/
#ifndef __COMMON_H__
#define __COMMON_H__
#include <glib.h>
#include <nm-connection.h>
/* General info about the plugin that the code may want to use for logging
* purposes.
*/
#define EXAMPLE_PLUGIN_NAME "example"
#define EXAMPLE_PLUGIN_INFO "(c) 2012 Red Hat, Inc. To report bugs please use the NetworkManager mailing list."
#define EXAMPLE_DIR NMCONFDIR "/example-plugin"
/* Prototypes for the reader/writer functions */
NMConnection *connection_from_file (const char *filename, GError **error);
gboolean write_connection (NMConnection *connection,
const char *existing_path,
char **out_path,
GError **error);
#endif /* __COMMON_H__ */

View file

@ -1,189 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager system settings service - keyfile plugin
*
* 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2012 Red Hat, Inc.
*/
#include "config.h"
#include <string.h>
#include <glib/gstdio.h>
#include <nm-dbus-interface.h>
#include <nm-setting-connection.h>
#include <nm-utils.h>
#include "nm-system-config-interface.h"
#include "nm-dbus-glib-types.h"
#include "nm-example-connection.h"
#include "common.h"
/* GObject boilerplate; this object is a subclass of NMSettingsConnection
* which is specified by the NM_TYPE_SETTINGS_CONNECTION bit here. That
* in turn is a subclass of NMConnection, so it ends up that NMExampleConnection
* is a subclass of NMConnection too.
*/
G_DEFINE_TYPE (NMExampleConnection, nm_example_connection, NM_TYPE_SETTINGS_CONNECTION)
#define NM_EXAMPLE_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_EXAMPLE_CONNECTION, NMExampleConnectionPrivate))
/* Object private instance data */
typedef struct {
char *path;
} NMExampleConnectionPrivate;
/* Creates a new object which encapsulates an on-disk connection and any
* plugin-specific operations or data.
*/
NMExampleConnection *
nm_example_connection_new (const char *full_path,
NMConnection *source,
GError **error)
{
GObject *object;
NMExampleConnectionPrivate *priv;
NMConnection *tmp;
const char *uuid;
g_return_val_if_fail (full_path != NULL, NULL);
/* If we're given a connection already, prefer that instead of re-reading */
if (source)
tmp = g_object_ref (source);
else {
/* Read the data offdisk and translate it into a simple NMConnection object */
tmp = connection_from_file (full_path, error);
if (!tmp)
return NULL;
}
/* Actually create the new NMExampleConnection object */
object = (GObject *) g_object_new (NM_TYPE_EXAMPLE_CONNECTION, NULL);
priv = NM_EXAMPLE_CONNECTION_GET_PRIVATE (object);
priv->path = g_strdup (full_path);
/* Update our settings with what was read from the file or what got passed
* in as a source NMConnection.
*/
if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object),
tmp,
TRUE,
NULL,
error)) {
g_object_unref (object);
object = NULL;
goto out;
}
/* Make sure we have a UUID; just a sanity check */
uuid = nm_connection_get_uuid (NM_CONNECTION (object));
if (!uuid) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Connection in file %s had no UUID", full_path);
g_object_unref (object);
object = NULL;
}
out:
g_object_unref (tmp);
return (NMExampleConnection *) object;
}
const char *
nm_example_connection_get_path (NMExampleConnection *self)
{
g_return_val_if_fail (NM_IS_EXAMPLE_CONNECTION (self), NULL);
/* Simple accessor that returns the file path from our private instance data */
return NM_EXAMPLE_CONNECTION_GET_PRIVATE (self)->path;
}
static void
commit_changes (NMSettingsConnection *connection,
NMSettingsConnectionCommitFunc callback,
gpointer user_data)
{
NMExampleConnectionPrivate *priv = NM_EXAMPLE_CONNECTION_GET_PRIVATE (connection);
char *path = NULL;
GError *error = NULL;
/* Write the new connection data out to disk. This function passes
* back the path of the file it wrote out so that we know what that
* path is if the connection is a completely new one.
*/
if (!write_connection (NM_CONNECTION (connection), priv->path, &path, &error)) {
callback (connection, error, user_data);
g_clear_error (&error);
return;
}
/* Update the filename if it changed */
if (path) {
g_free (priv->path);
priv->path = path;
}
/* Chain up to parent for generic commit stuff */
NM_SETTINGS_CONNECTION_CLASS (nm_example_connection_parent_class)->commit_changes (connection,
callback,
user_data);
}
static void
do_delete (NMSettingsConnection *connection,
NMSettingsConnectionDeleteFunc callback,
gpointer user_data)
{
NMExampleConnectionPrivate *priv = NM_EXAMPLE_CONNECTION_GET_PRIVATE (connection);
g_unlink (priv->path);
/* Chain up to parent for generic deletion stuff */
NM_SETTINGS_CONNECTION_CLASS (nm_example_connection_parent_class)->delete (connection,
callback,
user_data);
}
/**************************************************************/
static void
nm_example_connection_init (NMExampleConnection *connection)
{
}
static void
finalize (GObject *object)
{
g_free (NM_EXAMPLE_CONNECTION_GET_PRIVATE (object)->path);
G_OBJECT_CLASS (nm_example_connection_parent_class)->finalize (object);
}
static void
nm_example_connection_class_init (NMExampleConnectionClass *keyfile_connection_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (keyfile_connection_class);
NMSettingsConnectionClass *settings_class = NM_SETTINGS_CONNECTION_CLASS (keyfile_connection_class);
/* Tells GObject to allocate and zero our instance data pointer */
g_type_class_add_private (keyfile_connection_class, sizeof (NMExampleConnectionPrivate));
/* Overrides of various superclass methods */
object_class->finalize = finalize;
settings_class->commit_changes = commit_changes;
settings_class->delete = do_delete;
}

View file

@ -1,55 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager system settings service - keyfile plugin
*
* 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2012 Red Hat, Inc.
*/
#ifndef __NETWORKMANAGER_EXAMPLE_CONNECTION_H__
#define __NETWORKMANAGER_EXAMPLE_CONNECTION_H__
#include <nm-settings-connection.h>
G_BEGIN_DECLS
/* GObject boilerplate */
#define NM_TYPE_EXAMPLE_CONNECTION (nm_example_connection_get_type ())
#define NM_EXAMPLE_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_EXAMPLE_CONNECTION, NMExampleConnection))
#define NM_EXAMPLE_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_EXAMPLE_CONNECTION, NMExampleConnectionClass))
#define NM_IS_EXAMPLE_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_EXAMPLE_CONNECTION))
#define NM_IS_EXAMPLE_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_EXAMPLE_CONNECTION))
#define NM_EXAMPLE_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_EXAMPLE_CONNECTION, NMExampleConnectionClass))
typedef struct {
NMSettingsConnection parent;
} NMExampleConnection;
typedef struct {
NMSettingsConnectionClass parent;
} NMExampleConnectionClass;
GType nm_example_connection_get_type (void);
/* Actual API that plugin.c will call */
NMExampleConnection *nm_example_connection_new (const char *filename,
NMConnection *source,
GError **error);
const char *nm_example_connection_get_path (NMExampleConnection *self);
G_END_DECLS
#endif /* __NETWORKMANAGER_EXAMPLE_CONNECTION_H__ */

View file

@ -1,858 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager system settings service - keyfile plugin
*
* 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2012 Red Hat, Inc.
*/
#include "config.h"
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <gmodule.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <gio/gio.h>
#include <nm-connection.h>
#include <nm-setting.h>
#include <nm-setting-connection.h>
#include <nm-utils.h>
#include <nm-config.h>
#include <nm-logging.h>
#include "plugin.h"
#include "nm-system-config-interface.h"
#include "common.h"
#include "nm-example-connection.h"
static char *plugin_get_hostname (SCPluginExample *plugin);
static void system_config_interface_init (NMSystemConfigInterface *system_config_interface_class);
/* GObject object definition. This actually defines the object and tells
* GObject about the interfaces this object provides. Here we provide
* the "system config interface" which is the API that NetworkManager uses
* to communicate with this plugin.
*
* Interface and super/sub-class access with GObject works via casting and
* GObject magically figures out what needs to be called. So, given:
*
* SCPluginExample *plugin = <new plugin>;
*
* you can call GObject methods since SCPluginExample inherits from GObject
* via the G_TYPE_OBJECT argument of G_DEFINE_TYPE_EXTENDED below:
*
* g_object_set_data (G_OBJECT (plugin), ...);
*
* and since SCPluginExample implements NMSystemConfigInterface via the
* G_IMPLEMENT_INTERFACE bit below, we can also call any methods of
* NMSystemConfigInterface (defined in NM sources in nm-system-config-interface.c):
*
* connections = nm_system_config_interface_get_connections (NM_SYSTEM_CONFIG_INTERFACE (plugin));
*
* For the call to nm_system_config_interface_get_connections() that eventually
* ends up in the get_connections() method in this file because the
* system_config_interface_init() function sets up the vtable for this objects
* implementation of NMSystemConfigInterface.
*/
G_DEFINE_TYPE_EXTENDED (SCPluginExample, sc_plugin_example, G_TYPE_OBJECT, 0,
G_IMPLEMENT_INTERFACE (NM_TYPE_SYSTEM_CONFIG_INTERFACE, system_config_interface_init))
/* Quick define to access the object's private data pointer; this pointer
* points to the object's instance data.
*/
#define SC_PLUGIN_EXAMPLE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SC_TYPE_PLUGIN_EXAMPLE, SCPluginExamplePrivate))
/* Instance data. When the object is created, a new structure of this type
* will be created and zeroed for this instance of the object to use. This
* is actually done by g_type_class_add_private() when called from the object's
* class init function.
*/
typedef struct {
/* This hash holds each connection known to this plugin */
GHashTable *connections;
/* A watch for changes on the directory that holds the configuration files
* so the plugin can respond to configuration changes on-the-fly and
* tell NM that the connection data has changed. Typically the plugin
* needs to monitor the directory itself (to watch for completely new files)
* while the individual connections watch their individual config files.
*/
GFileMonitor *monitor;
guint monitor_id;
/* Tracks changes to the global NM config file, just in case our
* plugin has some specific options (like unmanaged devices) that
* might be changed at runtime.
*/
const char *conf_file;
GFileMonitor *conf_file_monitor;
guint conf_file_monitor_id;
/* Persistent hostname if the plugin supports hostnames. Normally used
* for distro plugins; ie Red Hat uses /etc/sysconfig/hostname while
* Debian uses /etc/hostname. Plugins can abstract the storage location
* and just tell NM what the persisten hostname is and when its backing
* file has changed. NM handles actually setting the hostname.
*/
char *hostname;
} SCPluginExamplePrivate;
static NMSettingsConnection *
_internal_new_connection (SCPluginExample *self,
const char *full_path,
NMConnection *source,
GError **error)
{
SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (self);
NMExampleConnection *connection;
g_return_val_if_fail (full_path != NULL, NULL);
/* 'source' will usually be NULL if we're going to read the connection
* off disk. But if the new connection is coming from NetworkManager
* (ie, from a D-Bus AddConnection request) then we'll have 'source' too.
* This function expects the connection to already be written to disk
* so that the NMExampleConnection object can re-read it and intialize
* state in the same manner as when getting a change notification from
* the config directory. That simplifies things somewhat.
*/
connection = nm_example_connection_new (full_path, source, error);
if (connection) {
g_hash_table_insert (priv->connections,
g_strdup (nm_example_connection_get_path (connection)),
connection);
}
return (NMSettingsConnection *) connection;
}
/* Read each file in our config directory and try to create a new
* NMExamplePlugin for it.
*/
static void
read_connections (NMSystemConfigInterface *config)
{
SCPluginExample *self = SC_PLUGIN_EXAMPLE (config);
GDir *dir;
GError *error = NULL;
const char *item;
dir = g_dir_open (EXAMPLE_DIR, 0, &error);
if (!dir) {
nm_log_warn (LOGD_SETTINGS, "Cannot read directory '%s': (%d) %s",
EXAMPLE_DIR,
error ? error->code : -1,
error && error->message ? error->message : "(unknown)");
g_clear_error (&error);
return;
}
while ((item = g_dir_read_name (dir))) {
NMSettingsConnection *connection;
char *full_path;
/* XXX: Check file extension and ignore "~", ".tmp", ".bak", etc */
full_path = g_build_filename (EXAMPLE_DIR, item, NULL);
nm_log_info (LOGD_SETTINGS, "parsing %s ... ", item);
connection = _internal_new_connection (self, full_path, NULL, &error);
if (connection) {
nm_log_info (LOGD_SETTINGS, " read connection '%s'",
nm_connection_get_id (NM_CONNECTION (connection)));
} else {
nm_log_info (LOGD_SETTINGS, " error: %s",
(error && error->message) ? error->message : "(unknown)");
}
g_clear_error (&error);
g_free (full_path);
}
g_dir_close (dir);
}
static void
update_connection_settings_commit_cb (NMSettingsConnection *orig, GError *error, gpointer user_data)
{
/* If there was an error updating the connection's internal stuff, then
* we can't do anything except log it and remove the connection. This might
* happen due to invalid data, but as the data would already have been
* verified before it ever got to this plugin, we shouldn't ever get
* an error here.
*/
if (error) {
nm_log_warn (LOGD_SETTINGS, "%s: connection invalid: %s",
__func__, error->message);
g_clear_error (&error);
nm_settings_connection_signal_remove (orig);
}
}
static void
update_connection_settings (NMExampleConnection *orig,
NMExampleConnection *new)
{
/* This just replaces the orig's internal settings with those from new */
nm_settings_connection_replace_and_commit (NM_SETTINGS_CONNECTION (orig),
NM_CONNECTION (new),
update_connection_settings_commit_cb, NULL);
}
/* Monitoring */
static void
remove_connection (SCPluginExample *self,
NMExampleConnection *connection,
const char *name)
{
g_return_if_fail (connection != NULL);
g_return_if_fail (name != NULL);
/* Removing from the hash table should drop the last reference, but since
* we need the object to stay alive across the signal emission to NM,
* we grab a temporary reference.
*/
g_object_ref (connection);
g_hash_table_remove (SC_PLUGIN_EXAMPLE_GET_PRIVATE (self)->connections, name);
/* Tell NM the connection is gone */
nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (connection));
/* Remove the temporary reference; connection will now be destroyed */
g_object_unref (connection);
}
/* Look through all connections we know about and return one with a given UUID */
static NMExampleConnection *
find_by_uuid (SCPluginExample *self, const char *uuid)
{
SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (self);
GHashTableIter iter;
gpointer data = NULL;
g_return_val_if_fail (uuid != NULL, NULL);
g_hash_table_iter_init (&iter, priv->connections);
while (g_hash_table_iter_next (&iter, NULL, &data)) {
NMConnection *candidate = NM_CONNECTION (data);
if (strcmp (uuid, nm_connection_get_uuid (candidate)) == 0)
return NM_EXAMPLE_CONNECTION (candidate);
}
return NULL;
}
static void
dir_changed (GFileMonitor *monitor,
GFile *file,
GFile *other_file,
GFileMonitorEvent event_type,
gpointer user_data)
{
NMSystemConfigInterface *config = NM_SYSTEM_CONFIG_INTERFACE (user_data);
SCPluginExample *self = SC_PLUGIN_EXAMPLE (config);
SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (self);
char *full_path;
NMExampleConnection *connection;
GError *error = NULL;
full_path = g_file_get_path (file);
/* XXX: Check here if you need to ignore this file, ie by checking for
* extensions like "~" and ".bak" or ".tmp". If so just return;
*/
/* Check if we know about this connection already */
connection = g_hash_table_lookup (priv->connections, full_path);
switch (event_type) {
case G_FILE_MONITOR_EVENT_DELETED:
if (connection) {
nm_log_info (LOGD_SETTINGS, "removed %s.", full_path);
remove_connection (SC_PLUGIN_EXAMPLE (config), connection, full_path);
}
break;
case G_FILE_MONITOR_EVENT_CREATED:
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
if (connection) {
/* Update of an existing connection. Here we re-read the file and
* compare it against the existing connection to check if anything
* actually changed.
*/
NMExampleConnection *tmp;
tmp = nm_example_connection_new (full_path, NULL, &error);
if (tmp) {
if (!nm_connection_compare (NM_CONNECTION (connection),
NM_CONNECTION (tmp),
NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS |
NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)) {
/* Connection changed; update our internal connection object */
nm_log_info (LOGD_SETTINGS, "updating %s", full_path);
update_connection_settings (connection, tmp);
}
g_object_unref (tmp);
} else {
/* There was an error parsing the updated connection; it may
* no longer be valid and thus we've got to delete it. If it
* becomes valid again later we'll get another change
* notification, we'll re-read it, and we'll treat it as new.
*/
nm_log_info (LOGD_SETTINGS, " error: %s",
(error && error->message) ? error->message : "(unknown)");
remove_connection (SC_PLUGIN_EXAMPLE (config), connection, full_path);
}
g_clear_error (&error);
} else {
nm_log_info (LOGD_SETTINGS, "updating %s", full_path);
/* We don't know about the connection yet, so the change represents
* a completely new connection.
*/
connection = nm_example_connection_new (full_path, NULL, &error);
if (connection) {
NMExampleConnection *found = NULL;
/* Connection renames will show up as different files but with
* the same UUID. Try to find the original connection.
* A connection rename is treated just like an update except
* there's a bit more housekeeping with the hash table.
*/
found = find_by_uuid (self, nm_connection_get_uuid (NM_CONNECTION (connection)));
if (found) {
const char *old_path = nm_example_connection_get_path (connection);
/* Removing from the hash table should drop the last reference,
* but of course we want to keep the connection around.
*/
g_object_ref (found);
g_hash_table_remove (priv->connections, old_path);
/* Updating settings should update the NMExampleConnection's
* filename property too.
*/
update_connection_settings (found, connection);
/* Re-insert the connection back into the hash with the new filename */
g_hash_table_insert (priv->connections,
g_strdup (nm_example_connection_get_path (found)),
found);
/* Get rid of the temporary connection */
g_object_unref (connection);
} else {
/* Completely new connection, not a rename. */
g_hash_table_insert (priv->connections,
g_strdup (nm_example_connection_get_path (connection)),
connection);
/* Tell NM we found a new connection */
g_signal_emit_by_name (config, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection);
}
} else {
nm_log_info (LOGD_SETTINGS, " error: %s", (error && error->message) ? error->message : "(unknown)");
g_clear_error (&error);
}
}
break;
default:
break;
}
g_free (full_path);
}
static void
conf_file_changed (GFileMonitor *monitor,
GFile *file,
GFile *other_file,
GFileMonitorEvent event_type,
gpointer data)
{
SCPluginExample *self = SC_PLUGIN_EXAMPLE (data);
SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (self);
char *tmp;
switch (event_type) {
case G_FILE_MONITOR_EVENT_DELETED:
case G_FILE_MONITOR_EVENT_CREATED:
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
/* Unmanaged devices option may have changed; just emit the changed
* signal for unmanaged specs and when NM calls back in to get the
* updated specs we'll re-read the config file then.
*/
g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED);
/* Hostname may also have changed; read it and if it did actually
* change, notify NM.
*/
tmp = plugin_get_hostname (self);
if (g_strcmp0 (tmp, priv->hostname) != 0) {
g_free (priv->hostname);
priv->hostname = tmp;
tmp = NULL;
g_object_notify (G_OBJECT (self), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME);
}
g_free (tmp);
break;
default:
break;
}
}
/* This function starts the inotify monitors that watch the plugin's config
* file directory for new connections and changes to existing connections
* (if not disabled by NetworkManager.conf), and for changes to the plugin's
* non-connection config files.
*/
static void
setup_monitoring (NMSystemConfigInterface *config)
{
SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (config);
GFileMonitor *monitor;
GFile *file;
/* Initialize connection hash here; we use the connection hash as the
* "are we initialized yet" variable.
*/
priv->connections = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
if (nm_config_get_monitor_connection_files (nm_config_get ())) {
/* Set up the watch for our config directory */
file = g_file_new_for_path (EXAMPLE_DIR);
monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL);
g_object_unref (file);
if (monitor) {
/* This registers the dir_changed() function to be called whenever
* the GFileMonitor object notices a change in the directory.
*/
priv->monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (dir_changed), config);
priv->monitor = monitor;
}
}
/* Set up a watch on our configuration file, basically just for watching
* whether the user has changed the unmanaged devices option or the
* persistent hostname.
*/
if (priv->conf_file) {
file = g_file_new_for_path (priv->conf_file);
monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
g_object_unref (file);
if (monitor) {
priv->conf_file_monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (conf_file_changed), config);
priv->conf_file_monitor = monitor;
}
}
}
/*******************************************************************/
/* Return to NM the full list of connections this plugin owns */
static GSList *
get_connections (NMSystemConfigInterface *config)
{
SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (config);
GHashTableIter iter;
NMSettingsConnection *connection;
GSList *list = NULL;
if (!priv->connections) {
/* If we haven't read connections in yet, do so now */
setup_monitoring (config);
read_connections (config);
}
/* Add each connection from our internal hash table to a list returned
* to NetworkManager.
*/
g_hash_table_iter_init (&iter, priv->connections);
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &connection))
list = g_slist_prepend (list, connection);
return list;
}
/* Called by NetworkManager when a user adds a new connection via D-Bus.
* The plugin should convert the data in 'connection' to its on-disk format
* write it out to disk, and return an object that's a subclass of
* NMSettingsConnection. Typically plugins will subclass NMSettingsConnection
* and use that class to handle any plugin-specific stuff like monitoring
* the on-disk config files for changes, and/or parsing the file-format and
* converting back and forth from that to NMConnection.
*/
static NMSettingsConnection *
add_connection (NMSystemConfigInterface *config,
NMConnection *connection,
gboolean save_to_disk,
GError **error)
{
SCPluginExample *self = SC_PLUGIN_EXAMPLE (config);
NMSettingsConnection *added = NULL;
char *path = NULL;
/* Write it out first, then add the connection to our internal list; that
* way we don't trigger the new NMSettingsConnection subclass' file watch
* functions needlessly.
*/
if (save_to_disk && !write_connection (connection, NULL, &path, error))
return NULL;
added = _internal_new_connection (self, path, connection, error);
g_free (path);
return added;
}
/* This function returns a list of "unmanaged device specs" which represent
* a list of devices that NetworkManager should not manage. Each unmanaged
* spec item has a specific format starting with a "tag" and followed by
* tag-specific data. The only currently specified items are "mac:" followed
* by the MAC address of the interface NM should not manage, or "interface-name:"
* followed by the name of the interface NM should not manage. This function
* reads the list of unmanaged devices from wherever the plugin wants to
* store them and returns that list to NetworkManager.
*/
static GSList *
get_unmanaged_specs (NMSystemConfigInterface *config)
{
SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (config);
GKeyFile *key_file;
GSList *specs = NULL;
GError *error = NULL;
char *str, **ids;
int i;
if (!priv->conf_file)
return NULL;
key_file = g_key_file_new ();
if (!g_key_file_load_from_file (key_file, priv->conf_file, G_KEY_FILE_NONE, &error)) {
nm_log_warn (LOGD_SETTINGS, "Error parsing file '%s': %s", priv->conf_file, error->message);
g_error_free (error);
goto out;
}
str = g_key_file_get_value (key_file, "keyfile", "unmanaged-devices", NULL);
if (!str)
goto out;
ids = g_strsplit (str, ";", -1);
for (i = 0; ids[i] != NULL; i++) {
/* Verify unmanaged specification and add it to the list */
if (!strncmp (ids[i], "mac:", 4) && nm_utils_hwaddr_valid (ids[i] + 4, -1)) {
specs = g_slist_append (specs, ids[i]);
} else if (!strncmp (ids[i], "interface-name:", 15) && nm_utils_iface_valid_name (ids[i] + 15)) {
specs = g_slist_append (specs, ids[i]);
} else {
nm_log_warn (LOGD_SETTINGS, "Error in file '%s': invalid unmanaged-devices entry: '%s'", priv->conf_file, ids[i]);
g_free (ids[i]);
}
}
g_free (ids); /* Yes, g_free, not g_strfreev because we need the strings in the list */
g_free (str);
out:
g_key_file_free (key_file);
return specs;
}
static char *
plugin_get_hostname (SCPluginExample *plugin)
{
SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (plugin);
GKeyFile *key_file;
char *hostname = NULL;
GError *error = NULL;
if (!priv->conf_file)
return NULL;
/* Read the persistent hostname out of backing storage, which happens
* to be the NM config file. Other plugins (like distro-specific ones)
* should read it from the distro-specific location like /etc/hostname.
*/
key_file = g_key_file_new ();
if (g_key_file_load_from_file (key_file, priv->conf_file, G_KEY_FILE_NONE, &error))
hostname = g_key_file_get_value (key_file, "keyfile", "hostname", NULL);
else {
nm_log_warn (LOGD_SETTINGS, "Error parsing file '%s': %s", priv->conf_file, error->message);
g_error_free (error);
}
g_key_file_free (key_file);
return hostname;
}
static gboolean
plugin_set_hostname (SCPluginExample *plugin, const char *hostname)
{
SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (plugin);
GKeyFile *key_file;
GError *error = NULL;
gboolean success = FALSE;
char *data;
gsize len;
if (!priv->conf_file) {
nm_log_warn (LOGD_SETTINGS, "Error saving hostname: no config file");
return FALSE;
}
/* This just saves the hostname to the NM config file in a section
* private to this plugin.
*/
key_file = g_key_file_new ();
if (!g_key_file_load_from_file (key_file, priv->conf_file, G_KEY_FILE_NONE, &error)) {
nm_log_warn (LOGD_SETTINGS, "Error parsing file '%s': %s", priv->conf_file, error->message);
g_error_free (error);
goto out;
}
g_key_file_set_string (key_file, "example", "hostname", hostname);
data = g_key_file_to_data (key_file, &len, &error);
if (data) {
/* Save updated file to disk */
g_file_set_contents (priv->conf_file, data, len, &error);
g_free (data);
/* Update internal copy of hostname */
g_free (priv->hostname);
priv->hostname = g_strdup (hostname);
success = TRUE;
}
if (error) {
nm_log_warn (LOGD_SETTINGS, "Error saving hostname: %s", error->message);
g_error_free (error);
}
out:
g_key_file_free (key_file);
return success;
}
/* GObject */
static void
sc_plugin_example_init (SCPluginExample *plugin)
{
/* Here we'd do any instance-specific initialization like setting
* members of SCPluginExamplePrivate to default values. But we
* don't have anything to do here since most initialization is done
* when NM calls the various entry points.
*/
}
static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
switch (prop_id) {
case NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME:
g_value_set_string (value, EXAMPLE_PLUGIN_NAME);
break;
case NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO:
g_value_set_string (value, EXAMPLE_PLUGIN_INFO);
break;
case NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES:
/* Return capabilities to NM; this plugin supports changing connections
* as well as being capable of saving the hostname to persistent storage.
* If the plugin can't write out updated configuration, then obviously
* it shouldn't advertise that capability. If it can't save hostnames
* to persistent storage, it shouldn't advertise that capability either.
*/
g_value_set_uint (value, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS |
NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME);
break;
case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME:
/* Return the hostname we've read from persistent storage */
g_value_set_string (value, SC_PLUGIN_EXAMPLE_GET_PRIVATE (object)->hostname);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
const char *hostname;
switch (prop_id) {
case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME:
/* We'll get here when the user has changed the hostname via NM's
* D-Bus interface and we're requested to save this hostname to
* persistent storage.
*/
hostname = g_value_get_string (value);
if (hostname && strlen (hostname) < 1)
hostname = NULL;
plugin_set_hostname (SC_PLUGIN_EXAMPLE (object), hostname);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
dispose (GObject *object)
{
SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (object);
/* GObject has a two-stage object destruction process: dispose and finalize.
* In dispose the object should free any references it might have on other
* objects to break circular refs, then it's finally cleaned up by finalize.
* We don't bother to implement a finalize, so we just make sure that we
* clean everything up (including clearing pointers) in dispose so that
* if GObject decides to revive this object post-dispose (yes, legal)
* we don't crash on dangling pointers.
*/
if (priv->monitor) {
if (priv->monitor_id) {
g_signal_handler_disconnect (priv->monitor, priv->monitor_id);
priv->monitor_id = 0;
}
g_file_monitor_cancel (priv->monitor);
g_object_unref (priv->monitor);
priv->monitor = NULL;
}
if (priv->conf_file_monitor) {
if (priv->conf_file_monitor_id) {
g_signal_handler_disconnect (priv->conf_file_monitor, priv->conf_file_monitor_id);
priv->conf_file_monitor_id = 0;
}
g_file_monitor_cancel (priv->conf_file_monitor);
g_object_unref (priv->conf_file_monitor);
priv->conf_file_monitor = NULL;
}
if (priv->connections) {
/* Destroying the connections hash unrefs each connection in it
* due to the GHashTable value_destroy_func that we passed into
* g_hash_table_new_full().
*/
g_hash_table_destroy (priv->connections);
priv->connections = NULL;
}
g_free (priv->hostname);
priv->hostname = NULL;
/* Chain up to the superclass */
G_OBJECT_CLASS (sc_plugin_example_parent_class)->dispose (object);
}
/* This function gets called to set up any method and property overrides
* of superclasses, and also (if we actually had any) to set up any
* custom properties and signals this object might have. This is called before
* the object is actually instantiated; it just sets up the generic class
* stuff, not anything related to a specific object instance.
*/
static void
sc_plugin_example_class_init (SCPluginExampleClass *req_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (req_class);
/* This actually creates and zeros the object's instance data struct */
g_type_class_add_private (req_class, sizeof (SCPluginExamplePrivate));
/* Override GObject base class methods with our custom implementations */
object_class->dispose = dispose;
object_class->get_property = get_property;
object_class->set_property = set_property;
/* Override various GObject properties that we need to change. Here we
* just tell GObject that we will be handling the get/set operations for
* these specific properties. They are actually defined by the
* NMSystemConfigInterface interface in nm-system-config-interface.c.
* What happens here is that we tell GObject that for a given property
* name (ie NM_SYSTEM_CONFIG_INTERFACE_NAME) we'll be using the enum value
* NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME locally in get_property() and
* set_property().
*/
g_object_class_override_property (object_class,
NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME,
NM_SYSTEM_CONFIG_INTERFACE_NAME);
g_object_class_override_property (object_class,
NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO,
NM_SYSTEM_CONFIG_INTERFACE_INFO);
g_object_class_override_property (object_class,
NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES,
NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES);
g_object_class_override_property (object_class,
NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME,
NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME);
}
static void
system_config_interface_init (NMSystemConfigInterface *sci_intf)
{
/* Interface implementation for NMSystemConfigInterface. This sets
* up the GInterface vtable that lets GObject know what functions to
* call for each method of the NMSystemConfigInterface interface.
*/
sci_intf->get_connections = get_connections;
sci_intf->add_connection = add_connection;
sci_intf->get_unmanaged_specs = get_unmanaged_specs;
}
/*******************************************************************/
/* Factory function: this is the first entry point for NetworkManager, which
* gets called during NM startup to create the instance of this plugin
* that NetworkManager will actually use. Since every plugin is a singleton
* we just return a singleton instance. This function should never be called
* twice.
*/
G_MODULE_EXPORT GObject *
nm_system_config_factory (void)
{
static SCPluginExample *singleton = NULL;
SCPluginExamplePrivate *priv;
if (!singleton) {
/* Instantiate our plugin */
singleton = SC_PLUGIN_EXAMPLE (g_object_new (SC_TYPE_PLUGIN_EXAMPLE, NULL));
priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (singleton);
/* Cache the config file path */
priv->conf_file = nm_config_data_get_config_main_file (nm_config_get_data (nm_config_get ()));
} else {
/* This function should never be called twice */
g_assert_not_reached ();
}
return G_OBJECT (singleton);
}

View file

@ -1,55 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager system settings service - example plugin
*
* 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2012 Red Hat, Inc.
*/
#ifndef _PLUGIN_H_
#define _PLUGIN_H_
#include <glib-object.h>
/* GObject boilerplate: you usually only need to rename 'example' here to
* your plugin's name. These functions get used when casting pointers
* to your plugin's object type.
*/
#define SC_TYPE_PLUGIN_EXAMPLE (sc_plugin_example_get_type ())
#define SC_PLUGIN_EXAMPLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SC_TYPE_PLUGIN_EXAMPLE, SCPluginExample))
#define SC_PLUGIN_EXAMPLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SC_TYPE_PLUGIN_EXAMPLE, SCPluginExampleClass))
#define SC_IS_PLUGIN_EXAMPLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SC_TYPE_PLUGIN_EXAMPLE))
#define SC_IS_PLUGIN_EXAMPLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SC_TYPE_PLUGIN_EXAMPLE))
#define SC_PLUGIN_EXAMPLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SC_TYPE_PLUGIN_EXAMPLE, SCPluginExampleClass))
typedef struct {
/* GObject instance structure for the plugin; we don't do anything special
* here so this object's instance is exactly the same as its parent.
*/
GObject parent;
} SCPluginExample;
typedef struct {
/* GObject class structure; we don't do anything special here
* so this object's class is exactly the same as its parent. Typically
* if the plugin implemented custom signals their prototypes would go
* here, but most plugins don't need to do this.
*/
GObjectClass parent;
} SCPluginExampleClass;
GType sc_plugin_example_get_type (void);
#endif /* _PLUGIN_H_ */

View file

@ -1,47 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager system settings service
*
* 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2012 Red Hat, Inc.
*/
#include "config.h"
#include <glib.h>
#include <nm-connection.h>
#include <nm-dbus-interface.h>
#include "common.h"
NMConnection *
connection_from_file (const char *filename, GError **error)
{
/* This function should, given a file path, read that file and convert its
* data into an NMConnection. There are two approaches to this. First,
* if the plugin data format is similar to the NMConnection internal
* format, you can get away with calling nm_connection_for_each_setting_value()
* to iterate through every possible setting's keys and read that value
* from the plugin's format. If the plugin's format is siginificantly
* different then you may have to build up the connection manually by
* determining the type of connection from the on-disk data, creating
* each setting object, adding the values, then adding that setting to
* the NMConnection.
*/
return NULL;
}

View file

@ -1,56 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager system settings service
*
* 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2012 Red Hat, Inc.
*/
#include "config.h"
#include <glib.h>
#include <nm-connection.h>
#include "common.h"
gboolean
write_connection (NMConnection *connection,
const char *existing_path,
char **out_path,
GError **error)
{
/* This function should take the NMConnection and convert it to the format
* which this plugin uses on-disk and then write out that data. It returns
* the file path of the file that represents this connection data so that
* the plugin can track it for change notification and updates. If
* 'existing_path' is given we can assume that this is an update of an
* existing connection and not a completely new one.
*/
/* There are two approaches to converting the data. The first more manual
* approach consists of grabbing each setting value from the NMConnection
* and converting it into the appropriate value for the plugin's data
* format. This is usually taken by distro plugins because their format
* is significantly different than NetworkManager's internal format.
* The second uses nm_connection_for_each_setting_value() to iterate
* through each value of each setting in the NMConnection, convert it to
* the required format, and write it out, but this requires that the
* plugin format more closely follow the NetworkManager internal format.
*/
return FALSE;
}

View file

@ -182,10 +182,6 @@ sc_plugin_ibft_class_init (SCPluginIbftClass *req_class)
g_object_class_override_property (object_class,
NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES,
NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES);
g_object_class_override_property (object_class,
NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME,
NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME);
}
static void

View file

@ -53,7 +53,6 @@
#include "NetworkManagerUtils.h"
#include "nm-ifcfg-connection.h"
#include "nm-inotify-helper.h"
#include "shvar.h"
#include "reader.h"
#include "writer.h"
@ -110,13 +109,7 @@ G_DEFINE_TYPE_EXTENDED (SCPluginIfcfg, sc_plugin_ifcfg, G_TYPE_OBJECT, 0,
typedef struct {
GHashTable *connections; /* uuid::connection */
gboolean initialized;
gulong ih_event_id;
int sc_network_wd;
GFileMonitor *hostname_monitor;
guint hostname_monitor_id;
char *hostname;
GFileMonitor *ifcfg_monitor;
guint ifcfg_monitor_id;
@ -707,139 +700,6 @@ add_connection (NMSystemConfigInterface *config,
return NM_SETTINGS_CONNECTION (update_connection (self, connection, path, NULL, FALSE, NULL, error));
}
#define SC_NETWORK_FILE "/etc/sysconfig/network"
#define HOSTNAME_FILE "/etc/hostname"
static char *
plugin_get_hostname (SCPluginIfcfg *plugin)
{
shvarFile *network;
char *hostname;
gboolean ignore_localhost;
if (g_file_get_contents (HOSTNAME_FILE, &hostname, NULL, NULL)) {
g_strchomp (hostname);
return hostname;
}
network = svOpenFile (SC_NETWORK_FILE, NULL);
if (!network) {
_LOGW ("Could not get hostname: failed to read " SC_NETWORK_FILE);
return NULL;
}
hostname = svGetValue (network, "HOSTNAME", FALSE);
ignore_localhost = svTrueValue (network, "NM_IGNORE_HOSTNAME_LOCALHOST", FALSE);
if (ignore_localhost) {
/* Ignore a default hostname ('localhost[6]' or 'localhost[6].localdomain[6]')
* to preserve 'network' service behavior.
*/
if (hostname && !nm_utils_is_specific_hostname (hostname)) {
g_free (hostname);
hostname = NULL;
}
}
svCloseFile (network);
return hostname;
}
static gboolean
plugin_set_hostname (SCPluginIfcfg *plugin, const char *hostname)
{
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
shvarFile *network;
char *hostname_eol;
gboolean ret;
#if HAVE_SELINUX
security_context_t se_ctx_prev = NULL, se_ctx = NULL;
struct stat file_stat = { .st_mode = 0 };
mode_t st_mode = 0;
/* Get default context for HOSTNAME_FILE and set it for fscreate */
if (stat (HOSTNAME_FILE, &file_stat) == 0)
st_mode = file_stat.st_mode;
matchpathcon (HOSTNAME_FILE, st_mode, &se_ctx);
matchpathcon_fini ();
getfscreatecon (&se_ctx_prev);
setfscreatecon (se_ctx);
#endif
hostname_eol = g_strdup_printf ("%s\n", hostname);
ret = g_file_set_contents (HOSTNAME_FILE, hostname_eol, -1, NULL);
#if HAVE_SELINUX
/* Restore previous context and cleanup */
setfscreatecon (se_ctx_prev);
freecon (se_ctx);
freecon (se_ctx_prev);
#endif
if (!ret) {
_LOGW ("Could not save hostname: failed to create/open " HOSTNAME_FILE);
g_free (hostname_eol);
return FALSE;
}
g_free (priv->hostname);
priv->hostname = g_strdup (hostname);
g_free (hostname_eol);
/* Remove "HOSTNAME" from SC_NETWORK_FILE, if present */
network = svOpenFile (SC_NETWORK_FILE, NULL);
if (network) {
svSetValue (network, "HOSTNAME", NULL, FALSE);
svWriteFile (network, 0644, NULL);
svCloseFile (network);
}
return TRUE;
}
static void
hostname_maybe_changed (SCPluginIfcfg *plugin)
{
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
char *new_hostname;
new_hostname = plugin_get_hostname (plugin);
if ( (new_hostname && !priv->hostname)
|| (!new_hostname && priv->hostname)
|| (priv->hostname && new_hostname && strcmp (priv->hostname, new_hostname))) {
g_free (priv->hostname);
priv->hostname = new_hostname;
g_object_notify (G_OBJECT (plugin), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME);
} else
g_free (new_hostname);
}
static void
sc_network_changed_cb (NMInotifyHelper *ih,
struct inotify_event *evt,
const char *path,
gpointer user_data)
{
SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (user_data);
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
if (evt->wd != priv->sc_network_wd)
return;
hostname_maybe_changed (plugin);
}
static void
hostname_changed_cb (GFileMonitor *monitor,
GFile *file,
GFile *other_file,
GFileMonitorEvent event_type,
gpointer user_data)
{
SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (user_data);
hostname_maybe_changed (plugin);
}
static gboolean
impl_ifcfgrh_get_ifcfg_details (SCPluginIfcfg *plugin,
const char *in_ifcfg,
@ -913,36 +773,11 @@ static void
sc_plugin_ifcfg_init (SCPluginIfcfg *plugin)
{
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
NMInotifyHelper *ih;
GError *error = NULL;
gboolean success = FALSE;
GFile *file;
GFileMonitor *monitor;
priv->connections = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
/* We watch SC_NETWORK_FILE via NMInotifyHelper (which doesn't track file creation but
* *does* track modifications made via other hard links), since we expect it to always
* exist. But we watch HOSTNAME_FILE via GFileMonitor (which has the opposite
* semantics), since /etc/hostname might not exist, but is unlikely to have hard
* links. bgo 532815 is the bug for being able to just use GFileMonitor for both.
*/
ih = nm_inotify_helper_get ();
priv->ih_event_id = g_signal_connect (ih, "event", G_CALLBACK (sc_network_changed_cb), plugin);
priv->sc_network_wd = nm_inotify_helper_add_watch (ih, SC_NETWORK_FILE);
file = g_file_new_for_path (HOSTNAME_FILE);
monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
g_object_unref (file);
if (monitor) {
priv->hostname_monitor_id =
g_signal_connect (monitor, "changed", G_CALLBACK (hostname_changed_cb), plugin);
priv->hostname_monitor = monitor;
}
priv->hostname = plugin_get_hostname (plugin);
priv->bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
if (!priv->bus) {
_LOGW ("Couldn't connect to D-Bus: %s", error->message);
@ -987,33 +822,12 @@ dispose (GObject *object)
{
SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (object);
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
NMInotifyHelper *ih;
if (priv->bus) {
dbus_g_connection_unref (priv->bus);
priv->bus = NULL;
}
if (priv->ih_event_id) {
ih = nm_inotify_helper_get ();
g_signal_handler_disconnect (ih, priv->ih_event_id);
priv->ih_event_id = 0;
if (priv->sc_network_wd >= 0)
nm_inotify_helper_remove_watch (ih, priv->sc_network_wd);
}
if (priv->hostname_monitor) {
if (priv->hostname_monitor_id)
g_signal_handler_disconnect (priv->hostname_monitor, priv->hostname_monitor_id);
g_file_monitor_cancel (priv->hostname_monitor);
g_object_unref (priv->hostname_monitor);
}
g_free (priv->hostname);
if (priv->connections) {
g_hash_table_destroy (priv->connections);
priv->connections = NULL;
@ -1034,8 +848,6 @@ static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (object);
switch (prop_id) {
case NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME:
g_value_set_string (value, IFCFG_PLUGIN_NAME);
@ -1044,10 +856,7 @@ get_property (GObject *object, guint prop_id,
g_value_set_string (value, IFCFG_PLUGIN_INFO);
break;
case NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES:
g_value_set_uint (value, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS | NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME);
break;
case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME:
g_value_set_string (value, priv->hostname);
g_value_set_uint (value, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -1059,15 +868,7 @@ static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
const char *hostname;
switch (prop_id) {
case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME:
hostname = g_value_get_string (value);
if (hostname && strlen (hostname) < 1)
hostname = NULL;
plugin_set_hostname (SC_PLUGIN_IFCFG (object), hostname);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -1097,10 +898,6 @@ sc_plugin_ifcfg_class_init (SCPluginIfcfgClass *req_class)
NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES,
NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES);
g_object_class_override_property (object_class,
NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME,
NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME);
dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (req_class),
&dbus_glib_nm_ifcfg_rh_object_info);
}

View file

@ -1,19 +0,0 @@
AM_CPPFLAGS = \
$(GLIB_CFLAGS) \
-I${top_srcdir}/src \
-I${top_srcdir}/src/settings \
-I$(top_srcdir)/include \
-I$(top_srcdir)/libnm-core \
-I$(top_builddir)/libnm-core \
-DG_LOG_DOMAIN=\""NetworkManager-ifcfg-suse"\" \
-DNETWORKMANAGER_COMPILATION \
-DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
-DSYSCONFDIR=\"$(sysconfdir)\"
pkglib_LTLIBRARIES = libnm-settings-plugin-ifcfg-suse.la
libnm_settings_plugin_ifcfg_suse_la_SOURCES = \
plugin.c \
plugin.h
libnm_settings_plugin_ifcfg_suse_la_LDFLAGS = -module -avoid-version

View file

@ -1,312 +0,0 @@
/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
/* NetworkManager system settings service
*
* Søren Sandmann <sandmann@daimi.au.dk>
*
* 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* (C) Copyright 2007 - 2011 Red Hat, Inc.
* (C) Copyright 2007 - 2008 Novell, Inc.
*/
#include "config.h"
#include <string.h>
#include <gmodule.h>
#include <glib-object.h>
#include <gio/gio.h>
#include "plugin.h"
#include "nm-system-config-interface.h"
#define IFCFG_PLUGIN_NAME "ifcfg-suse"
#define IFCFG_PLUGIN_INFO "(C) 2008 Novell, Inc. To report bugs please use the NetworkManager mailing list."
#define IFCFG_DIR SYSCONFDIR "/sysconfig/network"
#define CONF_DHCP IFCFG_DIR "/dhcp"
#define HOSTNAME_FILE "/etc/HOSTNAME"
static void system_config_interface_init (NMSystemConfigInterface *system_config_interface_class);
G_DEFINE_TYPE_EXTENDED (SCPluginIfcfg, sc_plugin_ifcfg, G_TYPE_OBJECT, 0,
G_IMPLEMENT_INTERFACE (NM_TYPE_SYSTEM_CONFIG_INTERFACE,
system_config_interface_init))
#define SC_PLUGIN_IFCFG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SC_TYPE_PLUGIN_IFCFG, SCPluginIfcfgPrivate))
#define IFCFG_FILE_PATH_TAG "ifcfg-file-path"
typedef struct {
GFileMonitor *hostname_monitor;
GFileMonitor *dhcp_monitor;
char *hostname;
} SCPluginIfcfgPrivate;
typedef void (*FileChangedFn) (gpointer user_data);
typedef struct {
FileChangedFn callback;
gpointer user_data;
} FileMonitorInfo;
static void
file_changed (GFileMonitor *monitor,
GFile *file,
GFile *other_file,
GFileMonitorEvent event_type,
gpointer user_data)
{
FileMonitorInfo *info;
switch (event_type) {
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
case G_FILE_MONITOR_EVENT_DELETED:
info = (FileMonitorInfo *) user_data;
info->callback (info->user_data);
break;
default:
break;
}
}
static GFileMonitor *
monitor_file_changes (const char *filename,
FileChangedFn callback,
gpointer user_data)
{
GFile *file;
GFileMonitor *monitor;
FileMonitorInfo *info;
file = g_file_new_for_path (filename);
monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
g_object_unref (file);
if (monitor) {
info = g_new0 (FileMonitorInfo, 1);
info->callback = callback;
info->user_data = user_data;
g_object_weak_ref (G_OBJECT (monitor), (GWeakNotify) g_free, info);
g_signal_connect (monitor, "changed", G_CALLBACK (file_changed), info);
}
return monitor;
}
static gboolean
hostname_is_dynamic (void)
{
GIOChannel *channel;
const char *pattern = "DHCLIENT_SET_HOSTNAME=";
char *str = NULL;
int pattern_len;
gboolean dynamic = FALSE;
channel = g_io_channel_new_file (CONF_DHCP, "r", NULL);
if (!channel)
return dynamic;
pattern_len = strlen (pattern);
while (g_io_channel_read_line (channel, &str, NULL, NULL, NULL) != G_IO_STATUS_EOF) {
if (!strncmp (str, pattern, pattern_len)) {
if (!strncmp (str + pattern_len, "\"yes\"", 5))
dynamic = TRUE;
break;
}
g_free (str);
}
g_io_channel_shutdown (channel, FALSE, NULL);
g_io_channel_unref (channel);
return dynamic;
}
static char *
hostname_read (void)
{
GIOChannel *channel;
char *hostname = NULL;
channel = g_io_channel_new_file (HOSTNAME_FILE, "r", NULL);
if (channel) {
g_io_channel_read_line (channel, &hostname, NULL, NULL, NULL);
g_io_channel_shutdown (channel, FALSE, NULL);
g_io_channel_unref (channel);
if (hostname)
hostname = g_strchomp (hostname);
}
return hostname;
}
static void
hostname_changed (gpointer data)
{
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (data);
g_free (priv->hostname);
if (hostname_is_dynamic ())
priv->hostname = NULL;
else
priv->hostname = hostname_read ();
g_object_notify (G_OBJECT (data), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME);
}
static void
plugin_set_hostname (SCPluginIfcfg *plugin, const char *hostname)
{
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
GIOChannel *channel;
channel = g_io_channel_new_file (HOSTNAME_FILE, "w", NULL);
if (channel) {
g_io_channel_write_chars (channel, hostname, -1, NULL, NULL);
g_io_channel_write_chars (channel, "\n", -1, NULL, NULL);
g_io_channel_shutdown (channel, TRUE, NULL);
g_io_channel_unref (channel);
}
g_free (priv->hostname);
priv->hostname = g_strdup (hostname);
}
static void
init (NMSystemConfigInterface *config)
{
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (config);
priv->hostname_monitor = monitor_file_changes (HOSTNAME_FILE, hostname_changed, config);
priv->dhcp_monitor = monitor_file_changes (CONF_DHCP, hostname_changed, config);
if (!hostname_is_dynamic ())
priv->hostname = hostname_read ();
}
static void
sc_plugin_ifcfg_init (SCPluginIfcfg *self)
{
}
static void
dispose (GObject *object)
{
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (object);
if (priv->dhcp_monitor)
g_object_unref (priv->dhcp_monitor);
if (priv->hostname_monitor)
g_object_unref (priv->hostname_monitor);
g_free (priv->hostname);
G_OBJECT_CLASS (sc_plugin_ifcfg_parent_class)->dispose (object);
}
static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
switch (prop_id) {
case NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME:
g_value_set_string (value, IFCFG_PLUGIN_NAME);
break;
case NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO:
g_value_set_string (value, IFCFG_PLUGIN_INFO);
break;
case NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES:
g_value_set_uint (value, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME);
break;
case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME:
g_value_set_string (value, SC_PLUGIN_IFCFG_GET_PRIVATE (object)->hostname);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
const char *hostname;
switch (prop_id) {
case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME:
hostname = g_value_get_string (value);
if (hostname && strlen (hostname) < 1)
hostname = NULL;
plugin_set_hostname (SC_PLUGIN_IFCFG (object), hostname);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
sc_plugin_ifcfg_class_init (SCPluginIfcfgClass *req_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (req_class);
g_type_class_add_private (req_class, sizeof (SCPluginIfcfgPrivate));
object_class->get_property = get_property;
object_class->set_property = set_property;
object_class->dispose = dispose;
g_object_class_override_property (object_class,
NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME,
NM_SYSTEM_CONFIG_INTERFACE_NAME);
g_object_class_override_property (object_class,
NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO,
NM_SYSTEM_CONFIG_INTERFACE_INFO);
g_object_class_override_property (object_class,
NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES,
NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES);
g_object_class_override_property (object_class,
NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME,
NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME);
}
static void
system_config_interface_init (NMSystemConfigInterface *system_config_interface_class)
{
/* interface implementation */
system_config_interface_class->init = init;
}
G_MODULE_EXPORT GObject *
nm_system_config_factory (void)
{
static SCPluginIfcfg *singleton = NULL;
if (!singleton)
singleton = SC_PLUGIN_IFCFG (g_object_new (SC_TYPE_PLUGIN_IFCFG, NULL));
else
g_object_ref (singleton);
return G_OBJECT (singleton);
}

View file

@ -1,50 +0,0 @@
/* NetworkManager system settings service
*
* Søren Sandmann <sandmann@daimi.au.dk>
*
* 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* (C) Copyright 2007 Red Hat, Inc.
*/
#ifndef _PLUGIN_H_
#define _PLUGIN_H_
#include <glib-object.h>
#define PLUGIN_NAME "ifcfg-suse"
#define SC_TYPE_PLUGIN_IFCFG (sc_plugin_ifcfg_get_type ())
#define SC_PLUGIN_IFCFG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SC_TYPE_PLUGIN_IFCFG, SCPluginIfcfg))
#define SC_PLUGIN_IFCFG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SC_TYPE_PLUGIN_IFCFG, SCPluginIfcfgClass))
#define SC_IS_PLUGIN_IFCFG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SC_TYPE_PLUGIN_IFCFG))
#define SC_IS_PLUGIN_IFCFG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SC_TYPE_PLUGIN_IFCFG))
#define SC_PLUGIN_IFCFG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SC_TYPE_PLUGIN_IFCFG, SCPluginIfcfgClass))
typedef struct _SCPluginIfcfg SCPluginIfcfg;
typedef struct _SCPluginIfcfgClass SCPluginIfcfgClass;
struct _SCPluginIfcfg {
GObject parent;
};
struct _SCPluginIfcfgClass {
GObjectClass parent;
};
GType sc_plugin_ifcfg_get_type (void);
#endif /* _PLUGIN_H_ */

View file

@ -136,47 +136,6 @@ reload_parsers (void)
return TRUE;
}
gchar *
read_hostname (const char *path)
{
gchar *contents = NULL, *result = NULL, *tmp;
gchar **all_lines = NULL;
guint line_num, i;
if (!g_file_get_contents (path, &contents, NULL, NULL))
return NULL;
all_lines = g_strsplit (contents, "\n", 0);
line_num = g_strv_length (all_lines);
for (i = 0; i < line_num; i++) {
g_strstrip (all_lines[i]);
if (all_lines[i][0] == '#' || all_lines[i][0] == '\0')
continue;
if (g_str_has_prefix (all_lines[i], "hostname")) {
tmp = strstr (all_lines[i], "=");
tmp++;
result = g_shell_unquote (tmp, NULL);
break;
}
}
g_strfreev (all_lines);
g_free (contents);
return result;
}
gboolean
write_hostname (const char *path, const gchar *hostname)
{
gboolean result;
char *contents;
contents = g_strdup_printf ("#Generated by NetworkManager\n"
"hostname=\"%s\"\n", hostname);
result = g_file_set_contents (path, contents, -1, NULL);
g_free (contents);
return result;
}
gboolean
is_static_ip4 (const char *conn_name)
{

View file

@ -37,8 +37,6 @@ typedef struct _ip_block {
struct _ip_block *next;
} ip_block;
gchar *read_hostname (const char *path);
gboolean write_hostname (const char *path, const char *hostname);
gboolean is_static_ip4 (const char *conn_name);
gboolean is_static_ip6 (const char *conn_name);
gboolean is_ip4_address (const char *in_address);

View file

@ -45,16 +45,13 @@
#define IFNET_PLUGIN_NAME_PRINT "ifnet"
#define IFNET_PLUGIN_INFO "(C) 1999-2010 Gentoo Foundation, Inc. To report bugs please use bugs.gentoo.org with [networkmanager] or [qiaomuf] prefix."
#define IFNET_SYSTEM_HOSTNAME_FILE "/etc/conf.d/hostname"
#define IFNET_MANAGE_WELL_KNOWN_DEFAULT TRUE
#define IFNET_KEY_FILE_KEY_MANAGED "managed"
typedef struct {
GHashTable *connections; /* uuid::connection */
gchar *hostname;
gboolean unmanaged_well_known;
GFileMonitor *hostname_monitor;
GFileMonitor *net_monitor;
GFileMonitor *wpa_monitor;
@ -81,42 +78,6 @@ ignore_cb(NMSettingsConnectionInterface * connection,
{
}
*/
static const char *
get_hostname (NMSystemConfigInterface * config)
{
return SC_PLUGIN_IFNET_GET_PRIVATE (config)->hostname;
}
static void
update_system_hostname (gpointer config)
{
SCPluginIfnetPrivate *priv = SC_PLUGIN_IFNET_GET_PRIVATE (config);
if (priv->hostname)
g_free (priv->hostname);
priv->hostname = read_hostname (IFNET_SYSTEM_HOSTNAME_FILE);
g_object_notify (G_OBJECT (config),
NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME);
nm_log_info (LOGD_SETTINGS, "Hostname updated to: %s", priv->hostname);
}
static void
write_system_hostname (NMSystemConfigInterface * config,
const gchar * newhostname)
{
SCPluginIfnetPrivate *priv = SC_PLUGIN_IFNET_GET_PRIVATE (config);
g_return_if_fail (newhostname);
nm_log_info (LOGD_SETTINGS, "Write system hostname: %s", newhostname);
if (write_hostname (IFNET_SYSTEM_HOSTNAME_FILE, newhostname)) {
g_free (priv->hostname);
priv->hostname = g_strdup (newhostname);
g_object_notify (G_OBJECT (config),
NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME);
} else
nm_log_warn (LOGD_SETTINGS, "Write system hostname: %s failed", newhostname);
}
static gboolean
is_managed_plugin (void)
@ -189,9 +150,6 @@ setup_monitors (NMIfnetConnection * connection, gpointer user_data)
SCPluginIfnet *self = SC_PLUGIN_IFNET (user_data);
SCPluginIfnetPrivate *priv = SC_PLUGIN_IFNET_GET_PRIVATE (self);
priv->hostname_monitor =
monitor_file_changes (IFNET_SYSTEM_HOSTNAME_FILE,
update_system_hostname, user_data);
if (nm_config_get_monitor_connection_files (nm_config_get ())) {
priv->net_monitor =
monitor_file_changes (CONF_NET_FILE, (FileChangedFn) reload_connections,
@ -208,10 +166,6 @@ cancel_monitors (NMIfnetConnection * connection, gpointer user_data)
SCPluginIfnet *self = SC_PLUGIN_IFNET (user_data);
SCPluginIfnetPrivate *priv = SC_PLUGIN_IFNET_GET_PRIVATE (self);
if (priv->hostname_monitor) {
g_file_monitor_cancel (priv->hostname_monitor);
g_object_unref (priv->hostname_monitor);
}
if (priv->net_monitor) {
g_file_monitor_cancel (priv->net_monitor);
g_object_unref (priv->net_monitor);
@ -444,7 +398,6 @@ init (NMSystemConfigInterface *config)
setup_monitors (NULL, config);
reload_connections (config);
update_system_hostname (self);
nm_log_info (LOGD_SETTINGS, "Initialzation complete!");
}
@ -490,8 +443,6 @@ static void
get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
NMSystemConfigInterface *self = NM_SYSTEM_CONFIG_INTERFACE (object);
switch (prop_id) {
case NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME:
g_value_set_string (value, IFNET_PLUGIN_NAME_PRINT);
@ -501,12 +452,7 @@ get_property (GObject * object, guint prop_id, GValue * value,
break;
case NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES:
g_value_set_uint (value,
NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS
|
NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME);
break;
case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME:
g_value_set_string (value, get_hostname (self));
NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -519,15 +465,6 @@ set_property (GObject * object, guint prop_id, const GValue * value,
GParamSpec * pspec)
{
switch (prop_id) {
case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME:{
const gchar *hostname = g_value_get_string (value);
if (hostname && strlen (hostname) < 1)
hostname = NULL;
write_system_hostname (NM_SYSTEM_CONFIG_INTERFACE
(object), hostname);
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -546,9 +483,6 @@ dispose (GObject * object)
priv->connections = NULL;
}
g_free (priv->hostname);
priv->hostname = NULL;
ifnet_destroy ();
wpa_parser_destroy ();
G_OBJECT_CLASS (sc_plugin_ifnet_parent_class)->dispose (object);
@ -576,10 +510,6 @@ sc_plugin_ifnet_class_init (SCPluginIfnetClass * req_class)
g_object_class_override_property (object_class,
NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES,
NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES);
g_object_class_override_property (object_class,
NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME,
NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME);
}
G_MODULE_EXPORT GObject *

View file

@ -40,7 +40,6 @@ TESTS = test-ifnet
endif
EXTRA_DIST = \
hostname \
net \
net.all \
nm-system-settings.conf \

View file

@ -1,2 +0,0 @@
#Generated by NetworkManager
hostname="gentoo"

View file

@ -69,32 +69,6 @@ test_getdata (void)
strcmp ("!wpa_supplicant", ifnet_get_global_data ("modules")) == 0);
}
static void
test_read_hostname (void)
{
char *hostname;
hostname = read_hostname (TEST_IFNET_DIR "/hostname");
g_assert_cmpstr (hostname, ==, "gentoo");
g_free (hostname);
}
static void
test_write_hostname (void)
{
char *hostname_path = TEST_SCRATCH_DIR "/hostname-test";
char *hostname;
write_hostname (hostname_path, "gentoo-nm");
hostname = read_hostname (hostname_path);
g_assert_cmpstr (hostname, ==, "gentoo-nm");
g_free (hostname);
unlink (hostname_path);
}
static void
test_is_static (void)
{
@ -404,8 +378,6 @@ main (int argc, char **argv)
g_test_add_func (TPATH "has-ip6-address", test_has_ip6_address);
g_test_add_func (TPATH "has-default-route", test_has_default_route);
g_test_add_func (TPATH "get-data", test_getdata);
g_test_add_func (TPATH "read-hostname", test_read_hostname);
g_test_add_func (TPATH "write-hostname", test_write_hostname);
g_test_add_func (TPATH "is-ip4-address", test_is_ip4_address);
g_test_add_func (TPATH "is-ip6-address", test_is_ip6_address);
g_test_add_func (TPATH "convert-ip4-config", test_convert_ipv4_config_block);

View file

@ -25,8 +25,6 @@
#include "config.h"
#include <string.h>
#include <sys/inotify.h>
#include <gmodule.h>
#include <glib-object.h>
@ -48,7 +46,6 @@
#include "nm-ifupdown-connection.h"
#include "plugin.h"
#include "parser.h"
#include "nm-inotify-helper.h"
#include "nm-logging.h"
#include "nm-config.h"
@ -61,7 +58,6 @@
#define IFUPDOWN_PLUGIN_NAME "ifupdown"
#define IFUPDOWN_PLUGIN_INFO "(C) 2008 Canonical Ltd. To report bugs please use the NetworkManager mailing list."
#define IFUPDOWN_SYSTEM_HOSTNAME_FILE "/etc/hostname"
#define IFUPDOWN_KEY_FILE_GROUP "ifupdown"
#define IFUPDOWN_KEY_FILE_KEY_MANAGED "managed"
@ -76,7 +72,6 @@ typedef struct {
GUdevClient *client;
GHashTable *connections; /* /e/n/i block name :: NMIfupdownConnection */
gchar* hostname;
/* Stores all blocks/interfaces read from /e/n/i regardless of whether
* there is an NMIfupdownConnection for block.
@ -87,9 +82,6 @@ typedef struct {
GHashTable *kernel_ifaces;
gboolean unmanage_well_known;
gulong inotify_event_id;
int inotify_system_hostname_wd;
} SCPluginIfupdownPrivate;
static void
@ -134,18 +126,6 @@ GObject__set_property (GObject *object, guint prop_id,
static void
GObject__dispose (GObject *object);
/* other helpers */
static const char *
get_hostname (NMSystemConfigInterface *config);
static void
update_system_hostname(NMInotifyHelper *inotify_helper,
struct inotify_event *evt,
const char *path,
NMSystemConfigInterface *config);
static void
system_config_interface_init (NMSystemConfigInterface *system_config_interface_class)
{
@ -176,10 +156,6 @@ sc_plugin_ifupdown_class_init (SCPluginIfupdownClass *req_class)
g_object_class_override_property (object_class,
NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES,
NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES);
g_object_class_override_property (object_class,
NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME,
NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME);
}
static void
@ -326,7 +302,6 @@ SCPluginIfupdown_init (NMSystemConfigInterface *config)
SCPluginIfupdownPrivate *priv = SC_PLUGIN_IFUPDOWN_GET_PRIVATE (self);
GHashTable *auto_ifaces;
if_block *block = NULL;
NMInotifyHelper *inotify_helper;
char *value;
GError *error = NULL;
GList *keys, *iter;
@ -355,17 +330,6 @@ SCPluginIfupdown_init (NMSystemConfigInterface *config)
g_signal_connect (priv->client, "uevent", G_CALLBACK (handle_uevent), self);
priv->unmanage_well_known = IFUPDOWN_UNMANAGE_WELL_KNOWN_DEFAULT;
inotify_helper = nm_inotify_helper_get ();
priv->inotify_event_id = g_signal_connect (inotify_helper,
"event",
G_CALLBACK (update_system_hostname),
config);
priv->inotify_system_hostname_wd =
nm_inotify_helper_add_watch (inotify_helper, IFUPDOWN_SYSTEM_HOSTNAME_FILE);
update_system_hostname (inotify_helper, NULL, NULL, config);
/* Read in all the interfaces */
ifparser_init (ENI_INTERFACES_FILE, 0);
@ -553,76 +517,6 @@ SCPluginIfupdown_get_unmanaged_specs (NMSystemConfigInterface *config)
return specs;
}
static const char *
get_hostname (NMSystemConfigInterface *config)
{
SCPluginIfupdownPrivate *priv = SC_PLUGIN_IFUPDOWN_GET_PRIVATE (config);
return priv->hostname;
}
static void
update_system_hostname(NMInotifyHelper *inotify_helper,
struct inotify_event *evt,
const char *path,
NMSystemConfigInterface *config)
{
SCPluginIfupdownPrivate *priv = SC_PLUGIN_IFUPDOWN_GET_PRIVATE (config);
gchar *hostname_file = NULL;
gsize hostname_file_len = 0;
GError *error = NULL;
nm_log_info (LOGD_SETTINGS, "update_system_hostname");
if (evt && evt->wd != priv->inotify_system_hostname_wd)
return;
if(!g_file_get_contents ( IFUPDOWN_SYSTEM_HOSTNAME_FILE,
&hostname_file,
&hostname_file_len,
&error)) {
nm_log_warn (LOGD_SETTINGS, "update_system_hostname() - couldn't read "
IFUPDOWN_SYSTEM_HOSTNAME_FILE " (%d/%s)",
error->code, error->message);
return;
}
g_free(priv->hostname);
priv->hostname = g_strstrip(hostname_file);
/* We shouldn't return a zero-length hostname, but NULL */
if (priv->hostname && !strlen (priv->hostname)) {
g_free (priv->hostname);
priv->hostname = NULL;
}
g_object_notify (G_OBJECT (config), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME);
}
static void
write_system_hostname(NMSystemConfigInterface *config,
const char *newhostname)
{
GError *error = NULL;
SCPluginIfupdownPrivate *priv = SC_PLUGIN_IFUPDOWN_GET_PRIVATE (config);
nm_log_info (LOGD_SETTINGS, "write_system_hostname: %s", newhostname);
g_return_if_fail (newhostname);
if(!g_file_set_contents ( IFUPDOWN_SYSTEM_HOSTNAME_FILE,
newhostname,
-1,
&error)) {
nm_log_warn (LOGD_SETTINGS, "update_system_hostname() - couldn't write hostname (%s) to "
IFUPDOWN_SYSTEM_HOSTNAME_FILE " (%d/%s)",
newhostname, error->code, error->message);
} else {
priv->hostname = g_strdup (newhostname);
}
g_object_notify (G_OBJECT (config), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME);
}
static void
sc_plugin_ifupdown_init (SCPluginIfupdown *plugin)
{
@ -632,8 +526,6 @@ static void
GObject__get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
NMSystemConfigInterface *self = NM_SYSTEM_CONFIG_INTERFACE (object);
switch (prop_id) {
case NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME:
g_value_set_string (value, IFUPDOWN_PLUGIN_NAME);
@ -642,13 +534,8 @@ GObject__get_property (GObject *object, guint prop_id,
g_value_set_string (value, IFUPDOWN_PLUGIN_INFO);
break;
case NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES:
g_value_set_uint (value, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME);
g_value_set_uint (value, NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE);
break;
case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME:
{
g_value_set_string (value, get_hostname(self));
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -660,15 +547,6 @@ GObject__set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
switch (prop_id) {
case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME:
{
const gchar *hostname = g_value_get_string (value);
if (hostname && strlen (hostname) < 1)
hostname = NULL;
write_system_hostname(NM_SYSTEM_CONFIG_INTERFACE(object),
hostname);
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -680,12 +558,6 @@ GObject__dispose (GObject *object)
{
SCPluginIfupdown *plugin = SC_PLUGIN_IFUPDOWN (object);
SCPluginIfupdownPrivate *priv = SC_PLUGIN_IFUPDOWN_GET_PRIVATE (plugin);
NMInotifyHelper *inotify_helper = nm_inotify_helper_get ();
g_signal_handler_disconnect (inotify_helper, priv->inotify_event_id);
if (priv->inotify_system_hostname_wd >= 0)
nm_inotify_helper_remove_watch (inotify_helper, priv->inotify_system_hostname_wd);
if (priv->kernel_ifaces)
g_hash_table_destroy(priv->kernel_ifaces);

View file

@ -47,7 +47,6 @@
#include "utils.h"
#include "gsystem-local-alloc.h"
static char *plugin_get_hostname (SCPluginKeyfile *plugin);
static void system_config_interface_init (NMSystemConfigInterface *system_config_interface_class);
G_DEFINE_TYPE_EXTENDED (SCPluginKeyfile, sc_plugin_keyfile, G_TYPE_OBJECT, 0,
@ -63,13 +62,7 @@ typedef struct {
GFileMonitor *monitor;
guint monitor_id;
const char *conf_file;
GFileMonitor *conf_file_monitor;
guint conf_file_monitor_id;
char *hostname;
gboolean disposed;
NMConfig *config;
} SCPluginKeyfilePrivate;
static void
@ -322,40 +315,19 @@ dir_changed (GFileMonitor *monitor,
}
static void
conf_file_changed (GFileMonitor *monitor,
GFile *file,
GFile *other_file,
GFileMonitorEvent event_type,
gpointer data)
config_changed_cb (NMConfig *config,
NMConfigData *config_data,
NMConfigChangeFlags changes,
NMConfigData *old_data,
SCPluginKeyfile *self)
{
SCPluginKeyfile *self = SC_PLUGIN_KEYFILE (data);
SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (self);
char *tmp;
gs_free char *old_value = NULL, *new_value = NULL;
switch (event_type) {
case G_FILE_MONITOR_EVENT_DELETED:
case G_FILE_MONITOR_EVENT_CREATED:
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
old_value = nm_config_data_get_value (old_data, "keyfile", "unmanaged-devices", NULL);
new_value = nm_config_data_get_value (config_data, "keyfile", "unmanaged-devices", NULL);
if (g_strcmp0 (old_value, new_value) != 0)
g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED);
/* hostname */
tmp = plugin_get_hostname (self);
if ((tmp && !priv->hostname)
|| (!tmp && priv->hostname)
|| (priv->hostname && tmp && strcmp (priv->hostname, tmp))) {
g_free (priv->hostname);
priv->hostname = tmp;
tmp = NULL;
g_object_notify (G_OBJECT (self), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME);
}
g_free (tmp);
break;
default:
break;
}
}
static void
@ -376,16 +348,10 @@ setup_monitoring (NMSystemConfigInterface *config)
}
}
if (priv->conf_file) {
file = g_file_new_for_path (priv->conf_file);
monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
g_object_unref (file);
if (monitor) {
priv->conf_file_monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (conf_file_changed), config);
priv->conf_file_monitor = monitor;
}
}
g_signal_connect (G_OBJECT (priv->config),
NM_CONFIG_SIGNAL_CONFIG_CHANGED,
G_CALLBACK (config_changed_cb),
config);
}
static GHashTable *
@ -554,128 +520,14 @@ add_connection (NMSystemConfigInterface *config,
return NM_SETTINGS_CONNECTION (update_connection (self, connection, path, NULL, FALSE, NULL, error));
}
static gboolean
parse_key_file_allow_none (SCPluginKeyfilePrivate *priv,
GKeyFile *key_file,
GError **error)
{
gboolean ret = FALSE;
GError *local_error = NULL;
if (!g_key_file_load_from_file (key_file, priv->conf_file, G_KEY_FILE_NONE, &local_error)) {
if (g_error_matches (local_error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
g_clear_error (&local_error);
else {
g_propagate_prefixed_error (error, local_error,
"Error parsing file '%s': ",
priv->conf_file);
goto out;
}
}
ret = TRUE;
out:
return ret;
}
static GSList *
get_unmanaged_specs (NMSystemConfigInterface *config)
{
SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (config);
GKeyFile *key_file;
GSList *specs = NULL;
GError *error = NULL;
gs_free char *value = NULL;
if (!priv->conf_file)
return NULL;
key_file = nm_config_create_keyfile ();
if (parse_key_file_allow_none (priv, key_file, &error))
specs = nm_config_get_device_match_spec (key_file, "keyfile", "unmanaged-devices");
if (error) {
nm_log_warn (LOGD_SETTINGS, "keyfile: error getting unmanaged specs: %s", error->message);
g_error_free (error);
}
g_key_file_free (key_file);
return specs;
}
static char *
plugin_get_hostname (SCPluginKeyfile *plugin)
{
SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (plugin);
GKeyFile *key_file;
char *hostname = NULL;
GError *error = NULL;
if (!priv->conf_file)
return NULL;
key_file = g_key_file_new ();
if (!parse_key_file_allow_none (priv, key_file, &error))
goto out;
hostname = g_key_file_get_value (key_file, "keyfile", "hostname", NULL);
out:
if (error) {
nm_log_warn (LOGD_SETTINGS, "keyfile: error getting hostname: %s", error->message);
g_error_free (error);
}
if (key_file)
g_key_file_free (key_file);
return hostname;
}
static gboolean
plugin_set_hostname (SCPluginKeyfile *plugin, const char *hostname)
{
gboolean ret = FALSE;
SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (plugin);
GKeyFile *key_file = NULL;
GError *error = NULL;
char *data = NULL;
gsize len;
if (!priv->conf_file) {
g_set_error (&error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Error saving hostname: no config file");
goto out;
}
g_free (priv->hostname);
priv->hostname = g_strdup (hostname);
key_file = g_key_file_new ();
if (!parse_key_file_allow_none (priv, key_file, &error))
goto out;
g_key_file_set_string (key_file, "keyfile", "hostname", hostname);
data = g_key_file_to_data (key_file, &len, &error);
if (!data)
goto out;
if (!g_file_set_contents (priv->conf_file, data, len, &error)) {
g_prefix_error (&error, "Error saving hostname: ");
goto out;
}
ret = TRUE;
out:
if (error) {
nm_log_warn (LOGD_SETTINGS, "keyfile: error setting hostname: %s", error->message);
g_error_free (error);
}
g_free (data);
if (key_file)
g_key_file_free (key_file);
return ret;
value = nm_config_data_get_value (nm_config_get_data (priv->config), "keyfile", "unmanaged-devices", NULL);
return nm_match_spec_split (value);
}
/* GObject */
@ -700,11 +552,7 @@ get_property (GObject *object, guint prop_id,
g_value_set_string (value, KEYFILE_PLUGIN_INFO);
break;
case NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES:
g_value_set_uint (value, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS |
NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME);
break;
case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME:
g_value_set_string (value, SC_PLUGIN_KEYFILE_GET_PRIVATE (object)->hostname);
g_value_set_uint (value, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -716,15 +564,7 @@ static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
const char *hostname;
switch (prop_id) {
case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME:
hostname = g_value_get_string (value);
if (hostname && strlen (hostname) < 1)
hostname = NULL;
plugin_set_hostname (SC_PLUGIN_KEYFILE (object), hostname);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -736,35 +576,26 @@ dispose (GObject *object)
{
SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (object);
if (priv->disposed)
goto out;
priv->disposed = TRUE;
if (priv->monitor) {
if (priv->monitor_id)
if (priv->monitor_id) {
g_signal_handler_disconnect (priv->monitor, priv->monitor_id);
priv->monitor_id = 0;
}
g_file_monitor_cancel (priv->monitor);
g_object_unref (priv->monitor);
g_clear_object (&priv->monitor);
}
if (priv->conf_file_monitor) {
if (priv->conf_file_monitor_id)
g_signal_handler_disconnect (priv->conf_file_monitor, priv->conf_file_monitor_id);
g_file_monitor_cancel (priv->conf_file_monitor);
g_object_unref (priv->conf_file_monitor);
}
g_free (priv->hostname);
if (priv->connections) {
g_hash_table_destroy (priv->connections);
priv->connections = NULL;
}
out:
if (priv->config) {
g_signal_handlers_disconnect_by_func (priv->config, config_changed_cb, object);
g_clear_object (&priv->config);
}
G_OBJECT_CLASS (sc_plugin_keyfile_parent_class)->dispose (object);
}
@ -790,10 +621,6 @@ sc_plugin_keyfile_class_init (SCPluginKeyfileClass *req_class)
g_object_class_override_property (object_class,
NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES,
NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES);
g_object_class_override_property (object_class,
NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME,
NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME);
}
static void
@ -812,15 +639,19 @@ nm_settings_keyfile_plugin_new (void)
{
static SCPluginKeyfile *singleton = NULL;
SCPluginKeyfilePrivate *priv;
char *value;
if (!singleton) {
singleton = SC_PLUGIN_KEYFILE (g_object_new (SC_TYPE_PLUGIN_KEYFILE, NULL));
priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (singleton);
priv->conf_file = nm_config_data_get_config_main_file (nm_config_get_data (nm_config_get ()));
/* plugin_set_hostname() has to be called *after* priv->conf_file is set */
priv->hostname = plugin_get_hostname (singleton);
priv->config = g_object_ref (nm_config_get ());
value = nm_config_data_get_value (nm_config_get_data (priv->config),
"keyfile", "hostname", NULL);
if (value) {
nm_log_warn (LOGD_SETTINGS, "keyfile: 'hostname' option is deprecated and has no effect");
g_free (value);
}
} else
g_object_ref (singleton);