From 07d3ffbcec1c717c8cc71bffd6ebc01769e08d2a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 12 Jan 2009 18:23:30 -0500 Subject: [PATCH] keyfile: write nicely formatted MAC addresses; clean up "special" key handling Add testcases for keyfile ip4-config setting writing too. --- system-settings/plugins/keyfile/io/writer.c | 182 +++++++++++++----- .../plugins/keyfile/tests/test-keyfile.c | 81 ++++++++ 2 files changed, 214 insertions(+), 49 deletions(-) diff --git a/system-settings/plugins/keyfile/io/writer.c b/system-settings/plugins/keyfile/io/writer.c index 7f1bb17cec..ab4b15e39d 100644 --- a/system-settings/plugins/keyfile/io/writer.c +++ b/system-settings/plugins/keyfile/io/writer.c @@ -27,9 +27,13 @@ #include #include #include +#include +#include +#include #include #include #include +#include #include #include "nm-dbus-glib-types.h" @@ -44,44 +48,53 @@ write_array_of_uint (GKeyFile *file, { GArray *array; int i; + int *tmp_array; array = (GArray *) g_value_get_boxed (value); if (!array || !array->len) return TRUE; - if (NM_IS_SETTING_IP4_CONFIG (setting) && !strcmp (key, NM_SETTING_IP4_CONFIG_DNS)) { - char **list; + tmp_array = g_new (gint, array->len); + for (i = 0; i < array->len; i++) + tmp_array[i] = g_array_index (array, int, i); - list = g_new0 (char *, array->len + 1); + g_key_file_set_integer_list (file, nm_setting_get_name (setting), key, tmp_array, array->len); + g_free (tmp_array); + return TRUE; +} - for (i = 0; i < array->len; i++) { - char buf[INET_ADDRSTRLEN + 1]; - struct in_addr addr; +static void +ip4_dns_writer (GKeyFile *file, + NMSetting *setting, + const char *key, + const GValue *value) +{ + GArray *array; + char **list; + int i, num = 0; - addr.s_addr = g_array_index (array, guint32, i); - if (!inet_ntop (AF_INET, &addr, buf, sizeof (buf))) { - nm_warning ("%s: error converting IP4 address 0x%X", - __func__, ntohl (addr.s_addr)); - list[i] = NULL; - } else { - list[i] = g_strdup (buf); - } - } + g_return_if_fail (G_VALUE_HOLDS (value, DBUS_TYPE_G_UINT_ARRAY)); - g_key_file_set_string_list (file, nm_setting_get_name (setting), key, (const char **) list, array->len); - g_strfreev (list); - } else { - int *tmp_array; + array = (GArray *) g_value_get_boxed (value); + if (!array || !array->len) + return; - tmp_array = g_new (gint, array->len); - for (i = 0; i < array->len; i++) - tmp_array[i] = g_array_index (array, int, i); + list = g_new0 (char *, array->len + 1); - g_key_file_set_integer_list (file, nm_setting_get_name (setting), key, tmp_array, array->len); - g_free (tmp_array); + for (i = 0; i < array->len; i++) { + char buf[INET_ADDRSTRLEN + 1]; + struct in_addr addr; + + addr.s_addr = g_array_index (array, guint32, i); + if (!inet_ntop (AF_INET, &addr, buf, sizeof (buf))) { + nm_warning ("%s: error converting IP4 address 0x%X", + __func__, ntohl (addr.s_addr)); + } else + list[num++] = g_strdup (buf); } - return TRUE; + g_key_file_set_string_list (file, nm_setting_get_name (setting), key, (const char **) list, num); + g_strfreev (list); } static void @@ -96,7 +109,7 @@ write_ip4_values (GKeyFile *file, char **list = NULL; int i, j; - list = g_malloc (tuple_len); + list = g_new (char *, tuple_len); for (i = 0, j = 0; i < array->len; i++, j++) { GArray *tuple = g_ptr_array_index (array, i); @@ -104,7 +117,7 @@ write_ip4_values (GKeyFile *file, char *key_name; int k; - memset (list, 0, tuple_len); + memset (list, 0, tuple_len * sizeof (char *)); for (k = 0; k < tuple_len; k++) { if (k == addr1_pos || k == addr2_pos) { @@ -139,28 +152,64 @@ write_ip4_values (GKeyFile *file, g_free (list); } -static gboolean -write_array_of_array_of_uint (GKeyFile *file, - NMSetting *setting, - const char *key, - const GValue *value) +static void +ip4_addr_writer (GKeyFile *file, + NMSetting *setting, + const char *key, + const GValue *value) { GPtrArray *array; + const char *setting_name = nm_setting_get_name (setting); - /* Only handle IPv4 addresses and routes for now */ - if (!NM_IS_SETTING_IP4_CONFIG (setting)) - return FALSE; + g_return_if_fail (G_VALUE_HOLDS (value, DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT)); array = (GPtrArray *) g_value_get_boxed (value); - if (!array || !array->len) - return TRUE; + if (array && array->len) + write_ip4_values (file, setting_name, key, array, 3, 0, 2); +} - if (!strcmp (key, NM_SETTING_IP4_CONFIG_ADDRESSES)) - write_ip4_values (file, nm_setting_get_name (setting), key, array, 3, 0, 2); - else if (!strcmp (key, NM_SETTING_IP4_CONFIG_ROUTES)) - write_ip4_values (file, nm_setting_get_name (setting), key, array, 4, 0, 2); +static void +ip4_route_writer (GKeyFile *file, + NMSetting *setting, + const char *key, + const GValue *value) +{ + GPtrArray *array; + const char *setting_name = nm_setting_get_name (setting); - return TRUE; + g_return_if_fail (G_VALUE_HOLDS (value, DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT)); + + array = (GPtrArray *) g_value_get_boxed (value); + if (array && array->len) + write_ip4_values (file, setting_name, key, array, 4, 0, 2); +} + +static void +mac_address_writer (GKeyFile *file, + NMSetting *setting, + const char *key, + const GValue *value) +{ + GByteArray *array; + const char *setting_name = nm_setting_get_name (setting); + char *mac; + struct ether_addr tmp; + + g_return_if_fail (G_VALUE_HOLDS (value, DBUS_TYPE_G_UCHAR_ARRAY)); + + array = (GByteArray *) g_value_get_boxed (value); + if (!array) + return; + + if (array->len != ETH_ALEN) { + nm_warning ("%s: invalid %s / %s MAC address length %d", + __func__, setting_name, key, array->len); + return; + } + + memcpy (tmp.ether_addr_octet, array->data, ETH_ALEN); + mac = ether_ntoa (&tmp); + g_key_file_set_string (file, setting_name, key, mac); } typedef struct { @@ -202,6 +251,36 @@ write_hash_of_string (GKeyFile *file, g_hash_table_foreach (hash, write_hash_of_string_helper, &info); } +typedef struct { + const char *setting_name; + const char *key; + void (*writer) (GKeyFile *keyfile, NMSetting *setting, const char *key, const GValue *value); +} KeyWriter; + +/* A table of keys that require further parsing/conversion becuase they are + * stored in a format that can't be automatically read using the key's type. + * i.e. IP addresses, which are stored in NetworkManager as guint32, but are + * stored in keyfiles as strings, eg "10.1.1.2". + */ +static KeyWriter key_writers[] = { + { NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_ADDRESSES, + ip4_addr_writer }, + { NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_ROUTES, + ip4_route_writer }, + { NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_DNS, + ip4_dns_writer }, + { NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_MAC_ADDRESS, + mac_address_writer }, + { NM_SETTING_WIRELESS_SETTING_NAME, + NM_SETTING_WIRELESS_MAC_ADDRESS, + mac_address_writer }, + { NULL, NULL, NULL } +}; + static void write_setting_value (NMSetting *setting, const char *key, @@ -212,6 +291,7 @@ write_setting_value (NMSetting *setting, GKeyFile *file = (GKeyFile *) user_data; const char *setting_name; GType type; + KeyWriter *writer = &key_writers[0]; type = G_VALUE_TYPE (value); @@ -226,6 +306,15 @@ write_setting_value (NMSetting *setting, setting_name = nm_setting_get_name (setting); + /* Look through the list of handlers for non-standard format key values */ + while (writer->setting_name) { + if (!strcmp (writer->setting_name, setting_name) && !strcmp (writer->key, key)) { + (*writer->writer) (file, setting, key, value); + return; + } + writer++; + } + if (type == G_TYPE_STRING) { const char *str; @@ -261,7 +350,7 @@ write_setting_value (NMSetting *setting, g_key_file_set_integer_list (file, setting_name, key, tmp_array, array->len); g_free (tmp_array); } - } else if (type == dbus_g_type_get_collection ("GSList", G_TYPE_STRING)) { + } else if (type == DBUS_TYPE_G_LIST_OF_STRING) { GSList *list; GSList *iter; @@ -277,18 +366,13 @@ write_setting_value (NMSetting *setting, g_key_file_set_string_list (file, setting_name, key, (const gchar **const) array, i); g_free (array); } - } else if (type == dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING)) { + } else if (type == DBUS_TYPE_G_MAP_OF_STRING) { write_hash_of_string (file, setting, key, value); } else if (type == DBUS_TYPE_G_UINT_ARRAY) { if (!write_array_of_uint (file, setting, key, value)) { g_warning ("Unhandled setting property type (write) '%s/%s' : '%s'", setting_name, key, g_type_name (type)); } - } else if (type == DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT) { - if (!write_array_of_array_of_uint (file, setting, key, value)) { - g_warning ("Unhandled setting property type (write) '%s/%s' : '%s'", - setting_name, key, g_type_name (type)); - } } else { g_warning ("Unhandled setting property type (write) '%s/%s' : '%s'", setting_name, key, g_type_name (type)); diff --git a/system-settings/plugins/keyfile/tests/test-keyfile.c b/system-settings/plugins/keyfile/tests/test-keyfile.c index 31e2a60b16..01668cbf18 100644 --- a/system-settings/plugins/keyfile/tests/test-keyfile.c +++ b/system-settings/plugins/keyfile/tests/test-keyfile.c @@ -297,6 +297,52 @@ test_read_valid_wired_connection (void) g_object_unref (connection); } +static void +add_one_ip4_address (NMSettingIP4Config *s_ip4, + const char *addr, + const char *gw, + guint32 prefix) +{ + struct in_addr tmp; + NMIP4Address *ip4_addr; + + ip4_addr = nm_ip4_address_new (); + nm_ip4_address_set_prefix (ip4_addr, prefix); + + inet_pton (AF_INET, addr, &tmp); + nm_ip4_address_set_address (ip4_addr, tmp.s_addr); + + inet_pton (AF_INET, gw, &tmp); + nm_ip4_address_set_gateway (ip4_addr, tmp.s_addr); + + nm_setting_ip4_config_add_address (s_ip4, ip4_addr); + nm_ip4_address_unref (ip4_addr); +} + +static void +add_one_ip4_route (NMSettingIP4Config *s_ip4, + const char *dest, + const char *nh, + guint32 prefix, + guint32 metric) +{ + struct in_addr addr; + NMIP4Route *route; + + route = nm_ip4_route_new (); + nm_ip4_route_set_prefix (route, prefix); + nm_ip4_route_set_metric (route, metric); + + inet_pton (AF_INET, dest, &addr); + nm_ip4_route_set_dest (route, addr.s_addr); + + inet_pton (AF_INET, nh, &addr); + nm_ip4_route_set_next_hop (route, addr.s_addr); + + nm_setting_ip4_config_add_route (s_ip4, route); + nm_ip4_route_unref (route); +} + static void test_write_wired_connection (void) { @@ -313,11 +359,24 @@ test_write_wired_connection (void) GError *error = NULL; pid_t owner_grp; uid_t owner_uid; + struct in_addr addr; + const char *dns1 = "4.2.2.1"; + const char *dns2 = "4.2.2.2"; + const char *address1 = "192.168.0.5"; + const char *address1_gw = "192.168.0.1"; + const char *address2 = "1.2.3.4"; + const char *address2_gw = "1.2.1.1"; + const char *route1 = "10.10.10.2"; + const char *route1_nh = "10.10.10.1"; + const char *route2 = "0.0.0.0"; + const char *route2_nh = "1.2.1.1"; connection = nm_connection_new (); ASSERT (connection != NULL, "connection-write", "failed to allocate new connection"); + /* Connection setting */ + s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ()); ASSERT (s_con != NULL, "connection-write", "failed to allocate new %s setting", @@ -334,6 +393,8 @@ test_write_wired_connection (void) NULL); g_free (uuid); + /* Wired setting */ + s_wired = NM_SETTING_WIRED (nm_setting_wired_new ()); ASSERT (s_wired != NULL, "connection-write", "failed to allocate new %s setting", @@ -348,12 +409,32 @@ test_write_wired_connection (void) NULL); g_byte_array_free (mac, TRUE); + /* IP4 setting */ + s_ip4 = NM_SETTING_IP4_CONFIG (nm_setting_ip4_config_new ()); ASSERT (s_ip4 != NULL, "connection-write", "failed to allocate new %s setting", NM_SETTING_WIRED_SETTING_NAME); nm_connection_add_setting (connection, NM_SETTING (s_ip4)); + g_object_set (s_ip4, + NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL, + NULL); + + /* Addresses */ + add_one_ip4_address (s_ip4, address1, address1_gw, 24); + add_one_ip4_address (s_ip4, address2, address2_gw, 8); + + /* Routes */ + add_one_ip4_route (s_ip4, route1, route1_nh, 24, 3); + add_one_ip4_route (s_ip4, route2, route2_nh, 8, 1); + + /* DNS servers */ + inet_pton (AF_INET, dns1, &addr); + nm_setting_ip4_config_add_dns (s_ip4, addr.s_addr); + inet_pton (AF_INET, dns2, &addr); + nm_setting_ip4_config_add_dns (s_ip4, addr.s_addr); + /* Write out the connection */ owner_uid = geteuid (); owner_grp = getegid ();