From 48ed1abca77195ed9b36645593733da143e3be3f Mon Sep 17 00:00:00 2001 From: Michael Wisheu Date: Wed, 4 Sep 2013 16:21:20 +0200 Subject: [PATCH] ifupdown: add support for source stanza Since Debian 7 (Wheezy) / Ubuntu 11.04 (Natty Narwhal) ifupdown supports the source stanza to source in other configuration files from /etc/network/interfaces. Add support to the ifupdown plugin to include configuration files via source. Patch did not apply cleanly and was slightly modified by Thomas Haller. https://bugzilla.gnome.org/show_bug.cgi?id=707276 Signed-off-by: Thomas Haller Reviewed-by: Sebastian Harl --- .../plugins/ifupdown/interface_parser.c | 92 ++++++++++++++++++- .../plugins/ifupdown/tests/test-ifupdown.c | 28 ++++++ .../ifupdown/tests/test20-source-stanza | 1 + .../ifupdown/tests/test20-source-stanza.eth0 | 2 + .../ifupdown/tests/test20-source-stanza.eth1 | 2 + 5 files changed, 120 insertions(+), 5 deletions(-) create mode 100644 src/settings/plugins/ifupdown/tests/test20-source-stanza create mode 100644 src/settings/plugins/ifupdown/tests/test20-source-stanza.eth0 create mode 100644 src/settings/plugins/ifupdown/tests/test20-source-stanza.eth1 diff --git a/src/settings/plugins/ifupdown/interface_parser.c b/src/settings/plugins/ifupdown/interface_parser.c index 38ed14792..62844f5e4 100644 --- a/src/settings/plugins/ifupdown/interface_parser.c +++ b/src/settings/plugins/ifupdown/interface_parser.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include "nm-utils.h" if_block* first; @@ -96,21 +98,33 @@ static char *join_values_with_spaces(char *dst, char **src) return(dst); } -void ifparser_init (const char *eni_file, int quiet) +void _ifparser_source (const char *path, const char *en_dir, int quiet); +void _recursive_ifparser (const char *eni_file, int quiet); + +void _recursive_ifparser (const char *eni_file, int quiet) { - FILE *inp = fopen (eni_file, "r"); + FILE *inp; char line[255]; int skip_to_block = 1; int skip_long_line = 0; int offs = 0; + // Check if interfaces file exists and open it + if (!g_file_test (eni_file, G_FILE_TEST_EXISTS)) { + if (!quiet) + g_warning ("Warning: interfaces file %s doesn't exist\n", eni_file); + return; + } + inp = fopen (eni_file, "r"); if (inp == NULL) { if (!quiet) g_warning ("Error: Can't open %s\n", eni_file); return; } + if (!quiet) + g_message (" interface-parser: parsing file %s\n", eni_file); + - first = last = NULL; while (!feof(inp)) { char *token[128]; // 255 chars can only be split into 127 tokens @@ -175,8 +189,9 @@ void ifparser_init (const char *eni_file, int quiet) continue; } - // There are four different stanzas: - // iface, mapping, auto and allow-*. Create a block for each of them. + // There are five different stanzas: + // iface, mapping, auto, allow-* and source. + // Create a block for each of them except source. // iface stanza takes at least 3 parameters if (strcmp(token[0], "iface") == 0) { @@ -211,6 +226,33 @@ void ifparser_init (const char *eni_file, int quiet) add_block(token[0], token[i]); skip_to_block = 0; } + // source stanza takes one or more filepaths as parameters + else if (strcmp(token[0], "source") == 0) { + uint i; + + skip_to_block = 0; + + if (toknum == 1) { + if (!quiet) + g_warning ("Error: Invalid source line without parameters\n"); + continue; + } + for (i = 1; i < toknum; ++i) { + char *eni_file_copy; + char *en_dir; + + eni_file_copy = strdup (eni_file); + if (!eni_file_copy) { + if (!quiet) + g_warning ("Error: Skipping interfaces file %s because strdup failed\n", + eni_file); + continue; + } + en_dir = dirname (eni_file_copy); + _ifparser_source (token[i], en_dir, quiet); + free (eni_file_copy); + } + } else { if (skip_to_block) { if (!quiet) { @@ -222,6 +264,46 @@ void ifparser_init (const char *eni_file, int quiet) } } fclose(inp); + + if (!quiet) + g_message (" interface-parser: finished parsing file %s\n", eni_file); +} + +void _ifparser_source (const char *path, const char *en_dir, int quiet) +{ + // abs_path = en_dir + '/' + path + '\0' + char abs_path[strlen (en_dir) + strlen (path) + 2]; + wordexp_t we; + uint i; + + if (path[0] == '/') { + strncpy (abs_path, path, sizeof (abs_path)); + } + else { + // Convert relative path to absolute path + snprintf (abs_path, sizeof (abs_path), "%s/%s", en_dir, path); + } + if (!quiet) + g_message (" interface-parser: source line includes interfaces file(s) %s\n", abs_path); + + // Recursively parse sourced in interfaces files + // (ifupdown uses WRDE_NOCMD for wordexp) + memset (&we, 0, sizeof (we)); + if (wordexp (abs_path, &we, WRDE_NOCMD)) { + if (!quiet) + g_warning ("Error: word expansion for %s failed\n", abs_path); + return; + } + for (i = 0; i < we.we_wordc; i++) { + _recursive_ifparser (we.we_wordv[i], quiet); + } + wordfree (&we); +} + +void ifparser_init (const char *eni_file, int quiet) +{ + first = last = NULL; + _recursive_ifparser (eni_file, quiet); } void _destroy_data(if_data *ifd) diff --git a/src/settings/plugins/ifupdown/tests/test-ifupdown.c b/src/settings/plugins/ifupdown/tests/test-ifupdown.c index 5d861bb3e..506789fc0 100644 --- a/src/settings/plugins/ifupdown/tests/test-ifupdown.c +++ b/src/settings/plugins/ifupdown/tests/test-ifupdown.c @@ -903,6 +903,32 @@ test19_read_static_ipv4_plen (const char *path) g_object_unref (connection); } +static void +test20_source_stanza (const char *path) +{ + Expected *e; + ExpectedBlock *b; + + e = expected_new (); + + b = expected_block_new ("auto", "eth0"); + expected_add_block (e, b); + b = expected_block_new ("iface", "eth0"); + expected_add_block (e, b); + expected_block_add_key (b, expected_key_new ("inet", "dhcp")); + + b = expected_block_new ("auto", "eth1"); + expected_add_block (e, b); + b = expected_block_new ("iface", "eth1"); + 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); + + ifparser_destroy (); + expected_free (e); +} int main (int argc, char **argv) @@ -955,6 +981,8 @@ main (int argc, char **argv) (GTestDataFunc) test18_read_static_ipv6); g_test_add_data_func ("/ifupdate/read_static_ipv4_plen", TEST_ENI_DIR, (GTestDataFunc) test19_read_static_ipv4_plen); + g_test_add_data_func ("/ifupdate/source_stanza", TEST_ENI_DIR, + (GTestDataFunc) test20_source_stanza); return g_test_run (); } diff --git a/src/settings/plugins/ifupdown/tests/test20-source-stanza b/src/settings/plugins/ifupdown/tests/test20-source-stanza new file mode 100644 index 000000000..5cfe1730c --- /dev/null +++ b/src/settings/plugins/ifupdown/tests/test20-source-stanza @@ -0,0 +1 @@ +source test20-source-stanza.eth* diff --git a/src/settings/plugins/ifupdown/tests/test20-source-stanza.eth0 b/src/settings/plugins/ifupdown/tests/test20-source-stanza.eth0 new file mode 100644 index 000000000..81922cea6 --- /dev/null +++ b/src/settings/plugins/ifupdown/tests/test20-source-stanza.eth0 @@ -0,0 +1,2 @@ +auto eth0 +iface eth0 inet dhcp diff --git a/src/settings/plugins/ifupdown/tests/test20-source-stanza.eth1 b/src/settings/plugins/ifupdown/tests/test20-source-stanza.eth1 new file mode 100644 index 000000000..b8a783f58 --- /dev/null +++ b/src/settings/plugins/ifupdown/tests/test20-source-stanza.eth1 @@ -0,0 +1,2 @@ +auto eth1 +iface eth1 inet dhcp