config: merge branch 'th/nm-config-intern-bgo750558'

Add write support to NMConfig.

Also, add a new configuration directory /usr/lib/NetworkManager/conf.d/
which allows us to install configuration snippets under /usr, instead
of /etc.

https://bugzilla.gnome.org/show_bug.cgi?id=738853
https://bugzilla.gnome.org/show_bug.cgi?id=750558
This commit is contained in:
Thomas Haller 2015-07-02 16:02:36 +02:00
commit 05db3ee08a
14 changed files with 1503 additions and 188 deletions

View file

@ -78,6 +78,7 @@ AC_SUBST(runstatedir)
# NetworkManager paths
AC_SUBST(nmbinary, "$sbindir/$PACKAGE", [NetworkManager binary executable])
AC_SUBST(nmconfdir, "$sysconfdir/$PACKAGE", [NetworkManager configuration directory])
AC_SUBST(nmlibdir, "$libdir/$PACKAGE", [NetworkManager library directory])
AC_SUBST(nmdatadir, "$datadir/$PACKAGE", [NetworkManager shared data directory])
AC_SUBST(nmstatedir, "$localstatedir/lib/$PACKAGE", [NetworkManager persistent state directory])
AC_SUBST(nmrundir, "$runstatedir/$PACKAGE", [NetworkManager runtime state directory])
@ -125,6 +126,11 @@ test "$enable_ifnet" = "yes" && distro_plugins="$distro_plugins,ifn
distro_plugins="${distro_plugins#,}"
AC_DEFINE_UNQUOTED(CONFIG_PLUGINS_DEFAULT, "$config_plugins_default", [Default configuration option for main.plugins setting])
if test "${enable_config_plugin_ibft}" = yes; then
AC_DEFINE(WITH_SETTINGS_PLUGIN_IBFT, 1, [Whether compilation of ibft setting plugin is enabled])
else
AC_DEFINE(WITH_SETTINGS_PLUGIN_IBFT, 0, [Whether compilation of ibft setting plugin is enabled])
fi
if test "$enable_ifcfg_rh" = "yes"; then
DISTRO_NETWORK_SERVICE=network.service
@ -1065,6 +1071,7 @@ echo " exec_prefix: $exec_prefix"
echo " systemdunitdir: $with_systemdsystemunitdir"
echo " nmbinary: $nmbinary"
echo " nmconfdir: $nmconfdir"
echo " nmlibdir: $nmlibdir"
echo " nmdatadir: $nmdatadir"
echo " nmstatedir: $nmstatedir"
echo " nmrundir: $nmrundir"

View file

@ -2,14 +2,24 @@
#
# See "man 5 NetworkManager.conf" for details.
#
# The directory /usr/lib/NetworkManager/conf.d/ can contain additional configuration
# snippets installed by packages. These files are read before NetworkManager.conf
# and have thus lowest priority.
# The directory /etc/NetworkManager/conf.d/ can contain additional configuration
# snippets that are installed by some packages. Those snippets override the
# settings from this main file.
# To override a configuration from a conf.d/ snippet, add another configuration
# with a name sorted lastly (such as 99-my.conf).
# snippets. Those snippets override the settings from this main file.
#
# The files within one conf.d/ directory are read in asciibetical order.
#
# If /etc/NetworkManager/conf.d/ contains a file with the same name as
# /usr/lib/NetworkManager/conf.d/, the latter file is shadowed and thus ignored.
# Hence, to disable loading a file from /usr/lib/NetworkManager/conf.d/ you can
# put an empty file with the same name.
#
# If two files define the same key, the one that is read afterwards will overwrite
# the previous one.
[main]
plugins=ifcfg-rh,ibft
#plugins=ifcfg-rh,ibft
[logging]
#level=DEBUG

View file

