summary refs log tree commit diff
path: root/src/settings/plugins/ifupdown
diff options
context:
space:
mode:
Diffstat (limited to 'src/settings/plugins/ifupdown')
-rw-r--r--src/settings/plugins/ifupdown/meson.build4
-rw-r--r--src/settings/plugins/ifupdown/nms-ifupdown-connection.c33
-rw-r--r--src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c303
-rw-r--r--src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.h50
-rw-r--r--src/settings/plugins/ifupdown/nms-ifupdown-parser.c452
-rw-r--r--src/settings/plugins/ifupdown/nms-ifupdown-plugin.c453
-rw-r--r--src/settings/plugins/ifupdown/tests/meson.build1
-rw-r--r--src/settings/plugins/ifupdown/tests/test-ifupdown.c259
8 files changed, 678 insertions, 877 deletions
diff --git a/src/settings/plugins/ifupdown/meson.build b/src/settings/plugins/ifupdown/meson.build
index fd028f4d..826c7458 100644
--- a/src/settings/plugins/ifupdown/meson.build
+++ b/src/settings/plugins/ifupdown/meson.build
@@ -8,13 +8,10 @@ deps = [
   nm_dep
 ]
 
-cflags = '-DSYSCONFDIR="@0@"'.format(nm_sysconfdir)
-
 libnms_ifupdown_core = static_library(
   'nms-ifupdown-core',
   sources: sources,
   dependencies: deps,
-  c_args: cflags
 )
 
 sources = files(
@@ -26,7 +23,6 @@ libnm_settings_plugin_ifupdown = shared_module(
   'nm-settings-plugin-ifupdown',
   sources: sources,
   dependencies: deps,
-  c_args: cflags,
   link_with: libnms_ifupdown_core,
   link_args: ldflags_linker_script_settings,
   link_depends: linker_script_settings,
diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-connection.c b/src/settings/plugins/ifupdown/nms-ifupdown-connection.c
index c3d231fe..1b817044 100644
--- a/src/settings/plugins/ifupdown/nms-ifupdown-connection.c
+++ b/src/settings/plugins/ifupdown/nms-ifupdown-connection.c
@@ -49,10 +49,20 @@ G_DEFINE_TYPE (NMIfupdownConnection, nm_ifupdown_connection, NM_TYPE_SETTINGS_CO
 
 /*****************************************************************************/
 
+#define _NMLOG_PREFIX_NAME      "ifupdown"
+#define _NMLOG_DOMAIN           LOGD_SETTINGS
+#define _NMLOG(level, ...) \
+    nm_log ((level), _NMLOG_DOMAIN, NULL, NULL, \
+            "%s" _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
+            _NMLOG_PREFIX_NAME": " \
+            _NM_UTILS_MACRO_REST (__VA_ARGS__))
+
+/*****************************************************************************/
+
 static gboolean
 supports_secrets (NMSettingsConnection *connection, const char *setting_name)
 {
-	nm_log_info (LOGD_SETTINGS, "supports_secrets() for setting_name: '%s'", setting_name);
+	_LOGI ("supports_secrets() for setting_name: '%s'", setting_name);
 
 	return (strcmp (setting_name, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME) == 0);
 }
@@ -64,26 +74,27 @@ nm_ifupdown_connection_init (NMIfupdownConnection *connection)
 {
 }
 
-NMIfupdownConnection*
+NMIfupdownConnection *
 nm_ifupdown_connection_new (if_block *block)
 {
-	GObject *object;
+	NMIfupdownConnection *connection;
 	GError *error = NULL;
 
 	g_return_val_if_fail (block != NULL, NULL);
 
-	object = g_object_new (NM_TYPE_IFUPDOWN_CONNECTION, NULL);
+	connection = g_object_new (NM_TYPE_IFUPDOWN_CONNECTION, NULL);
 
-	if (!ifupdown_update_connection_from_if_block (NM_CONNECTION (object), block, &error)) {
-		nm_log_warn (LOGD_SETTINGS, "%s.%d - invalid connection read from /etc/network/interfaces: %s",
-		             __FILE__,
-		             __LINE__,
-		             error->message);
-		g_object_unref (object);
+	/* FIXME(copy-on-write-connection): avoid modifying NMConnection instances and share them via copy-on-write. */
+	if (!ifupdown_update_connection_from_if_block (nm_settings_connection_get_connection (NM_SETTINGS_CONNECTION (connection)),
+	                                               block,
+	                                               &error)) {
+		_LOGW ("invalid connection read from /etc/network/interfaces: %s",
+		       error->message);
+		g_object_unref (connection);
 		return NULL;
 	}
 
-	return (NMIfupdownConnection *) object;
+	return connection;
 }
 
 static void
diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c b/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c
index 94a65ecb..73ecc2f9 100644
--- a/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c
+++ b/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c
@@ -32,78 +32,90 @@
 
 #include "nm-utils.h"
 
-if_block* first;
-if_block* last;
+/*****************************************************************************/
 
-if_data* last_data;
+static void _ifparser_source (if_parser *parser, const char *path, const char *en_dir, int quiet, int dir);
 
-void add_block(const char *type, const char* name)
+/*****************************************************************************/
+
+#define _NMLOG_PREFIX_NAME      "ifupdown"
+#define _NMLOG_DOMAIN           LOGD_SETTINGS
+#define _NMLOG(level, ...) \
+    nm_log ((level), _NMLOG_DOMAIN, NULL, NULL, \
+            "%s" _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
+            _NMLOG_PREFIX_NAME": " \
+            _NM_UTILS_MACRO_REST (__VA_ARGS__))
+
+/*****************************************************************************/
+
+static void
+add_block (if_parser *parser, const char *type, const char* name)
 {
-	if_block *ret = g_slice_new0 (struct _if_block);
-	ret->name = g_strdup(name);
-	ret->type = g_strdup(type);
-	if (first == NULL)
-		first = last = ret;
-	else
-	{
-		last->next = ret;
-		last = ret;
-	}
-	last_data = NULL;
+	if_block *ifb;
+	gsize l_type, l_name;
+
+	l_type = strlen (type) + 1;
+	l_name = strlen (name) + 1;
+
+	ifb = g_malloc (sizeof (if_block) + l_type + l_name);
+	memcpy ((char *) ifb->name, name, l_name);
+	ifb->type = &ifb->name[l_name];
+	memcpy ((char *) ifb->type, type, l_type);
+	c_list_init (&ifb->data_lst_head);
+	c_list_link_tail (&parser->block_lst_head, &ifb->block_lst);
 }
 
-void add_data(const char *key,const char *data)
+static void
+add_data (if_parser *parser, const char *key, const char *data)
 {
-	if_data *ret;
+	if_block *last_block;
+	if_data *ifd;
 	char *idx;
+	gsize l_key, l_data;
+
+	last_block = c_list_last_entry (&parser->block_lst_head, if_block, block_lst);
 
 	/* Check if there is a block where we can attach our data */
-	if (first == NULL)
+	if (!last_block)
 		return;
 
-	ret = g_slice_new0 (struct _if_data);
-	ret->key = g_strdup(key);
+	l_key = strlen (key) + 1;
+	l_data = strlen (data) + 1;
+
+	ifd = g_malloc (sizeof (if_data) + l_key + l_data);
+	memcpy ((char *) ifd->key, key, l_key);
+	ifd->data = &ifd->key[l_key];
+	memcpy ((char *) ifd->data, data, l_data);
 
 	/* Normalize keys. Convert '_' to '-', as ifupdown accepts both variants.
 	 * When querying keys via ifparser_getkey(), use '-'. */
-	while ((idx = strrchr(ret->key, '_'))) {
-		*idx = '-';
-	}
-	ret->data = g_strdup(data);
+	idx = (char *) ifd->key;
+	while ((idx = strchr (idx, '_')))
+		*(idx++) = '-';
 
-	if (last->info == NULL)
-	{
-		last->info = ret;
-		last_data = ret;
-	}
-	else
-	{
-		last_data->next = ret;
-		last_data = last_data->next;
-	}
+	c_list_link_tail (&last_block->data_lst_head, &ifd->data_lst);
 }
 
 /* join values in src with spaces into dst;  dst needs to be large enough */
-static char *join_values_with_spaces(char *dst, char **src)
+static char *
+join_values_with_spaces (char *dst, char **src)
 {
 	if (dst != NULL) {
 		*dst = '\0';
 		if (src != NULL && *src != NULL) {
-			strcat(dst, *src);
+			strcat (dst, *src);
 
 			for (src++; *src != NULL; src++) {
-				strcat(dst, " ");
-				strcat(dst, *src);
+				strcat (dst, " ");
+				strcat (dst, *src);
 			}
 		}
 	}
-	return(dst);
+	return (dst);
 }
 
-static void _ifparser_source (const char *path, const char *en_dir, int quiet, int dir);
-
 static void
-_recursive_ifparser (const char *eni_file, int quiet)
+_recursive_ifparser (if_parser *parser, const char *eni_file, int quiet)
 {
 	FILE *inp;
 	char line[255];
@@ -114,36 +126,35 @@ _recursive_ifparser (const char *eni_file, int quiet)
 	/* Check if interfaces file exists and open it */
 	if (!g_file_test (eni_file, G_FILE_TEST_EXISTS)) {
 		if (!quiet)
-			nm_log_warn (LOGD_SETTINGS, "interfaces file %s doesn't exist\n", eni_file);
+			_LOGW ("interfaces file %s doesn't exist", eni_file);
 		return;
 	}
 	inp = fopen (eni_file, "re");
 	if (inp == NULL) {
 		if (!quiet)
-			nm_log_warn (LOGD_SETTINGS, "Can't open %s\n", eni_file);
+			_LOGW ("Can't open %s", eni_file);
 		return;
 	}
 	if (!quiet)
-		nm_log_info (LOGD_SETTINGS, "      interface-parser: parsing file %s\n", eni_file);
+		_LOGI ("      interface-parser: parsing file %s", eni_file);
 
-	while (!feof(inp))
-	{
+	while (!feof (inp)) {
 		char *token[128]; /* 255 chars can only be split into 127 tokens */
 		char value[255];  /* large enough to join previously split tokens */
 		char *safeptr;
 		int toknum;
 		int len = 0;
 
-		char *ptr = fgets(line+offs, 255-offs, inp);
+		char *ptr = fgets (line+offs, 255-offs, inp);
 		if (ptr == NULL)
 			break;
 
-		len = strlen(line);
+		len = strlen (line);
 		/* skip over-long lines */
-		if (!feof(inp) && len > 0 &&  line[len-1] != '\n') {
+		if (!feof (inp) && len > 0 &&  line[len-1] != '\n') {
 			if (!skip_long_line) {
 				if (!quiet)
-					nm_log_warn (LOGD_SETTINGS, "Skipping over-long-line '%s...'\n", line);
+					_LOGW ("Skipping over-long-line '%s...'", line);
 			}
 			skip_long_line = 1;
 			continue;
@@ -170,9 +181,9 @@ _recursive_ifparser (const char *eni_file, int quiet)
 
 #define SPACES " \t"
 		/* tokenize input; */
-		for (toknum = 0, token[toknum] = strtok_r(line, SPACES, &safeptr);
+		for (toknum = 0, token[toknum] = strtok_r (line, SPACES, &safeptr);
 		     token[toknum] != NULL;
-		     toknum++, token[toknum] = strtok_r(NULL, SPACES, &safeptr))
+		     toknum++, token[toknum] = strtok_r (NULL, SPACES, &safeptr))
 			;
 
 		/* ignore comments and empty lines */
@@ -181,8 +192,8 @@ _recursive_ifparser (const char *eni_file, int quiet)
 
 		if (toknum < 2) {
 			if (!quiet) {
-				nm_log_warn (LOGD_SETTINGS, "Can't parse interface line '%s'\n",
-				             join_values_with_spaces(value, token));
+				_LOGW ("Can't parse interface line '%s'",
+				       join_values_with_spaces (value, token));
 			}
 			skip_to_block = 1;
 			continue;
@@ -193,71 +204,71 @@ _recursive_ifparser (const char *eni_file, int quiet)
 		 * Create a block for each of them except source and source-directory.  */
 
 		/* iface stanza takes at least 3 parameters */
-		if (strcmp(token[0], "iface") == 0) {
+		if (nm_streq (token[0], "iface")) {
 			if (toknum < 4) {
 				if (!quiet) {
-					nm_log_warn (LOGD_SETTINGS, "Can't parse iface line '%s'\n",
-					             join_values_with_spaces(value, token));
+					_LOGW ("Can't parse iface line '%s'",
+					       join_values_with_spaces (value, token));
 				}
 				continue;
 			}
-			add_block(token[0], token[1]);
+			add_block (parser, token[0], token[1]);
 			skip_to_block = 0;
-			add_data(token[2], join_values_with_spaces(value, token + 3));
+			add_data (parser, token[2], join_values_with_spaces (value, token + 3));
 		}
 		/* auto and allow-auto stanzas are equivalent,
 		 * both can take multiple interfaces as parameters: add one block for each */
-		else if (strcmp(token[0], "auto") == 0 ||
-			 strcmp(token[0], "allow-auto") == 0) {
+		else if (NM_IN_STRSET (token[0], "auto", "allow-auto")) {
 			int i;
+
 			for (i = 1; i < toknum; i++)
-				add_block("auto", token[i]);
+				add_block (parser, "auto", token[i]);
 			skip_to_block = 0;
 		}
-		else if (strcmp(token[0], "mapping") == 0) {
-			add_block(token[0], join_values_with_spaces(value, token + 1));
+		else if (nm_streq (token[0], "mapping")) {
+			add_block (parser, token[0], join_values_with_spaces (value, token + 1));
 			skip_to_block = 0;
 		}
 		/* allow-* can take multiple interfaces as parameters: add one block for each */
-		else if (strncmp(token[0],"allow-",6) == 0) {
+		else if (g_str_has_prefix (token[0], "allow-")) {
 			int i;
 			for (i = 1; i < toknum; i++)
-				add_block(token[0], token[i]);
+				add_block (parser, token[0], token[i]);
 			skip_to_block = 0;
 		}
 		/* source and source-directory stanzas take one or more paths as parameters */
-		else if (strcmp (token[0], "source") == 0 || strcmp (token[0], "source-directory") == 0) {
+		else if (NM_IN_STRSET (token[0], "source", "source-directory")) {
 			int i;
 			char *en_dir;
 
 			skip_to_block = 0;
 			en_dir = g_path_get_dirname (eni_file);
 			for (i = 1; i < toknum; ++i) {
-				if (strcmp (token[0], "source-directory") == 0)
-					_ifparser_source (token[i], en_dir, quiet, TRUE);
+				if (nm_streq (token[0], "source-directory"))
+					_ifparser_source (parser, token[i], en_dir, quiet, TRUE);
 				else
-					_ifparser_source (token[i], en_dir, quiet, FALSE);
+					_ifparser_source (parser, token[i], en_dir, quiet, FALSE);
 			}
 			g_free (en_dir);
 		}
 		else {
 			if (skip_to_block) {
 				if (!quiet) {
-					nm_log_warn (LOGD_SETTINGS, "ignoring out-of-block data '%s'\n",
-					             join_values_with_spaces(value, token));
+					_LOGW ("ignoring out-of-block data '%s'",
+					       join_values_with_spaces (value, token));
 				}
 			} else
-				add_data(token[0], join_values_with_spaces(value, token + 1));
+				add_data (parser, token[0], join_values_with_spaces (value, token + 1));
 		}
 	}
-	fclose(inp);
+	fclose (inp);
 
 	if (!quiet)
-		nm_log_info (LOGD_SETTINGS, "      interface-parser: finished parsing file %s\n", eni_file);
+		_LOGI ("      interface-parser: finished parsing file %s", eni_file);
 }
 
 static void
-_ifparser_source (const char *path, const char *en_dir, int quiet, int dir)
+_ifparser_source (if_parser *parser, const char *path, const char *en_dir, int quiet, int dir)
 {
 	char *abs_path;
 	const char *item;
@@ -272,132 +283,128 @@ _ifparser_source (const char *path, const char *en_dir, int quiet, int dir)
 		abs_path = g_build_filename (en_dir, path, NULL);
 
 	if (!quiet)
-		nm_log_info (LOGD_SETTINGS, "      interface-parser: source line includes interfaces file(s) %s\n", abs_path);
+		_LOGI ("      interface-parser: source line includes interfaces file(s) %s", abs_path);
 
 	/* ifupdown uses WRDE_NOCMD for wordexp. */
 	if (wordexp (abs_path, &we, WRDE_NOCMD)) {
 		if (!quiet)
-			nm_log_warn (LOGD_SETTINGS, "word expansion for %s failed\n", abs_path);
+			_LOGW ("word expansion for %s failed", abs_path);
 	} else {
 		for (i = 0; i < we.we_wordc; i++) {
 			if (dir) {
 				source_dir = g_dir_open (we.we_wordv[i], 0, &error);
 				if (!source_dir) {
 					if (!quiet) {
-						nm_log_warn (LOGD_SETTINGS, "Failed to open directory %s: %s",
-						             we.we_wordv[i], error->message);
+						_LOGW ("Failed to open directory %s: %s",
+						       we.we_wordv[i], error->message);
 					}
 					g_clear_error (&error);
 				} else {
 					while ((item = g_dir_read_name (source_dir)))
-						_ifparser_source (item, we.we_wordv[i], quiet, FALSE);
+						_ifparser_source (parser, item, we.we_wordv[i], quiet, FALSE);
 					g_dir_close (source_dir);
 				}
 			} else
-				_recursive_ifparser (we.we_wordv[i], quiet);
+				_recursive_ifparser (parser, we.we_wordv[i], quiet);
 		}
 		wordfree (&we);
 	}
 	g_free (abs_path);
 }
 
-void ifparser_init (const char *eni_file, int quiet)
+if_parser *
+ifparser_parse (const char *eni_file, int quiet)
 {
-	first = last = NULL;
-	_recursive_ifparser (eni_file, quiet);
+	if_parser *parser;
+
+	parser = g_slice_new (if_parser);
+	c_list_init (&parser->block_lst_head);
+	_recursive_ifparser (parser, eni_file, quiet);
+	return parser;
 }
 
-void _destroy_data(if_data *ifd)
+static void
+_destroy_data (if_data *ifd)
 {
-	if (ifd == NULL)
-		return;
-	_destroy_data(ifd->next);
-	g_free(ifd->key);
-	g_free(ifd->data);
-	g_slice_free(struct _if_data, ifd);
-	return;
+	c_list_unlink_stale (&ifd->data_lst);
+	g_free (ifd);
 }
 
-void _destroy_block(if_block* ifb)
+static void
+_destroy_block (if_block* ifb)
 {
-	if (ifb == NULL)
-		return;
-	_destroy_block(ifb->next);
-	_destroy_data(ifb->info);
-	g_free(ifb->name);
-	g_free(ifb->type);
-	g_slice_free(struct _if_block, ifb);
-	return;
+	if_data *ifd;
+
+	while ((ifd = c_list_first_entry (&ifb->data_lst_head, if_data, data_lst)))
+		_destroy_data (ifd);
+	c_list_unlink_stale (&ifb->block_lst);
+	g_free (ifb);
 }
 
-void ifparser_destroy(void)
+void
+ifparser_destroy (if_parser *parser)
 {
-	_destroy_block(first);
-	first = last = NULL;
+	if_block *ifb;
+
+	while ((ifb = c_list_first_entry (&parser->block_lst_head, if_block, block_lst)))
+		_destroy_block (ifb);
+	g_slice_free (if_parser, parser);
 }
 
-if_block *ifparser_getfirst(void)
+if_block *
+ifparser_getfirst (if_parser *parser)
 {
-	return first;
+	return c_list_first_entry (&parser->block_lst_head, if_block, block_lst);
 }
 
-int ifparser_get_num_blocks(void)
+guint
+ifparser_get_num_blocks (if_parser *parser)
 {
-	int i = 0;
-	if_block *iter = first;
-
-	while (iter) {
-		i++;
-		iter = iter->next;
-	}
-	return i;
+	return c_list_length (&parser->block_lst_head);
 }
 
-if_block *ifparser_getif(const char* iface)
+if_block *
+ifparser_getif (if_parser *parser, const char* iface)
 {
-	if_block *curr = first;
-	while(curr!=NULL)
-	{
-		if (strcmp(curr->type,"iface")==0 && strcmp(curr->name,iface)==0)
-			return curr;
-		curr = curr->next;
+	if_block *ifb;
+
+	c_list_for_each_entry (ifb, &parser->block_lst_head, block_lst) {
+		if (   nm_streq (ifb->type, "iface")
+		    && nm_streq (ifb->name, iface))
+			return ifb;
 	}
 	return NULL;
 }
 
-const char *ifparser_getkey(if_block* iface, const char *key)
+static if_data *
+ifparser_findkey (if_block* iface, const char *key)
 {
-	if_data *curr = iface->info;
-	while(curr!=NULL)
-	{
-		if (strcmp(curr->key,key)==0)
-			return curr->data;
-		curr = curr->next;
+	if_data *ifd;
+
+	c_list_for_each_entry (ifd, &iface->data_lst_head, data_lst) {
+		if (nm_streq (ifd->key, key))
+			return ifd;
 	}
 	return NULL;
 }
 
-gboolean
-ifparser_haskey(if_block* iface, const char *key)
+const char *
+ifparser_getkey (if_block* iface, const char *key)
 {
-	if_data *curr = iface->info;
+	if_data *ifd;
 
-	while (curr != NULL) {
-		if (strcmp (curr->key, key) == 0)
-			return TRUE;
-		curr = curr->next;
-	}
-	return FALSE;
+	ifd = ifparser_findkey (iface, key);
+	return ifd ? ifd->data : NULL;
 }
 
-int ifparser_get_num_info(if_block* iface)
+gboolean
+ifparser_haskey (if_block* iface, const char *key)
 {
-	int i = 0;
-	if_data *iter = iface->info;
+	return !!ifparser_findkey (iface, key);
+}
 
-	while (iter) {
-		i++;
-		iter = iter->next;
-	}
-	return i;
+guint
+ifparser_get_num_info (if_block* iface)
+{
+	return c_list_length (&iface->data_lst_head);
 }
diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.h b/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.h
index 7e6c8e34..f367f626 100644
--- a/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.h
+++ b/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.h
@@ -23,33 +23,37 @@
 #ifndef _INTERFACE_PARSER_H
 #define _INTERFACE_PARSER_H
 
-typedef struct _if_data
-{
-	char *key;
-	char *data;
-	struct _if_data *next;
+#include "c-list/src/c-list.h"
+
+typedef struct {
+	CList data_lst;
+	const char *data;
+	const char key[];
 } if_data;
 
-typedef struct _if_block
-{
-	char *type;
-	char *name;
-	if_data *info;
-	struct _if_block *next;
+typedef struct {
+	CList block_lst;
+	CList data_lst_head;
+	const char *type;
+	const char name[];
 } if_block;
 
-void ifparser_init(const char *eni_file, int quiet);
-void ifparser_destroy(void);
+typedef struct {
+	CList block_lst_head;
+} if_parser;
+
+if_parser *ifparser_parse (const char *eni_file, int quiet);
+
+void ifparser_destroy (if_parser *parser);
+NM_AUTO_DEFINE_FCN0 (if_parser *, _nm_auto_ifparser, ifparser_destroy);
+#define nm_auto_ifparser nm_auto(_nm_auto_ifparser)
+
+if_block *ifparser_getif (if_parser *parser, const char* iface);
+if_block *ifparser_getfirst (if_parser *parser);
+const char *ifparser_getkey (if_block* iface, const char *key);
+gboolean ifparser_haskey (if_block* iface, const char *key);
 
-if_block *ifparser_getif(const char* iface);
-if_block *ifparser_getfirst(void);
-const char *ifparser_getkey(if_block* iface, const char *key);
-gboolean ifparser_haskey(if_block* iface, const char *key);
-int ifparser_get_num_blocks(void);
-int ifparser_get_num_info(if_block* iface);
+guint ifparser_get_num_blocks (if_parser *parser);
+guint ifparser_get_num_info (if_block* iface);
 
-void add_block(const char *type, const char* name);
-void add_data(const char *key,const char *data);
-void _destroy_data(if_data *ifd);
-void _destroy_block(if_block* ifb);
 #endif
diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-parser.c b/src/settings/plugins/ifupdown/nms-ifupdown-parser.c
index 884c6591..369fa70d 100644
--- a/src/settings/plugins/ifupdown/nms-ifupdown-parser.c
+++ b/src/settings/plugins/ifupdown/nms-ifupdown-parser.c
@@ -37,42 +37,64 @@
 #include "nms-ifupdown-plugin.h"
 #include "nms-ifupdown-parser.h"
 
-static const gchar*
+/*****************************************************************************/
+
+#define _NMLOG_PREFIX_NAME      "ifupdown"
+#define _NMLOG_DOMAIN           LOGD_SETTINGS
+#define _NMLOG(level, ...) \
+    nm_log ((level), _NMLOG_DOMAIN, NULL, NULL, \
+            "%s" _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
+            _NMLOG_PREFIX_NAME": " \
+            _NM_UTILS_MACRO_REST (__VA_ARGS__))
+
+/*****************************************************************************/
+
+#define _str_has_prefix(val, prefix, require_suffix) \
+	({ \
+		const char *_val = (val); \
+		\
+		   (strncmp (_val, ""prefix"", NM_STRLEN (prefix)) == 0) \
+		&& (   !(require_suffix) \
+		    || _val[NM_STRLEN (prefix)] != '\0'); \
+	})
+
+static const char*
 _ifupdownplugin_guess_connection_type (if_block *block)
 {
-	if_data *curr = block->info;
-	const gchar* ret_type = NULL;
-	const gchar* value = ifparser_getkey(block, "inet");
-	if(value && !strcmp("ppp", value)) {
-		ret_type = NM_SETTING_PPP_SETTING_NAME;
-	}
+	const char *ret_type = NULL;
 
-	while(!ret_type && curr) {
-		if(!strncmp("wireless-", curr->key, strlen("wireless-")) ||
-		   !strncmp("wpa-", curr->key, strlen("wpa-"))) {
-			ret_type = NM_SETTING_WIRELESS_SETTING_NAME;
+	if(nm_streq0 (ifparser_getkey (block, "inet"), "ppp"))
+		ret_type = NM_SETTING_PPP_SETTING_NAME;
+	else {
+		if_data *ifb;
+
+		c_list_for_each_entry (ifb, &block->data_lst_head, data_lst) {
+			if (   _str_has_prefix (ifb->key, "wireless-", FALSE)
+			    || _str_has_prefix (ifb->key, "wpa-", FALSE)) {
+				ret_type = NM_SETTING_WIRELESS_SETTING_NAME;
+				break;
+			}
 		}
-		curr = curr->next;
+		if(!ret_type)
+			ret_type = NM_SETTING_WIRED_SETTING_NAME;
 	}
 
-	if(!ret_type)
-		ret_type = NM_SETTING_WIRED_SETTING_NAME;
-
-	nm_log_info (LOGD_SETTINGS, "guessed connection type (%s) = %s", block->name, ret_type);
+	_LOGI ("guessed connection type (%s) = %s", block->name, ret_type);
 	return ret_type;
 }
 
 struct _Mapping {
-	const gchar *domain;
+	const char *domain;
 	const gpointer target;
 };
 
 static gpointer
-map_by_mapping(struct _Mapping *mapping, const gchar *key)
+map_by_mapping (struct _Mapping *mapping, const char *key)
 {
 	struct _Mapping *curr = mapping;
-	while(curr->domain) {
-		if(!strcmp(curr->domain, key))
+
+	while (curr->domain) {
+		if (nm_streq (curr->domain, key))
 			return curr->target;
 		curr++;
 	}
@@ -80,14 +102,11 @@ map_by_mapping(struct _Mapping *mapping, const gchar *key)
 }
 
 static void
-update_wireless_setting_from_if_block(NMConnection *connection,
-							   if_block *block)
+update_wireless_setting_from_if_block (NMConnection *connection,
+                                       if_block *block)
 {
-	gint wpa_l= strlen("wpa-");
-	gint wireless_l= strlen("wireless-");
-
-	if_data *curr = block->info;
-	const gchar* value = ifparser_getkey (block, "inet");
+	if_data *curr;
+	const char *value = ifparser_getkey (block, "inet");
 	struct _Mapping mapping[] = {
 		{"ssid", "ssid"},
 		{"essid", "ssid"},
@@ -97,27 +116,26 @@ update_wireless_setting_from_if_block(NMConnection *connection,
 
 	NMSettingWireless *wireless_setting = NULL;
 
-	if(value && !strcmp("ppp", value)) {
+	if (nm_streq0 (value, "ppp"))
 		return;
-	}
 
-	nm_log_info (LOGD_SETTINGS, "update wireless settings (%s).", block->name);
-	wireless_setting = NM_SETTING_WIRELESS(nm_setting_wireless_new());
+	_LOGI ("update wireless settings (%s).", block->name);
+	wireless_setting = NM_SETTING_WIRELESS (nm_setting_wireless_new ());
+
+	c_list_for_each_entry (curr, &block->data_lst_head, data_lst) {
+		if (_str_has_prefix (curr->key, "wireless-", TRUE)) {
+			const char* newkey = map_by_mapping (mapping, curr->key + NM_STRLEN ("wireless-"));
 
-	while(curr) {
-		if(strlen(curr->key) > wireless_l &&
-		   !strncmp("wireless-", curr->key, wireless_l)) {
-			const gchar* newkey = map_by_mapping(mapping, curr->key+wireless_l);
-			nm_log_info (LOGD_SETTINGS, "wireless setting key: %s='%s'", newkey, curr->data);
-			if(newkey && !strcmp("ssid", newkey)) {
+			_LOGI ("wireless setting key: %s='%s'", newkey, curr->data);
+			if (nm_streq0 (newkey, "ssid")) {
 				GBytes *ssid;
-				gint len = strlen(curr->data);
+				int len = strlen (curr->data);
 
 				ssid = g_bytes_new (curr->data, len);
 				g_object_set (wireless_setting, NM_SETTING_WIRELESS_SSID, ssid, NULL);
 				g_bytes_unref (ssid);
-				nm_log_info (LOGD_SETTINGS, "setting wireless ssid = %d", len);
-			} else if(newkey && !strcmp("mode", newkey)) {
+				_LOGI ("setting wireless ssid = %d", len);
+			} else if (nm_streq0 (newkey, "mode")) {
 				if (!g_ascii_strcasecmp (curr->data, "Managed") || !g_ascii_strcasecmp (curr->data, "Auto"))
 					g_object_set (wireless_setting, NM_SETTING_WIRELESS_MODE, NM_SETTING_WIRELESS_MODE_INFRA, NULL);
 				else if (!g_ascii_strcasecmp (curr->data, "Ad-Hoc"))
@@ -125,39 +143,37 @@ update_wireless_setting_from_if_block(NMConnection *connection,
 				else if (!g_ascii_strcasecmp (curr->data, "Master"))
 					g_object_set (wireless_setting, NM_SETTING_WIRELESS_MODE, NM_SETTING_WIRELESS_MODE_AP, NULL);
 				else
-					nm_log_warn (LOGD_SETTINGS, "Invalid mode '%s' (not 'Ad-Hoc', 'Ap', 'Managed', or 'Auto')", curr->data);
+					_LOGW ("Invalid mode '%s' (not 'Ad-Hoc', 'Ap', 'Managed', or 'Auto')", curr->data);
 			} else {
-				g_object_set(wireless_setting,
-					   newkey, curr->data,
-					   NULL);
+				g_object_set (wireless_setting,
+				              newkey, curr->data,
+				              NULL);
 			}
-		} else if(strlen(curr->key) > wpa_l &&
-				!strncmp("wpa-", curr->key, wpa_l)) {
-			const gchar* newkey = map_by_mapping(mapping, curr->key+wpa_l);
+		} else if (_str_has_prefix (curr->key, "wpa-", TRUE)) {
+			const char* newkey = map_by_mapping (mapping, curr->key + NM_STRLEN ("wpa-"));
 
-			if(newkey && !strcmp("ssid", newkey)) {
+			if (nm_streq0 (newkey, "ssid")) {
 				GBytes *ssid;
-				gint len = strlen(curr->data);
+				int len = strlen (curr->data);
 
 				ssid = g_bytes_new (curr->data, len);
 				g_object_set (wireless_setting, NM_SETTING_WIRELESS_SSID, ssid, NULL);
 				g_bytes_unref (ssid);
-				nm_log_info (LOGD_SETTINGS, "setting wpa ssid = %d", len);
-			} else if(newkey) {
+				_LOGI ("setting wpa ssid = %d", len);
+			} else if (newkey) {
 
-				g_object_set(wireless_setting,
-						   newkey, curr->data,
-						   NULL);
-				nm_log_info (LOGD_SETTINGS, "setting wpa newkey(%s)=data(%s)", newkey, curr->data);
+				g_object_set (wireless_setting,
+				              newkey, curr->data,
+				              NULL);
+				_LOGI ("setting wpa newkey(%s)=data(%s)", newkey, curr->data);
 			}
 		}
-		curr = curr->next;
 	}
-	nm_connection_add_setting(connection, (NMSetting*) wireless_setting);
+	nm_connection_add_setting (connection, (NMSetting*) wireless_setting);
 }
 
-typedef gchar* (*IfupdownStrDupeFunc) (gpointer value, gpointer data);
-typedef gpointer (*IfupdownStrToTypeFunc) (const gchar* value);
+typedef char* (*IfupdownStrDupeFunc) (gconstpointer value, gpointer data);
+typedef gpointer (*IfupdownStrToTypeFunc) (const char* value);
 
 static char*
 normalize_dupe_wireless_key (gpointer value, gpointer data) {
@@ -177,7 +193,7 @@ normalize_dupe_wireless_key (gpointer value, gpointer data) {
 		result_cur += next - delim;
 		delim = next + 1;
 	}
-	if (*delim && strlen (valuec) > GPOINTER_TO_UINT(delim - valuec)) {
+	if (*delim && strlen (valuec) > GPOINTER_TO_UINT (delim - valuec)) {
 		strncpy (result_cur, delim, endc - delim);
 		result_cur += endc - delim;
 	}
@@ -187,12 +203,12 @@ normalize_dupe_wireless_key (gpointer value, gpointer data) {
 
 static char*
 normalize_dupe (gpointer value, gpointer data) {
-	return g_strdup(value);
+	return g_strdup (value);
 }
 
 static char*
 normalize_tolower (gpointer value, gpointer data) {
-	return g_ascii_strdown(value, -1);
+	return g_ascii_strdown (value, -1);
 }
 
 static char *normalize_psk (gpointer value, gpointer data)
@@ -203,25 +219,25 @@ static char *normalize_psk (gpointer value, gpointer data)
 }
 
 static gpointer
-string_to_gpointerint(const gchar* data)
+string_to_gpointerint (const char* data)
 {
-	gint result = (gint) strtol (data, NULL, 10);
-	return GINT_TO_POINTER(result);
+	int result = (int) strtol (data, NULL, 10);
+	return GINT_TO_POINTER (result);
 }
 
 static gpointer
-string_to_glist_of_strings(const gchar* data)
+string_to_glist_of_strings (const char* data)
 {
 	GSList *ret = NULL;
-	gchar *string = (gchar*) data;
-	while(string) {
-		gchar* next = NULL;
-		if( (next = strchr(string, ' '))  ||
-		    (next = strchr(string, '\t')) ||
-		    (next = strchr(string, '\0')) ) {
-
-			gchar *part = g_strndup(string, (next - string));
-			ret = g_slist_append(ret, part);
+	char *string = (char*) data;
+	while (string) {
+		char* next = NULL;
+		if ( (next = strchr (string, ' '))  ||
+		     (next = strchr (string, '\t')) ||
+		     (next = strchr (string, '\0')) ) {
+
+			char *part = g_strndup (string, (next - string));
+			ret = g_slist_append (ret, part);
 			if (*next)
 				string = next+1;
 			else
@@ -234,19 +250,17 @@ string_to_glist_of_strings(const gchar* data)
 }
 
 static void
-slist_free_all(gpointer slist)
+slist_free_all (gpointer slist)
 {
 	g_slist_free_full ((GSList *) slist, g_free);
 }
 
 static void
-update_wireless_security_setting_from_if_block(NMConnection *connection,
-									  if_block *block)
+update_wireless_security_setting_from_if_block (NMConnection *connection,
+                                                if_block *block)
 {
-	gint wpa_l= strlen("wpa-");
-	gint wireless_l= strlen("wireless-");
-	if_data *curr = block->info;
-	const gchar* value = ifparser_getkey (block, "inet");
+	if_data *curr;
+	const char* value = ifparser_getkey (block, "inet");
 	struct _Mapping mapping[] = {
 		{"psk", "psk"},
 		{"identity", "leap-username"},
@@ -302,101 +316,93 @@ update_wireless_security_setting_from_if_block(NMConnection *connection,
 	NMSettingWireless *s_wireless;
 	gboolean security = FALSE;
 
-	if(value && !strcmp("ppp", value)) {
+	if (nm_streq0 (value, "ppp"))
 		return;
-	}
-
-	s_wireless = nm_connection_get_setting_wireless(connection);
-	g_return_if_fail(s_wireless);
 
-	nm_log_info (LOGD_SETTINGS, "update wireless security settings (%s).", block->name);
-	wireless_security_setting =
-		NM_SETTING_WIRELESS_SECURITY(nm_setting_wireless_security_new());
+	s_wireless = nm_connection_get_setting_wireless (connection);
+	g_return_if_fail (s_wireless);
 
-	while(curr) {
-		if(strlen(curr->key) > wireless_l &&
-		   !strncmp("wireless-", curr->key, wireless_l)) {
+	_LOGI ("update wireless security settings (%s).", block->name);
+	wireless_security_setting = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
 
-			gchar *property_value = NULL;
+	c_list_for_each_entry (curr, &block->data_lst_head, data_lst) {
+		if (_str_has_prefix (curr->key, "wireless-", TRUE)) {
+			const char *key = curr->key + NM_STRLEN ("wireless-");
+			char *property_value = NULL;
 			gpointer typed_property_value = NULL;
-			const gchar* newkey = map_by_mapping(mapping, curr->key+wireless_l);
-			IfupdownStrDupeFunc dupe_func = map_by_mapping (dupe_mapping, curr->key+wireless_l);
-			IfupdownStrToTypeFunc type_map_func = map_by_mapping (type_mapping, curr->key+wireless_l);
-			GFreeFunc free_func = map_by_mapping (free_type_mapping, curr->key+wireless_l);
-			if(!newkey || !dupe_func)
+			const char* newkey = map_by_mapping (mapping, key);
+			IfupdownStrDupeFunc dupe_func = map_by_mapping (dupe_mapping, key);
+			IfupdownStrToTypeFunc type_map_func = map_by_mapping (type_mapping, key);
+			GFreeFunc free_func = map_by_mapping (free_type_mapping, key);
+			if (!newkey || !dupe_func)
 				goto next;
 
 			property_value = (*dupe_func) (curr->data, connection);
-			nm_log_info (LOGD_SETTINGS, "setting wireless security key: %s=%s",
-			             newkey, property_value);
+			_LOGI ("setting wireless security key: %s=%s",
+			       newkey, property_value);
 
 			if (type_map_func) {
 				errno = 0;
 				typed_property_value = (*type_map_func) (property_value);
-				if(errno)
+				if (errno)
 					goto wireless_next;
 			}
 
-			g_object_set(wireless_security_setting,
-					   newkey, typed_property_value ?: property_value,
-					   NULL);
+			g_object_set (wireless_security_setting,
+			              newkey, typed_property_value ?: property_value,
+			              NULL);
 			security = TRUE;
 
-		wireless_next:
-			g_free(property_value);
+wireless_next:
+			g_free (property_value);
 			if (typed_property_value && free_func)
 				(*free_func) (typed_property_value);
 
-		} else if(strlen(curr->key) > wpa_l &&
-				!strncmp("wpa-", curr->key, wpa_l)) {
-
-			gchar *property_value = NULL;
+		} else if (_str_has_prefix (curr->key, "wpa-", TRUE)) {
+			const char *key = curr->key + NM_STRLEN ("wpa-");
+			char *property_value = NULL;
 			gpointer typed_property_value = NULL;
-			const gchar* newkey = map_by_mapping(mapping, curr->key+wpa_l);
-			IfupdownStrDupeFunc dupe_func = map_by_mapping (dupe_mapping, curr->key+wpa_l);
-			IfupdownStrToTypeFunc type_map_func = map_by_mapping (type_mapping, curr->key+wpa_l);
-			GFreeFunc free_func = map_by_mapping (free_type_mapping, curr->key+wpa_l);
-			if(!newkey || !dupe_func)
+			const char* newkey = map_by_mapping (mapping, key);
+			IfupdownStrDupeFunc dupe_func = map_by_mapping (dupe_mapping, key);
+			IfupdownStrToTypeFunc type_map_func = map_by_mapping (type_mapping, key);
+			GFreeFunc free_func = map_by_mapping (free_type_mapping, key);
+			if (!newkey || !dupe_func)
 				goto next;
 
 			property_value = (*dupe_func) (curr->data, connection);
-			nm_log_info (LOGD_SETTINGS, "setting wpa security key: %s=%s",
-			             newkey,
-#ifdef DEBUG_SECRETS
-			             property_value
-#else /* DEBUG_SECRETS */
-			             !strcmp("key", newkey) ||
-			             !strcmp("leap-password", newkey) ||
-			             !strcmp("pin", newkey) ||
-			             !strcmp("psk", newkey) ||
-			             !strcmp("wep-key0", newkey) ||
-			             !strcmp("wep-key1", newkey) ||
-			             !strcmp("wep-key2", newkey) ||
-			             !strcmp("wep-key3", newkey) ||
-			             NULL ?
-			             "<omitted>" : property_value
-#endif /* DEBUG_SECRETS */
-			             );
+			_LOGI ("setting wpa security key: %s=%s",
+			       newkey,
+			       NM_IN_STRSET (newkey, "key",
+			                             "leap-password",
+			                             "pin",
+			                             "psk",
+			                             "wep-key0",
+			                             "wep-key1",
+			                             "wep-key2",
+			                             "wep-key3")
+			         ? "<omitted>"
+			         : property_value
+			       );
 
 			if (type_map_func) {
 				errno = 0;
 				typed_property_value = (*type_map_func) (property_value);
-				if(errno)
+				if (errno)
 					goto wpa_next;
 			}
 
-			g_object_set(wireless_security_setting,
-					   newkey, typed_property_value ?: property_value,
-					   NULL);
+			g_object_set (wireless_security_setting,
+			              newkey, typed_property_value ?: property_value,
+			              NULL);
 			security = TRUE;
 
-		wpa_next:
-			g_free(property_value);
+wpa_next:
+			g_free (property_value);
 			if (free_func && typed_property_value)
 				(*free_func) (typed_property_value);
 		}
-	next:
-		curr = curr->next;
+next:
+		;
 	}
 
 	if (security)
@@ -404,51 +410,52 @@ update_wireless_security_setting_from_if_block(NMConnection *connection,
 }
 
 static void
-update_wired_setting_from_if_block(NMConnection *connection,
-							if_block *block)
+update_wired_setting_from_if_block (NMConnection *connection,
+                                    if_block *block)
 {
 	NMSettingWired *s_wired = NULL;
-	s_wired = NM_SETTING_WIRED(nm_setting_wired_new());
-	nm_connection_add_setting(connection, NM_SETTING(s_wired));
+	s_wired = NM_SETTING_WIRED (nm_setting_wired_new ());
+	nm_connection_add_setting (connection, NM_SETTING (s_wired));
 }
 
 static void
 ifupdown_ip4_add_dns (NMSettingIPConfig *s_ip4, const char *dns)
 {
 	guint32 addr;
-	char **list, **iter;
+	gs_strfreev char **list = NULL;
+	char **iter;
 
 	if (dns == NULL)
 		return;
 
 	list = g_strsplit_set (dns, " \t", -1);
 	for (iter = list; iter && *iter; iter++) {
-		g_strstrip (*iter);
-		if (g_ascii_isspace (*iter[0]))
+		if ((*iter)[0] == '\0')
 			continue;
 		if (!inet_pton (AF_INET, *iter, &addr)) {
-			nm_log_warn (LOGD_SETTINGS, "    ignoring invalid nameserver '%s'", *iter);
+			_LOGW ("    ignoring invalid nameserver '%s'", *iter);
 			continue;
 		}
 
 		if (!nm_setting_ip_config_add_dns (s_ip4, *iter))
-			nm_log_warn (LOGD_SETTINGS, "    duplicate DNS domain '%s'", *iter);
+			_LOGW ("    duplicate DNS domain '%s'", *iter);
 	}
-	g_strfreev (list);
 }
 
 static gboolean
-update_ip4_setting_from_if_block(NMConnection *connection,
-						   if_block *block,
-						   GError **error)
+update_ip4_setting_from_if_block (NMConnection *connection,
+                                  if_block *block,
+                                  GError **error)
 {
 
-	NMSettingIPConfig *s_ip4 = NM_SETTING_IP_CONFIG (nm_setting_ip4_config_new());
-	const char *type = ifparser_getkey(block, "inet");
-	gboolean is_static = type && !strcmp("static", type);
+	gs_unref_object NMSettingIPConfig *s_ip4 = NM_SETTING_IP_CONFIG (nm_setting_ip4_config_new ());
+	const char *type = ifparser_getkey (block, "inet");
 
-	if (!is_static) {
-		g_object_set (s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);
+	if (!nm_streq0 (type, "static")) {
+		g_object_set (s_ip4,
+		              NM_SETTING_IP_CONFIG_METHOD,
+		              NM_SETTING_IP4_CONFIG_METHOD_AUTO,
+		              NULL);
 	} else {
 		guint32 tmp_mask;
 		NMIPAddress *addr;
@@ -458,7 +465,6 @@ update_ip4_setting_from_if_block(NMConnection *connection,
 		const char *nameserver_v;
 		const char *nameservers_v;
 		const char *search_v;
-		char **list, **iter;
 		guint32 netmask_int = 32;
 
 		/* Address */
@@ -466,7 +472,7 @@ update_ip4_setting_from_if_block(NMConnection *connection,
 		if (!address_v) {
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 			             "Missing IPv4 address");
-			goto error;
+			return FALSE;
 		}
 
 		/* mask/prefix */
@@ -476,8 +482,8 @@ update_ip4_setting_from_if_block(NMConnection *connection,
 				netmask_int = atoi (netmask_v);
 			} else if (!inet_pton (AF_INET, netmask_v, &tmp_mask)) {
 				g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-						   "Invalid IPv4 netmask '%s'", netmask_v);
-				goto error;
+				             "Invalid IPv4 netmask '%s'", netmask_v);
+				return FALSE;
 			} else {
 				netmask_int = nm_utils_ip4_netmask_to_prefix (tmp_mask);
 			}
@@ -486,13 +492,13 @@ update_ip4_setting_from_if_block(NMConnection *connection,
 		/* Add the new address to the setting */
 		addr = nm_ip_address_new (AF_INET, address_v, netmask_int, error);
 		if (!addr)
-			goto error;
+			return FALSE;
 
 		if (nm_setting_ip_config_add_address (s_ip4, addr)) {
-			nm_log_info (LOGD_SETTINGS, "addresses count: %d",
-			             nm_setting_ip_config_get_num_addresses (s_ip4));
+			_LOGI ("addresses count: %d",
+			       nm_setting_ip_config_get_num_addresses (s_ip4));
 		} else {
-			nm_log_info (LOGD_SETTINGS, "ignoring duplicate IP4 address");
+			_LOGI ("ignoring duplicate IP4 address");
 		}
 		nm_ip_address_unref (addr);
 
@@ -502,7 +508,7 @@ update_ip4_setting_from_if_block(NMConnection *connection,
 			if (!nm_utils_ipaddr_valid (AF_INET, gateway_v)) {
 				g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 				             "Invalid IPv4 gateway '%s'", gateway_v);
-				goto error;
+				return FALSE;
 			}
 			if (!nm_setting_ip_config_get_gateway (s_ip4))
 				g_object_set (s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, gateway_v, NULL);
@@ -515,70 +521,67 @@ update_ip4_setting_from_if_block(NMConnection *connection,
 		ifupdown_ip4_add_dns (s_ip4, nameservers_v);
 
 		if (!nm_setting_ip_config_get_num_dns (s_ip4))
-			nm_log_info (LOGD_SETTINGS, "No dns-nameserver configured in /etc/network/interfaces");
+			_LOGI ("No dns-nameserver configured in /etc/network/interfaces");
 
 		/* DNS searches */
 		search_v = ifparser_getkey (block, "dns-search");
 		if (search_v) {
+			gs_strfreev char **list = NULL;
+			char **iter;
+
 			list = g_strsplit_set (search_v, " \t", -1);
 			for (iter = list; iter && *iter; iter++) {
-				g_strstrip (*iter);
-				if (g_ascii_isspace (*iter[0]))
+				if ((*iter)[0] == '\0')
 					continue;
 				if (!nm_setting_ip_config_add_dns_search (s_ip4, *iter))
-					nm_log_warn (LOGD_SETTINGS, "    duplicate DNS domain '%s'", *iter);
+					_LOGW ("    duplicate DNS domain '%s'", *iter);
 			}
-			g_strfreev (list);
 		}
 
 		g_object_set (s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL, NULL);
 	}
 
-	nm_connection_add_setting (connection, NM_SETTING (s_ip4));
+	nm_connection_add_setting (connection, NM_SETTING (g_steal_pointer (&s_ip4)));
 	return TRUE;
-
-error:
-	g_object_unref (s_ip4);
-	return FALSE;
 }
 
 static void
 ifupdown_ip6_add_dns (NMSettingIPConfig *s_ip6, const char *dns)
 {
 	struct in6_addr addr;
-	char **list, **iter;
+	gs_strfreev char **list = NULL;
+	char **iter;
 
 	if (dns == NULL)
 		return;
 
 	list = g_strsplit_set (dns, " \t", -1);
 	for (iter = list; iter && *iter; iter++) {
-		g_strstrip (*iter);
-		if (g_ascii_isspace (*iter[0]))
+		if ((*iter)[0] == '\0')
 			continue;
 		if (!inet_pton (AF_INET6, *iter, &addr)) {
-			nm_log_warn (LOGD_SETTINGS, "    ignoring invalid nameserver '%s'", *iter);
+			_LOGW ("    ignoring invalid nameserver '%s'", *iter);
 			continue;
 		}
 
 		if (!nm_setting_ip_config_add_dns (s_ip6, *iter))
-			nm_log_warn (LOGD_SETTINGS, "    duplicate DNS domain '%s'", *iter);
+			_LOGW ("    duplicate DNS domain '%s'", *iter);
 	}
-	g_strfreev (list);
 }
 
 static gboolean
-update_ip6_setting_from_if_block(NMConnection *connection,
-						   if_block *block,
-						   GError **error)
+update_ip6_setting_from_if_block (NMConnection *connection,
+                                  if_block *block,
+                                  GError **error)
 {
-	NMSettingIPConfig *s_ip6 = NM_SETTING_IP_CONFIG (nm_setting_ip6_config_new());
-	const char *type = ifparser_getkey(block, "inet6");
-	gboolean is_static = type && (!strcmp("static", type) ||
-							!strcmp("v4tunnel", type));
+	gs_unref_object NMSettingIPConfig *s_ip6 = NM_SETTING_IP_CONFIG (nm_setting_ip6_config_new ());
+	const char *type = ifparser_getkey (block, "inet6");
 
-	if (!is_static) {
-		g_object_set(s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NULL);
+	if (!NM_IN_STRSET (type, "static", "v4tunnel")) {
+		g_object_set (s_ip6,
+		              NM_SETTING_IP_CONFIG_METHOD,
+		              NM_SETTING_IP6_CONFIG_METHOD_AUTO,
+		              NULL);
 	} else {
 		NMIPAddress *addr;
 		const char *address_v;
@@ -588,31 +591,30 @@ update_ip6_setting_from_if_block(NMConnection *connection,
 		const char *nameservers_v;
 		const char *search_v;
 		int prefix_int = 128;
-		char **list, **iter;
 
 		/* Address */
-		address_v = ifparser_getkey(block, "address");
+		address_v = ifparser_getkey (block, "address");
 		if (!address_v) {
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 			             "Missing IPv6 address");
-			goto error;
+			return FALSE;
 		}
 
 		/* Prefix */
-		prefix_v = ifparser_getkey(block, "netmask");
+		prefix_v = ifparser_getkey (block, "netmask");
 		if (prefix_v)
 			prefix_int = g_ascii_strtoll (prefix_v, NULL, 10);
 
 		/* Add the new address to the setting */
 		addr = nm_ip_address_new (AF_INET6, address_v, prefix_int, error);
 		if (!addr)
-			goto error;
+			return FALSE;
 
 		if (nm_setting_ip_config_add_address (s_ip6, addr)) {
-			nm_log_info (LOGD_SETTINGS, "addresses count: %d",
+			_LOGI ("addresses count: %d",
 			             nm_setting_ip_config_get_num_addresses (s_ip6));
 		} else {
-			nm_log_info (LOGD_SETTINGS, "ignoring duplicate IP6 address");
+			_LOGI ("ignoring duplicate IP6 address");
 		}
 		nm_ip_address_unref (addr);
 
@@ -622,33 +624,34 @@ update_ip6_setting_from_if_block(NMConnection *connection,
 			if (!nm_utils_ipaddr_valid (AF_INET6, gateway_v)) {
 				g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 				             "Invalid IPv6 gateway '%s'", gateway_v);
-				goto error;
+				return FALSE;
 			}
 			if (!nm_setting_ip_config_get_gateway (s_ip6))
 				g_object_set (s_ip6, NM_SETTING_IP_CONFIG_GATEWAY, gateway_v, NULL);
 		}
 
-		nameserver_v = ifparser_getkey(block, "dns-nameserver");
+		nameserver_v = ifparser_getkey (block, "dns-nameserver");
 		ifupdown_ip6_add_dns (s_ip6, nameserver_v);
 
-		nameservers_v = ifparser_getkey(block, "dns-nameservers");
+		nameservers_v = ifparser_getkey (block, "dns-nameservers");
 		ifupdown_ip6_add_dns (s_ip6, nameservers_v);
 
 		if (!nm_setting_ip_config_get_num_dns (s_ip6))
-			nm_log_info (LOGD_SETTINGS, "No dns-nameserver configured in /etc/network/interfaces");
+			_LOGI ("No dns-nameserver configured in /etc/network/interfaces");
 
 		/* DNS searches */
 		search_v = ifparser_getkey (block, "dns-search");
 		if (search_v) {
+			gs_strfreev char **list = NULL;
+			char **iter;
+
 			list = g_strsplit_set (search_v, " \t", -1);
 			for (iter = list; iter && *iter; iter++) {
-				g_strstrip (*iter);
-				if (isblank (*iter[0]))
+				if ((*iter)[0] == '\0')
 					continue;
 				if (!nm_setting_ip_config_add_dns_search (s_ip6, *iter))
-					nm_log_warn (LOGD_SETTINGS, "    duplicate DNS domain '%s'", *iter);
+					_LOGW ("    duplicate DNS domain '%s'", *iter);
 			}
-			g_strfreev (list);
 		}
 
 		g_object_set (s_ip6,
@@ -656,12 +659,8 @@ update_ip6_setting_from_if_block(NMConnection *connection,
 		              NULL);
 	}
 
-	nm_connection_add_setting (connection, NM_SETTING (s_ip6));
+	nm_connection_add_setting (connection, NM_SETTING (g_steal_pointer (&s_ip6)));
 	return TRUE;
-
-error:
-	g_object_unref (s_ip6);
-	return FALSE;
 }
 
 gboolean
@@ -669,25 +668,22 @@ ifupdown_update_connection_from_if_block (NMConnection *connection,
                                           if_block *block,
                                           GError **error)
 {
-	const char *type = NULL;
-	char *idstr = NULL;
-	char *uuid_base = NULL;
-	char *uuid = NULL;
+	const char *type;
+	gs_free char *idstr = NULL;
+	gs_free char *uuid = NULL;
 	NMSettingConnection *s_con;
 	gboolean success = FALSE;
 
 	s_con = nm_connection_get_setting_connection (connection);
-	if(!s_con) {
-		s_con = NM_SETTING_CONNECTION (nm_setting_connection_new());
-		g_assert (s_con);
+	if (!s_con) {
+		s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
 		nm_connection_add_setting (connection, NM_SETTING (s_con));
 	}
 
 	type = _ifupdownplugin_guess_connection_type (block);
 	idstr = g_strconcat ("Ifupdown (", block->name, ")", NULL);
-	uuid_base = idstr;
 
-	uuid = nm_utils_uuid_generate_from_string (uuid_base, -1, NM_UTILS_UUID_TYPE_LEGACY, NULL);
+	uuid = nm_utils_uuid_generate_from_string (idstr, -1, NM_UTILS_UUID_TYPE_LEGACY, NULL);
 	g_object_set (s_con,
 	              NM_SETTING_CONNECTION_TYPE, type,
 	              NM_SETTING_CONNECTION_INTERFACE_NAME, block->name,
@@ -696,19 +692,18 @@ ifupdown_update_connection_from_if_block (NMConnection *connection,
 	              NM_SETTING_CONNECTION_READ_ONLY, TRUE,
 	              NM_SETTING_CONNECTION_AUTOCONNECT, FALSE,
 	              NULL);
-	g_free (uuid);
 
-	nm_log_info (LOGD_SETTINGS, "update_connection_setting_from_if_block: name:%s, type:%s, id:%s, uuid: %s",
-	             block->name, type, idstr, nm_setting_connection_get_uuid (s_con));
+	_LOGI ("update_connection_setting_from_if_block: name:%s, type:%s, id:%s, uuid: %s",
+	       block->name, type, idstr, nm_setting_connection_get_uuid (s_con));
 
-	if (!strcmp (NM_SETTING_WIRED_SETTING_NAME, type))
+	if (nm_streq (type, NM_SETTING_WIRED_SETTING_NAME))
 		update_wired_setting_from_if_block (connection, block);
-	else if (!strcmp (NM_SETTING_WIRELESS_SETTING_NAME, type)) {
+	else if (nm_streq (type, NM_SETTING_WIRELESS_SETTING_NAME)) {
 		update_wireless_setting_from_if_block (connection, block);
 		update_wireless_security_setting_from_if_block (connection, block);
 	}
 
-	if (ifparser_haskey(block, "inet6"))
+	if (ifparser_haskey (block, "inet6"))
 		success = update_ip6_setting_from_if_block (connection, block, error);
 	else
 		success = update_ip4_setting_from_if_block (connection, block, error);
@@ -716,6 +711,5 @@ ifupdown_update_connection_from_if_block (NMConnection *connection,
 	if (success == TRUE)
 		success = nm_connection_verify (connection, error);
 
-	g_free (idstr);
 	return success;
 }
diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c b/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c
index 8bd72d02..88c651b8 100644
--- a/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c
+++ b/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c
@@ -29,7 +29,6 @@
 #include <string.h>
 #include <arpa/inet.h>
 #include <gmodule.h>
-#include <libudev.h>
 
 #include "nm-setting-connection.h"
 #include "nm-dbus-interface.h"
@@ -42,7 +41,6 @@
 #include "nm-core-internal.h"
 #include "NetworkManagerUtils.h"
 #include "nm-config.h"
-#include "nm-utils/nm-udev-utils.h"
 
 #include "nms-ifupdown-interface-parser.h"
 #include "nms-ifupdown-connection.h"
@@ -52,43 +50,27 @@
 
 #define IFUPDOWN_UNMANAGE_WELL_KNOWN_DEFAULT TRUE
 
-/* #define ALWAYS_UNMANAGE TRUE */
-#ifndef ALWAYS_UNMANAGE
-#define ALWAYS_UNMANAGE FALSE
-#endif
-
 /*****************************************************************************/
 
 typedef struct {
-	NMUdevClient *udev_client;
-
-	GHashTable *connections;  /* /e/n/i block name :: NMIfupdownConnection */
-
-	/* Stores all blocks/interfaces read from /e/n/i regardless of whether
-	 * there is an NMIfupdownConnection for block.
+	/* Stores an entry for blocks/interfaces read from /e/n/i and (if exists)
+	 * the NMIfupdownConnection associated with the block.
 	 */
 	GHashTable *eni_ifaces;
 
-	/* Stores any network interfaces the kernel knows about */
-	GHashTable *kernel_ifaces;
-
-	gboolean unmanage_well_known;
+	bool ifupdown_managed;
 } SettingsPluginIfupdownPrivate;
 
 struct _SettingsPluginIfupdown {
-	GObject parent;
+	NMSettingsPlugin parent;
 	SettingsPluginIfupdownPrivate _priv;
 };
 
 struct _SettingsPluginIfupdownClass {
-	GObjectClass parent;
+	NMSettingsPluginClass parent;
 };
 
-static void settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface);
-
-G_DEFINE_TYPE_EXTENDED (SettingsPluginIfupdown, settings_plugin_ifupdown, G_TYPE_OBJECT, 0,
-                        G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_PLUGIN,
-                                               settings_plugin_interface_init))
+G_DEFINE_TYPE (SettingsPluginIfupdown, settings_plugin_ifupdown, NM_TYPE_SETTINGS_PLUGIN)
 
 #define SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE(self) _NM_GET_PRIVATE (self, SettingsPluginIfupdown, SETTINGS_IS_PLUGIN_IFUPDOWN)
 
@@ -99,169 +81,41 @@ NM_DEFINE_SINGLETON_GETTER (SettingsPluginIfupdown, settings_plugin_ifupdown_get
 
 /*****************************************************************************/
 
-static void
-bind_device_to_connection (SettingsPluginIfupdown *self,
-                           struct udev_device *device,
-                           NMIfupdownConnection *exported)
-{
-	NMSettingWired *s_wired;
-	NMSettingWireless *s_wifi;
-	const char *iface, *address;
-
-	iface = udev_device_get_sysname (device);
-	if (!iface) {
-		nm_log_warn (LOGD_SETTINGS, "failed to get ifname for device.");
-		return;
-	}
-
-	address = udev_device_get_sysattr_value (device, "address");
-	if (!address || !address[0]) {
-		nm_log_warn (LOGD_SETTINGS, "failed to get MAC address for %s", iface);
-		return;
-	}
-
-	if (!nm_utils_hwaddr_valid (address, ETH_ALEN)) {
-		nm_log_warn (LOGD_SETTINGS, "failed to parse MAC address '%s' for %s",
-		             address, iface);
-		return;
-	}
-
-	s_wired = nm_connection_get_setting_wired (NM_CONNECTION (exported));
-	s_wifi = nm_connection_get_setting_wireless (NM_CONNECTION (exported));
-	if (s_wired) {
-		nm_log_info (LOGD_SETTINGS, "locking wired connection setting");
-		g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, address, NULL);
-	} else if (s_wifi) {
-		nm_log_info (LOGD_SETTINGS, "locking wireless connection setting");
-		g_object_set (s_wifi, NM_SETTING_WIRELESS_MAC_ADDRESS, address, NULL);
-	}
-
-	nm_settings_connection_update (NM_SETTINGS_CONNECTION (exported),
-	                               NULL,
-	                               NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK,
-	                               NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE,
-	                               "ifupdown-new",
-	                               NULL);
-}
-
-static void
-udev_device_added (SettingsPluginIfupdown *self, struct udev_device *device)
-{
-	SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (self);
-	const char *iface, *path;
-	NMIfupdownConnection *exported;
-
-	iface = udev_device_get_sysname (device);
-	path = udev_device_get_syspath (device);
-	if (!iface || !path)
-		return;
-
-	nm_log_info (LOGD_SETTINGS, "devices added (path: %s, iface: %s)", path, iface);
-
-	/* if we have a configured connection for this particular iface
-	 * we want to either unmanage the device or lock it
-	 */
-	exported = g_hash_table_lookup (priv->connections, iface);
-	if (!exported && !g_hash_table_lookup (priv->eni_ifaces, iface)) {
-		nm_log_info (LOGD_SETTINGS, "device added (path: %s, iface: %s): no ifupdown configuration found.",
-		             path, iface);
-		return;
-	}
-
-	g_hash_table_insert (priv->kernel_ifaces, g_strdup (iface), udev_device_ref (device));
-
-	if (exported)
-		bind_device_to_connection (self, device, exported);
-
-	if (ALWAYS_UNMANAGE || priv->unmanage_well_known)
-		g_signal_emit_by_name (G_OBJECT (self), NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED);
-}
-
-static void
-udev_device_removed (SettingsPluginIfupdown *self, struct udev_device *device)
-{
-	SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (self);
-	const char *iface, *path;
-
-	iface = udev_device_get_sysname (device);
-	path = udev_device_get_syspath (device);
-	if (!iface || !path)
-		return;
-
-	nm_log_info (LOGD_SETTINGS, "devices removed (path: %s, iface: %s)", path, iface);
-
-	if (!g_hash_table_remove (priv->kernel_ifaces, iface))
-		return;
-
-	if (ALWAYS_UNMANAGE || priv->unmanage_well_known)
-		g_signal_emit_by_name (G_OBJECT (self), NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED);
-}
-
-static void
-udev_device_changed (SettingsPluginIfupdown *self, struct udev_device *device)
-{
-	SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (self);
-	const char *iface, *path;
-
-	iface = udev_device_get_sysname (device);
-	path = udev_device_get_syspath (device);
-	if (!iface || !path)
-		return;
-
-	nm_log_info (LOGD_SETTINGS, "device changed (path: %s, iface: %s)", path, iface);
-
-	if (!g_hash_table_lookup (priv->kernel_ifaces, iface))
-		return;
-
-	if (ALWAYS_UNMANAGE || priv->unmanage_well_known)
-		g_signal_emit_by_name (G_OBJECT (self), NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED);
-}
-
-static void
-handle_uevent (NMUdevClient *client,
-               struct udev_device *device,
-               gpointer user_data)
-{
-	SettingsPluginIfupdown *self = SETTINGS_PLUGIN_IFUPDOWN (user_data);
-	const char *subsys;
-	const char *action;
-
-	action = udev_device_get_action (device);
-
-	g_return_if_fail (action != NULL);
+#define _NMLOG_PREFIX_NAME      "ifupdown"
+#define _NMLOG_DOMAIN           LOGD_SETTINGS
+#define _NMLOG(level, ...) \
+    nm_log ((level), _NMLOG_DOMAIN, NULL, NULL, \
+            "%s" _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
+            _NMLOG_PREFIX_NAME": " \
+            _NM_UTILS_MACRO_REST (__VA_ARGS__))
 
-	/* A bit paranoid */
-	subsys = udev_device_get_subsystem (device);
-	g_return_if_fail (nm_streq0 (subsys, "net"));
-
-	if (!strcmp (action, "add"))
-		udev_device_added (self, device);
-	else if (!strcmp (action, "remove"))
-		udev_device_removed (self, device);
-	else if (!strcmp (action, "change"))
-		udev_device_changed (self, device);
-}
+/*****************************************************************************/
 
 /* Returns the plugins currently known list of connections.  The returned
  * list is freed by the system settings service.
  */
 static GSList*
-get_connections (NMSettingsPlugin *config)
+get_connections (NMSettingsPlugin *plugin)
 {
-	SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE ((SettingsPluginIfupdown *) config);
-	GSList *connections;
-
-	nm_log_info (LOGD_SETTINGS, "(%d) ... get_connections.", GPOINTER_TO_UINT(config));
+	SettingsPluginIfupdown *self = SETTINGS_PLUGIN_IFUPDOWN (plugin);
+	SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (self);
+	GSList *list = NULL;
+	GHashTableIter iter;
+	void *value;
 
-	if(priv->unmanage_well_known) {
-		nm_log_info (LOGD_SETTINGS, "(%d) ... get_connections (managed=false): return empty list.", GPOINTER_TO_UINT(config));
+	if (!priv->ifupdown_managed) {
+		_LOGD ("get_connections: not connections due to managed=false");
 		return NULL;
 	}
 
-	connections = _nm_utils_hash_values_to_slist (priv->connections);
+	g_hash_table_iter_init (&iter, priv->eni_ifaces);
+	while (g_hash_table_iter_next (&iter, NULL, &value)) {
+		if (value)
+			list = g_slist_prepend (list, value);
+	}
 
-	nm_log_info (LOGD_SETTINGS, "(%d) connections count: %d", GPOINTER_TO_UINT(config), g_slist_length(connections));
-	return connections;
+	_LOGD ("get_connections: %u connections", g_slist_length (list));
+	return list;
 }
 
 /*
@@ -270,202 +124,178 @@ get_connections (NMSettingsPlugin *config)
  * each element must be allocated using g_malloc() or its variants.
  */
 static GSList*
-get_unmanaged_specs (NMSettingsPlugin *config)
+get_unmanaged_specs (NMSettingsPlugin *plugin)
 {
-	SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE ((SettingsPluginIfupdown *) config);
+	SettingsPluginIfupdown *self = SETTINGS_PLUGIN_IFUPDOWN (plugin);
+	SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (self);
 	GSList *specs = NULL;
 	GHashTableIter iter;
-	struct udev_device *device;
 	const char *iface;
 
-	if (!ALWAYS_UNMANAGE && !priv->unmanage_well_known)
+	if (priv->ifupdown_managed)
 		return NULL;
 
-	nm_log_info (LOGD_SETTINGS, "get unmanaged devices count: %d",
-	             g_hash_table_size (priv->kernel_ifaces));
-
-	g_hash_table_iter_init (&iter, priv->kernel_ifaces);
-	while (g_hash_table_iter_next (&iter, (gpointer) &iface, (gpointer) &device)) {
-		const char *address;
+	_LOGD ("unmanaged-specs: unmanaged devices count %u",
+	       g_hash_table_size (priv->eni_ifaces));
 
-		address = udev_device_get_sysattr_value (device, "address");
-		if (address)
-			specs = g_slist_append (specs, g_strdup_printf ("mac:%s", address));
-		else
-			specs = g_slist_append (specs, g_strdup_printf ("interface-name:%s", iface));
-	}
+	g_hash_table_iter_init (&iter, priv->eni_ifaces);
+	while (g_hash_table_iter_next (&iter, (gpointer) &iface, NULL))
+		specs = g_slist_append (specs, g_strdup_printf ("interface-name:=%s", iface));
 	return specs;
 }
 
 /*****************************************************************************/
 
 static void
-_udev_device_unref (gpointer ptr)
+initialize (NMSettingsPlugin *plugin)
 {
-	udev_device_unref (ptr);
-}
-
-static void
-init (NMSettingsPlugin *config)
-{
-	SettingsPluginIfupdown *self = SETTINGS_PLUGIN_IFUPDOWN (config);
+	SettingsPluginIfupdown *self = SETTINGS_PLUGIN_IFUPDOWN (plugin);
 	SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (self);
-	GHashTable *auto_ifaces;
-	if_block *block = NULL;
-	struct udev_enumerate *enumerate;
-	struct udev_list_entry *keys;
+	gs_unref_hashtable GHashTable *auto_ifaces = NULL;
+	nm_auto_ifparser if_parser *parser = NULL;
+	if_block *block;
 	GHashTableIter con_iter;
 	const char *block_name;
-	NMIfupdownConnection *connection;
-
-	auto_ifaces = g_hash_table_new (nm_str_hash, g_str_equal);
-
-	if(!priv->connections)
-		priv->connections = g_hash_table_new (nm_str_hash, g_str_equal);
-
-	if(!priv->kernel_ifaces)
-		priv->kernel_ifaces = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, _udev_device_unref);
+	NMIfupdownConnection *conn;
 
-	if(!priv->eni_ifaces)
-		priv->eni_ifaces = g_hash_table_new (nm_str_hash, g_str_equal);
+	parser = ifparser_parse (ENI_INTERFACES_FILE, 0);
 
-	nm_log_info (LOGD_SETTINGS, "init!");
+	c_list_for_each_entry (block, &parser->block_lst_head, block_lst) {
 
-	priv->udev_client = nm_udev_client_new ((const char *[]) { "net", NULL },
-	                                        handle_uevent, self);
-
-	/* Read in all the interfaces */
-	ifparser_init (ENI_INTERFACES_FILE, 0);
-	block = ifparser_getfirst ();
-	while (block) {
-		if(!strcmp ("auto", block->type) || !strcmp ("allow-hotplug", block->type))
-			g_hash_table_insert (auto_ifaces, block->name, GUINT_TO_POINTER (1));
-		else if (!strcmp ("iface", block->type)) {
-			NMIfupdownConnection *exported;
+		if (NM_IN_STRSET (block->type, "auto", "allow-hotplug")) {
+			if (!auto_ifaces)
+				auto_ifaces = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, NULL);
+			g_hash_table_add (auto_ifaces, g_strdup (block->name));
+			continue;
+		}
 
+		if (nm_streq (block->type, "iface")) {
 			/* Bridge configuration */
-			if(!strncmp ("br", block->name, 2)) {
+			if (g_str_has_prefix (block_name, "br")) {
 				/* Try to find bridge ports */
 				const char *ports = ifparser_getkey (block, "bridge-ports");
+
 				if (ports) {
-					int i;
+					guint i;
 					int state = 0;
-					char **port_ifaces;
+					gs_strfreev char **port_ifaces = NULL;
 
-					nm_log_info (LOGD_SETTINGS, "found bridge ports %s for %s", ports, block->name);
+					_LOGD ("parse: found bridge ports %s for %s", ports, block->name);
 
 					port_ifaces = g_strsplit_set (ports, " \t", -1);
-					for (i = 0; i < g_strv_length (port_ifaces); i++) {
-						char *token = port_ifaces[i];
+					for (i = 0; port_ifaces[i]; i++) {
+						const char *token = port_ifaces[i];
+
 						/* Skip crazy stuff like regex or all */
-						if (!strcmp ("all", token)) {
+						if (nm_streq (token, "all"))
 							continue;
-						}
+
 						/* Small SM to skip everything inside regex */
-						if (!strcmp ("regex", token)) {
+						if (nm_streq (token, "regex")) {
 							state++;
 							continue;
 						}
-						if (!strcmp ("noregex", token)) {
+						if (nm_streq (token, "noregex")) {
 							state--;
 							continue;
 						}
+						if (nm_streq (token, "none"))
+							continue;
 						if (state == 0 && strlen (token) > 0) {
-							nm_log_info (LOGD_SETTINGS, "adding bridge port %s to eni_ifaces", token);
-							g_hash_table_insert (priv->eni_ifaces, g_strdup (token), "known");
+							conn = g_hash_table_lookup (priv->eni_ifaces, block->name);
+							if (!conn) {
+								_LOGD ("parse: adding bridge port \"%s\"", token);
+								g_hash_table_insert (priv->eni_ifaces, g_strdup (token), NULL);
+							} else {
+								_LOGD ("parse: adding bridge port \"%s\" (have connection %s)", token,
+								       nm_settings_connection_get_uuid (NM_SETTINGS_CONNECTION (conn)));
+							}
 						}
 					}
-					g_strfreev (port_ifaces);
 				}
-				goto next;
+				continue;
 			}
 
 			/* Skip loopback configuration */
-			if(!strcmp ("lo", block->name)) {
-				goto next;
-			}
+			if (nm_streq (block->name, "lo"))
+				continue;
 
 			/* Remove any connection for this block that was previously found */
-			exported = g_hash_table_lookup (priv->connections, block->name);
-			if (exported) {
-				nm_log_info (LOGD_SETTINGS, "deleting %s from connections", block->name);
-				nm_settings_connection_delete (NM_SETTINGS_CONNECTION (exported), NULL);
-				g_hash_table_remove (priv->connections, block->name);
+			conn = g_hash_table_lookup (priv->eni_ifaces, block->name);
+			if (conn) {
+				_LOGD ("parse: replace connection \"%s\" (%s)",
+				       block->name,
+				       nm_settings_connection_get_uuid (NM_SETTINGS_CONNECTION (conn)));
+				nm_settings_connection_delete (NM_SETTINGS_CONNECTION (conn), NULL);
+				g_hash_table_remove (priv->eni_ifaces, block->name);
 			}
 
 			/* add the new connection */
-			exported = nm_ifupdown_connection_new (block);
-			if (exported) {
-				nm_log_info (LOGD_SETTINGS, "adding %s to connections", block->name);
-				g_hash_table_insert (priv->connections, block->name, exported);
+			conn = nm_ifupdown_connection_new (block);
+			if (conn) {
+				_LOGD ("parse: adding connection \"%s\" (%s)", block->name,
+				       nm_settings_connection_get_uuid (NM_SETTINGS_CONNECTION (conn)));
+			} else
+				_LOGD ("parse: adding place holder for connection \"%s\"", block->name);
+			g_hash_table_insert (priv->eni_ifaces, g_strdup (block->name), conn);
+			continue;
+		}
+
+		if (nm_streq (block->type, "mapping")) {
+			conn = g_hash_table_lookup (priv->eni_ifaces, block->name);
+			if (!conn) {
+				_LOGD ("parse: adding mapping \"%s\"", block->name);
+				g_hash_table_insert (priv->eni_ifaces, g_strdup (block->name), NULL);
+			} else {
+				_LOGD ("parse: adding mapping \"%s\" (have connection %s)", block->name,
+				       nm_settings_connection_get_uuid (NM_SETTINGS_CONNECTION (conn)));
 			}
-			nm_log_info (LOGD_SETTINGS, "adding iface %s to eni_ifaces", block->name);
-			g_hash_table_insert (priv->eni_ifaces, block->name, "known");
-		} else if (!strcmp ("mapping", block->type)) {
-			g_hash_table_insert (priv->eni_ifaces, block->name, "known");
-			nm_log_info (LOGD_SETTINGS, "adding mapping %s to eni_ifaces", block->name);
+			continue;
 		}
-	next:
-		block = block->next;
 	}
 
 	/* Make 'auto' interfaces autoconnect=TRUE */
-	g_hash_table_iter_init (&con_iter, priv->connections);
-	while (g_hash_table_iter_next (&con_iter, (gpointer) &block_name, (gpointer) &connection)) {
+	g_hash_table_iter_init (&con_iter, priv->eni_ifaces);
+	while (g_hash_table_iter_next (&con_iter, (gpointer) &block_name, (gpointer) &conn)) {
 		NMSettingConnection *setting;
 
-		if (g_hash_table_lookup (auto_ifaces, block_name)) {
-			setting = nm_connection_get_setting_connection (NM_CONNECTION (connection));
-			g_object_set (setting, NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NULL);
-			nm_log_info (LOGD_SETTINGS, "autoconnect");
-		}
+		if (   !conn
+		    || !auto_ifaces
+		    || !g_hash_table_contains (auto_ifaces, block_name))
+			continue;
+
+		/* FIXME(copy-on-write-connection): avoid modifying NMConnection instances and share them via copy-on-write. */
+		setting = nm_connection_get_setting_connection (nm_settings_connection_get_connection (NM_SETTINGS_CONNECTION (conn)));
+		g_object_set (setting, NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NULL);
 	}
-	g_hash_table_destroy (auto_ifaces);
 
 	/* Check the config file to find out whether to manage interfaces */
-	priv->unmanage_well_known = !nm_config_data_get_value_boolean (NM_CONFIG_GET_DATA_ORIG,
-	                                                               NM_CONFIG_KEYFILE_GROUP_IFUPDOWN,
-	                                                               NM_CONFIG_KEYFILE_KEY_IFUPDOWN_MANAGED,
-	                                                               !IFUPDOWN_UNMANAGE_WELL_KNOWN_DEFAULT);
-	nm_log_info (LOGD_SETTINGS, "management mode: %s", priv->unmanage_well_known ? "unmanaged" : "managed");
-
-	/* Add well-known interfaces */
-	enumerate = nm_udev_client_enumerate_new (priv->udev_client);
-	udev_enumerate_scan_devices (enumerate);
-	keys = udev_enumerate_get_list_entry (enumerate);
-	for (; keys; keys = udev_list_entry_get_next (keys)) {
-		struct udev_device *udevice;
-
-		udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate),
-		                                        udev_list_entry_get_name (keys));
-		if (udevice) {
-			udev_device_added (self, udevice);
-			udev_device_unref (udevice);
-		}
-	}
-	udev_enumerate_unref (enumerate);
+	priv->ifupdown_managed = nm_config_data_get_value_boolean (NM_CONFIG_GET_DATA_ORIG,
+	                                                           NM_CONFIG_KEYFILE_GROUP_IFUPDOWN,
+	                                                           NM_CONFIG_KEYFILE_KEY_IFUPDOWN_MANAGED,
+	                                                           !IFUPDOWN_UNMANAGE_WELL_KNOWN_DEFAULT);
+	_LOGI ("management mode: %s", priv->ifupdown_managed ? "managed" : "unmanaged");
 
 	/* Now if we're running in managed mode, let NM know there are new connections */
-	if (!priv->unmanage_well_known) {
-		GList *con_list = g_hash_table_get_values (priv->connections);
-		GList *cl_iter;
-
-		for (cl_iter = con_list; cl_iter; cl_iter = g_list_next (cl_iter)) {
-			g_signal_emit_by_name (self,
-			                       NM_SETTINGS_PLUGIN_CONNECTION_ADDED,
-			                       NM_SETTINGS_CONNECTION (cl_iter->data));
+	if (priv->ifupdown_managed) {
+		GHashTableIter iter;
+
+		g_hash_table_iter_init (&iter, priv->eni_ifaces);
+		while (g_hash_table_iter_next (&iter, NULL, (gpointer *) conn)) {
+			_nm_settings_plugin_emit_signal_connection_added (NM_SETTINGS_PLUGIN (self),
+			                                                  NM_SETTINGS_CONNECTION (conn));
 		}
-		g_list_free (con_list);
 	}
-
-	nm_log_info (LOGD_SETTINGS, "end _init.");
 }
 
 /*****************************************************************************/
 
 static void
-settings_plugin_ifupdown_init (SettingsPluginIfupdown *plugin)
+settings_plugin_ifupdown_init (SettingsPluginIfupdown *self)
 {
+	SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (self);
+
+	priv->eni_ifaces = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_object_unref);
 }
 
 static void
@@ -474,35 +304,28 @@ dispose (GObject *object)
 	SettingsPluginIfupdown *plugin = SETTINGS_PLUGIN_IFUPDOWN (object);
 	SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (plugin);
 
-	g_clear_pointer (&priv->kernel_ifaces, g_hash_table_destroy);
 	g_clear_pointer (&priv->eni_ifaces, g_hash_table_destroy);
 
-	priv->udev_client = nm_udev_client_unref (priv->udev_client);
-
 	G_OBJECT_CLASS (settings_plugin_ifupdown_parent_class)->dispose (object);
 }
 
 static void
-settings_plugin_ifupdown_class_init (SettingsPluginIfupdownClass *req_class)
+settings_plugin_ifupdown_class_init (SettingsPluginIfupdownClass *klass)
 {
-	GObjectClass *object_class = G_OBJECT_CLASS (req_class);
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	NMSettingsPluginClass *plugin_class = NM_SETTINGS_PLUGIN_CLASS (klass);
 
 	object_class->dispose = dispose;
-}
 
-static void
-settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface)
-{
-	plugin_iface->init = init;
-	plugin_iface->get_connections = get_connections;
-	plugin_iface->get_unmanaged_specs = get_unmanaged_specs;
+	plugin_class->initialize          = initialize;
+	plugin_class->get_connections     = get_connections;
+	plugin_class->get_unmanaged_specs = get_unmanaged_specs;
 }
 
 /*****************************************************************************/
 
-G_MODULE_EXPORT GObject *
+G_MODULE_EXPORT NMSettingsPlugin *
 nm_settings_plugin_factory (void)
 {
-	return G_OBJECT (g_object_ref (settings_plugin_ifupdown_get ()));
+	return NM_SETTINGS_PLUGIN (g_object_ref (settings_plugin_ifupdown_get ()));
 }
-
diff --git a/src/settings/plugins/ifupdown/tests/meson.build b/src/settings/plugins/ifupdown/tests/meson.build
index ee3b6a34..5a2383d9 100644
--- a/src/settings/plugins/ifupdown/tests/meson.build
+++ b/src/settings/plugins/ifupdown/tests/meson.build
@@ -4,7 +4,6 @@ exe = executable(
   test_unit,
   test_unit + '.c',
   dependencies: test_nm_dep,
-  c_args: nm_build_cflags,
   link_with: libnms_ifupdown_core
 )
 
diff --git a/src/settings/plugins/ifupdown/tests/test-ifupdown.c b/src/settings/plugins/ifupdown/tests/test-ifupdown.c
index 18bad65e..82ee1c4a 100644
--- a/src/settings/plugins/ifupdown/tests/test-ifupdown.c
+++ b/src/settings/plugins/ifupdown/tests/test-ifupdown.c
@@ -130,46 +130,50 @@ expected_free (Expected *e)
 }
 
 static void
-compare_expected_to_ifparser (Expected *e)
+compare_expected_to_ifparser (if_parser *parser, Expected *e)
 {
 	if_block *n;
 	GSList *biter, *kiter;
 
-	g_assert_cmpint (g_slist_length (e->blocks), ==, ifparser_get_num_blocks ());
+	g_assert_cmpint (g_slist_length (e->blocks), ==, ifparser_get_num_blocks (parser));
 
-	for (n = ifparser_getfirst (), biter = e->blocks;
-	     n && biter;
-	     n = n->next, biter = g_slist_next (biter)) {
+	biter = e->blocks;
+	c_list_for_each_entry (n, &parser->block_lst_head, block_lst) {
 		if_data *m;
 		ExpectedBlock *b = biter->data;
 
 		g_assert (b->type && n->type);
 		g_assert_cmpstr (b->type, ==, n->type);
-		g_assert (b->name && n->name);
+		g_assert (b->name);
 		g_assert_cmpstr (b->name, ==, n->name);
 
 		g_assert_cmpint (g_slist_length (b->keys), ==, ifparser_get_num_info (n));
 
-		for (m = n->info, kiter = b->keys;
-		     m && kiter;
-		     m = m->next, kiter = g_slist_next (kiter)) {
+		kiter = b->keys;
+		c_list_for_each_entry (m, &n->data_lst_head, data_lst) {
 			ExpectedKey *k = kiter->data;
 
-			g_assert (k->key && m->key);
+			g_assert (k->key);
 			g_assert_cmpstr (k->key, ==, m->key);
 			g_assert (k->data && m->data);
 			g_assert_cmpstr (k->data, ==, m->data);
+
+			kiter = g_slist_next (kiter);
 		}
+		g_assert (!kiter);
+
+		biter = g_slist_next (biter);
 	}
+	g_assert (!biter);
 }
 
 static void
-dump_blocks (void)
+dump_blocks (if_parser *parser)
 {
 	if_block *n;
 
 	g_message ("\n***************************************************");
-	for (n = ifparser_getfirst (); n != NULL; n = n->next) {
+	c_list_for_each_entry (n, &parser->block_lst_head, block_lst) {
 		if_data *m;
 
 		// each block start with its type & name
@@ -178,8 +182,8 @@ dump_blocks (void)
 
 		// each key-value pair within a block is indented & separated by a tab
 		// (single quotes used to show typ & name baoundaries)
-		for (m = n->info; m != NULL; m = m->next)
-			   g_print("\t'%s'\t'%s'\n", m->key, m->data);
+		c_list_for_each_entry (m, &n->data_lst_head, data_lst)
+			g_print("\t'%s'\t'%s'\n", m->key, m->data);
 
 		// blocks are separated by an empty line
 		g_print("\n");
@@ -187,21 +191,24 @@ dump_blocks (void)
 	g_message ("##################################################\n");
 }
 
-static void
-init_ifparser_with_file (const char *path, const char *file)
+static if_parser *
+init_ifparser_with_file (const char *file)
 {
-	char *tmp;
+	if_parser *parser;
+	gs_free char *tmp = NULL;
 
-	tmp = g_strdup_printf ("%s/%s", path, file);
-	ifparser_init (tmp, 1);
-	g_free (tmp);
+	tmp = g_strdup_printf ("%s/%s", TEST_DIR, file);
+	parser = ifparser_parse (tmp, 1);
+	g_assert (parser);
+	return parser;
 }
 
 static void
-test1_ignore_line_before_first_block (const char *path)
+test1_ignore_line_before_first_block (void)
 {
 	Expected *e;
 	ExpectedBlock *b;
+	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test1");
 
 	e = expected_new ();
 	b = expected_block_new ("auto", "eth0");
@@ -210,35 +217,33 @@ test1_ignore_line_before_first_block (const char *path)
 	expected_add_block (e, b);
 	expected_block_add_key (b, expected_key_new ("inet", "dhcp"));
 
-	init_ifparser_with_file (path, "test1");
-	compare_expected_to_ifparser (e);
+	compare_expected_to_ifparser (parser, e);
 
-	ifparser_destroy ();
 	expected_free (e);
 }
 
 static void
-test2_wrapped_line (const char *path)
+test2_wrapped_line (void)
 {
 	Expected *e;
 	ExpectedBlock *b;
+	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test2");
 
 	e = expected_new ();
 	b = expected_block_new ("auto", "lo");
 	expected_add_block (e, b);
 
-	init_ifparser_with_file (path, "test2");
-	compare_expected_to_ifparser (e);
+	compare_expected_to_ifparser (parser, e);
 
-	ifparser_destroy ();
 	expected_free (e);
 }
 
 static void
-test3_wrapped_multiline_multiarg (const char *path)
+test3_wrapped_multiline_multiarg (void)
 {
 	Expected *e;
 	ExpectedBlock *b;
+	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test3");
 
 	e = expected_new ();
 	b = expected_block_new ("allow-hotplug", "eth0");
@@ -248,35 +253,33 @@ test3_wrapped_multiline_multiarg (const char *path)
 	b = expected_block_new ("allow-hotplug", "bnep0");
 	expected_add_block (e, b);
 
-	init_ifparser_with_file (path, "test3");
-	compare_expected_to_ifparser (e);
+	compare_expected_to_ifparser (parser, e);
 
-	ifparser_destroy ();
 	expected_free (e);
 }
 
 static void
-test4_allow_auto_is_auto (const char *path)
+test4_allow_auto_is_auto (void)
 {
 	Expected *e;
 	ExpectedBlock *b;
+	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test4");
 
 	e = expected_new ();
 	b = expected_block_new ("auto", "eth0");
 	expected_add_block (e, b);
 
-	init_ifparser_with_file (path, "test4");
-	compare_expected_to_ifparser (e);
+	compare_expected_to_ifparser (parser, e);
 
-	ifparser_destroy ();
 	expected_free (e);
 }
 
 static void
-test5_allow_auto_multiarg (const char *path)
+test5_allow_auto_multiarg (void)
 {
 	Expected *e;
 	ExpectedBlock *b;
+	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test5");
 
 	e = expected_new ();
 	b = expected_block_new ("allow-hotplug", "eth0");
@@ -284,52 +287,50 @@ test5_allow_auto_multiarg (const char *path)
 	b = expected_block_new ("allow-hotplug", "wlan0");
 	expected_add_block (e, b);
 
-	init_ifparser_with_file (path, "test5");
-	compare_expected_to_ifparser (e);
+	compare_expected_to_ifparser (parser, e);
 
-	ifparser_destroy ();
 	expected_free (e);
 }
 
 static void
-test6_mixed_whitespace (const char *path)
+test6_mixed_whitespace (void)
 {
 	Expected *e;
 	ExpectedBlock *b;
+	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test6");
 
 	e = expected_new ();
 	b = expected_block_new ("iface", "lo");
 	expected_block_add_key (b, expected_key_new ("inet", "loopback"));
 	expected_add_block (e, b);
 
-	init_ifparser_with_file (path, "test6");
-	compare_expected_to_ifparser (e);
+	compare_expected_to_ifparser (parser, e);
 
-	ifparser_destroy ();
 	expected_free (e);
 }
 
 static void
-test7_long_line (const char *path)
+test7_long_line (void)
 {
-	init_ifparser_with_file (path, "test7");
-	g_assert_cmpint (ifparser_get_num_blocks (), ==, 0);
-	ifparser_destroy ();
+	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test7");
+
+	g_assert_cmpint (ifparser_get_num_blocks (parser), ==, 0);
 }
 
 static void
-test8_long_line_wrapped (const char *path)
+test8_long_line_wrapped (void)
 {
-	init_ifparser_with_file (path, "test8");
-	g_assert_cmpint (ifparser_get_num_blocks (), ==, 0);
-	ifparser_destroy ();
+	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test8");
+
+	g_assert_cmpint (ifparser_get_num_blocks (parser), ==, 0);
 }
 
 static void
-test9_wrapped_lines_in_block (const char *path)
+test9_wrapped_lines_in_block (void)
 {
 	Expected *e;
 	ExpectedBlock *b;
+	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test9");
 
 	e = expected_new ();
 	b = expected_block_new ("iface", "eth0");
@@ -340,18 +341,17 @@ test9_wrapped_lines_in_block (const char *path)
 	expected_block_add_key (b, expected_key_new ("broadcast", "10.250.2.63"));
 	expected_block_add_key (b, expected_key_new ("gateway", "10.250.2.50"));
 
-	init_ifparser_with_file (path, "test9");
-	compare_expected_to_ifparser (e);
+	compare_expected_to_ifparser (parser, e);
 
-	ifparser_destroy ();
 	expected_free (e);
 }
 
 static void
-test11_complex_wrap (const char *path)
+test11_complex_wrap (void)
 {
 	Expected *e;
 	ExpectedBlock *b;
+	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test11");
 
 	e = expected_new ();
 	b = expected_block_new ("iface", "pppoe");
@@ -359,18 +359,17 @@ test11_complex_wrap (const char *path)
 	expected_block_add_key (b, expected_key_new ("inet", "manual"));
 	expected_block_add_key (b, expected_key_new ("pre-up", "/sbin/ifconfig eth0 up"));
 
-	init_ifparser_with_file (path, "test11");
-	compare_expected_to_ifparser (e);
+	compare_expected_to_ifparser (parser, e);
 
-	ifparser_destroy ();
 	expected_free (e);
 }
 
 static void
-test12_complex_wrap_split_word (const char *path)
+test12_complex_wrap_split_word (void)
 {
 	Expected *e;
 	ExpectedBlock *b;
+	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test12");
 
 	e = expected_new ();
 	b = expected_block_new ("iface", "pppoe");
@@ -378,36 +377,34 @@ test12_complex_wrap_split_word (const char *path)
 	expected_block_add_key (b, expected_key_new ("inet", "manual"));
 	expected_block_add_key (b, expected_key_new ("up", "ifup ppp0=dsl"));
 
-	init_ifparser_with_file (path, "test12");
-	compare_expected_to_ifparser (e);
+	compare_expected_to_ifparser (parser, e);
 
-	ifparser_destroy ();
 	expected_free (e);
 }
 
 static void
-test13_more_mixed_whitespace (const char *path)
+test13_more_mixed_whitespace (void)
 {
 	Expected *e;
 	ExpectedBlock *b;
+	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test13");
 
 	e = expected_new ();
 	b = expected_block_new ("iface", "dsl");
 	expected_block_add_key (b, expected_key_new ("inet", "ppp"));
 	expected_add_block (e, b);
 
-	init_ifparser_with_file (path, "test13");
-	compare_expected_to_ifparser (e);
+	compare_expected_to_ifparser (parser, e);
 
-	ifparser_destroy ();
 	expected_free (e);
 }
 
 static void
-test14_mixed_whitespace_block_start (const char *path)
+test14_mixed_whitespace_block_start (void)
 {
 	Expected *e;
 	ExpectedBlock *b;
+	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test14");
 
 	e = expected_new ();
 	b = expected_block_new ("iface", "wlan0");
@@ -420,47 +417,43 @@ test14_mixed_whitespace_block_start (const char *path)
 	expected_block_add_key (b, expected_key_new ("inet", "dhcp"));
 	expected_add_block (e, b);
 
-	init_ifparser_with_file (path, "test14");
-	compare_expected_to_ifparser (e);
+	compare_expected_to_ifparser (parser, e);
 
-	ifparser_destroy ();
 	expected_free (e);
 }
 
 static void
-test15_trailing_space (const char *path)
+test15_trailing_space (void)
 {
 	Expected *e;
 	ExpectedBlock *b;
+	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test15");
 
 	e = expected_new ();
 	b = expected_block_new ("iface", "bnep0");
 	expected_block_add_key (b, expected_key_new ("inet", "static"));
 	expected_add_block (e, b);
 
-	init_ifparser_with_file (path, "test15");
-	compare_expected_to_ifparser (e);
+	compare_expected_to_ifparser (parser, e);
 
-	ifparser_destroy ();
 	expected_free (e);
 }
 
 static void
-test16_missing_newline (const char *path)
+test16_missing_newline (void)
 {
 	Expected *e;
+	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test16");
 
 	e = expected_new ();
 	expected_add_block (e, expected_block_new ("mapping", "eth0"));
 
-	init_ifparser_with_file (path, "test16");
-	compare_expected_to_ifparser (e);
+	compare_expected_to_ifparser (parser, e);
 
-	ifparser_destroy ();
 	expected_free (e);
 }
 static void
-test17_read_static_ipv4 (const char *path)
+test17_read_static_ipv4 (void)
 {
 	NMConnection *connection;
 	NMSettingConnection *s_con;
@@ -470,13 +463,13 @@ test17_read_static_ipv4 (const char *path)
 	gboolean success;
 	NMIPAddress *ip4_addr;
 	if_block *block = NULL;
+	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test17-wired-static-verify-ip4");
 
-	init_ifparser_with_file (path, "test17-wired-static-verify-ip4");
-	block = ifparser_getfirst ();
+	block = ifparser_getfirst (parser);
 	connection = nm_simple_connection_new();
 	g_assert (connection);
 
-	ifupdown_update_connection_from_if_block(connection, block, &error);
+	ifupdown_update_connection_from_if_block (connection, block, &error);
 	g_assert_no_error (error);
 
 	success = nm_connection_verify (connection, &error);
@@ -511,12 +504,11 @@ test17_read_static_ipv4 (const char *path)
 	g_assert_cmpstr (nm_setting_ip_config_get_dns_search (s_ip4, 0), ==, "example.com");
 	g_assert_cmpstr (nm_setting_ip_config_get_dns_search (s_ip4, 1), ==, "foo.example.com");
 
-	ifparser_destroy ();
 	g_object_unref (connection);
 }
 
 static void
-test18_read_static_ipv6 (const char *path)
+test18_read_static_ipv6 (void)
 {
 	NMConnection *connection;
 	NMSettingConnection *s_con;
@@ -526,12 +518,12 @@ test18_read_static_ipv6 (const char *path)
 	gboolean success;
 	NMIPAddress *ip6_addr;
 	if_block *block = NULL;
+	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test18-wired-static-verify-ip6");
 
-	init_ifparser_with_file (path, "test18-wired-static-verify-ip6");
-	block = ifparser_getfirst ();
+	block = ifparser_getfirst (parser);
 	connection = nm_simple_connection_new();
 	g_assert (connection);
-	ifupdown_update_connection_from_if_block(connection, block, &error);
+	ifupdown_update_connection_from_if_block (connection, block, &error);
 	g_assert_no_error (error);
 
 	success = nm_connection_verify (connection, &error);
@@ -566,12 +558,11 @@ test18_read_static_ipv6 (const char *path)
 	g_assert_cmpstr (nm_setting_ip_config_get_dns_search (s_ip6, 0), ==, "example.com");
 	g_assert_cmpstr (nm_setting_ip_config_get_dns_search (s_ip6, 1), ==, "foo.example.com");
 
-	ifparser_destroy ();
 	g_object_unref (connection);
 }
 
 static void
-test19_read_static_ipv4_plen (const char *path)
+test19_read_static_ipv4_plen (void)
 {
 	NMConnection *connection;
 	NMSettingIPConfig *s_ip4;
@@ -579,12 +570,12 @@ test19_read_static_ipv4_plen (const char *path)
 	NMIPAddress *ip4_addr;
 	if_block *block = NULL;
 	gboolean success;
+	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test19-wired-static-verify-ip4-plen");
 
-	init_ifparser_with_file (path, "test19-wired-static-verify-ip4-plen");
-	block = ifparser_getfirst ();
+	block = ifparser_getfirst (parser);
 	connection = nm_simple_connection_new();
 	g_assert (connection);
-	ifupdown_update_connection_from_if_block(connection, block, &error);
+	ifupdown_update_connection_from_if_block (connection, block, &error);
 	g_assert_no_error (error);
 
 	success = nm_connection_verify (connection, &error);
@@ -601,15 +592,15 @@ test19_read_static_ipv4_plen (const char *path)
 	g_assert_cmpstr (nm_ip_address_get_address (ip4_addr), ==, "10.0.0.3");
 	g_assert_cmpint (nm_ip_address_get_prefix (ip4_addr), ==, 8);
 
-	ifparser_destroy ();
 	g_object_unref (connection);
 }
 
 static void
-test20_source_stanza (const char *path)
+test20_source_stanza (void)
 {
 	Expected *e;
 	ExpectedBlock *b;
+	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test20-source-stanza");
 
 	e = expected_new ();
 
@@ -625,18 +616,17 @@ test20_source_stanza (const char *path)
 	expected_add_block (e, b);
 	expected_block_add_key (b, expected_key_new ("inet", "dhcp"));
 
-	init_ifparser_with_file (path, "test20-source-stanza");
-	compare_expected_to_ifparser (e);
+	compare_expected_to_ifparser (parser, e);
 
-	ifparser_destroy ();
 	expected_free (e);
 }
 
 static void
-test21_source_dir_stanza (const char *path)
+test21_source_dir_stanza (void)
 {
 	Expected *e;
 	ExpectedBlock *b;
+	nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test21-source-dir-stanza");
 
 	e = expected_new ();
 
@@ -646,10 +636,8 @@ test21_source_dir_stanza (const char *path)
 	expected_add_block (e, b);
 	expected_block_add_key (b, expected_key_new ("inet", "dhcp"));
 
-	init_ifparser_with_file (path, "test21-source-dir-stanza");
-	compare_expected_to_ifparser (e);
+	compare_expected_to_ifparser (parser, e);
 
-	ifparser_destroy ();
 	expected_free (e);
 }
 
@@ -660,49 +648,28 @@ main (int argc, char **argv)
 {
 	nmtst_init_assert_logging (&argc, &argv, "WARN", "DEFAULT");
 
-	if (0)
-		dump_blocks ();
-
-	g_test_add_data_func ("/ifupdate/ignore_line_before_first_block", TEST_DIR,
-	                      (GTestDataFunc) test1_ignore_line_before_first_block);
-	g_test_add_data_func ("/ifupdate/wrapped_line", TEST_DIR,
-	                      (GTestDataFunc) test2_wrapped_line);
-	g_test_add_data_func ("/ifupdate/wrapped_multiline_multiarg", TEST_DIR,
-	                      (GTestDataFunc) test3_wrapped_multiline_multiarg);
-	g_test_add_data_func ("/ifupdate/allow_auto_is_auto", TEST_DIR,
-	                      (GTestDataFunc) test4_allow_auto_is_auto);
-	g_test_add_data_func ("/ifupdate/allow_auto_multiarg", TEST_DIR,
-	                      (GTestDataFunc) test5_allow_auto_multiarg);
-	g_test_add_data_func ("/ifupdate/mixed_whitespace", TEST_DIR,
-	                      (GTestDataFunc) test6_mixed_whitespace);
-	g_test_add_data_func ("/ifupdate/long_line", TEST_DIR,
-	                      (GTestDataFunc) test7_long_line);
-	g_test_add_data_func ("/ifupdate/long_line_wrapped", TEST_DIR,
-	                      (GTestDataFunc) test8_long_line_wrapped);
-	g_test_add_data_func ("/ifupdate/wrapped_lines_in_block", TEST_DIR,
-	                      (GTestDataFunc) test9_wrapped_lines_in_block);
-	g_test_add_data_func ("/ifupdate/complex_wrap", TEST_DIR,
-	                      (GTestDataFunc) test11_complex_wrap);
-	g_test_add_data_func ("/ifupdate/complex_wrap_split_word", TEST_DIR,
-	                      (GTestDataFunc) test12_complex_wrap_split_word);
-	g_test_add_data_func ("/ifupdate/more_mixed_whitespace", TEST_DIR,
-	                      (GTestDataFunc) test13_more_mixed_whitespace);
-	g_test_add_data_func ("/ifupdate/mixed_whitespace_block_start", TEST_DIR,
-	                      (GTestDataFunc) test14_mixed_whitespace_block_start);
-	g_test_add_data_func ("/ifupdate/trailing_space", TEST_DIR,
-	                      (GTestDataFunc) test15_trailing_space);
-	g_test_add_data_func ("/ifupdate/missing_newline", TEST_DIR,
-	                      (GTestDataFunc) test16_missing_newline);
-	g_test_add_data_func ("/ifupdate/read_static_ipv4", TEST_DIR,
-	                      (GTestDataFunc) test17_read_static_ipv4);
-	g_test_add_data_func ("/ifupdate/read_static_ipv6", TEST_DIR,
-	                      (GTestDataFunc) test18_read_static_ipv6);
-	g_test_add_data_func ("/ifupdate/read_static_ipv4_plen", TEST_DIR,
-	                      (GTestDataFunc) test19_read_static_ipv4_plen);
-	g_test_add_data_func ("/ifupdate/source_stanza", TEST_DIR,
-	                      (GTestDataFunc) test20_source_stanza);
-	g_test_add_data_func ("/ifupdate/source_dir_stanza", TEST_DIR,
-	                      (GTestDataFunc) test21_source_dir_stanza);
+	(void) dump_blocks;
+
+	g_test_add_func ("/ifupdate/ignore_line_before_first_block", test1_ignore_line_before_first_block);
+	g_test_add_func ("/ifupdate/wrapped_line",                   test2_wrapped_line);
+	g_test_add_func ("/ifupdate/wrapped_multiline_multiarg",     test3_wrapped_multiline_multiarg);
+	g_test_add_func ("/ifupdate/allow_auto_is_auto",             test4_allow_auto_is_auto);
+	g_test_add_func ("/ifupdate/allow_auto_multiarg",            test5_allow_auto_multiarg);
+	g_test_add_func ("/ifupdate/mixed_whitespace",               test6_mixed_whitespace);
+	g_test_add_func ("/ifupdate/long_line",                      test7_long_line);
+	g_test_add_func ("/ifupdate/long_line_wrapped",              test8_long_line_wrapped);
+	g_test_add_func ("/ifupdate/wrapped_lines_in_block",         test9_wrapped_lines_in_block);
+	g_test_add_func ("/ifupdate/complex_wrap",                   test11_complex_wrap);
+	g_test_add_func ("/ifupdate/complex_wrap_split_word",        test12_complex_wrap_split_word);
+	g_test_add_func ("/ifupdate/more_mixed_whitespace",          test13_more_mixed_whitespace);
+	g_test_add_func ("/ifupdate/mixed_whitespace_block_start",   test14_mixed_whitespace_block_start);
+	g_test_add_func ("/ifupdate/trailing_space",                 test15_trailing_space);
+	g_test_add_func ("/ifupdate/missing_newline",                test16_missing_newline);
+	g_test_add_func ("/ifupdate/read_static_ipv4",               test17_read_static_ipv4);
+	g_test_add_func ("/ifupdate/read_static_ipv6",               test18_read_static_ipv6);
+	g_test_add_func ("/ifupdate/read_static_ipv4_plen",          test19_read_static_ipv4_plen);
+	g_test_add_func ("/ifupdate/source_stanza",                  test20_source_stanza);
+	g_test_add_func ("/ifupdate/source_dir_stanza",              test21_source_dir_stanza);
 
 	return g_test_run ();
 }