libnm-util, libnm-glib: add device/connection describing functions

Add functions to describe and disambiguate devices and connections for
display to the user. Originally from libnm-gtk.
This commit is contained in:
Dan Winship 2013-12-18 15:15:21 -05:00
parent 078d177874
commit f7b1b28202
7 changed files with 502 additions and 12 deletions

View file

@ -102,6 +102,7 @@ global:
nm_device_bt_new;
nm_device_connection_compatible;
nm_device_connection_valid;
nm_device_disambiguate_names;
nm_device_disconnect;
nm_device_error_get_type;
nm_device_error_quark;
@ -123,6 +124,7 @@ global:
nm_device_get_autoconnect;
nm_device_get_available_connections;
nm_device_get_capabilities;
nm_device_get_description;
nm_device_get_device_type;
nm_device_get_dhcp4_config;
nm_device_get_dhcp6_config;

View file

@ -23,6 +23,7 @@
#include <string.h>
#include <glib/gi18n.h>
#include <gudev/gudev.h>
#include "NetworkManager.h"
@ -94,8 +95,9 @@ typedef struct {
GPtrArray *available_connections;
GUdevClient *client;
char *product;
char *vendor;
char *product, *short_product;
char *vendor, *short_vendor;
char *description, *bus_name;
char *physical_port_id;
guint32 mtu;
@ -394,7 +396,11 @@ finalize (GObject *object)
g_free (priv->driver_version);
g_free (priv->firmware_version);
g_free (priv->product);
g_free (priv->short_product);
g_free (priv->vendor);
g_free (priv->short_vendor);
g_free (priv->description);
g_free (priv->bus_name);
g_free (priv->type_description);
g_free (priv->physical_port_id);
@ -1481,23 +1487,31 @@ get_decoded_property (GUdevDevice *device, const char *property)
return unescaped;
}
static gboolean
ensure_udev_client (NMDevice *device)
{
static const char *const subsys[3] = { "net", "tty", NULL };
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
if (!priv->client)
priv->client = g_udev_client_new (subsys);
return priv->client != NULL;
}
static char *
_get_udev_property (NMDevice *device,
const char *enc_prop, /* ID_XXX_ENC */
const char *db_prop) /* ID_XXX_FROM_DATABASE */
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
const char *subsys[3] = { "net", "tty", NULL };
GUdevDevice *udev_device = NULL, *tmpdev, *olddev;
const char *ifname;
guint32 count = 0;
char *enc_value = NULL, *db_value = NULL;
if (!priv->client) {
priv->client = g_udev_client_new (subsys);
if (!priv->client)
return NULL;
}
if (!ensure_udev_client (device))
return NULL;
ifname = nm_device_get_iface (device);
if (!ifname)
@ -1600,6 +1614,429 @@ nm_device_get_vendor (NMDevice *device)
return priv->vendor;
}
static const char * const ignored_words[] = {
"Semiconductor",
"Components",
"Corporation",
"Communications",
"Company",
"Corp.",
"Corp",
"Co.",
"Inc.",
"Inc",
"Incorporated",
"Ltd.",
"Limited.",
"Intel?",
"chipset",
"adapter",
"[hex]",
"NDIS",
"Module",
NULL
};
static const char * const ignored_phrases[] = {
"Multiprotocol MAC/baseband processor",
"Wireless LAN Controller",
"Wireless LAN Adapter",
"Wireless Adapter",
"Network Connection",
"Wireless Cardbus Adapter",
"Wireless CardBus Adapter",
"54 Mbps Wireless PC Card",
"Wireless PC Card",
"Wireless PC",
"PC Card with XJACK(r) Antenna",
"Wireless cardbus",
"Wireless LAN PC Card",
"Technology Group Ltd.",
"Communication S.p.A.",
"Business Mobile Networks BV",
"Mobile Broadband Minicard Composite Device",
"Mobile Communications AB",
"(PC-Suite Mode)",
NULL
};
static char *
fixup_desc_string (const char *desc)
{
char *p, *temp;
char **words, **item;
GString *str;
int i;
if (!desc)
return NULL;
p = temp = g_strdup (desc);
while (*p) {
if (*p == '_' || *p == ',')
*p = ' ';
p++;
}
/* Attempt to shorten ID by ignoring certain phrases */
for (i = 0; ignored_phrases[i]; i++) {
p = strstr (temp, ignored_phrases[i]);
if (p) {
guint32 ignored_len = strlen (ignored_phrases[i]);
memmove (p, p + ignored_len, strlen (p + ignored_len) + 1); /* +1 for the \0 */
}
}
/* Attempt to shorten ID by ignoring certain individual words */
words = g_strsplit (temp, " ", 0);
str = g_string_new_len (NULL, strlen (temp));
g_free (temp);
for (item = words; *item; item++) {
gboolean ignore = FALSE;
if (**item == '\0')
continue;
for (i = 0; ignored_words[i]; i++) {
if (!strcmp (*item, ignored_words[i])) {
ignore = TRUE;
break;
}
}
if (!ignore) {
if (str->len)
g_string_append_c (str, ' ');
g_string_append (str, *item);
}
}
g_strfreev (words);
temp = str->str;
g_string_free (str, FALSE);
return temp;
}
static void
get_description (NMDevice *device)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
const char *dev_product;
const char *dev_vendor;
char *pdown;
char *vdown;
GString *str;
dev_product = nm_device_get_product (device);
priv->short_product = fixup_desc_string (dev_product);
dev_vendor = nm_device_get_vendor (device);
priv->short_vendor = fixup_desc_string (dev_vendor);
if (!dev_product || !dev_vendor) {
priv->description = g_strdup (nm_device_get_iface (device));
return;
}
str = g_string_new_len (NULL, strlen (priv->short_vendor) + strlen (priv->short_product) + 1);
/* Another quick hack; if all of the fixed up vendor string
* is found in product, ignore the vendor.
*/
pdown = g_ascii_strdown (priv->short_product, -1);
vdown = g_ascii_strdown (priv->short_vendor, -1);
if (!strstr (pdown, vdown)) {
g_string_append (str, priv->short_vendor);
g_string_append_c (str, ' ');
}
g_free (pdown);
g_free (vdown);
g_string_append (str, priv->short_product);
priv->description = g_string_free (str, FALSE);
}
static const char *
get_short_vendor (NMDevice *device)
{
NMDevicePrivate *priv;
g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
priv = NM_DEVICE_GET_PRIVATE (device);
if (!priv->description)
get_description (device);
return priv->short_vendor;
}
/**
* nm_device_get_description:
* @device: an #NMDevice
*
* Gets a description of @device, incorporating the results of
* nm_device_get_short_vendor() and nm_device_get_short_product().
*
* Returns: a description of @device. If either the vendor or the
* product name is unknown, this returns the interface name.
*
* Since: 0.9.10
*/
const char *
nm_device_get_description (NMDevice *device)
{
NMDevicePrivate *priv;
g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
priv = NM_DEVICE_GET_PRIVATE (device);
if (!priv->description)
get_description (device);
return priv->description;
}
static const char *
get_type_name (NMDevice *device)
{
switch (nm_device_get_device_type (device)) {
case NM_DEVICE_TYPE_ETHERNET:
return _("Ethernet");
case NM_DEVICE_TYPE_WIFI:
return _("Wi-Fi");
case NM_DEVICE_TYPE_BT:
return _("Bluetooth");
case NM_DEVICE_TYPE_OLPC_MESH:
return _("OLPC Mesh");
case NM_DEVICE_TYPE_WIMAX:
return _("WiMAX");
case NM_DEVICE_TYPE_MODEM:
return _("Mobile Broadband");
case NM_DEVICE_TYPE_INFINIBAND:
return _("InfiniBand");
case NM_DEVICE_TYPE_BOND:
return _("Bond");
case NM_DEVICE_TYPE_TEAM:
return _("Team");
case NM_DEVICE_TYPE_BRIDGE:
return _("Bridge");
case NM_DEVICE_TYPE_VLAN:
return _("VLAN");
case NM_DEVICE_TYPE_ADSL:
return _("ADSL");
default:
return _("Unknown");
}
}
static char *
get_device_type_name_with_iface (NMDevice *device)
{
const char *type_name = get_type_name (device);
switch (nm_device_get_device_type (device)) {
case NM_DEVICE_TYPE_BOND:
case NM_DEVICE_TYPE_TEAM:
case NM_DEVICE_TYPE_BRIDGE:
case NM_DEVICE_TYPE_VLAN:
return g_strdup_printf ("%s (%s)", type_name, nm_device_get_iface (device));
default:
return g_strdup (type_name);
}
}
static char *
get_device_generic_type_name_with_iface (NMDevice *device)
{
switch (nm_device_get_device_type (device)) {
case NM_DEVICE_TYPE_ETHERNET:
case NM_DEVICE_TYPE_INFINIBAND:
return g_strdup (_("Wired"));
default:
return get_device_type_name_with_iface (device);
}
}
static const char *
get_bus_name (NMDevice *device)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
GUdevDevice *udevice;
const char *ifname, *bus;
if (priv->bus_name)
goto out;
if (!ensure_udev_client (device))
return NULL;
ifname = nm_device_get_iface (device);
if (!ifname)
return NULL;
udevice = g_udev_client_query_by_subsystem_and_name (priv->client, "net", ifname);
if (!udevice)
udevice = g_udev_client_query_by_subsystem_and_name (priv->client, "tty", ifname);
if (!udevice)
return NULL;
bus = g_udev_device_get_property (udevice, "ID_BUS");
if (!g_strcmp0 (bus, "pci"))
priv->bus_name = g_strdup (_("PCI"));
else if (!g_strcmp0 (bus, "usb"))
priv->bus_name = g_strdup (_("USB"));
else {
/* Use "" instead of NULL so we can tell later that we've
* already tried.
*/
priv->bus_name = g_strdup ("");
}
out:
if (*priv->bus_name)
return priv->bus_name;
else
return NULL;
}
static gboolean
find_duplicates (char **names,
gboolean *duplicates,
int num_devices)
{
int i, j;
gboolean found_any = FALSE;
memset (duplicates, 0, num_devices * sizeof (gboolean));
for (i = 0; i < num_devices; i++) {
if (duplicates[i])
continue;
for (j = i + 1; j < num_devices; j++) {
if (duplicates[j])
continue;
if (!strcmp (names[i], names[j]))
duplicates[i] = duplicates[j] = found_any = TRUE;
}
}
return found_any;
}
/**
* nm_device_disambiguate_names:
* @devices: (array length=num_devices): an array of #NMDevice
* @num_devices: length of @devices
*
* Generates a list of short-ish unique presentation names for the
* devices in @devices.
*
* Returns: (transfer full) (array zero-terminated=1): the device names
*
* Since: 0.9.10
*/
char **
nm_device_disambiguate_names (NMDevice **devices,
int num_devices)
{
char **names;
gboolean *duplicates;
int i;
names = g_new (char *, num_devices + 1);
duplicates = g_new (gboolean, num_devices);
/* Generic device name */
for (i = 0; i < num_devices; i++)
names[i] = get_device_generic_type_name_with_iface (devices[i]);
if (!find_duplicates (names, duplicates, num_devices))
goto done;
/* Try specific names (eg, "Ethernet" and "InfiniBand" rather
* than "Wired")
*/
for (i = 0; i < num_devices; i++) {
if (duplicates[i]) {
g_free (names[i]);
names[i] = get_device_type_name_with_iface (devices[i]);
}
}
if (!find_duplicates (names, duplicates, num_devices))
goto done;
/* Try prefixing bus name (eg, "PCI Ethernet" vs "USB Ethernet") */
for (i = 0; i < num_devices; i++) {
if (duplicates[i]) {
const char *bus = get_bus_name (devices[i]);
char *name;
if (!bus)
continue;
g_free (names[i]);
name = get_device_type_name_with_iface (devices[i]);
/* Translators: the first %s is a bus name (eg, "USB") or
* product name, the second is a device type (eg,
* "Ethernet"). You can change this to something like
* "%2$s (%1$s)" if there's no grammatical way to combine
* the strings otherwise.
*/
names[i] = g_strdup_printf (C_("long device name", "%s %s"),
bus, name);
g_free (name);
}
}
if (!find_duplicates (names, duplicates, num_devices))
goto done;
/* Try prefixing vendor name */
for (i = 0; i < num_devices; i++) {
if (duplicates[i]) {
const char *vendor = get_short_vendor (devices[i]);
char *name;
if (!vendor)
continue;
g_free (names[i]);
name = get_device_type_name_with_iface (devices[i]);
names[i] = g_strdup_printf (C_("long device name", "%s %s"),
vendor,
get_type_name (devices[i]));
g_free (name);
}
}
if (!find_duplicates (names, duplicates, num_devices))
goto done;
/* We have multiple identical network cards, so we have to differentiate
* them by interface name.
*/
for (i = 0; i < num_devices; i++) {
if (duplicates[i]) {
const char *interface = nm_device_get_iface (devices[i]);
if (!interface)
continue;
g_free (names[i]);
names[i] = g_strdup_printf ("%s (%s)",
get_type_name (devices[i]),
interface);
}
}
done:
g_free (duplicates);
names[num_devices] = NULL;
return names;
}
/**
* nm_device_get_physical_port_id:
* @device: a #NMDevice

View file

@ -136,11 +136,15 @@ NMDeviceState nm_device_get_state (NMDevice *device);
NMDeviceState nm_device_get_state_reason (NMDevice *device, NMDeviceStateReason *reason);
NMActiveConnection * nm_device_get_active_connection(NMDevice *device);
const GPtrArray * nm_device_get_available_connections(NMDevice *device);
const char * nm_device_get_product (NMDevice *device);
const char * nm_device_get_vendor (NMDevice *device);
const char * nm_device_get_physical_port_id (NMDevice *device);
guint32 nm_device_get_mtu (NMDevice *device);
const char * nm_device_get_product (NMDevice *device);
const char * nm_device_get_vendor (NMDevice *device);
const char * nm_device_get_description (NMDevice *device);
char ** nm_device_disambiguate_names (NMDevice **devices,
int num_devices);
typedef void (*NMDeviceDeactivateFn) (NMDevice *device, GError *error, gpointer user_data);
void nm_device_disconnect (NMDevice *device,

View file

@ -43,6 +43,7 @@ global:
nm_connection_get_setting_wireless_security;
nm_connection_get_type;
nm_connection_get_uuid;
nm_connection_get_virtual_device_description;
nm_connection_get_virtual_iface_name;
nm_connection_is_type;
nm_connection_lookup_setting_type;

View file

@ -24,6 +24,7 @@
*/
#include <glib-object.h>
#include <glib/gi18n.h>
#include <dbus/dbus-glib.h>
#include <string.h>
#include "nm-connection.h"
@ -1242,6 +1243,47 @@ nm_connection_get_id (NMConnection *connection)
return nm_setting_connection_get_id (s_con);
}
/**
* nm_connection_get_virtual_device_description:
* @connection: an #NMConnection for a virtual device type
*
* Returns the name that nm_device_disambiguate_names() would
* return for the virtual device that would be created for @connection.
* Eg, "VLAN (eth1.1)".
*
* Returns: (transfer full): the name of @connection's device,
* or %NULL if @connection is not a virtual connection type
*/
char *
nm_connection_get_virtual_device_description (NMConnection *connection)
{
const char *iface, *type, *display_type;
NMSettingConnection *s_con;
iface = nm_connection_get_virtual_iface_name (connection);
if (!iface)
return NULL;
s_con = nm_connection_get_setting_connection (connection);
g_return_val_if_fail (s_con != NULL, NULL);
type = nm_setting_connection_get_connection_type (s_con);
if (!strcmp (type, NM_SETTING_BOND_SETTING_NAME))
display_type = _("Bond");
else if (!strcmp (type, NM_SETTING_TEAM_SETTING_NAME))
display_type = _("Team");
else if (!strcmp (type, NM_SETTING_BRIDGE_SETTING_NAME))
display_type = _("Bridge");
else if (!strcmp (type, NM_SETTING_VLAN_SETTING_NAME))
display_type = _("VLAN");
else {
g_warning ("Unrecognized virtual device type '%s'", type);
display_type = type;
}
return g_strdup_printf ("%s (%s)", display_type, iface);
}
/*************************************************************/
/**

View file

@ -196,9 +196,11 @@ GType nm_connection_lookup_setting_type (const char *name);
GType nm_connection_lookup_setting_type_by_quark (GQuark error_quark);
/* Helpers */
const char * nm_connection_get_uuid (NMConnection *connection);
const char * nm_connection_get_uuid (NMConnection *connection);
const char * nm_connection_get_id (NMConnection *connection);
const char * nm_connection_get_id (NMConnection *connection);
char * nm_connection_get_virtual_device_description (NMConnection *connection);
NMSetting8021x * nm_connection_get_setting_802_1x (NMConnection *connection);
NMSettingBluetooth * nm_connection_get_setting_bluetooth (NMConnection *connection);

View file

@ -8,9 +8,11 @@ cli/src/network-manager.c
cli/src/nmcli.c
cli/src/settings.c
cli/src/utils.c
libnm-glib/nm-device.c
libnm-util/crypto.c
libnm-util/crypto_gnutls.c
libnm-util/crypto_nss.c
libnm-util/nm-connection.c
libnm-util/nm-setting-8021x.c
libnm-util/nm-setting-adsl.c
libnm-util/nm-setting-bluetooth.c