@ -34,6 +34,7 @@
%define systemd_dir %{_prefix}/lib/systemd/system
%define udev_dir %{_prefix}/lib/udev
%define nmlibdir %{_prefix}/lib/%{name}
%global with_adsl 1
%global with_bluetooth 1
@ -83,8 +84,7 @@ URL: http://www.gnome.org/projects/NetworkManager/
Source: __SOURCE1__
Source1: NetworkManager.conf
Source2: 00-server.conf
Source3: 10-ibft-plugin.conf
Source4: 20-connectivity-fedora.conf
Source3: 20-connectivity-fedora.conf
#Patch1: 0001-some.patch
@ -443,9 +443,9 @@ make install DESTDIR=$RPM_BUILD_ROOT
%{__cp} %{SOURCE1} $RPM_BUILD_ROOT%{_sysconfdir}/%{name}/
mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/%{name}/conf.d
%{__cp} %{SOURCE2} $RPM_BUILD_ROOT%{_sysconfdir}/%{name}/conf.d
%{__cp} %{SOURCE3} $RPM_BUILD_ROOT%{_sysconfdir}/%{name}/conf.d
%{__cp} %{SOURCE4} $RPM_BUILD_ROOT%{_sysconfdir}/%{name}/conf.d
mkdir -p $RPM_BUILD_ROOT%{nmlibdir}/conf.d
%{__cp} %{SOURCE2} $RPM_BUILD_ROOT%{nmlibdir}/conf.d/
%{__cp} %{SOURCE3} $RPM_BUILD_ROOT%{nmlibdir}/conf.d/
# create a VPN directory
%{__mkdir_p} $RPM_BUILD_ROOT%{_sysconfdir}/NetworkManager/VPN
@ -543,7 +543,8 @@ fi
%endif
%dir %{_sysconfdir}/%{name}
%dir %{_sysconfdir}/%{name}/conf.d
%config %{_sysconfdir}/%{name}/conf.d/10-ibft-plugin.conf
%dir %{nmlibdir}
%dir %{nmlibdir}/conf.d
%{_mandir}/man1/*
%{_mandir}/man5/*
%{_mandir}/man8/*
@ -660,15 +661,15 @@ fi
%files config-connectivity-fedora
%defattr(-,root,root,0755)
%dir %{_sysconfdir}/%{name}
%dir %{_sysconfdir}/%{name}/conf.d
%config(noreplace) %{_sysconfdir}/%{name}/conf.d/20-connectivity-fedora.conf
%dir %{nmlibdir}
%dir %{nmlibdir}/conf.d
%{nmlibdir}/conf.d/20-connectivity-fedora.conf
%files config-server
%defattr(-,root,root,0755)
%dir %{_sysconfdir}/%{name}
%dir %{_sysconfdir}/%{name}/conf.d
%config(noreplace) %{_sysconfdir}/%{name}/conf.d/00-server.conf
%dir %{nmlibdir}
%dir %{nmlibdir}/conf.d
%{nmlibdir}/conf.d/00-server.conf
%if 0%{?with_nmtui}
%files tui

View file

@ -73,7 +73,6 @@ SOURCE="$(abs_path "$SOURCE" "$(ls -1 "$GITDIR/NetworkManager-$VERSION"*.tar* 2>
[[ -f "$SOURCE" ]] || die "could not find source ${_SOURCE:-$GITDIR/NetworkManager-$VERSION*.tar*} . Did you execute \`make dist\`? Otherwise set \$SOURCE variable"
SOURCE_NETWORKMANAGER_CONF="$(abs_path "$SOURCE_NETWORKMANAGER_CONF" "$SCRIPTDIR/NetworkManager.conf")"
SOURCE_CONFIG_SERVER="$(abs_path "$SOURCE_CONFIG_SERVER" "$SCRIPTDIR/00-server.conf")"
SOURCE_CONFIG_IBFT_PLUGIN="$(abs_path "$SOURCE_CONFIG_IBFT_PLUGIN" "$SCRIPTDIR/10-ibft-plugin.conf")"
SOURCE_CONFIG_CONNECTIVITY_FEDORA="$(abs_path "$SOURCE_CONFIG_CONNECTIVITY_FEDORA" "$SCRIPTDIR/20-connectivity-fedora.conf")"
TEMP="$(mktemp -d "$SCRIPTDIR/NetworkManager.$DATE.XXXXXX")"
@ -88,7 +87,6 @@ LOG "SPECFILE=$SPECFILE"
LOG "SOURCE=$SOURCE"
LOG "SOURCE_NETWORKMANAGER_CONF=$SOURCE_NETWORKMANAGER_CONF"
LOG "SOURCE_CONFIG_SERVER=$SOURCE_CONFIG_SERVER"
LOG "SOURCE_CONFIG_IBFT_PLUGIN=$SOURCE_CONFIG_IBFT_PLUGIN"
LOG "SOURCE_CONFIG_CONNECTIVITY_FEDORA=$SOURCE_CONFIG_CONNECTIVITY_FEDORA"
LOG "BASEDIR=$TEMP"
@ -102,7 +100,6 @@ mkdir -p "$TEMP/SOURCES/" "$TEMP/SPECS/" || die "error creating SPECS directoy"
cp "$SOURCE" "$TEMP/SOURCES/" || die "Could not copy source $SOURCE to $TEMP/SOURCES"
cp "$SOURCE_NETWORKMANAGER_CONF" "$TEMP/SOURCES/NetworkManager.conf" || die "Could not copy source $SOURCE_NETWORKMANAGER_CONF to $TEMP/SOURCES"
cp "$SOURCE_CONFIG_SERVER" "$TEMP/SOURCES/00-server.conf" || die "Could not copy source $SOURCE_CONFIG_SERVER to $TEMP/SOURCES"
cp "$SOURCE_CONFIG_IBFT_PLUGIN" "$TEMP/SOURCES/10-ibft-plugin.conf" || die "Could not copy source $SOURCE_CONFIG_IBFT_PLUGIN to $TEMP/SOURCES"
cp "$SOURCE_CONFIG_CONNECTIVITY_FEDORA" "$TEMP/SOURCES/20-connectivity-fedora.conf" || die "Could not copy source $SOURCE_CONFIG_CONNECTIVITY_FEDORA to $TEMP/SOURCES"
write_changelog

View file

@ -27,23 +27,39 @@ Copyright 2010 - 2014 Red Hat, Inc.
<refsynopsisdiv>
<para><filename>/etc/NetworkManager/NetworkManager.conf</filename>,
<filename>/etc/NetworkManager/conf.d/<replaceable>name</replaceable>.conf</filename>
<filename>/etc/NetworkManager/conf.d/<replaceable>name</replaceable>.conf</filename>,
<filename>/usr/lib/NetworkManager/conf.d/<replaceable>name</replaceable>.conf</filename>,
<filename>/var/lib/NetworkManager/NetworkManager-intern.conf</filename>
</para>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>This is a configuration file for NetworkManager. It is used
<para><literal>NetworkManager.conf</literal> is the configuration file for NetworkManager. It is used
to set up various aspects of NetworkManager's behavior. The
location of the file may be changed through use of the
<option>--config</option> argument for NetworkManager.
location of the main file and configuration directories may be changed
through use of the <option>--config</option>, <option>--config-dir</option>,
<option>--system-config-dir</option>, and <option>--intern-config</option>
argument for NetworkManager, respectively.
</para>
<para>If a default <literal>NetworkManager.conf</literal> is
provided by your distribution's packages, you should not modify
it, since your changes may get overwritten by package
updates. Instead, you can add additional <literal>.conf</literal>
files to the <literal>conf.d</literal> directory. These will be read in order,
with later files overriding earlier ones.
files to the <literal>/etc/NetworkManager/conf.d</literal> directory.
These will be read in order, with later files overriding earlier ones.
Packages might install further configuration snippets to <literal>/usr/lib/NetworkManager/conf.d</literal>.
This directory is parsed first, even before <literal>NetworkManager.conf</literal>.
The loading of a file <literal>/usr/lib/NetworkManager/conf.d/<replaceable>name</replaceable>.conf</literal>
can be prevented by adding a file <literal>/etc/NetworkManager/conf.d/<replaceable>name</replaceable>.conf</literal>.
In this case, the file from the etc configuration shadows the file from the
system configuration directory.
</para>
<para>
NetworkManager can overwrite certain user configuration options via D-Bus or other internal
operations. In this case it writes those changes to <literal>/var/lib/NetworkManager/NetworkManager-intern.conf</literal>.
This file is not intended to be modified by the user, but it is read last and can shadow
user configuration from <literal>NetworkManager.conf</literal>.
</para>
</refsect1>
@ -625,6 +641,9 @@ ipv6.ip6-privacy=1
<filename>/etc/sysconfig/network-scripts/ifcfg-*</filename>
files. It currently supports reading Ethernet, Wi-Fi,
InfiniBand, VLAN, Bond, Bridge, and Team connections.
Enabling <literal>ifcfg-rh</literal> implicitly enables
<literal>ibft</literal> plugin, if it is available.
This can be disabled by adding <literal>no-ibft</literal>.
</para>
</listitem>
</varlistentry>
@ -658,12 +677,16 @@ ipv6.ip6-privacy=1
</varlistentry>
<varlistentry>
<term><varname>ibft</varname></term>
<term><varname>ibft</varname>, <varname>no-ibft</varname></term>
<listitem>
<para>
This plugin allows to read iBFT configuration (iSCSI Boot Firmware Table).
The configuration is read using /sbin/iscsiadm. Users are expected to
configure iBFT connections via the firmware interfaces.
If ibft support is available, it is automatically enabled after
<literal>ifcfg-rh</literal>. This can be disabled by <literal>no-ibft</literal>.
You can also explicitly specify <literal>ibft</literal> to load the
plugin without <literal>ifcfg-rh</literal> or to change the plugin order.
</para>
</listitem>
</varlistentry>

View file

@ -428,6 +428,7 @@ AM_CPPFLAGS += \
-DNMPLUGINDIR=\"$(pkglibdir)\" \
-DNMRUNDIR=\"$(nmrundir)\" \
-DNMSTATEDIR=\"$(nmstatedir)\" \
-DNMLIBDIR=\"$(nmlibdir)\" \
\
-DDHCLIENT_PATH=\"$(DHCLIENT_PATH)\" \
-DDHCPCD_PATH=\"$(DHCPCD_PATH)\" \

View file

@ -3323,7 +3323,7 @@ ip4_config_merge_and_apply (NMDevice *self,
if ( !priv->default_route.v4_configure_first_time
&& !nm_device_uses_assumed_connection (self)
&& connection_is_never_default) {
/* If the connection is explicitly configured as never-default, we enforce the (absense of the)
/* If the connection is explicitly configured as never-default, we enforce the (absence of the)
* default-route only once. That allows the user to configure a connection as never-default,
* but he can add default routes externally (via a dispatcher script) and NM will not interfere. */
goto END_ADD_DEFAULT_ROUTE;

View file

