git: c4ba4aa54718 - main - libifconfig: Overhaul ifconfig_media_* interfaces

Ryan Moeller freqlabs at FreeBSD.org
Fri Mar 5 11:23:57 UTC 2021


The branch main has been updated by freqlabs:

URL: https://cgit.FreeBSD.org/src/commit/?id=c4ba4aa547184ab401204096cdad9def4ab37964

commit c4ba4aa547184ab401204096cdad9def4ab37964
Author:     Ryan Moeller <freqlabs at FreeBSD.org>
AuthorDate: 2021-03-02 10:29:17 +0000
Commit:     Ryan Moeller <freqlabs at FreeBSD.org>
CommitDate: 2021-03-05 09:15:55 +0000

    libifconfig: Overhaul ifconfig_media_* interfaces
    
    Define an ifmedia_t type to use for ifmedia words.
    
    Add ifconfig_media_lookup_* functions to lookup ifmedia words by name.
    
    Get media options as an array of option names rather than formatting it
    as a comma-delimited list into a buffer.
    
    Sprinkle const on static the static description tables for peace of
    mind.
    
    Don't need to zero memory allocated by calloc.
    
    Reviewed by:    kp
    MFC after:      2 weeks
    Differential Revision:  https://reviews.freebsd.org/D29029
---
 lib/libifconfig/Makefile            |   2 +-
 lib/libifconfig/Symbol.map          |   9 +-
 lib/libifconfig/libifconfig.h       |  69 +++++++-
 lib/libifconfig/libifconfig_media.c | 339 ++++++++++++++++++++++++------------
 share/examples/libifconfig/status.c |  27 ++-
 5 files changed, 324 insertions(+), 122 deletions(-)

diff --git a/lib/libifconfig/Makefile b/lib/libifconfig/Makefile
index 73dad36c1dc5..c6f006018427 100644
--- a/lib/libifconfig/Makefile
+++ b/lib/libifconfig/Makefile
@@ -7,7 +7,7 @@ INTERNALLIB=	true
 LIBADD=		m
 
 SHLIBDIR?=	/lib
-SHLIB_MAJOR=	1
+SHLIB_MAJOR=	2
 
 VERSION_DEF=	${LIBCSRCDIR}/Versions.def
 SYMBOL_MAPS=	${.CURDIR}/Symbol.map
