#define NLM_F_ACK_TLVS 0x200 /* extended ACK TVLs were included */
#endif
-#ifndef NLA_NUL_STRING
-# define NLA_NUL_STRING 10
+#ifndef NLA_S8
+# define NLA_S8 12
#endif
#ifndef NLA_S16
#define NLA_PUT_S64(msg, attrtype, value) \
NLA_PUT_TYPE(msg, int64_t, attrtype, value)
-#endif /* ! HAVE_NLA_GET_S64 */
+#ifndef NLA_NUL_STRING
+#define NLA_NUL_STRING 10
+#endif
+
+enum nla_types {
+ LNET_NLA_UNSPEC = NLA_UNSPEC,
+ LNET_NLA_U8 = NLA_U8,
+ LNET_NLA_U16 = NLA_U16,
+ LNET_NLA_U32 = NLA_U32,
+ LNET_NLA_U64 = NLA_U64,
+ LNET_NLA_STRING = NLA_STRING,
+ LNET_NLA_FLAG = NLA_FLAG,
+ LNET_NLA_MSECS = NLA_MSECS,
+ LNET_NLA_NESTED = NLA_NESTED,
+ LNET_NLA_NESTED_COMPAT = NLA_NESTED + 1,
+ LNET_NLA_NUL_STRING = NLA_NUL_STRING,
+ LNET_NLA_BINARY = NLA_NUL_STRING + 1,
+ LNET_NLA_S8 = NLA_S8,
+ LNET_NLA_S16 = NLA_S16,
+ LNET_NLA_S32 = NLA_S32,
+ LNET_NLA_S64 = NLA_S64,
+ __LNET_NLA_TYPE_MAX,
+};
+
+#define LNET_NLA_TYPE_MAX (__LNET_NLA_TYPE_MAX - 1)
+
+static uint16_t nla_attr_minlen[LNET_NLA_TYPE_MAX+1] = {
+ [NLA_U8] = sizeof(uint8_t),
+ [NLA_U16] = sizeof(uint16_t),
+ [NLA_U32] = sizeof(uint32_t),
+ [NLA_U64] = sizeof(uint64_t),
+ [NLA_STRING] = 1,
+ [NLA_FLAG] = 0,
+};
+
+static int lnet_validate_nla(const struct nlattr *nla, int maxtype,
+ const struct nla_policy *policy)
+{
+ const struct nla_policy *pt;
+ unsigned int minlen = 0;
+ int type = nla_type(nla);
+
+ if (type < 0 || type > maxtype)
+ return 0;
+
+ pt = &policy[type];
+
+ if (pt->type > NLA_TYPE_MAX)
+ return -NLE_INVAL;
+
+ if (pt->minlen)
+ minlen = pt->minlen;
+ else if (pt->type != NLA_UNSPEC)
+ minlen = nla_attr_minlen[pt->type];
+
+ if (nla_len(nla) < minlen)
+ return -NLE_RANGE;
+
+ if (pt->maxlen && nla_len(nla) > pt->maxlen)
+ return -NLE_RANGE;
+
+ if (pt->type == NLA_STRING) {
+ const char *data = nla_data(nla);
+
+ if (data[nla_len(nla) - 1] != '\0')
+ return -NLE_INVAL;
+ }
+
+ return 0;
+}
+
+int lnet_nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head,
+ int len, const struct nla_policy *policy)
+{
+ struct nlattr *nla;
+ int rem, err;
+
+ memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
+
+ nla_for_each_attr(nla, head, len, rem) {
+ int type = nla_type(nla);
+
+ if (type > maxtype)
+ continue;
+
+ if (policy) {
+ err = lnet_validate_nla(nla, maxtype, policy);
+ if (err < 0)
+ return err;
+ }
+
+ tb[type] = nla;
+ }
+
+ return 0;
+}
+
+int lnet_genlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
+ int maxtype, const struct nla_policy *policy)
+{
+ struct genlmsghdr *ghdr;
+
+ if (!genlmsg_valid_hdr(nlh, hdrlen))
+ return -NLE_MSG_TOOSHORT;
+
+ ghdr = nlmsg_data(nlh);
+ return lnet_nla_parse(tb, maxtype, genlmsg_attrdata(ghdr, hdrlen),
+ genlmsg_attrlen(ghdr, hdrlen), policy);
+}
+
+#else /* !HAVE_NLA_GET_S64 */
+
+#define lnet_genlmsg_parse genlmsg_parse
+
+#endif /* HAVE_NLA_GET_S64 */
/**
* Set NETLINK_BROADCAST_ERROR flags on socket to report ENOBUFS errors.
*
* Return 0 on success or a Netlink error code.
*/
-int nl_socket_enable_broadcast_error(struct nl_sock *sk)
+static int nl_socket_enable_broadcast_error(struct nl_sock *sk)
{
const int state = 1; /* enable errors */
int err;
*
* @return 0 on success or a negative error code
*/
-int nl_socket_set_ext_ack(struct nl_sock *sk, int state)
+static int nl_socket_set_ext_ack(struct nl_sock *sk, int state)
{
int err;
*
* Return 0 on success or a negative error code.
*/
-int lustre_netlink_register(struct nl_sock *sk, bool async_events)
+static int lustre_netlink_register(struct nl_sock *sk, bool async_events)
{
int rc;
*
* Return 0 on success or a negative error code.
*/
-int lustre_netlink_add_group(struct nl_sock *nl, const char *family,
- const char *group)
+static int lustre_netlink_add_group(struct nl_sock *nl, const char *family,
+ const char *group)
{
int group_id;
return NL_OK;
}
+/* We translate Netlink nested list into either a YAML mappping or sequence.
+ * This generates the start of such a YAML block.
+ */
+static int yaml_nested_header(struct yaml_netlink_input *data,
+ int *size, unsigned int *indent,
+ int mapping, struct ln_key_props *keys)
+{
+ int len = 0;
+
+ if (keys->lkp_key_format & LNKF_FLOW) {
+ char brace = '{';
+
+ if (keys->lkp_key_format & LNKF_SEQUENCE)
+ brace = '[';
+
+ len = snprintf(data->buffer, *size, "%*s%s: %c ", data->indent,
+ "", keys->lkp_value, brace);
+ } else {
+ int count = mapping & LNKF_SEQUENCE ? 0 : data->indent;
+
+ if (keys->lkp_key_format & LNKF_MAPPING)
+ *indent += 2;
+ if (keys->lkp_key_format & LNKF_SEQUENCE)
+ *indent += 2;
+
+ len = snprintf(data->buffer, *size, "%*s%s:\n", count, "",
+ keys->lkp_value);
+ }
+
+ return len;
+}
+
static struct yaml_nl_node *get_next_child(struct yaml_nl_node *node,
unsigned int idx)
{
struct ln_key_props *keys = node->keys.lkl_list;
int mapping = parent->lkp_key_format;
int child_idx = 0, len = 0, i;
+ bool first = true;
for (i = 1; i < node->keys.lkl_maxattr; i++) {
struct nlattr *attr;
if (!attr && !keys[i].lkp_value)
continue;
- if (keys[i].lkp_data_type != NLA_NUL_STRING &&
- keys[i].lkp_data_type != NLA_NESTED) {
+ /* This function is called for each Netlink nested list.
+ * Each nested list is treated as a YAML block. It is here
+ * we handle data for the YAML block. How that data is seen
+ * for YAML is based on the parents mapping and the type of
+ * data value sent.
+ *
+ * The cases are:
+ *
+ * the value type is NLA_NUL_STRING which is interepted as
+ * key:\n
+ *
+ * Also NLA_NUL_STRING is used to update a single key value.
+ *
+ * the key has no lkp_value and we do receive a 'value'
+ * that is not a nested list in the Netlink packet. This is
+ * treated as a plain scalar.
+ *
+ * we have a key lkp_value and the parent mapping is
+ * LNKF_MAPPING then we have a key : value pair. During
+ * our loop the key normally doesn't change.
+ *
+ * This data belongs to a YAML block which can be of
+ * different kinds (FLOW, SEQUENCE, MAPPING). We determine
+ * the type and adjust the first line of output for the
+ * YAML results if needed. Most of the time the creation
+ * of the nested header is done in the NLA_NESTED case
+ * switch below which happens before this function is
+ * called. Specific handling is done here.
+ *
+ * The common case handled here is for building of the
+ * mapping key : value pair. Another case is that we
+ * are at the start of a SEQUENCE block. If this is the
+ * case we add '-' to the output and clear the flag
+ * LNKF_SEQUENCE to prevent multiple instanstances of
+ * '-'. Only one '-' per SEQUENCE block. We need to
+ * manually add '-' also in the case of were our nested
+ * block first PROCESSED attr instance is another nested
+ * block. For example:
+ * local NI(s):
+ * - interfaces:
+ * 0: ib0
+ */
+ if ((first && (mapping & LNKF_SEQUENCE) &&
+ keys[i].lkp_data_type == NLA_NESTED) ||
+ (keys[i].lkp_data_type != NLA_NUL_STRING &&
+ keys[i].lkp_data_type != NLA_NESTED)) {
if (!attr && keys[i].lkp_data_type != NLA_FLAG)
continue;
+ /* Mark this as the start of a SEQUENCE block */
if (!(mapping & LNKF_FLOW)) {
unsigned int indent = data->indent ?
data->indent : 2;
memset(data->buffer, ' ', indent);
if (mapping & LNKF_SEQUENCE) {
((char *)data->buffer)[indent - 2] = '-';
- if (mapping & LNKF_MAPPING)
+ if (keys[i].lkp_data_type != NLA_NESTED &&
+ mapping & LNKF_MAPPING)
mapping &= ~LNKF_SEQUENCE;
}
data->buffer += indent;
*size -= indent;
}
- if (mapping & LNKF_MAPPING) {
+ /* Start of the build of the key : value pair.
+ * Very common case.
+ */
+ if (keys[i].lkp_data_type != NLA_NESTED &&
+ mapping & LNKF_MAPPING) {
len = snprintf(data->buffer, *size, "%s: ",
keys[i].lkp_value);
if (len < 0)
case NLA_NESTED: {
struct yaml_nl_node *next = get_next_child(node,
child_idx++);
- int num = next->keys.lkl_maxattr;
+ int num = next ? next->keys.lkl_maxattr : 0;
struct nla_policy nest_policy[num];
struct yaml_nl_node *old;
struct nlattr *cnt_attr;
+ unsigned int indent = 0;
+ bool start = true;
int rem, j;
- if (!attr)
+ if (!attr || !next)
continue;
memset(nest_policy, 0, sizeof(struct nla_policy) * num);
for (j = 1; j < num; j++)
nest_policy[j].type = next->keys.lkl_list[j].lkp_data_type;
+ /* We might have a empty list but by YAML standards
+ * we still need to display the header.
+ */
+ if (!nla_len(attr)) {
+ len = yaml_nested_header(data, size, &indent,
+ first ? mapping : 0,
+ &keys[i]);
+ if (len < 0)
+ goto unwind;
+ data->buffer += len;
+ *size -= len;
+ len = 0;
+ }
+
old = data->cur;
data->cur = next;
nla_for_each_nested(cnt_attr, attr, rem) {
struct nlattr *nest_info[num];
- uint16_t indent = 0;
if (nla_parse_nested(nest_info, num, cnt_attr,
nest_policy))
break;
- if (keys[i].lkp_key_format & LNKF_FLOW) {
- char brace = '{';
-
- if (keys[i].lkp_key_format &
- LNKF_SEQUENCE)
- brace = '[';
-
- len = snprintf(data->buffer, *size,
- "%*s%s: %c ",
- data->indent, "",
- keys[i].lkp_value,
- brace);
- } else {
- if (keys[i].lkp_key_format &
- LNKF_MAPPING)
- indent += 2;
- if (keys[i].lkp_key_format &
- LNKF_SEQUENCE)
- indent += 2;
-
- if (keys[i].lkp_value) {
- len = snprintf(data->buffer,
- *size,
- "%*s%s:\n",
- data->indent, "",
- keys[i].lkp_value);
- } else {
- len = 0;
- }
- }
+ /* Create the nested header only once at start */
+ if (!start)
+ goto skip_nested_header;
+ start = false;
+
+ /* Update the header's first key */
+ if (next->keys.lkl_list[1].lkp_data_type == NLA_NUL_STRING &&
+ !keys[i].lkp_value)
+ keys[i].lkp_value = nla_strdup(nest_info[1]);
+
+ len = yaml_nested_header(data, size, &indent,
+ first ? mapping : 0,
+ &keys[i]);
if (len < 0)
goto unwind;
data->buffer += len;
*size -= len;
len = 0;
-
+skip_nested_header:
data->indent += indent;
yaml_parse_value_list(data, size, nest_info,
&keys[i]);
data->indent -= indent;
+ }
- if (keys[i].lkp_key_format & LNKF_FLOW) {
- char *tmp = (char *)data->buffer - 2;
- char *brace = " }\n";
+ /* nested bookend header */
+ if (keys[i].lkp_key_format & LNKF_FLOW) {
+ char *tmp = (char *)data->buffer - 2;
+ char *brace = " }\n";
- if (keys[i].lkp_key_format &
- LNKF_SEQUENCE)
- brace = " ]\n";
+ if (keys[i].lkp_key_format &
+ LNKF_SEQUENCE)
+ brace = " ]\n";
- memcpy(tmp, brace, strlen(brace));
- data->buffer++;
- *size -= 1;
- }
+ memcpy(tmp, brace, strlen(brace));
+ data->buffer++;
+ *size -= 1;
}
data->cur = old;
+
+ /* This is for the special case of the first attr of
+ * a nested list is another nested list. We had to
+ * insert a '-' but that is only done once so clear
+ * the mapping of LNKF_SEQUENCE.
+ */
+ if (first && attr) {
+ if (mapping & LNKF_MAPPING)
+ mapping &= ~LNKF_SEQUENCE;
+ first = false;
+ }
break;
}
+ /* Handle the key:\n YAML case or updating an individual key */
case NLA_NUL_STRING:
if (i == 1) {
if (data->cur != data->root)
}
break;
+ /* The below is used for a plain scalar or to complete the
+ * key : value pair.
+ */
case NLA_STRING:
len = snprintf(data->buffer, *size, "%s",
nla_get_string(attr));
}
}
+static bool cleanup_children(struct yaml_nl_node *parent)
+{
+ struct yaml_nl_node *child;
+
+ if (nl_list_empty(&parent->children)) {
+ struct ln_key_props *keys = parent->keys.lkl_list;
+ int i;
+
+ for (i = 1; i < parent->keys.lkl_maxattr; i++)
+ if (keys[i].lkp_value)
+ free(keys[i].lkp_value);
+ nl_list_del(&parent->list);
+ return true;
+ }
+
+ while ((child = get_next_child(parent, 0)) != NULL) {
+ if (cleanup_children(child))
+ free(child);
+ }
+
+ return false;
+}
+
/* This is the CB_VALID callback for the Netlink library that we
* have hooked into. Any successful Netlink message is passed to
* this function which handles both the incoming key tables and
struct genlmsghdr *ghdr = genlmsg_hdr(nlh);
struct nlattr *attrs[LN_SCALAR_MAX + 1];
- if (genlmsg_parse(nlh, 0, attrs, LN_SCALAR_MAX,
- scalar_attr_policy))
+ if (lnet_genlmsg_parse(nlh, 0, attrs, LN_SCALAR_MAX,
+ scalar_attr_policy))
return NL_SKIP;
+ /* If root already exists this means we are updating the
+ * key table. Free old key table.
+ */
+ if (data->root && (nlh->nlmsg_flags & NLM_F_REPLACE)) {
+ cleanup_children(data->root);
+ free(data->root);
+ data->root = NULL;
+ }
+
if (attrs[LN_SCALAR_ATTR_LIST]) {
int rc = yaml_parse_key_list(data, NULL,
attrs[LN_SCALAR_ATTR_LIST]);
for (i = 1; i < maxtype; i++)
policy[i].type = data->cur->keys.lkl_list[i].lkp_data_type;
- if (genlmsg_parse(nlh, 0, attrs, maxtype, policy))
+ if (lnet_genlmsg_parse(nlh, 0, attrs, maxtype, policy))
return NL_SKIP;
size = data->parser->raw_buffer.end -
return NL_STOP;
}
-static bool cleanup_children(struct yaml_nl_node *parent)
-{
- struct yaml_nl_node *child;
-
- if (nl_list_empty(&parent->children)) {
- struct ln_key_props *keys = parent->keys.lkl_list;
- int i;
-
- for (i = 1; i < parent->keys.lkl_maxattr; i++)
- if (keys[i].lkp_value)
- free(keys[i].lkp_value);
- nl_list_del(&parent->list);
- return true;
- }
-
- while ((child = get_next_child(parent, 0)) != NULL) {
- if (cleanup_children(child))
- free(child);
- }
-
- return false;
-}
-
/* This is the libnl callback for when the last Netlink packet
* is finished being parsed or its called right away in case
* the Linux kernel reports back an error from the Netlink layer.
return tmp - str;
}
-#define LNKF_END 8
+#define LNKF_BLOCK 8
static enum lnet_nl_key_format yaml_format_type(yaml_emitter_t *emitter,
char *line,
new_indent = indent_level(line);
if (new_indent < indent) {
*offset = indent - emitter->best_indent;
- return LNKF_END;
+ return LNKF_BLOCK;
}
if (strncmp(line + new_indent, "- ", 2) == 0) {
memset(line + new_indent, ' ', 2);
- new_indent += 2;
+ /* Eat white spaces physical YAML config files have */
+ new_indent += strspn(line + new_indent, " ");
+ fmt |= LNKF_SEQUENCE;
}
/* hdr: [ a : 1, b : 2, c : 3 ] */
if (indent != new_indent) {
*offset = new_indent;
- fmt |= LNKF_SEQUENCE;
+ fmt |= LNKF_BLOCK;
}
return fmt;
sep = tmp;
}
if (sep)
- *sep++ = '\0';
+ *sep = '\0';
if (strspn(line, "-0123456789") == strlen(line)) {
num = strtoll(line, NULL, 0);
}
if (fmt & LNKF_MAPPING && sep) {
+ char *end = strchr(sep, '\n');
+ int len;
+
+ /* restore ':' */
+ *sep = ':';
+ sep++;
while (isspace(*sep))
++sep;
- if (!strlen(sep))
+ len = end ? end - sep : strlen(sep);
+ if (len <= 0)
goto nla_put_failure;
-
- if (strspn(sep, "-0123456789") == strlen(sep)) {
+ sep[len] = '\0';
+
+ if (strcasecmp(sep, "yes") == 0 ||
+ strcasecmp(sep, "true") == 0 ||
+ strcasecmp(sep, "on") == 0 ||
+ strcasecmp(sep, "y") == 0) {
+ NLA_PUT_S64(msg, LN_SCALAR_ATTR_INT_VALUE, 1);
+ } else if (strcasecmp(sep, "no") == 0 ||
+ strcasecmp(sep, "false") == 0 ||
+ strcasecmp(sep, "off") == 0 ||
+ strcasecmp(sep, "n") == 0) {
+ NLA_PUT_S64(msg, LN_SCALAR_ATTR_INT_VALUE, 0);
+ } else if (strspn(sep, "-0123456789") == strlen(sep)) {
num = strtoll(sep, NULL, 0);
NLA_PUT_S64(msg, LN_SCALAR_ATTR_INT_VALUE, num);
} else {
NLA_PUT_STRING(msg, LN_SCALAR_ATTR_VALUE, sep);
}
+ sep[len] = '\n';
}
nla_put_failure:
return rc;
char **entry, unsigned int *indent,
enum lnet_nl_key_format fmt)
{
- bool nested = fmt & LNKF_SEQUENCE;
- struct nlattr *list = NULL;
- char *line;
+ struct nlattr *mapping = NULL, *seq = NULL;
+ char *line, *tmp;
int rc = 0;
/* Not needed for FLOW only case */
- if (nested) {
- list = nla_nest_start(msg, LN_SCALAR_ATTR_LIST);
- if (!list) {
+ if (fmt & LNKF_SEQUENCE) {
+ seq = nla_nest_start(msg, LN_SCALAR_ATTR_LIST);
+ if (!seq) {
yaml_emitter_set_writer_error(out->emitter,
"Emmitter netlink list creation failed");
rc = -EINVAL;
}
}
- if (fmt != LNKF_FLOW) {
- rc = yaml_fill_scalar_data(msg, fmt, *hdr + *indent);
- if (rc < 0)
- goto nla_put_failure;
- }
-
if (fmt & LNKF_FLOW) {
- char *tmp = strchr(*hdr, '{'), *split = NULL;
+ struct nlattr *list = NULL;
bool format = false;
+ char *split = NULL;
+
+ if (fmt != LNKF_FLOW) {
+ rc = yaml_fill_scalar_data(msg, fmt, *hdr + *indent);
+ if (rc < 0)
+ goto nla_put_failure;
+ }
+ tmp = strchr(*hdr, '{');
if (!tmp) {
tmp = strchr(*hdr, '[');
if (!tmp) {
nla_nest_end(msg, list);
} else {
+next_mapping:
+ if (fmt & LNKF_BLOCK && strchr(*hdr, ':')) {
+ mapping = nla_nest_start(msg, LN_SCALAR_ATTR_LIST);
+ if (!mapping) {
+ yaml_emitter_set_writer_error(out->emitter,
+ "Emmitter netlink list creation failed");
+ rc = -EINVAL;
+ goto nla_put_failure;
+ }
+ }
+
+ rc = yaml_fill_scalar_data(msg, fmt, *hdr + *indent);
+ if (rc < 0)
+ goto nla_put_failure;
+
do {
line = strsep(entry, "\n");
have_next_line:
break;
fmt = yaml_format_type(out->emitter, line, indent);
- if (fmt == LNKF_END)
+ if (fmt == LNKF_BLOCK)
break;
- if (fmt & ~LNKF_MAPPING) { /* Filter out mappings */
+ /* sequences of simple scalars, general mappings, and
+ * plain scalars are not nested structures in a
+ * netlink packet.
+ */
+ if (fmt == LNKF_SEQUENCE || fmt == LNKF_MAPPING || fmt == 0) {
+ rc = yaml_fill_scalar_data(msg, fmt,
+ line + *indent);
+ if (rc < 0)
+ goto nla_put_failure;
+ } else {
rc = yaml_create_nested_list(out, msg, &line,
entry, indent,
fmt);
if (rc < 0)
goto nla_put_failure;
+
+ /* if the original line that called
+ * yaml_create_nested_list above was an
+ * sequence and the next line is also
+ * then break to treat it as a mapping / scalar
+ * instead to avoid over nesting.
+ */
+ if (line && seq) {
+ fmt = yaml_format_type(out->emitter, line, indent);
+ if ((fmt & LNKF_SEQUENCE) || (fmt & LNKF_BLOCK))
+ break;
+ }
+
if (line)
goto have_next_line;
- } else {
- rc = yaml_fill_scalar_data(msg, fmt,
- line + *indent);
- if (rc < 0)
- goto nla_put_failure;
}
} while (strcmp(*entry, ""));
- if (line && line[*indent] == '-') {
- line[*indent] = ' ';
- *indent += 2;
+ if (mapping) {
+ nla_nest_end(msg, mapping);
+ mapping = NULL;
+ }
+ }
+
+ /* test if next line is sequence at the same level. */
+ if (line && (line[0] != '\0') && (fmt & LNKF_BLOCK)) {
+ int old_indent = indent_level(*hdr);
+
+ fmt = yaml_format_type(out->emitter, line, indent);
+ if (fmt != LNKF_BLOCK && old_indent == *indent) {
+ /* If we have a normal mapping set then treate
+ * it as a collection of scalars i.e don't create
+ * another nested level. For scalar:\n and plain
+ * scalar case we send it to next_mapping to
+ * create another nested level.
+ */
+ tmp = strchr(line, ':');
+ if (tmp) {
+ fmt = LNKF_BLOCK;
+ if (strstr(line, ": "))
+ fmt |= LNKF_MAPPING;
+ if (strstr(line, "- "))
+ fmt |= LNKF_SEQUENCE;
+ *hdr = line;
+ goto next_mapping;
+ }
+
goto have_next_line;
}
- if (*entry && !strlen(*entry))
+ }
+
+ if (seq) {
+ if (*indent >= 2)
+ *indent -= 2;
+ nla_nest_end(msg, seq);
+ seq = NULL;
+ if (*entry && !strlen(*entry) && fmt != LNKF_BLOCK)
line = NULL;
- /* strsep in the above loop moves entry to a value pass the
- * end of the nested list. So to avoid losing this value we
- * replace hdr with line.
- */
- *hdr = line;
}
- if (nested)
- nla_nest_end(msg, list);
+ /* strsep in the above loop moves entry to a value pass the end of the
+ * nested list. So to avoid losing this value we replace hdr with line.
+ */
+ *hdr = line;
nla_put_failure:
return rc;
}
}
fmt = yaml_format_type(out->emitter, line, &indent);
- if (fmt & ~LNKF_MAPPING) {
+ if (fmt) {
rc = yaml_create_nested_list(out, msg, &line,
&entry, &indent,
fmt);