+typedef struct LinkInfo {
+ const char *name;
+ int ifindex;
+ unsigned iftype;
+} LinkInfo;
+
+static int link_info_compare(const void *a, const void *b) {
+ const LinkInfo *x = a, *y = b;
+
+ return x->ifindex - y->ifindex;
+}
+
+static int decode_and_sort_links(sd_rtnl_message *m, LinkInfo **ret) {
+ _cleanup_free_ LinkInfo *links = NULL;
+ size_t size = 0, c = 0;
+ sd_rtnl_message *i;
+ int r;
+
+ for (i = m; i; i = sd_rtnl_message_next(i)) {
+ const char *name;
+ unsigned iftype;
+ uint16_t type;
+ int ifindex;
+
+ r = sd_rtnl_message_get_type(i, &type);
+ if (r < 0)
+ return r;
+
+ if (type != RTM_NEWLINK)
+ continue;
+
+ r = sd_rtnl_message_link_get_ifindex(i, &ifindex);
+ if (r < 0)
+ return r;
+
+ r = sd_rtnl_message_read_string(i, IFLA_IFNAME, &name);
+ if (r < 0)
+ return r;
+
+ r = sd_rtnl_message_link_get_type(i, &iftype);
+ if (r < 0)
+ return r;
+
+ if (!GREEDY_REALLOC(links, size, c+1))
+ return -ENOMEM;
+
+ links[c].name = name;
+ links[c].ifindex = ifindex;
+ links[c].iftype = iftype;
+ c++;
+ }
+
+ qsort(links, c, sizeof(LinkInfo), link_info_compare);
+
+ *ret = links;
+ links = NULL;
+
+ return (int) c;
+}
+
+static void operational_state_to_color(const char *state, const char **on, const char **off) {
+ assert(on);
+ assert(off);
+
+ if (streq_ptr(state, "routable")) {
+ *on = ansi_highlight_green();
+ *off = ansi_highlight_off();
+ } else if (streq_ptr(state, "degraded")) {
+ *on = ansi_highlight_yellow();
+ *off = ansi_highlight_off();
+ } else
+ *on = *off = "";
+}
+
+static void setup_state_to_color(const char *state, const char **on, const char **off) {
+ assert(on);
+ assert(off);
+
+ if (streq_ptr(state, "configured")) {
+ *on = ansi_highlight_green();
+ *off = ansi_highlight_off();
+ } else if (streq_ptr(state, "configuring")) {
+ *on = ansi_highlight_yellow();
+ *off = ansi_highlight_off();
+ } else if (streq_ptr(state, "failed") || streq_ptr(state, "linger")) {
+ *on = ansi_highlight_red();
+ *off = ansi_highlight_off();
+ } else
+ *on = *off = "";
+}
+