Improve IP address list representation in libxo output.

Extract decision-making about special-case printing of certain
jail parameters into a function.

Refactor emitting of IPv4 and IPv6 address lists into a function.

Resulting user-facing changes:

XO_VERSION is bumped to 2.

In verbose mode (-v), IPv4 and IPv6-Addresses are now properly emitted
as separate lists.
This only affects the output in encoding styles, i.e. xml and json.

{                                    {
  "__version": "1",                    "__version": "2",
  "jail-information": {                "jail-information": {
    "jail": [                            "jail": [
      {                                    {
        "jid": 166,                          "jid": 166,
        "hostname": "foo.com",               "hostname": "foo.com",
        "path": "/var/jail/foo",             "path": "/var/jail/foo",
        "name": "foo",                       "name": "foo",
        "state": "ACTIVE",                   "state": "ACTIVE",
        "cpusetid": 2,                       "cpusetid": 2,
        "ipv4_addrs": [                      "ipv4_addrs": [
          "10.1.1.1",                          "10.1.1.1",
          "10.1.1.2",                          "10.1.1.2",
          "10.1.1.3",              |           "10.1.1.3"
                                   >         ],
                                   >         "ipv6_addrs": [
          "fe80::1000:1",                      "fe80::1000:1",
          "fe80::1000:2"                       "fe80::1000:2"
        ]                                    ]
      }                                    }
    ]                                    ]
  }                                    }
}                                    }

In -n mode, ip4.addr and ip6.addr are formatted in the encoding styles'
native list types, e.g. instead of comma-separated lists, JSON arrays
are printed.

jls -n all --libxo json
 ...
 "ip4.addr": [
    "10.1.1.1",
    "10.1.1.2",
    "10.1.1.3"
  ],
  "ip4.saddrsel": true,
  "ip6.addr": [
    "fe80::1000:1",
    "fe80::1000:2"
  ],
  ...

jls -n all --libxo xml
  ...
  <ip4.addr>10.1.1.1</ip4.addr>
  <ip4.addr>10.1.1.2</ip4.addr>
  <ip4.addr>10.1.1.3</ip4.addr>
  <ip4.saddrsel>true</ip4.saddrsel>
  <ip6.addr>fe80::1000:1</ip6.addr>
  <ip6.addr>fe80::1000:2</ip6.addr>
  ...

PR:		215008
Submitted by:	Christian Schwarz <me@cschwarz.com>
Differential Revision:	https://reviews.freebsd.org/D8766
This commit is contained in:
Jamie Gritton 2016-12-24 23:51:27 +00:00
parent e0625c4c1f
commit 8fd1ba2a5e

View File

