ifcfg-rh: better detect alias files

Alias files have a ':' to separate the base name from their
alias. But we didn't always ensure not to write-out files without
colon, and also initscripts doesn't have that restriction.

We should detect alias files and handle them properly (e.g. by
reloading the base file).

This fixes an error that a `nmcli con load` would have tried to
load the alias file. Also extend load_connection() to support
passing filenames other then the base file.

We only have to handle this in plugin.c. Inside reader.c we always
have the normalized base filename.

Or detection of alias files only looks whether the filename has a ':'
and whether a corresponding base file exists.
This commit is contained in:
Thomas Haller 2015-06-01 18:03:31 +02:00
parent 2e87df8408
commit 0aed4e2388
3 changed files with 57 additions and 45 deletions

View file

@ -425,25 +425,13 @@ ifcfg_dir_changed (GFileMonitor *monitor,
gpointer user_data)
{
SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (user_data);
char *path, *base, *ifcfg_path;
char *path, *ifcfg_path;
NMIfcfgConnection *connection;
path = g_file_get_path (file);
if (utils_should_ignore_file (path, FALSE)) {
g_free (path);
return;
}
_LOGD ("ifcfg_dir_changed(%s) = %d", path, event_type);
base = g_file_get_basename (file);
if (utils_is_ifcfg_alias_file (base, NULL)) {
/* Alias file changed. Get the base ifcfg file from it */
ifcfg_path = utils_get_ifcfg_from_alias (path);
} else {
/* Given any ifcfg, keys, or routes file, get the ifcfg file path */
ifcfg_path = utils_get_ifcfg_path (path);
}
ifcfg_path = utils_detect_ifcfg_path (path, FALSE);
_LOGD ("ifcfg_dir_changed(%s) = %d // %s", path, event_type, ifcfg_path ? ifcfg_path : "(none)");
if (ifcfg_path) {
connection = find_by_path (plugin, ifcfg_path);
switch (event_type) {
@ -462,7 +450,6 @@ ifcfg_dir_changed (GFileMonitor *monitor,
g_free (ifcfg_path);
}
g_free (path);
g_free (base);
}
static void
@ -546,18 +533,14 @@ read_connections (SCPluginIfcfg *plugin)
filenames = g_ptr_array_new_with_free_func (g_free);
while ((item = g_dir_read_name (dir))) {
char *full_path;
if (utils_should_ignore_file (item, TRUE))
continue;
if (utils_is_ifcfg_alias_file (item, NULL))
continue;
char *full_path, *real_path;
full_path = g_build_filename (IFCFG_DIR, item, NULL);
if (!utils_get_ifcfg_name (full_path, TRUE))
g_free (full_path);
else
g_ptr_array_add (filenames, full_path);
real_path = utils_detect_ifcfg_path (full_path, TRUE);
if (real_path)
g_ptr_array_add (filenames, real_path);
g_free (full_path);
}
g_dir_close (dir);
@ -629,20 +612,25 @@ load_connection (NMSystemConfigInterface *config,
SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (config);
NMIfcfgConnection *connection;
int dir_len = strlen (IFCFG_DIR);
char *ifcfg_path;
if ( strncmp (filename, IFCFG_DIR, dir_len) != 0
|| filename[dir_len] != '/'
|| strchr (filename + dir_len + 1, '/') != NULL)
return FALSE;
if (utils_should_ignore_file (filename + dir_len + 1, TRUE))
/* get the real ifcfg-path. This allows us to properly
* handle load command using a route-* file etc. */
ifcfg_path = utils_detect_ifcfg_path (filename, FALSE);
if (!ifcfg_path)
return FALSE;
connection = find_by_path (plugin, filename);
update_connection (plugin, NULL, filename, connection, TRUE, NULL, NULL);
connection = find_by_path (plugin, ifcfg_path);
update_connection (plugin, NULL, ifcfg_path, connection, TRUE, NULL, NULL);
if (!connection)
connection = find_by_path (plugin, filename);
connection = find_by_path (plugin, ifcfg_path);
g_free (ifcfg_path);
return (connection != NULL);
}

View file

@ -224,6 +224,12 @@ utils_get_ifcfg_name (const char *file, gboolean only_ifcfg)
} \
} G_STMT_END
/* Do not detect alias files and return 'eth0:0' instead of 'eth0'.
* Unfortunately, we cannot be sure that our files don't contain colons,
* so we cannot reject files with colons.
*
* Instead, you must not call utils_get_ifcfg_name() with an alias file
* or files that are ignored. */
MATCH_TAG_AND_RETURN (name, IFCFG_TAG);
if (!only_ifcfg) {
MATCH_TAG_AND_RETURN (name, KEYS_TAG);
@ -419,26 +425,43 @@ utils_is_ifcfg_alias_file (const char *alias, const char *ifcfg)
}
char *
utils_get_ifcfg_from_alias (const char *alias)
utils_detect_ifcfg_path (const char *path, gboolean only_ifcfg)
{
char *base, *ptr, *ifcfg = NULL;
gs_free char *base = NULL;
char *ptr, *ifcfg = NULL;
g_return_val_if_fail (alias != NULL, NULL);
g_return_val_if_fail (path != NULL, NULL);
base = g_path_get_basename (alias);
g_return_val_if_fail (base != NULL, NULL);
if (utils_should_ignore_file (path, only_ifcfg))
return NULL;
if (utils_is_ifcfg_alias_file (base, NULL)) {
ifcfg = g_strdup (alias);
ptr = strrchr (ifcfg, ':');
if (ptr)
*ptr = '\0';
else {
base = g_path_get_basename (path);
if (strncmp (base, IFCFG_TAG, STRLEN (IFCFG_TAG)) == 0) {
if (base[STRLEN (IFCFG_TAG)] == '\0')
return NULL;
if (utils_is_ifcfg_alias_file (base, NULL)) {
ifcfg = g_strdup (path);
ptr = strrchr (ifcfg, ':');
if (ptr && ptr > ifcfg) {
*ptr = '\0';
if (g_file_test (ifcfg, G_FILE_TEST_EXISTS)) {
/* the file has a colon, so it is probably an alias.
* To be ~more~ certain that this is an alias file,
* check whether a corresponding base file exists. */
if (only_ifcfg) {
g_free (ifcfg);
return NULL;
}
return ifcfg;
}
}
g_free (ifcfg);
ifcfg = NULL;
}
return g_strdup (path);
}
g_free (base);
return ifcfg;
if (only_ifcfg)
return NULL;
return utils_get_ifcfg_path (path);
}

View file

@ -59,7 +59,8 @@ gboolean utils_has_complex_routes (const char *filename);
gboolean utils_ignore_ip_config (NMConnection *connection);
gboolean utils_is_ifcfg_alias_file (const char *alias, const char *ifcfg);
char *utils_get_ifcfg_from_alias (const char *alias);
char *utils_detect_ifcfg_path (const char *path, gboolean only_ifcfg);
#endif /* _UTILS_H_ */