diff --git a/lib/libifconfig/Symbol.map b/lib/libifconfig/Symbol.map
index 235092376b11..2d80fb31652a 100644
--- a/lib/libifconfig/Symbol.map
+++ b/lib/libifconfig/Symbol.map
@@ -26,12 +26,17 @@ FBSD_1.6 {
 	ifconfig_lagg_get_lagg_status;
 	ifconfig_lagg_get_laggport_status;
 	ifconfig_list_cloners;
+	ifconfig_media_get_downreason;
 	ifconfig_media_get_mediareq;
-	ifconfig_media_get_options_string;
+	ifconfig_media_get_mode;
+	ifconfig_media_get_options;
 	ifconfig_media_get_status;
 	ifconfig_media_get_subtype;
 	ifconfig_media_get_type;
-	ifconfig_media_get_downreason;
+	ifconfig_media_lookup_mode;
+	ifconfig_media_lookup_options;
+	ifconfig_media_lookup_subtype;
+	ifconfig_media_lookup_type;
 	ifconfig_open;
 	ifconfig_set_capability;
 	ifconfig_set_description;
diff --git a/lib/libifconfig/libifconfig.h b/lib/libifconfig/libifconfig.h
index d8245ea13b23..e1cd6d1821a5 100644
--- a/lib/libifconfig/libifconfig.h
+++ b/lib/libifconfig/libifconfig.h
@@ -202,10 +202,73 @@ int ifconfig_get_ifstatus(ifconfig_handle_t *h, const char *name,
  */
 int ifconfig_media_get_mediareq(ifconfig_handle_t *h, const char *name,
     struct ifmediareq **ifmr);
-const char *ifconfig_media_get_type(int ifmw);
-const char *ifconfig_media_get_subtype(int ifmw);
+
 const char *ifconfig_media_get_status(const struct ifmediareq *ifmr);
-void ifconfig_media_get_options_string(int ifmw, char *buf, size_t buflen);
+
+typedef int ifmedia_t;
+
+#define INVALID_IFMEDIA ((ifmedia_t)-1)
+
+/** Retrieve the name of a media type
+ * @param media	The media to be named
+ * @return	A pointer to the media type name, or NULL on failure
+ */
+const char *ifconfig_media_get_type(ifmedia_t media);
+
+/** Retrieve a media type by its name
+ * @param name	The name of a media type
+ * @return	The media type value, or INVALID_IFMEDIA on failure
+ */
+ifmedia_t ifconfig_media_lookup_type(const char *name);
+
+/** Retrieve the name of a media subtype
+ * @param media	The media subtype to be named
+ * @return	A pointer to the media subtype name, or NULL on failure
+ */
+const char *ifconfig_media_get_subtype(ifmedia_t media);
+
+/** Retrieve a media subtype by its name
+ * @param media	The top level media type whose subtype we want
+ * @param name	The name of a media subtype
+ * @return	The media subtype value, or INVALID_IFMEDIA on failure
+ */
+ifmedia_t ifconfig_media_lookup_subtype(ifmedia_t media, const char *name);
+
+/** Retrieve the name of a media mode
+ * @param media	The media mode to be named
+ * @return	A pointer to the media mode name, or NULL on failure
+ */
+const char *ifconfig_media_get_mode(ifmedia_t media);
+
+/** Retrieve a media mode by its name
+ * @param media	The top level media type whose mode we want
+ * @param name	The name of a media mode
+ * @return	The media mode value, or INVALID_IFMEDIA on failure
+ */
+ifmedia_t ifconfig_media_lookup_mode(ifmedia_t media, const char *name);
+
+/** Retrieve an array of media options
+ * @param media	The media for which to obtain the options
+ * @return	Pointer to an array of pointers to option names,
+ * 		terminated by a NULL pointer, or simply NULL on failure.
+ * 		The caller is responsible for freeing the array but not its
+ * 		contents.
+ */
+const char **ifconfig_media_get_options(ifmedia_t media);
+
+/** Retrieve an array of media options by names
+ * @param media	The top level media type whose options we want
+ * @param opts	Pointer to an array of string pointers naming options
+ * @param nopts Number of elements in the opts array
+ * @return	Pointer to an array of media options, one for each option named
+ * 		in opts.  NULL is returned instead with errno set to ENOMEM if
+ * 		allocating the return array fails or EINVAL if media is not
+ * 		valid.  A media option in the array will be INVALID_IFMEDIA
+ * 		when lookup failed for the option named in that position in
+ * 		opts.  The caller is responsible for freeing the array.
+ */
+ifmedia_t *ifconfig_media_lookup_options(ifmedia_t media, const char **opts,
+    size_t nopts);
 
 /** Retrieve the reason the interface is down
  * @param h	An open ifconfig state object
diff --git a/lib/libifconfig/libifconfig_media.c b/lib/libifconfig/libifconfig_media.c
index d7ef507604be..e27f5900e3d3 100644
--- a/lib/libifconfig/libifconfig_media.c
+++ b/lib/libifconfig/libifconfig_media.c
@@ -45,6 +45,7 @@
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -53,11 +54,9 @@
 #include "libifconfig.h"
 #include "libifconfig_internal.h"
 
-
-static struct ifmedia_description *get_toptype_desc(int);
-static struct ifmedia_type_to_subtype *get_toptype_ttos(int);
-static struct ifmedia_description *get_subtype_desc(int,
-    struct ifmedia_type_to_subtype *ttos);
+static const struct ifmedia_description *lookup_media_desc(
+    const struct ifmedia_description *, const char *);
+static const struct ifmedia_type_to_subtype *get_toptype_ttos(ifmedia_t);
 
 #define IFM_OPMODE(x)							 \
 	((x) & (IFM_IEEE80211_ADHOC | IFM_IEEE80211_HOSTAP |		 \
@@ -65,74 +64,100 @@ static struct ifmedia_description *get_subtype_desc(int,
 	IFM_IEEE80211_MBSS))
 #define IFM_IEEE80211_STA    0
 
-static struct ifmedia_description ifm_type_descriptions[] =
+static const struct ifmedia_description
+    ifm_type_descriptions[] =
     IFM_TYPE_DESCRIPTIONS;
 
-static struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
+static const struct ifmedia_description
+    ifm_subtype_ethernet_descriptions[] =
     IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
 
-static struct ifmedia_description ifm_subtype_ethernet_aliases[] =
+static const struct ifmedia_description
+    ifm_subtype_ethernet_aliases[] =
     IFM_SUBTYPE_ETHERNET_ALIASES;
 
-static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
+static const struct ifmedia_description
+    ifm_subtype_ethernet_option_descriptions[] =
     IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
 
-static struct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
+static const struct ifmedia_description
+    ifm_subtype_ieee80211_descriptions[] =
     IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
 
-static struct ifmedia_description ifm_subtype_ieee80211_aliases[] =
+static const struct ifmedia_description
+    ifm_subtype_ieee80211_aliases[] =
     IFM_SUBTYPE_IEEE80211_ALIASES;
 
-static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
+static const struct ifmedia_description
+    ifm_subtype_ieee80211_option_descriptions[] =
     IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
 
-static struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] =
+static const struct ifmedia_description
+    ifm_subtype_ieee80211_mode_descriptions[] =
     IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS;
 
-static struct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] =
+static const struct ifmedia_description
+    ifm_subtype_ieee80211_mode_aliases[] =
     IFM_SUBTYPE_IEEE80211_MODE_ALIASES;
 
-static struct ifmedia_description ifm_subtype_atm_descriptions[] =
+static const struct ifmedia_description
+    ifm_subtype_atm_descriptions[] =
     IFM_SUBTYPE_ATM_DESCRIPTIONS;
 
-static struct ifmedia_description ifm_subtype_atm_aliases[] =
+static const struct ifmedia_description
+    ifm_subtype_atm_aliases[] =
     IFM_SUBTYPE_ATM_ALIASES;
 
-static struct ifmedia_description ifm_subtype_atm_option_descriptions[] =
+static const struct ifmedia_description
+    ifm_subtype_atm_option_descriptions[] =
     IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS;
 
-static struct ifmedia_description ifm_subtype_shared_descriptions[] =
+static const struct ifmedia_description
+    ifm_subtype_shared_descriptions[] =
     IFM_SUBTYPE_SHARED_DESCRIPTIONS;
 
-static struct ifmedia_description ifm_subtype_shared_aliases[] =
+static const struct ifmedia_description
+    ifm_subtype_shared_aliases[] =
     IFM_SUBTYPE_SHARED_ALIASES;
 
-static struct ifmedia_description ifm_shared_option_descriptions[] =
+static const struct ifmedia_description
+    ifm_shared_option_descriptions[] =
     IFM_SHARED_OPTION_DESCRIPTIONS;
 
-static struct ifmedia_description ifm_shared_option_aliases[] =
+static const struct ifmedia_description
+    ifm_shared_option_aliases[] =
     IFM_SHARED_OPTION_ALIASES;
 
+static const struct ifmedia_description *
+lookup_media_desc(const struct ifmedia_description *desc, const char *name)
+{
+
+	for (; desc->ifmt_string != NULL; ++desc)
+		if (strcasecmp(desc->ifmt_string, name) == 0)
+			return (desc);
+	return (NULL);
+}
+
 struct ifmedia_type_to_subtype {
 	struct {
-		struct ifmedia_description *desc;
-		int alias;
+		const struct ifmedia_description *desc;
+		bool alias;
 	}
 	subtypes[5];
 	struct {
-		struct ifmedia_description *desc;
-		int alias;
+		const struct ifmedia_description *desc;
+		bool alias;
 	}
 	options[4];
 	struct {
-		struct ifmedia_description *desc;
-		int alias;
+		const struct ifmedia_description *desc;
+		bool alias;
 	}
 	modes[3];
 };
 
 /* must be in the same order as IFM_TYPE_DESCRIPTIONS */
-static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] =
+static const struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] =
 {
 	{
 		{
@@ -192,83 +217,214 @@ static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] =
 	},
 };
 