@ -51,7 +51,7 @@ __FBSDID("$FreeBSD$");
#define JP_USER 0x01000000
#define JP_OPT 0x02000000
#define JLS_XO_VERSION "1"
#define JLS_XO_VERSION "2"
#define PRINT_DEFAULT 0x01
#define PRINT_HEADER 0x02
@ -77,7 +77,10 @@ static int sort_param(const void *a, const void *b);
static char *noname(const char *name);
static char *nononame(const char *name);
static int print_jail(int pflags, int jflags);
static int special_print(int pflags, struct jailparam *param);
static void quoted_print(int pflags, char *name, char *value);
static void emit_ip_addr_list(int af_family, const char *list_name,
struct jailparam *param);
int
main(int argc, char **argv)
@ -379,8 +382,7 @@ print_jail(int pflags, int jflags)
{
char *nname, *xo_nname;
char **param_values;
int i, ai, jid, count, n, spc;
char ipbuf[INET6_ADDRSTRLEN];
int i, jid, n, spc;
jid = jailparam_get(params, nparams, jflags);
if (jid < 0)
@ -401,29 +403,13 @@ print_jail(int pflags, int jflags)
n = 6;
#ifdef INET
if (ip4_ok && !strcmp(params[n].jp_name, "ip4.addr")) {
count = params[n].jp_valuelen / sizeof(struct in_addr);
for (ai = 0; ai < count; ai++)
if (inet_ntop(AF_INET,
&((struct in_addr *)params[n].jp_value)[ai],
ipbuf, sizeof(ipbuf)) == NULL)
xo_err(1, "inet_ntop");
else {
xo_emit("{P: }{l:ipv4_addrs}{P:\n}", ipbuf);
}
emit_ip_addr_list(AF_INET, "ipv4_addrs", params + n);
n++;
}
#endif
#ifdef INET6
if (ip6_ok && !strcmp(params[n].jp_name, "ip6.addr")) {
count = params[n].jp_valuelen / sizeof(struct in6_addr);
for (ai = 0; ai < count; ai++)
if (inet_ntop(AF_INET6,
&((struct in6_addr *)
params[n].jp_value)[ai],
ipbuf, sizeof(ipbuf)) == NULL)
xo_err(1, "inet_ntop");
else
xo_emit("{P: }{l:ipv6_addrs}{P:\n}", ipbuf);
emit_ip_addr_list(AF_INET6, "ipv6_addrs", params + n);
n++;
}
#endif
@ -499,14 +485,8 @@ print_jail(int pflags, int jflags)
}
xo_emit("{d:%s}=", params[i].jp_name);
}
if (params[i].jp_valuelen == 0) {
if (pflags & PRINT_QUOTED)
xo_emit("{P:\"\"}");
else if (!(pflags & PRINT_NAMEVAL))
xo_emit("{P:-}");
} else {
if (!special_print(pflags, params + i))
quoted_print(pflags, params[i].jp_name, param_values[i]);
}
}
xo_emit("{P:\n}");
for (i = 0; i < nparams; i++)
@ -553,3 +533,70 @@ quoted_print(int pflags, char *name, char *value)
if (qc && pflags & PRINT_QUOTED)
xo_emit("{P:/%c}", qc);
}
static int
special_print(int pflags, struct jailparam *param)
{
int ip_as_list;
switch (xo_get_style(NULL)) {
case XO_STYLE_JSON:
case XO_STYLE_XML:
ip_as_list = 1;
break;
default:
ip_as_list = 0;
}
if (!ip_as_list && param->jp_valuelen == 0) {
if (pflags & PRINT_QUOTED)
xo_emit("{P:\"\"}");
else if (!(pflags & PRINT_NAMEVAL))
xo_emit("{P:-}");
} else if (ip_as_list && !strcmp(param->jp_name, "ip4.addr")) {
emit_ip_addr_list(AF_INET, param->jp_name, param);
} else if (ip_as_list && !strcmp(param->jp_name, "ip6.addr")) {
emit_ip_addr_list(AF_INET6, param->jp_name, param);
} else {
return 0;
}
return 1;
}
static void
emit_ip_addr_list(int af_family, const char *list_name, struct jailparam *param)
{
char ipbuf[INET6_ADDRSTRLEN];
size_t addr_len;
const char *emit_str;
int ai, count;
switch (af_family) {
case AF_INET:
addr_len = sizeof(struct in_addr);
emit_str = "{P: }{ql:ipv4_addr}{P:\n}";
break;
case AF_INET6:
addr_len = sizeof(struct in6_addr);
emit_str = "{P: }{ql:ipv6_addr}{P:\n}";
break;
default:
xo_err(1, "unsupported af_family");
return;
}
count = param->jp_valuelen / addr_len;
xo_open_list(list_name);
for (ai = 0; ai < count; ai++) {
if (inet_ntop(af_family,
((uint8_t *)param->jp_value) + addr_len * ai,
ipbuf, sizeof(ipbuf)) == NULL) {
xo_err(1, "inet_ntop");
} else {
xo_emit(emit_str, ipbuf);
}
}
xo_close_list(list_name);
}