keyfile: write nicely formatted MAC addresses; clean up "special" key handling

Add testcases for keyfile ip4-config setting writing too.
This commit is contained in:
Dan Williams 2009-01-12 18:23:30 -05:00
parent 45f2f1144d
commit 07d3ffbcec
2 changed files with 214 additions and 49 deletions

View file

@ -27,9 +27,13 @@
#include <nm-setting-connection.h>
#include <nm-setting-ip4-config.h>
#include <nm-setting-vpn.h>
#include <nm-setting-wired.h>
#include <nm-setting-wireless.h>
#include <nm-setting-ip4-config.h>
#include <nm-utils.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/ether.h>
#include <nm-settings.h>
#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));

View file

@ -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 ();