-static struct ifmedia_description *
-get_toptype_desc(int ifmw)
+static const struct ifmedia_type_to_subtype *
+get_toptype_ttos(ifmedia_t media)
 {
-	struct ifmedia_description *desc;
+	const struct ifmedia_description *desc;
+	const struct ifmedia_type_to_subtype *ttos;
 
-	for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++) {
-		if (IFM_TYPE(ifmw) == desc->ifmt_word) {
-			break;
-		}
+	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
+	    desc->ifmt_string != NULL; desc++, ttos++) {
+		if (IFM_TYPE(media) == desc->ifmt_word)
+			return (ttos);
 	}
-
-	return (desc);
+	errno = ENOENT;
+	return (NULL);
 }
 
-static struct ifmedia_type_to_subtype *
-get_toptype_ttos(int ifmw)
+const char *
+ifconfig_media_get_type(ifmedia_t media)
 {
-	struct ifmedia_description *desc;
-	struct ifmedia_type_to_subtype *ttos;
+	const struct ifmedia_description *desc;
 
-	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
-	    desc->ifmt_string != NULL; desc++, ttos++) {
-		if (IFM_TYPE(ifmw) == desc->ifmt_word) {
-			break;
-		}
+	for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; ++desc) {
+		if (IFM_TYPE(media) == desc->ifmt_word)
+			return (desc->ifmt_string);
 	}