@ -343,7 +343,7 @@ main (int argc, char *argv[])
}
/* Read the config file and CLI overrides */
config = nm_config_setup (config_cli, &error);
config = nm_config_setup (config_cli, NULL, &error);
nm_config_cmd_line_options_free (config_cli);
config_cli = NULL;
if (config == NULL) {

View file

@ -48,6 +48,8 @@ typedef struct {
char *config_description;
GKeyFile *keyfile;
GKeyFile *keyfile_user;
GKeyFile *keyfile_intern;
/* A zero-terminated list of pre-processed information from the
* [connection] sections. This is to speed up lookup. */
@ -77,7 +79,8 @@ enum {
PROP_0,
PROP_CONFIG_MAIN_FILE,
PROP_CONFIG_DESCRIPTION,
PROP_KEYFILE,
PROP_KEYFILE_USER,
PROP_KEYFILE_INTERN,
PROP_CONNECTIVITY_URI,
PROP_CONNECTIVITY_INTERVAL,
PROP_CONNECTIVITY_RESPONSE,
@ -92,6 +95,14 @@ G_DEFINE_TYPE (NMConfigData, nm_config_data, G_TYPE_OBJECT)
/************************************************************************/
#define _HAS_PREFIX(str, prefix) \
({ \
const char *_str = (str); \
g_str_has_prefix ( _str, ""prefix"") && _str[STRLEN(prefix)] != '\0'; \
})
/************************************************************************/
const char *
nm_config_data_get_config_main_file (const NMConfigData *self)
{
@ -238,6 +249,40 @@ nm_config_data_get_assume_ipv6ll_only (const NMConfigData *self, NMDevice *devic
return nm_device_spec_match_list (device, NM_CONFIG_DATA_GET_PRIVATE (self)->assume_ipv6ll_only);
}
GKeyFile *
nm_config_data_clone_keyfile_intern (const NMConfigData *self)
{
NMConfigDataPrivate *priv;
GKeyFile *keyfile;
g_return_val_if_fail (NM_IS_CONFIG_DATA (self), FALSE);
priv = NM_CONFIG_DATA_GET_PRIVATE (self);
keyfile = nm_config_create_keyfile ();
if (priv->keyfile_intern)
_nm_keyfile_copy (keyfile, priv->keyfile_intern);
return keyfile;
}
GKeyFile *
_nm_config_data_get_keyfile (const NMConfigData *self)
{
return NM_CONFIG_DATA_GET_PRIVATE (self)->keyfile;
}
GKeyFile *
_nm_config_data_get_keyfile_intern (const NMConfigData *self)
{
return NM_CONFIG_DATA_GET_PRIVATE (self)->keyfile_intern;
}
GKeyFile *
_nm_config_data_get_keyfile_user (const NMConfigData *self)
{
return NM_CONFIG_DATA_GET_PRIVATE (self)->keyfile_user;
}
/************************************************************************/
/**
@ -265,15 +310,128 @@ nm_config_data_get_keys (const NMConfigData *self, const char *group)
return g_key_file_get_keys (NM_CONFIG_DATA_GET_PRIVATE (self)->keyfile, group, NULL, NULL);
}
/**
* nm_config_data_is_intern_atomic_group:
* @self:
* @group: name of the group to check.
*
* whether a configuration group @group exists and is entirely overwritten
* by internal configuration, i.e. whether it is an atomic group that is
* overwritten.
*
* It doesn't say, that there actually is a user setting that was overwritten. That
* means there could be no corresponding section defined in user configuration
* that required overwriting.
*
* Returns: %TRUE if @group exists and is an atomic group set via internal configuration.
*/
gboolean
nm_config_data_is_intern_atomic_group (const NMConfigData *self, const char *group)
{
NMConfigDataPrivate *priv;
g_return_val_if_fail (NM_IS_CONFIG_DATA (self), FALSE);
g_return_val_if_fail (group && *group, FALSE);
priv = NM_CONFIG_DATA_GET_PRIVATE (self);
if ( !priv->keyfile_intern
|| !g_key_file_has_key (priv->keyfile_intern, group, NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS, NULL))
return FALSE;
/* we have a .was entry for the section. That means that the section would be overwritten
* from user configuration. But it doesn't mean that the merged configuration contains this
* groups, because the internal setting could hide the user section.
* Only return TRUE, if we actually have such a group in the merged configuration.*/
return g_key_file_has_group (priv->keyfile, group);
}
/************************************************************************/
static GKeyFile *
_merge_keyfiles (GKeyFile *keyfile_user, GKeyFile *keyfile_intern)
{
gs_strfreev char **groups = NULL;
guint g, k;
GKeyFile *keyfile;
gsize ngroups;
keyfile = nm_config_create_keyfile ();
if (keyfile_user)
_nm_keyfile_copy (keyfile, keyfile_user);
if (!keyfile_intern)
return keyfile;
groups = g_key_file_get_groups (keyfile_intern, &ngroups);
if (!groups)
return keyfile;
/* we must reverse the order of the connection settings so that we
* have lowest priority last. */
_nm_config_sort_groups (groups, ngroups);
for (g = 0; groups[g]; g++) {
const char *group = groups[g];
gs_strfreev char **keys = NULL;
gboolean is_intern, is_atomic = FALSE;
keys = g_key_file_get_keys (keyfile_intern, group, NULL, NULL);
if (!keys)
continue;
is_intern = g_str_has_prefix (group, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN);
if ( !is_intern
&& g_key_file_has_key (keyfile_intern, group, NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS, NULL)) {
/* the entire section is atomically overwritten by @keyfile_intern. */
g_key_file_remove_group (keyfile, group, NULL);
is_atomic = TRUE;
}
for (k = 0; keys[k]; k++) {
const char *key = keys[k];
gs_free char *value = NULL;
if (is_atomic && strcmp (key, NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS) == 0)
continue;
if ( !is_intern && !is_atomic
&& _HAS_PREFIX (key, NM_CONFIG_KEYFILE_KEYPREFIX_WAS)) {
const char *key_base = &key[STRLEN (NM_CONFIG_KEYFILE_KEYPREFIX_WAS)];
if (!g_key_file_has_key (keyfile_intern, group, key_base, NULL))
g_key_file_remove_key (keyfile, group, key_base, NULL);
continue;
}
if (!is_intern && !is_atomic && _HAS_PREFIX (key, NM_CONFIG_KEYFILE_KEYPREFIX_SET))
continue;
value = g_key_file_get_value (keyfile_intern, group, key, NULL);
g_key_file_set_value (keyfile, group, key, value);
}
}
return keyfile;
}
/************************************************************************/
static int
_nm_config_data_log_sort (const char **pa, const char **pb, gpointer dummy)
{
gboolean a_is_connection, b_is_connection;
gboolean a_is_intern, b_is_intern;
const char *a = *pa;
const char *b = *pb;
/* we sort intern groups to the end. */
a_is_intern = g_str_has_prefix (a, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN);
b_is_intern = g_str_has_prefix (b, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN);
if (a_is_intern && b_is_intern)
return 0;
if (a_is_intern)
return 1;
if (b_is_intern)
return -1;
/* we sort connection groups before intern groups (to the end). */
a_is_connection = a && g_str_has_prefix (a, NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION);
b_is_connection = b && g_str_has_prefix (b, NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION);
@ -336,9 +494,12 @@ nm_config_data_log (const NMConfigData *self, const char *prefix)
for (g = 0; g < ngroups; g++) {
const char *group = groups[g];
gs_strfreev char **keys = NULL;
gboolean is_atomic;
is_atomic = nm_config_data_is_intern_atomic_group (self, group);
_LOG ("");
_LOG ("[%s]", group);
_LOG ("[%s]%s", group, is_atomic ? "*" : "");
keys = g_key_file_get_keys (priv->keyfile, group, NULL, NULL);
for (k = 0; keys && keys[k]; k++) {
@ -479,8 +640,11 @@ nm_config_data_diff (NMConfigData *old_data, NMConfigData *new_data)
priv_old = NM_CONFIG_DATA_GET_PRIVATE (old_data);
priv_new = NM_CONFIG_DATA_GET_PRIVATE (new_data);
if (!_nm_keyfile_equals (priv_old->keyfile, priv_new->keyfile, TRUE))
changes |= NM_CONFIG_CHANGE_VALUES;
if (!_nm_keyfile_equals (priv_old->keyfile_user, priv_new->keyfile_user, TRUE))
changes |= NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_USER;
if (!_nm_keyfile_equals (priv_old->keyfile_intern, priv_new->keyfile_intern, TRUE))
changes |= NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN;
if ( g_strcmp0 (nm_config_data_get_config_main_file (old_data), nm_config_data_get_config_main_file (new_data)) != 0
|| g_strcmp0 (nm_config_data_get_config_description (old_data), nm_config_data_get_config_description (new_data)) != 0)
@ -553,10 +717,21 @@ set_property (GObject *object,
case PROP_CONFIG_DESCRIPTION:
priv->config_description = g_value_dup_string (value);
break;
case PROP_KEYFILE:
priv->keyfile = g_value_dup_boxed (value);
if (!priv->keyfile)
priv->keyfile = nm_config_create_keyfile ();
case PROP_KEYFILE_USER:
priv->keyfile_user = g_value_dup_boxed (value);
if ( priv->keyfile_user
&& !_nm_keyfile_has_values (priv->keyfile_user)) {
g_key_file_unref (priv->keyfile_user);
priv->keyfile_user = NULL;
}
break;
case PROP_KEYFILE_INTERN:
priv->keyfile_intern = g_value_dup_boxed (value);
if ( priv->keyfile_intern
&& !_nm_keyfile_has_values (priv->keyfile_intern)) {
g_key_file_unref (priv->keyfile_intern);
priv->keyfile_intern = NULL;
}
break;
case PROP_NO_AUTO_DEFAULT:
{
@ -620,6 +795,10 @@ finalize (GObject *gobject)
}
g_key_file_unref (priv->keyfile);
if (priv->keyfile_user)
g_key_file_unref (priv->keyfile_user);
if (priv->keyfile_intern)
g_key_file_unref (priv->keyfile_intern);
G_OBJECT_CLASS (nm_config_data_parent_class)->finalize (gobject);
}
@ -636,6 +815,8 @@ constructed (GObject *object)
NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE (self);
char *interval;
priv->keyfile = _merge_keyfiles (priv->keyfile_user, priv->keyfile_intern);
priv->connection_infos = _get_connection_infos (priv->keyfile);
priv->connectivity.uri = nm_strstrip (g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "uri", NULL));
@ -664,16 +845,32 @@ NMConfigData *
nm_config_data_new (const char *config_main_file,
const char *config_description,
const char *const*no_auto_default,
GKeyFile *keyfile)
GKeyFile *keyfile_user,
GKeyFile *keyfile_intern)
{
return g_object_new (NM_TYPE_CONFIG_DATA,
NM_CONFIG_DATA_CONFIG_MAIN_FILE, config_main_file,
NM_CONFIG_DATA_CONFIG_DESCRIPTION, config_description,
NM_CONFIG_DATA_KEYFILE, keyfile,
NM_CONFIG_DATA_KEYFILE_USER, keyfile_user,
NM_CONFIG_DATA_KEYFILE_INTERN, keyfile_intern,
NM_CONFIG_DATA_NO_AUTO_DEFAULT, no_auto_default,
NULL);
}
NMConfigData *
nm_config_data_new_update_keyfile_intern (const NMConfigData *base, GKeyFile *keyfile_intern)
{
NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE (base);
return g_object_new (NM_TYPE_CONFIG_DATA,
NM_CONFIG_DATA_CONFIG_MAIN_FILE, priv->config_main_file,
NM_CONFIG_DATA_CONFIG_DESCRIPTION, priv->config_description,
NM_CONFIG_DATA_KEYFILE_USER, priv->keyfile_user, /* the keyfile is unchanged. It's safe to share it. */
NM_CONFIG_DATA_KEYFILE_INTERN, keyfile_intern,
NM_CONFIG_DATA_NO_AUTO_DEFAULT, priv->no_auto_default.arr,
NULL);
}
NMConfigData *
nm_config_data_new_update_no_auto_default (const NMConfigData *base,
const char *const*no_auto_default)
@ -683,7 +880,8 @@ nm_config_data_new_update_no_auto_default (const NMConfigData *base,
return g_object_new (NM_TYPE_CONFIG_DATA,
NM_CONFIG_DATA_CONFIG_MAIN_FILE, priv->config_main_file,
NM_CONFIG_DATA_CONFIG_DESCRIPTION, priv->config_description,
NM_CONFIG_DATA_KEYFILE, priv->keyfile, /* the keyfile is unchanged. It's safe to share it. */
NM_CONFIG_DATA_KEYFILE_USER, priv->keyfile_user, /* the keyfile is unchanged. It's safe to share it. */
NM_CONFIG_DATA_KEYFILE_INTERN, priv->keyfile_intern,
NM_CONFIG_DATA_NO_AUTO_DEFAULT, no_auto_default,
NULL);
}
@ -718,8 +916,16 @@ nm_config_data_class_init (NMConfigDataClass *config_class)
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_KEYFILE,
g_param_spec_boxed (NM_CONFIG_DATA_KEYFILE, "", "",
(object_class, PROP_KEYFILE_USER,
g_param_spec_boxed (NM_CONFIG_DATA_KEYFILE_USER, "", "",
G_TYPE_KEY_FILE,
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_KEYFILE_INTERN,
g_param_spec_boxed (NM_CONFIG_DATA_KEYFILE_INTERN, "", "",
G_TYPE_KEY_FILE,
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |

View file

@ -38,7 +38,8 @@ G_BEGIN_DECLS
#define NM_CONFIG_DATA_CONFIG_MAIN_FILE "config-main-file"
#define NM_CONFIG_DATA_CONFIG_DESCRIPTION "config-description"
#define NM_CONFIG_DATA_KEYFILE "keyfile"
#define NM_CONFIG_DATA_KEYFILE_USER "keyfile-user"
#define NM_CONFIG_DATA_KEYFILE_INTERN "keyfile-intern"
#define NM_CONFIG_DATA_CONNECTIVITY_URI "connectivity-uri"
#define NM_CONFIG_DATA_CONNECTIVITY_INTERVAL "connectivity-interval"
#define NM_CONFIG_DATA_CONNECTIVITY_RESPONSE "connectivity-response"
@ -71,10 +72,12 @@ typedef enum { /*< flags >*/
NM_CONFIG_CHANGE_CONFIG_FILES = (1L << 3),
NM_CONFIG_CHANGE_VALUES = (1L << 4),
NM_CONFIG_CHANGE_CONNECTIVITY = (1L << 5),
NM_CONFIG_CHANGE_NO_AUTO_DEFAULT = (1L << 6),
NM_CONFIG_CHANGE_DNS_MODE = (1L << 7),
NM_CONFIG_CHANGE_RC_MANAGER = (1L << 8),
NM_CONFIG_CHANGE_VALUES_USER = (1L << 5),
NM_CONFIG_CHANGE_VALUES_INTERN = (1L << 6),
NM_CONFIG_CHANGE_CONNECTIVITY = (1L << 7),
NM_CONFIG_CHANGE_NO_AUTO_DEFAULT = (1L << 8),
NM_CONFIG_CHANGE_DNS_MODE = (1L << 9),
NM_CONFIG_CHANGE_RC_MANAGER = (1L << 10),
_NM_CONFIG_CHANGE_LAST,
NM_CONFIG_CHANGE_ALL = ((_NM_CONFIG_CHANGE_LAST - 1) << 1) - 1,
@ -93,7 +96,9 @@ GType nm_config_data_get_type (void);
NMConfigData *nm_config_data_new (const char *config_main_file,
const char *config_description,
const char *const*no_auto_default,
GKeyFile *keyfile);
GKeyFile *keyfile_user,
GKeyFile *keyfile_intern);
NMConfigData *nm_config_data_new_update_keyfile_intern (const NMConfigData *base, GKeyFile *keyfile_intern);
NMConfigData *nm_config_data_new_update_no_auto_default (const NMConfigData *base, const char *const*no_auto_default);
NMConfigChangeFlags nm_config_data_diff (NMConfigData *old_data, NMConfigData *new_data);
@ -127,6 +132,14 @@ char *nm_config_data_get_connection_default (const NMConfigData *self,
char **nm_config_data_get_groups (const NMConfigData *self);
char **nm_config_data_get_keys (const NMConfigData *self, const char *group);
gboolean nm_config_data_is_intern_atomic_group (const NMConfigData *self, const char *group);
GKeyFile *nm_config_data_clone_keyfile_intern (const NMConfigData *self);
/* private accessors */
GKeyFile *_nm_config_data_get_keyfile (const NMConfigData *self);
GKeyFile *_nm_config_data_get_keyfile_user (const NMConfigData *self);
GKeyFile *_nm_config_data_get_keyfile_intern (const NMConfigData *self);
G_END_DECLS

File diff suppressed because it is too large Load diff

View file

@ -39,6 +39,7 @@ G_BEGIN_DECLS
/* Properties */
#define NM_CONFIG_CMD_LINE_OPTIONS "cmd-line-options"
#define NM_CONFIG_ATOMIC_SECTION_PREFIXES "atomic-section-prefixes"
/* Signals */
#define NM_CONFIG_SIGNAL_CONFIG_CHANGED "config-changed"
@ -48,6 +49,7 @@ G_BEGIN_DECLS
#define NM_CONFIG_KEYFILE_LIST_SEPARATOR ','
#define NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN ".intern."
#define NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION "connection"
#define NM_CONFIG_KEYFILE_GROUPPREFIX_TEST_APPEND_STRINGLIST ".test-append-stringlist"
@ -59,10 +61,14 @@ G_BEGIN_DECLS
#define NM_CONFIG_KEYFILE_GROUP_IFUPDOWN "ifupdown"
#define NM_CONFIG_KEYFILE_GROUP_IFNET "ifnet"
#define NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS ".was"
#define NM_CONFIG_KEYFILE_KEY_IFNET_AUTO_REFRESH "auto_refresh"
#define NM_CONFIG_KEYFILE_KEY_IFNET_MANAGED "managed"
#define NM_CONFIG_KEYFILE_KEY_IFUPDOWN_MANAGED "managed"
#define NM_CONFIG_KEYFILE_KEYPREFIX_WAS ".was."
#define NM_CONFIG_KEYFILE_KEYPREFIX_SET ".set."
typedef struct NMConfigCmdLineOptions NMConfigCmdLineOptions;
struct _NMConfig {
@ -97,6 +103,11 @@ const char *nm_config_get_log_domains (NMConfig *config);
const char *nm_config_get_debug (NMConfig *config);
gboolean nm_config_get_configure_and_quit (NMConfig *config);
void nm_config_set_values (NMConfig *self,
GKeyFile *keyfile_intern_new,
gboolean allow_write,
gboolean force_rewrite);
/* for main.c only */
NMConfigCmdLineOptions *nm_config_cmd_line_options_new (void);
void nm_config_cmd_line_options_free (NMConfigCmdLineOptions *cli);
@ -106,8 +117,8 @@ void nm_config_cmd_line_options_add_to_entries (NMConfigCmdLi
gboolean nm_config_get_no_auto_default_for_device (NMConfig *config, NMDevice *device);
void nm_config_set_no_auto_default_for_device (NMConfig *config, NMDevice *device);
NMConfig *nm_config_new (const NMConfigCmdLineOptions *cli, GError **error);
NMConfig *nm_config_setup (const NMConfigCmdLineOptions *cli, GError **error);
NMConfig *nm_config_new (const NMConfigCmdLineOptions *cli, char **atomic_section_prefixes, GError **error);
NMConfig *nm_config_setup (const NMConfigCmdLineOptions *cli, char **atomic_section_prefixes, GError **error);
void nm_config_reload (NMConfig *config, int signal);
gint nm_config_parse_boolean (const char *str, gint default_value);
@ -128,6 +139,8 @@ void nm_config_keyfile_set_string_list (GKeyFile *keyfile,
gssize len);
GSList *nm_config_get_device_match_spec (const GKeyFile *keyfile, const char *group, const char *key, gboolean *out_has_key);
void _nm_config_sort_groups (char **groups, gsize ngroups);
G_END_DECLS
#endif /* __NETWORKMANAGER_CONFIG_H__ */

View file

@ -764,18 +764,20 @@ load_plugins (NMSettings *self, const char **plugins, GError **error)
const char **iter;
gboolean keyfile_added = FALSE;
gboolean success = TRUE;
gboolean add_ibft = FALSE;
gboolean has_no_ibft;
gssize idx_no_ibft, idx_ibft;
idx_ibft = _nm_utils_strv_find_first ((char **) plugins, -1, "ibft");
idx_no_ibft = _nm_utils_strv_find_first ((char **) plugins, -1, "no-ibft");
has_no_ibft = idx_no_ibft >= 0 && idx_no_ibft > idx_ibft;
#if WITH_SETTINGS_PLUGIN_IBFT
add_ibft = idx_no_ibft < 0 && idx_ibft < 0;
#endif
for (iter = plugins; iter && *iter; iter++) {
GModule *plugin;
gs_free char *full_name = NULL;
gs_free char *path = NULL;
const char *pname;
const char *pname = *iter;
GObject *obj;
GObject * (*factory_func) (void);
struct stat st;
int errsv;
pname = *iter;
if (!*pname || strchr (pname, '/')) {
LOG (LOGL_WARN, "ignore invalid plugin \"%s\"", pname);
@ -787,6 +789,11 @@ load_plugins (NMSettings *self, const char **plugins, GError **error)
continue;
}
if (!strcmp (pname, "no-ibft"))
continue;
if (has_no_ibft && !strcmp (pname, "ibft"))
continue;
obj = find_plugin (list, pname);
if (obj)
continue;
@ -800,61 +807,79 @@ load_plugins (NMSettings *self, const char **plugins, GError **error)
continue;
}
full_name = g_strdup_printf ("nm-settings-plugin-%s", pname);
path = g_module_build_path (NMPLUGINDIR, full_name);
load_plugin:
{
GModule *plugin;
gs_free char *full_name = NULL;
gs_free char *path = NULL;
GObject * (*factory_func) (void);
struct stat st;
int errsv;
if (stat (path, &st) != 0) {
errsv = errno;
LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': %s", pname, path, strerror (errsv));
continue;
}
if (!S_ISREG (st.st_mode)) {
LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': not a file", pname, path);
continue;
}
if (st.st_uid != 0) {
LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': file must be owned by root", pname, path);
continue;
}
if (st.st_mode & (S_IWGRP | S_IWOTH | S_ISUID)) {
LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': invalid file permissions", pname, path);
continue;
}
full_name = g_strdup_printf ("nm-settings-plugin-%s", pname);
path = g_module_build_path (NMPLUGINDIR, full_name);
plugin = g_module_open (path, G_MODULE_BIND_LOCAL);
if (!plugin) {
LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': %s",
pname, path, g_module_error ());
continue;
if (stat (path, &st) != 0) {
errsv = errno;
LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': %s", pname, path, strerror (errsv));
goto next;
}
if (!S_ISREG (st.st_mode)) {
LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': not a file", pname, path);
goto next;
}
if (st.st_uid != 0) {
LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': file must be owned by root", pname, path);
goto next;
}
if (st.st_mode & (S_IWGRP | S_IWOTH | S_ISUID)) {
LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': invalid file permissions", pname, path);
goto next;
}
plugin = g_module_open (path, G_MODULE_BIND_LOCAL);
if (!plugin) {
LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': %s",
pname, path, g_module_error ());
goto next;
}
/* errors after this point are fatal, because we loaded the shared library already. */
if (!g_module_symbol (plugin, "nm_system_config_factory", (gpointer) (&factory_func))) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
"Could not find plugin '%s' factory function.",
pname);
success = FALSE;
g_module_close (plugin);
break;
}
obj = (*factory_func) ();
if (!obj || !NM_IS_SYSTEM_CONFIG_INTERFACE (obj)) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
"Plugin '%s' returned invalid system config object.",
pname);
success = FALSE;
g_module_close (plugin);
break;
}
g_module_make_resident (plugin);
g_object_weak_ref (obj, (GWeakNotify) g_module_close, plugin);
g_object_set_data_full (obj, PLUGIN_MODULE_PATH, path, g_free);
path = NULL;
add_plugin (self, NM_SYSTEM_CONFIG_INTERFACE (obj));
list = g_slist_append (list, obj);
}
/* errors after this point are fatal, because we loaded the shared library already. */
if (!g_module_symbol (plugin, "nm_system_config_factory", (gpointer) (&factory_func))) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
"Could not find plugin '%s' factory function.",
pname);
success = FALSE;
g_module_close (plugin);
break;
next:
if (add_ibft && !strcmp (pname, "ifcfg-rh")) {
/* The plugin ibft is not explicitly mentioned but we just enabled "ifcfg-rh".
* Enable "ibft" by default after "ifcfg-rh". */
pname = "ibft";
add_ibft = FALSE;
goto load_plugin;
}
obj = (*factory_func) ();
if (!obj || !NM_IS_SYSTEM_CONFIG_INTERFACE (obj)) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
"Plugin '%s' returned invalid system config object.",
pname);
success = FALSE;
g_module_close (plugin);
break;
}
g_module_make_resident (plugin);
g_object_weak_ref (obj, (GWeakNotify) g_module_close, plugin);
g_object_set_data_full (obj, PLUGIN_MODULE_PATH, path, g_free);
path = NULL;
add_plugin (self, NM_SYSTEM_CONFIG_INTERFACE (obj));
list = g_slist_append (list, obj);
}
/* If keyfile plugin was not among configured plugins, add it as the last one */

View file

@ -32,8 +32,27 @@
#include "nm-test-utils.h"
/********************************************************************************/
static void
_assert_config_value (const NMConfigData *config_data, const char *group, const char *key, const char *expected_value, const char *file, int line)
{
gs_free char *value = NULL;
value = nm_config_data_get_value (config_data, group, key, NM_CONFIG_GET_VALUE_NONE);
if (g_strcmp0 (value, expected_value)) {
g_error ("(%s:%d) invalid value in config-data %s.%s = %s%s%s (instead of %s%s%s)",
file, line, group, key,
NM_PRINT_FMT_QUOTED (value, "\"", value, "\"", "(null)"),
NM_PRINT_FMT_QUOTED (expected_value, "\"", expected_value, "\"", "(null)"));
}
}
#define assert_config_value(config_data, group, key, expected_value) _assert_config_value (config_data, group, key, expected_value, __FILE__, __LINE__)
/********************************************************************************/
static NMConfig *
setup_config (GError **error, const char *config_file, const char *config_dir, ...)
setup_config (GError **error, const char *config_file, const char *intern_config, const char *const* atomic_section_prefixes, const char *config_dir, const char *system_config_dir, ...)
{
va_list ap;
GPtrArray *args;
@ -51,10 +70,18 @@ setup_config (GError **error, const char *config_file, const char *config_dir, .
g_ptr_array_add (args, "test-config");
g_ptr_array_add (args, "--config");
g_ptr_array_add (args, (char *)config_file);
if (intern_config) {
g_ptr_array_add (args, "--intern-config");
g_ptr_array_add (args, (char *)intern_config);
}
g_ptr_array_add (args, "--config-dir");
g_ptr_array_add (args, (char *)config_dir);
if (system_config_dir) {
g_ptr_array_add (args, "--system-config-dir");
g_ptr_array_add (args, (char *) system_config_dir);
}
va_start (ap, config_dir);
va_start (ap, system_config_dir);
while ((arg = va_arg (ap, char *)))
g_ptr_array_add (args, arg);
va_end (ap);
@ -74,7 +101,7 @@ setup_config (GError **error, const char *config_file, const char *config_dir, .
g_ptr_array_free (args, TRUE);
config = nm_config_setup (cli, &local_error);
config = nm_config_setup (cli, (char **) atomic_section_prefixes, &local_error);
if (error) {
g_assert (!config);
g_assert (local_error);
@ -97,7 +124,7 @@ test_config_simple (void)
gs_unref_object NMDevice *dev51 = nm_test_device_new ("00:00:00:00:00:51");
gs_unref_object NMDevice *dev52 = nm_test_device_new ("00:00:00:00:00:52");
config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "/no/such/dir", NULL);
config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "", NULL, "/no/such/dir", "", NULL);
g_assert_cmpstr (nm_config_data_get_config_main_file (nm_config_get_data_orig (config)), ==, SRCDIR "/NetworkManager.conf");
g_assert_cmpstr (nm_config_get_dhcp_client (config), ==, "dhclient");
@ -176,7 +203,7 @@ test_config_non_existent (void)
{
GError *error = NULL;
setup_config (&error, SRCDIR "/no-such-file", "/no/such/dir", NULL);
setup_config (&error, SRCDIR "/no-such-file", "", NULL, "/no/such/dir", "", NULL);
g_assert_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND);
g_clear_error (&error);
}
@ -186,7 +213,7 @@ test_config_parse_error (void)
{
GError *error = NULL;
setup_config (&error, SRCDIR "/bad.conf", "/no/such/dir", NULL);
setup_config (&error, SRCDIR "/bad.conf", "", NULL, "/no/such/dir", "", NULL);
g_assert_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_PARSE);
g_clear_error (&error);
}
@ -197,7 +224,7 @@ test_config_override (void)
NMConfig *config;
const char **plugins;
config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "/no/such/dir",
config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "", NULL, "/no/such/dir", "",
"--plugins", "alpha,beta,gamma,delta",
"--connectivity-interval", "12",
NULL);
@ -235,7 +262,7 @@ test_config_no_auto_default (void)
g_assert_cmpint (nwrote, ==, 18);
close (fd);
config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "/no/such/dir",
config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "", NULL, "/no/such/dir", "",
"--no-auto-default", state_file,
NULL);
@ -257,7 +284,7 @@ test_config_no_auto_default (void)
g_object_unref (config);
config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "/no/such/dir",
config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "", NULL, "/no/such/dir", "",
"--no-auto-default", state_file,
NULL);
@ -285,7 +312,7 @@ test_config_confdir (void)
char *value;
GSList *specs;
config = setup_config (NULL, SRCDIR "/NetworkManager.conf", SRCDIR "/conf.d", NULL);
config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "", NULL, SRCDIR "/conf.d", "", NULL);
g_assert_cmpstr (nm_config_data_get_config_main_file (nm_config_get_data_orig (config)), ==, SRCDIR "/NetworkManager.conf");
g_assert_cmpstr (nm_config_get_dhcp_client (config), ==, "dhcpcd");
@ -391,11 +418,336 @@ test_config_confdir_parse_error (void)
GError *error = NULL;
/* Using SRCDIR as the conf dir will pick up bad.conf */
setup_config (&error, SRCDIR "/NetworkManager.conf", SRCDIR, NULL);
setup_config (&error, SRCDIR "/NetworkManager.conf", "", NULL, SRCDIR, "", NULL);
g_assert_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_PARSE);
g_clear_error (&error);
}
/*****************************************************************************/
typedef void (*TestSetValuesUserSetFcn) (NMConfig *config, gboolean is_user, GKeyFile *keyfile_user, NMConfigChangeFlags *out_expected_changes);
typedef void (*TestSetValuesCheckStateFcn) (NMConfig *config, NMConfigData *config_data, gboolean is_change_event, NMConfigChangeFlags changes, NMConfigData *old_data);
typedef struct {
NMConfigChangeFlags changes;
TestSetValuesCheckStateFcn check_state_fcn;
} TestSetValuesConfigChangedData;
static void
_set_values_config_changed_cb (NMConfig *config,
NMConfigData *config_data,
NMConfigChangeFlags changes,
NMConfigData *old_data,
TestSetValuesConfigChangedData *config_changed_data)
{
g_assert (changes != NM_CONFIG_CHANGE_NONE);
g_assert (config_changed_data);
g_assert (config_changed_data->changes == NM_CONFIG_CHANGE_NONE);
if (changes == NM_CONFIG_CHANGE_SIGHUP)
return;
changes &= ~NM_CONFIG_CHANGE_SIGHUP;
config_changed_data->changes = changes;
if (config_changed_data->check_state_fcn)
config_changed_data->check_state_fcn (config, config_data, TRUE, changes, old_data);
}
static void
_set_values_user (NMConfig *config,
const char *CONFIG_USER,
TestSetValuesUserSetFcn set_fcn,
TestSetValuesCheckStateFcn check_state_fcn)
{
GKeyFile *keyfile_user;
gboolean success;
gs_free_error GError *error = NULL;
TestSetValuesConfigChangedData config_changed_data = {
.changes = NM_CONFIG_CHANGE_NONE,
.check_state_fcn = check_state_fcn,
};
NMConfigChangeFlags expected_changes = NM_CONFIG_CHANGE_NONE;
gs_unref_object NMConfigData *config_data_before = NULL;
keyfile_user = nm_config_create_keyfile ();
success = g_key_file_load_from_file (keyfile_user, CONFIG_USER, G_KEY_FILE_NONE, &error);
nmtst_assert_success (success, error);
if (set_fcn)
set_fcn (config, TRUE, keyfile_user, &expected_changes);
success = g_key_file_save_to_file (keyfile_user, CONFIG_USER, &error);
nmtst_assert_success (success, error);
g_signal_connect (G_OBJECT (config),
NM_CONFIG_SIGNAL_CONFIG_CHANGED,
G_CALLBACK (_set_values_config_changed_cb),
&config_changed_data);
config_data_before = g_object_ref (nm_config_get_data (config));
if (expected_changes != NM_CONFIG_CHANGE_NONE)
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*config: update *");
else
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*config: signal SIGHUP (no changes from disk)*");
nm_config_reload (config, SIGHUP);
g_test_assert_expected_messages ();
g_assert (expected_changes == config_changed_data.changes);
if (check_state_fcn)
check_state_fcn (config, nm_config_get_data (config), FALSE, NM_CONFIG_CHANGE_NONE, config_data_before);
g_signal_handlers_disconnect_by_func (config, _set_values_config_changed_cb, &config_changed_data);
g_key_file_unref (keyfile_user);
}
static void
_set_values_intern (NMConfig *config,
TestSetValuesUserSetFcn set_fcn,
TestSetValuesCheckStateFcn check_state_fcn)
{
GKeyFile *keyfile_intern;
TestSetValuesConfigChangedData config_changed_data = {
.changes = NM_CONFIG_CHANGE_NONE,
.check_state_fcn = check_state_fcn,
};
NMConfigChangeFlags expected_changes = NM_CONFIG_CHANGE_NONE;
gs_unref_object NMConfigData *config_data_before = NULL;
config_data_before = g_object_ref (nm_config_get_data (config));
keyfile_intern = nm_config_data_clone_keyfile_intern (config_data_before);
if (set_fcn)
set_fcn (config, FALSE, keyfile_intern, &expected_changes);
g_signal_connect (G_OBJECT (config),
NM_CONFIG_SIGNAL_CONFIG_CHANGED,
G_CALLBACK (_set_values_config_changed_cb),
&config_changed_data);
if (expected_changes != NM_CONFIG_CHANGE_NONE)
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*config: update *");
nm_config_set_values (config, keyfile_intern, TRUE, FALSE);
g_test_assert_expected_messages ();
g_assert (expected_changes == config_changed_data.changes);
if (check_state_fcn)
check_state_fcn (config, nm_config_get_data (config), FALSE, NM_CONFIG_CHANGE_NONE, config_data_before);
g_signal_handlers_disconnect_by_func (config, _set_values_config_changed_cb, &config_changed_data);
g_key_file_unref (keyfile_intern);
}
static void
_set_values_user_intern_section_set (NMConfig *config, gboolean set_user, GKeyFile *keyfile, NMConfigChangeFlags *out_expected_changes)
{
g_key_file_set_string (keyfile, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN"section1", "key", "this-should-be-ignored");
}
static void
_set_values_user_intern_section_check (NMConfig *config, NMConfigData *config_data, gboolean is_change_event, NMConfigChangeFlags changes, NMConfigData *old_data)
{
g_assert (changes == NM_CONFIG_CHANGE_NONE);
g_assert (!nm_config_data_has_group (config_data, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN"section1"));
}
static void
_set_values_user_initial_values_set (NMConfig *config, gboolean set_user, GKeyFile *keyfile, NMConfigChangeFlags *out_expected_changes)
{
g_key_file_remove_group (keyfile, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN"section1", NULL);
g_key_file_set_string (keyfile, "section1", "key1", "value1");
*out_expected_changes = NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_USER;
}
static void
_set_values_user_initial_values_check (NMConfig *config, NMConfigData *config_data, gboolean is_change_event, NMConfigChangeFlags changes, NMConfigData *old_data)
{
if (is_change_event)
g_assert (changes == (NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_USER));
assert_config_value (config_data, "section1", "key1", "value1");
}
static void
_set_values_intern_internal_set (NMConfig *config, gboolean set_user, GKeyFile *keyfile, NMConfigChangeFlags *out_expected_changes)
{
g_key_file_set_string (keyfile, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN"section1", "key", "internal-section");
*out_expected_changes = NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN;
}
static void
_set_values_intern_internal_check (NMConfig *config, NMConfigData *config_data, gboolean is_change_event, NMConfigChangeFlags changes, NMConfigData *old_data)
{
if (is_change_event)
g_assert (changes == (NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN));
assert_config_value (config_data, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN"section1", "key", "internal-section");
}
static void
_set_values_user_atomic_section_1_set (NMConfig *config, gboolean set_user, GKeyFile *keyfile, NMConfigChangeFlags *out_expected_changes)
{
g_key_file_set_string (keyfile, "atomic-prefix-1.section-a", "key1", "user-value1");
g_key_file_set_string (keyfile, "atomic-prefix-1.section-a", "key2", "user-value2");
g_key_file_set_string (keyfile, "atomic-prefix-1.section-b", "key1", "user-value1");
g_key_file_set_string (keyfile, "non-atomic-prefix-1.section-a", "nap1-key1", "user-value1");
g_key_file_set_string (keyfile, "non-atomic-prefix-1.section-a", "nap1-key2", "user-value2");
*out_expected_changes = NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_USER;
}
static void
_set_values_user_atomic_section_1_check (NMConfig *config, NMConfigData *config_data, gboolean is_change_event, NMConfigChangeFlags changes, NMConfigData *old_data)
{
if (is_change_event)
g_assert (changes == (NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_USER));
assert_config_value (config_data, "atomic-prefix-1.section-a", "key1", "user-value1");
assert_config_value (config_data, "atomic-prefix-1.section-a", "key2", "user-value2");
assert_config_value (config_data, "atomic-prefix-1.section-b", "key1", "user-value1");
assert_config_value (config_data, "non-atomic-prefix-1.section-a", "nap1-key1", "user-value1");
assert_config_value (config_data, "non-atomic-prefix-1.section-a", "nap1-key2", "user-value2");
}
static void
_set_values_intern_atomic_section_1_set (NMConfig *config, gboolean set_user, GKeyFile *keyfile, NMConfigChangeFlags *out_expected_changes)
{
g_key_file_set_string (keyfile, "atomic-prefix-1.section-a", "key1", "intern-value1");
g_key_file_set_string (keyfile, "atomic-prefix-1.section-a", "key3", "intern-value3");
g_key_file_set_string (keyfile, "non-atomic-prefix-1.section-a", "nap1-key1", "intern-value1");
g_key_file_set_string (keyfile, "non-atomic-prefix-1.section-a", "nap1-key3", "intern-value3");
*out_expected_changes = NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN;
}
static void
_set_values_intern_atomic_section_1_check (NMConfig *config, NMConfigData *config_data, gboolean is_change_event, NMConfigChangeFlags changes, NMConfigData *old_data)
{
if (is_change_event)
g_assert (changes == (NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN));
assert_config_value (config_data, "atomic-prefix-1.section-a", "key1", "intern-value1");
assert_config_value (config_data, "atomic-prefix-1.section-a", "key2", NULL);
assert_config_value (config_data, "atomic-prefix-1.section-a", "key3", "intern-value3");
assert_config_value (config_data, "atomic-prefix-1.section-b", "key1", "user-value1");
assert_config_value (config_data, "non-atomic-prefix-1.section-a", "nap1-key1", "intern-value1");
assert_config_value (config_data, "non-atomic-prefix-1.section-a", "nap1-key2", "user-value2");
assert_config_value (config_data, "non-atomic-prefix-1.section-a", "nap1-key3", "intern-value3");
g_assert ( nm_config_data_is_intern_atomic_group (config_data, "atomic-prefix-1.section-a"));
g_assert (!nm_config_data_is_intern_atomic_group (config_data, "atomic-prefix-1.section-b"));
g_assert (!nm_config_data_is_intern_atomic_group (config_data, "non-atomic-prefix-1.section-a"));
}
static void
_set_values_user_atomic_section_2_set (NMConfig *config, gboolean set_user, GKeyFile *keyfile, NMConfigChangeFlags *out_expected_changes)
{
g_key_file_set_string (keyfile, "atomic-prefix-1.section-a", "key1", "user-value1-x");
g_key_file_set_string (keyfile, "atomic-prefix-1.section-a", "key2", "user-value2");
g_key_file_set_string (keyfile, "non-atomic-prefix-1.section-a", "nap1-key1", "user-value1-x");
g_key_file_set_string (keyfile, "non-atomic-prefix-1.section-a", "nap1-key2", "user-value2-x");
*out_expected_changes = NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_USER | NM_CONFIG_CHANGE_VALUES_INTERN;
}
static void
_set_values_user_atomic_section_2_check (NMConfig *config, NMConfigData *config_data, gboolean is_change_event, NMConfigChangeFlags changes, NMConfigData *old_data)
{
if (is_change_event)
g_assert (changes == (NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_USER | NM_CONFIG_CHANGE_VALUES_INTERN));
assert_config_value (config_data, "atomic-prefix-1.section-a", "key1", "user-value1-x");
assert_config_value (config_data, "atomic-prefix-1.section-a", "key2", "user-value2");
assert_config_value (config_data, "non-atomic-prefix-1.section-a", "nap1-key1", "user-value1-x");
assert_config_value (config_data, "non-atomic-prefix-1.section-a", "nap1-key2", "user-value2-x");
assert_config_value (config_data, "non-atomic-prefix-1.section-a", "nap1-key3", "intern-value3");
g_assert (!nm_config_data_is_intern_atomic_group (config_data, "atomic-prefix-1.section-a"));
g_assert (!nm_config_data_is_intern_atomic_group (config_data, "atomic-prefix-1.section-b"));
g_assert (!nm_config_data_is_intern_atomic_group (config_data, "non-atomic-prefix-1.section-a"));
}
static void
_set_values_intern_atomic_section_2_set (NMConfig *config, gboolean set_user, GKeyFile *keyfile, NMConfigChangeFlags *out_expected_changes)
{
/* let's hide an atomic section and one key. */
g_key_file_set_string (keyfile, "atomic-prefix-1.section-a", NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS, "any-value");
g_key_file_set_string (keyfile, "non-atomic-prefix-1.section-a", NM_CONFIG_KEYFILE_KEYPREFIX_WAS"nap1-key1", "any-value");
g_key_file_set_string (keyfile, "non-atomic-prefix-1.section-a", "nap1-key3", "intern-value3");
g_key_file_set_string (keyfile, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN"with-whitespace", "key1", " b c\\, d ");
g_key_file_set_value (keyfile, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN"with-whitespace", "key2", " b c\\, d ");
*out_expected_changes = NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN;
}
static void
_set_values_intern_atomic_section_2_check (NMConfig *config, NMConfigData *config_data, gboolean is_change_event, NMConfigChangeFlags changes, NMConfigData *old_data)
{
if (is_change_event)
g_assert (changes == (NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN));
g_assert (!nm_config_data_has_group (config_data, "atomic-prefix-1.section-a"));
assert_config_value (config_data, "atomic-prefix-1.section-b", "key1", "user-value1");
assert_config_value (config_data, "non-atomic-prefix-1.section-a", "nap1-key1", NULL);
assert_config_value (config_data, "non-atomic-prefix-1.section-a", "nap1-key2", "user-value2-x");
assert_config_value (config_data, "non-atomic-prefix-1.section-a", "nap1-key3", "intern-value3");
g_assert (!nm_config_data_is_intern_atomic_group (config_data, "atomic-prefix-1.section-a"));
g_assert (!nm_config_data_is_intern_atomic_group (config_data, "atomic-prefix-1.section-b"));
g_assert (!nm_config_data_is_intern_atomic_group (config_data, "non-atomic-prefix-1.section-a"));
assert_config_value (config_data, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN"with-whitespace", "key1", " b c\\, d ");
assert_config_value (config_data, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN"with-whitespace", "key2", " b c\\, d ");
}
static void
test_config_set_values (void)
{
gs_unref_object NMConfig *config = NULL;
const char *CONFIG_USER = SRCDIR"/test-set-values-user.conf";
const char *CONFIG_INTERN = SRCDIR"/test-set-values-intern.conf";
const char *atomic_section_prefixes[] = {
"atomic-prefix-1.",
"atomic-prefix-2.",
NULL,
};
g_assert (g_file_set_contents (CONFIG_USER, "", 0, NULL));
g_assert (g_file_set_contents (CONFIG_INTERN, "", 0, NULL));
config = setup_config (NULL, CONFIG_USER, CONFIG_INTERN, atomic_section_prefixes, "", "", NULL);
_set_values_user (config, CONFIG_USER,
_set_values_user_intern_section_set,
_set_values_user_intern_section_check);
_set_values_user (config, CONFIG_USER,
_set_values_user_initial_values_set,
_set_values_user_initial_values_check);
_set_values_intern (config,
_set_values_intern_internal_set,
_set_values_intern_internal_check);
_set_values_user (config, CONFIG_USER,
_set_values_user_atomic_section_1_set,
_set_values_user_atomic_section_1_check);
_set_values_intern (config,
_set_values_intern_atomic_section_1_set,
_set_values_intern_atomic_section_1_check);
_set_values_user (config, CONFIG_USER,
_set_values_user_atomic_section_2_set,
_set_values_user_atomic_section_2_check);
_set_values_intern (config,
_set_values_intern_atomic_section_2_set,
_set_values_intern_atomic_section_2_check);
g_assert (remove (CONFIG_USER) == 0);
g_assert (remove (CONFIG_INTERN) == 0);
}
/*****************************************************************************/
NMTST_DEFINE ();
int
@ -419,6 +771,8 @@ main (int argc, char **argv)
g_test_add_func ("/config/confdir", test_config_confdir);
g_test_add_func ("/config/confdir-parse-error", test_config_confdir_parse_error);
g_test_add_func ("/config/set-values", test_config_set_values);
/* This one has to come last, because it leaves its values in
* nm-config.c's global variables, and there's no way to reset
* those to NULL.