summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Winship <danw@gnome.org>2013-12-18 15:15:21 -0500
committerDan Winship <danw@gnome.org>2014-01-27 15:39:51 -0500
commitf7b1b2820245aff26da0c2c946b55752e91112e5 (patch)
tree61406813aec66b02005f698a2cb18895c3964b4b
parent078d177874736bdc9ee06ef7406a31702b63a69a (diff)
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.
-rw-r--r--libnm-glib/libnm-glib.ver2
-rw-r--r--libnm-glib/nm-device.c453
-rw-r--r--libnm-glib/nm-device.h8
-rw-r--r--libnm-util/libnm-util.ver1
-rw-r--r--libnm-util/nm-connection.c42
-rw-r--r--libnm-util/nm-connection.h6
-rw-r--r--po/POTFILES.in2
7 files changed, 502 insertions, 12 deletions
diff --git a/libnm-glib/libnm-glib.ver b/libnm-glib/libnm-glib.ver
index 9f0db93b23..ca47f9163b 100644
--- a/libnm-glib/libnm-glib.ver
+++ b/libnm-glib/libnm-glib.ver
@@ -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;
diff --git a/libnm-glib/nm-device.c b/libnm-glib/nm-device.c
index 806c9347d3..a8d66052a3 100644
--- a/libnm-glib/nm-device.c
+++ b/libnm-glib/nm-device.c
@@ -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
diff --git a/libnm-glib/nm-device.h b/libnm-glib/nm-device.h
index 33ab8a3dcb..3f38cf64c3 100644
--- a/libnm-glib/nm-device.h
+++ b/libnm-glib/nm-device.h
@@ -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,
diff --git a/libnm-util/libnm-util.ver b/libnm-util/libnm-util.ver
index 3797e2beae..60614d2e4a 100644
--- a/libnm-util/libnm-util.ver
+++ b/libnm-util/libnm-util.ver
@@ -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;
diff --git a/libnm-util/nm-connection.c b/libnm-util/nm-connection.c
index f7d643193c..52b541120b 100644
--- a/libnm-util/nm-connection.c
+++ b/libnm-util/nm-connection.c
@@ -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);
+}
+
/*************************************************************/
/**
diff --git a/libnm-util/nm-connection.h b/libnm-util/nm-connection.h
index cda8391e8b..79f6504313 100644
--- a/libnm-util/nm-connection.h
+++ b/libnm-util/nm-connection.h
@@ -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);
diff --git a/po/POTFILES.in b/po/POTFILES.in
index c365014f22..b530426a4c 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -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