+	errno = ENOENT;
+	return (NULL);
+}
+
+ifmedia_t
+ifconfig_media_lookup_type(const char *name)
+{
+	const struct ifmedia_description *desc;
 
-	return (ttos);
+	desc = lookup_media_desc(ifm_type_descriptions, name);
+	return (desc == NULL ? INVALID_IFMEDIA : desc->ifmt_word);
 }
 
-static struct ifmedia_description *
-get_subtype_desc(int ifmw,
-    struct ifmedia_type_to_subtype *ttos)
+const char *
+ifconfig_media_get_subtype(ifmedia_t media)
 {
-	int i;
-	struct ifmedia_description *desc;
+	const struct ifmedia_description *desc;
+	const struct ifmedia_type_to_subtype *ttos;
+
+	ttos = get_toptype_ttos(media);
+	if (ttos == NULL) {
+		errno = EINVAL;
+		return (NULL);
+	}
 
-	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
-		if (ttos->subtypes[i].alias) {
+	for (size_t i = 0; ttos->subtypes[i].desc != NULL; ++i) {
+		if (ttos->subtypes[i].alias)
 			continue;
-		}
 		for (desc = ttos->subtypes[i].desc;
-		    desc->ifmt_string != NULL; desc++) {
-			if (IFM_SUBTYPE(ifmw) == desc->ifmt_word) {
-				return (desc);
-			}
+		    desc->ifmt_string != NULL; ++desc) {
+			if (IFM_SUBTYPE(media) == desc->ifmt_word)
+				return (desc->ifmt_string);
 		}
 	}
-
+	errno = ENOENT;
 	return (NULL);
 }
 
-const char *
-ifconfig_media_get_type(int ifmw)
+ifmedia_t
+ifconfig_media_lookup_subtype(ifmedia_t media, const char *name)
 {
-	struct ifmedia_description *desc;
+	const struct ifmedia_description *desc;
+	const struct ifmedia_type_to_subtype *ttos;
 
-	/*int seen_option = 0, i;*/
+	ttos = get_toptype_ttos(media);
+	if (ttos == NULL) {
+		errno = EINVAL;
+		return (INVALID_IFMEDIA);
+	}
 
-	/* Find the top-level interface type. */
-	desc = get_toptype_desc(ifmw);
-	if (desc->ifmt_string == NULL) {
-		return ("<unknown type>");
-	} else {
-		return (desc->ifmt_string);
+	for (size_t i = 0; ttos->subtypes[i].desc != NULL; ++i) {
+		desc = lookup_media_desc(ttos->subtypes[i].desc, name);
+		if (desc != NULL)
+			return (desc->ifmt_word);
 	}
+	errno = ENOENT;
+	return (INVALID_IFMEDIA);
 }
 
 const char *
-ifconfig_media_get_subtype(int ifmw)
+ifconfig_media_get_mode(ifmedia_t media)
 {
-	struct ifmedia_description *desc;
-	struct ifmedia_type_to_subtype *ttos;
+	const struct ifmedia_description *desc;
+	const struct ifmedia_type_to_subtype *ttos;
+
+	ttos = get_toptype_ttos(media);
+	if (ttos == NULL) {
+		errno = EINVAL;
+		return (NULL);
+	}
 
-	ttos = get_toptype_ttos(ifmw);
-	desc = get_subtype_desc(ifmw, ttos);
-	return (desc->ifmt_string);
+	for (size_t i = 0; ttos->modes[i].desc != NULL; ++i) {
+		if (ttos->modes[i].alias)
+			continue;
+		for (desc = ttos->modes[i].desc;
+		    desc->ifmt_string != NULL; ++desc) {
+			if (IFM_MODE(media) == desc->ifmt_word)
+				return (desc->ifmt_string);
+		}
+	}
+	errno = ENOENT;
+	return (NULL);
+}
+
+ifmedia_t
+ifconfig_media_lookup_mode(ifmedia_t media, const char *name)
+{
+	const struct ifmedia_description *desc;
+	const struct ifmedia_type_to_subtype *ttos;
+
+	ttos = get_toptype_ttos(media);
+	if (ttos == NULL) {
+		errno = EINVAL;
+		return (INVALID_IFMEDIA);
+	}
+
+	for (size_t i = 0; ttos->modes[i].desc != NULL; ++i) {
+		desc = lookup_media_desc(ttos->modes[i].desc, name);
+		if (desc != NULL)
+			return (desc->ifmt_word);
+	}
+	errno = ENOENT;
+	return (INVALID_IFMEDIA);
+}
+
+const char **
+ifconfig_media_get_options(ifmedia_t media)
+{
+	const char **options;
+	const struct ifmedia_description *desc;
+	const struct ifmedia_type_to_subtype *ttos;
+	size_t n;
+
+	ttos = get_toptype_ttos(media);
+	if (ttos == NULL) {
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	n = 0;
+	for (size_t i = 0; ttos->options[i].desc != NULL; ++i) {
+		if (ttos->options[i].alias)
+			continue;
+		for (desc = ttos->options[i].desc;
+		    desc->ifmt_string != NULL; ++desc) {
+			if ((media & desc->ifmt_word) != 0)
+				++n;
+		}
+	}
+	if (n == 0) {
+		errno = ENOENT;
+		return (NULL);
+	}
+
+	options = calloc(n + 1, sizeof(*options));
+	if (options == NULL)
+		return (NULL);
+
+	options[n] = NULL;
+	n = 0;
+	for (size_t i = 0; ttos->options[i].desc != NULL; ++i) {
+		if (ttos->options[i].alias)
+			continue;
+		for (desc = ttos->options[i].desc;
+		    desc->ifmt_string != NULL; ++desc) {
+			if ((media & desc->ifmt_word) != 0) {
+				options[n] = desc->ifmt_string;
+				++n;
+			}
+		}
+	}
+	return (options);
+}
+
+ifmedia_t *
+ifconfig_media_lookup_options(ifmedia_t media, const char **opts, size_t nopts)
+{
+	ifmedia_t *options;
+	const struct ifmedia_description *desc, *opt;
+	const struct ifmedia_type_to_subtype *ttos;
+
+	assert(opts != NULL);
+	assert(nopts > 0);
+
+	ttos = get_toptype_ttos(media);
+	if (ttos == NULL) {
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	options = calloc(nopts, sizeof(*options));
+	if (options == NULL)
+		return (NULL);
+	(void)memset(options, INVALID_IFMEDIA, nopts * sizeof(ifmedia_t));
+
+	for (size_t i = 0; ttos->options[i].desc != NULL; ++i) {
+		desc = ttos->options[i].desc;
+		for (size_t j = 0; j < nopts; ++j) {
+			opt = lookup_media_desc(desc, opts[j]);
+			if (opt != NULL)
+				options[j] = opt->ifmt_word;
+		}
+	}
+	return (options);
 }
 
 /***************************************************************************
@@ -295,7 +451,6 @@ ifconfig_media_get_mediareq(ifconfig_handle_t *h, const char *name,
 		h->error.errcode = ENOMEM;
 		return (-1);
 	}
-	(void)memset(ms, 0, sizeof(*ms));
 	(void)strlcpy(ms->ifmr.ifm_name, name, sizeof(ms->ifmr.ifm_name));
 
 	/*
@@ -363,36 +518,6 @@ ifconfig_media_get_status(const struct ifmediareq *ifmr)
 	}
 }
 
-void
-ifconfig_media_get_options_string(int ifmw, char *buf, size_t buflen)
-{
-	struct ifmedia_type_to_subtype *ttos;
-	struct ifmedia_description *desc;
-	int i, seen_option = 0;
-	size_t len;
-
-	assert(buflen > 0);
-	buf[0] = '\0';
-	ttos = get_toptype_ttos(ifmw);
-	for (i = 0; ttos->options[i].desc != NULL; i++) {
-		if (ttos->options[i].alias) {
-			continue;
-		}
-		for (desc = ttos->options[i].desc;
-		    desc->ifmt_string != NULL; desc++) {
-			if (ifmw & desc->ifmt_word) {
-				if (seen_option++) {
-					strlcat(buf, ",", buflen);
-				}
-				len = strlcat(buf, desc->ifmt_string, buflen);
-				assert(len < buflen);
-				buf += len;
-				buflen -= len;
-			}
-		}
-	}
-}
-
 int
 ifconfig_media_get_downreason(ifconfig_handle_t *h, const char *name,
     struct ifdownreason *ifdr)
diff --git a/share/examples/libifconfig/status.c b/share/examples/libifconfig/status.c
index 62fd3f35c8de..114cf7e87a68 100644
--- a/share/examples/libifconfig/status.c
+++ b/share/examples/libifconfig/status.c
@@ -406,7 +406,6 @@ print_media(ifconfig_handle_t *lifh, struct ifaddrs *ifa)
 	 *    tables,  finding an entry with the right media subtype
 	 */
 	struct ifmediareq *ifmr;
-	char opts[80];
 
 	if (ifconfig_media_get_mediareq(lifh, ifa->ifa_name, &ifmr) != 0) {
 		if (ifconfig_err_errtype(lifh) != OK) {
@@ -419,14 +418,19 @@ print_media(ifconfig_handle_t *lifh, struct ifaddrs *ifa)
 	printf("\tmedia: %s %s", ifconfig_media_get_type(ifmr->ifm_current),
 	    ifconfig_media_get_subtype(ifmr->ifm_current));
 	if (ifmr->ifm_active != ifmr->ifm_current) {
+		const char **options;
+
 		printf(" (%s", ifconfig_media_get_subtype(ifmr->ifm_active));
-		ifconfig_media_get_options_string(ifmr->ifm_active, opts,
-		    sizeof(opts));
-		if (opts[0] != '\0') {
-			printf(" <%s>)\n", opts);
+		options = ifconfig_media_get_options(ifmr->ifm_active);
+		if (options != NULL && options[0] != NULL) {
+			printf(" <%s", options[0]);
+			for (size_t i = 1; options[i] != NULL; ++i)
+				printf(",%s", options[i]);
+			printf(">)\n");
 		} else {
 			printf(")\n");
 		}
+		free(options);
 	} else {
 		printf("\n");
 	}
@@ -438,15 +442,20 @@ print_media(ifconfig_handle_t *lifh, struct ifaddrs *ifa)
 
 	printf("\tsupported media:\n");
 	for (i = 0; i < ifmr->ifm_count; i++) {
+		const char **options;
+
 		printf("\t\tmedia %s",
 		    ifconfig_media_get_subtype(ifmr->ifm_ulist[i]));
-		ifconfig_media_get_options_string(ifmr->ifm_ulist[i], opts,
-		    sizeof(opts));
-		if (opts[0] != '\0') {
-			printf(" mediaopt %s\n", opts);
+		options = ifconfig_media_get_options(ifmr->ifm_ulist[i]);
+		if (options != NULL && options[0] != NULL) {
+			printf(" mediaopt %s", options[0]);
+			for (size_t i = 1; options[i] != NULL; ++i)
+				printf(",%s", options[i]);
+			printf("\n");
 		} else {
 			printf("\n");
 		}
+		free(options);
 	}
 	free(ifmr);
 }


More information about the dev-commits-src-all mailing list