static void print_counters(const struct nlattr *nest) { struct nlattr *tb[CTA_COUNTERS_MAX+1] = {}; mnl_attr_parse_nested(nest, parse_counters_cb, tb); if (tb[CTA_COUNTERS_PACKETS]) { printf("packets=%"PRIu64" ", be64toh(mnl_attr_get_u64(tb[CTA_COUNTERS_PACKETS]))); } if (tb[CTA_COUNTERS_BYTES]) { printf("bytes=%"PRIu64" ", be64toh(mnl_attr_get_u64(tb[CTA_COUNTERS_BYTES]))); } }
static int nfct_parse_counters(const struct nlattr *attr, struct nf_conntrack *ct, int dir) { struct nlattr *tb[CTA_COUNTERS_MAX+1] = {}; if (mnl_attr_parse_nested(attr, nfct_parse_counters_attr_cb, tb) < 0) return -1; if (tb[CTA_COUNTERS_PACKETS] || tb[CTA_COUNTERS32_PACKETS]) { if (tb[CTA_COUNTERS32_PACKETS]) { ct->counters[dir].packets = ntohl(mnl_attr_get_u32(tb[CTA_COUNTERS32_PACKETS])); } if (tb[CTA_COUNTERS_PACKETS]) { ct->counters[dir].packets = be64toh(mnl_attr_get_u64(tb[CTA_COUNTERS_PACKETS])); } switch(dir) { case __DIR_ORIG: set_bit(ATTR_ORIG_COUNTER_PACKETS, ct->head.set); break; case __DIR_REPL: set_bit(ATTR_REPL_COUNTER_PACKETS, ct->head.set); break; } } if (tb[CTA_COUNTERS_BYTES] || tb[CTA_COUNTERS32_BYTES]) { if (tb[CTA_COUNTERS32_BYTES]) { ct->counters[dir].bytes = ntohl(mnl_attr_get_u32(tb[CTA_COUNTERS32_BYTES])); } if (tb[CTA_COUNTERS_BYTES]) { ct->counters[dir].bytes = be64toh(mnl_attr_get_u64(tb[CTA_COUNTERS_BYTES])); } switch(dir) { case __DIR_ORIG: set_bit(ATTR_ORIG_COUNTER_BYTES, ct->head.set); break; case __DIR_REPL: set_bit(ATTR_REPL_COUNTER_BYTES, ct->head.set); break; } } return 0; }
static int res_print_summary(struct rd *rd, struct nlattr **tb) { struct nlattr *nla_table = tb[RDMA_NLDEV_ATTR_RES_SUMMARY]; struct nlattr *nla_entry; const char *name; uint64_t curr; int err; mnl_attr_for_each_nested(nla_entry, nla_table) { struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {}; char json_name[32]; err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line); if (err != MNL_CB_OK) return -EINVAL; if (!nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME] || !nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR]) { return -EINVAL; } name = mnl_attr_get_str(nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME]); curr = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR]); if (rd->json_output) { snprintf(json_name, 32, "%s", name); jsonw_lluint_field(rd->jw, json_name, curr); } else { pr_out("%s %"PRId64 " ", name, curr); } } return 0; }
static int link_mon_peer_list_cb(const struct nlmsghdr *nlh, void *data) { struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); struct nlattr *attrs[TIPC_NLA_MON_PEER_MAX + 1] = {}; struct nlattr *info[TIPC_NLA_MAX + 1] = {}; uint16_t member_cnt; uint32_t applied; uint32_t dom_gen; uint64_t up_map; char status[16]; char monitored[16]; mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); if (!info[TIPC_NLA_MON_PEER]) return MNL_CB_ERROR; open_json_object(NULL); mnl_attr_parse_nested(info[TIPC_NLA_MON_PEER], parse_attrs, attrs); (attrs[TIPC_NLA_MON_PEER_LOCAL] || attrs[TIPC_NLA_MON_PEER_HEAD]) ? strcpy(monitored, "direct") : strcpy(monitored, "indirect"); attrs[TIPC_NLA_MON_PEER_UP] ? strcpy(status, "up") : strcpy(status, "down"); dom_gen = attrs[TIPC_NLA_MON_PEER_DOMGEN] ? mnl_attr_get_u32(attrs[TIPC_NLA_MON_PEER_DOMGEN]) : 0; link_mon_print_peer_state(mnl_attr_get_u32(attrs[TIPC_NLA_MON_PEER_ADDR]), status, monitored, dom_gen); applied = mnl_attr_get_u32(attrs[TIPC_NLA_MON_PEER_APPLIED]); if (!applied) goto exit; up_map = mnl_attr_get_u64(attrs[TIPC_NLA_MON_PEER_UPMAP]); member_cnt = mnl_attr_get_payload_len(attrs[TIPC_NLA_MON_PEER_MEMBERS]); /* each tipc address occupies 4 bytes of payload, hence compensate it */ member_cnt /= sizeof(uint32_t); link_mon_print_applied(applied, up_map); link_mon_print_non_applied(applied, member_cnt, up_map, mnl_attr_get_payload(attrs[TIPC_NLA_MON_PEER_MEMBERS])); exit: print_string(PRINT_FP, NULL, "\n", ""); close_json_object(); return MNL_CB_OK; }
/** * nfacct_nlmsg_parse_payload - set accounting object attributes from message * \param nlh: netlink message that you want to use to add the payload. * \param nfacct: pointer to a accounting object * * This function returns -1 in case that some mandatory attributes are * missing. On sucess, it returns 0. */ int nfacct_nlmsg_parse_payload(const struct nlmsghdr *nlh, struct nfacct *nfacct) { struct nlattr *tb[NFACCT_MAX+1] = {}; struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh); mnl_attr_parse(nlh, sizeof(*nfg), nfacct_nlmsg_parse_attr_cb, tb); if (!tb[NFACCT_NAME] && !tb[NFACCT_PKTS] && !tb[NFACCT_BYTES]) return -1; nfacct_attr_set_str(nfacct, NFACCT_ATTR_NAME, mnl_attr_get_str(tb[NFACCT_NAME])); nfacct_attr_set_u64(nfacct, NFACCT_ATTR_PKTS, be64toh(mnl_attr_get_u64(tb[NFACCT_PKTS]))); nfacct_attr_set_u64(nfacct, NFACCT_ATTR_BYTES, be64toh(mnl_attr_get_u64(tb[NFACCT_BYTES]))); return 0; }
static int nfct_parse_timestamp(const struct nlattr *attr, struct nf_conntrack *ct) { struct nlattr *tb[CTA_TIMESTAMP_MAX+1] = {}; if (mnl_attr_parse_nested(attr, nfct_parse_timestamp_attr_cb, tb) < 0) return -1; if (tb[CTA_TIMESTAMP_START]) { ct->timestamp.start = be64toh(mnl_attr_get_u64(tb[CTA_TIMESTAMP_START])); set_bit(ATTR_TIMESTAMP_START, ct->head.set); } if (tb[CTA_TIMESTAMP_STOP]) { ct->timestamp.stop = be64toh(mnl_attr_get_u64(tb[CTA_TIMESTAMP_START])); set_bit(ATTR_TIMESTAMP_STOP, ct->head.set); } return 0; }
static int nfct_parse_protoinfo_dccp(const struct nlattr *attr, struct nf_conntrack *ct) { struct nlattr *tb[CTA_PROTOINFO_DCCP_MAX+1] = {}; if (mnl_attr_parse_nested(attr, nfct_parse_pinfo_dccp_attr_cb, tb) < 0) return -1; if (tb[CTA_PROTOINFO_DCCP_STATE]) { ct->protoinfo.dccp.state = mnl_attr_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]); set_bit(ATTR_DCCP_STATE, ct->head.set); } if (tb[CTA_PROTOINFO_DCCP_ROLE]) { ct->protoinfo.dccp.role = mnl_attr_get_u8(tb[CTA_PROTOINFO_DCCP_ROLE]); set_bit(ATTR_DCCP_ROLE, ct->head.set); } if (tb[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ]) { ct->protoinfo.dccp.handshake_seq = be64toh( mnl_attr_get_u64(tb[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ])); set_bit(ATTR_DCCP_HANDSHAKE_SEQ, ct->head.set); } return 0; }
static int res_pd_line(struct rd *rd, const char *name, int idx, struct nlattr **nla_line) { uint32_t local_dma_lkey = 0, unsafe_global_rkey = 0; char *comm = NULL; uint32_t ctxn = 0; uint32_t pid = 0; uint32_t pdn = 0; uint64_t users; if (!nla_line[RDMA_NLDEV_ATTR_RES_USECNT] || (!nla_line[RDMA_NLDEV_ATTR_RES_PID] && !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) { return MNL_CB_ERROR; } if (nla_line[RDMA_NLDEV_ATTR_RES_LOCAL_DMA_LKEY]) local_dma_lkey = mnl_attr_get_u32( nla_line[RDMA_NLDEV_ATTR_RES_LOCAL_DMA_LKEY]); users = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_USECNT]); if (rd_is_filtered_attr(rd, "users", users, nla_line[RDMA_NLDEV_ATTR_RES_USECNT])) goto out; if (nla_line[RDMA_NLDEV_ATTR_RES_UNSAFE_GLOBAL_RKEY]) unsafe_global_rkey = mnl_attr_get_u32( nla_line[RDMA_NLDEV_ATTR_RES_UNSAFE_GLOBAL_RKEY]); if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) { pid = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PID]); comm = get_task_name(pid); } if (rd_is_filtered_attr(rd, "pid", pid, nla_line[RDMA_NLDEV_ATTR_RES_PID])) goto out; if (nla_line[RDMA_NLDEV_ATTR_RES_CTXN]) ctxn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_CTXN]); if (rd_is_filtered_attr(rd, "ctxn", ctxn, nla_line[RDMA_NLDEV_ATTR_RES_CTXN])) goto out; if (nla_line[RDMA_NLDEV_ATTR_RES_PDN]) pdn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PDN]); if (rd_is_filtered_attr(rd, "pdn", pdn, nla_line[RDMA_NLDEV_ATTR_RES_PDN])) goto out; if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]) /* discard const from mnl_attr_get_str */ comm = (char *)mnl_attr_get_str( nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]); if (rd->json_output) jsonw_start_array(rd->jw); print_dev(rd, idx, name); res_print_uint(rd, "pdn", pdn, nla_line[RDMA_NLDEV_ATTR_RES_PDN]); print_key(rd, "local_dma_lkey", local_dma_lkey, nla_line[RDMA_NLDEV_ATTR_RES_LOCAL_DMA_LKEY]); res_print_uint(rd, "users", users, nla_line[RDMA_NLDEV_ATTR_RES_USECNT]); print_key(rd, "unsafe_global_rkey", unsafe_global_rkey, nla_line[RDMA_NLDEV_ATTR_RES_UNSAFE_GLOBAL_RKEY]); res_print_uint(rd, "ctxn", ctxn, nla_line[RDMA_NLDEV_ATTR_RES_CTXN]); res_print_uint(rd, "pid", pid, nla_line[RDMA_NLDEV_ATTR_RES_PID]); print_comm(rd, comm, nla_line); print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]); newline(rd); out: if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) free(comm); return MNL_CB_OK; }
static int res_pd_parse_cb(const struct nlmsghdr *nlh, void *data) { struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {}; struct nlattr *nla_table, *nla_entry; struct rd *rd = data; const char *name; uint32_t idx; mnl_attr_parse(nlh, 0, rd_attr_cb, tb); if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME] || !tb[RDMA_NLDEV_ATTR_RES_PD]) return MNL_CB_ERROR; name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]); idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); nla_table = tb[RDMA_NLDEV_ATTR_RES_PD]; mnl_attr_for_each_nested(nla_entry, nla_table) { uint32_t local_dma_lkey = 0, unsafe_global_rkey = 0; struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {}; char *comm = NULL; uint32_t pid = 0; uint64_t users; int err; err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line); if (err != MNL_CB_OK) return MNL_CB_ERROR; if (!nla_line[RDMA_NLDEV_ATTR_RES_USECNT] || (!nla_line[RDMA_NLDEV_ATTR_RES_PID] && !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) { return MNL_CB_ERROR; } if (nla_line[RDMA_NLDEV_ATTR_RES_LOCAL_DMA_LKEY]) local_dma_lkey = mnl_attr_get_u32( nla_line[RDMA_NLDEV_ATTR_RES_LOCAL_DMA_LKEY]); users = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_USECNT]); if (rd_check_is_filtered(rd, "users", users)) continue; if (nla_line[RDMA_NLDEV_ATTR_RES_UNSAFE_GLOBAL_RKEY]) unsafe_global_rkey = mnl_attr_get_u32( nla_line[RDMA_NLDEV_ATTR_RES_UNSAFE_GLOBAL_RKEY]); if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) { pid = mnl_attr_get_u32( nla_line[RDMA_NLDEV_ATTR_RES_PID]); comm = get_task_name(pid); } if (rd_check_is_filtered(rd, "pid", pid)) continue; if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]) /* discard const from mnl_attr_get_str */ comm = (char *)mnl_attr_get_str( nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]); if (rd->json_output) jsonw_start_array(rd->jw); print_dev(rd, idx, name); if (nla_line[RDMA_NLDEV_ATTR_RES_LOCAL_DMA_LKEY]) print_key(rd, "local_dma_lkey", local_dma_lkey); print_users(rd, users); if (nla_line[RDMA_NLDEV_ATTR_RES_UNSAFE_GLOBAL_RKEY]) print_key(rd, "unsafe_global_rkey", unsafe_global_rkey); print_pid(rd, pid); print_comm(rd, comm, nla_line); if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) free(comm); print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]); newline(rd); }
static int res_mr_parse_cb(const struct nlmsghdr *nlh, void *data) { struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {}; struct nlattr *nla_table, *nla_entry; struct rd *rd = data; const char *name; uint32_t idx; mnl_attr_parse(nlh, 0, rd_attr_cb, tb); if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME] || !tb[RDMA_NLDEV_ATTR_RES_MR]) return MNL_CB_ERROR; name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]); idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); nla_table = tb[RDMA_NLDEV_ATTR_RES_MR]; mnl_attr_for_each_nested(nla_entry, nla_table) { struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {}; uint32_t rkey = 0, lkey = 0; uint64_t iova = 0, mrlen; char *comm = NULL; uint32_t pid = 0; int err; err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line); if (err != MNL_CB_OK) return MNL_CB_ERROR; if (!nla_line[RDMA_NLDEV_ATTR_RES_MRLEN] || (!nla_line[RDMA_NLDEV_ATTR_RES_PID] && !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) { return MNL_CB_ERROR; } if (nla_line[RDMA_NLDEV_ATTR_RES_RKEY]) rkey = mnl_attr_get_u32( nla_line[RDMA_NLDEV_ATTR_RES_RKEY]); if (nla_line[RDMA_NLDEV_ATTR_RES_LKEY]) lkey = mnl_attr_get_u32( nla_line[RDMA_NLDEV_ATTR_RES_LKEY]); if (nla_line[RDMA_NLDEV_ATTR_RES_IOVA]) iova = mnl_attr_get_u64( nla_line[RDMA_NLDEV_ATTR_RES_IOVA]); mrlen = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_MRLEN]); if (rd_check_is_filtered(rd, "mrlen", mrlen)) continue; if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) { pid = mnl_attr_get_u32( nla_line[RDMA_NLDEV_ATTR_RES_PID]); comm = get_task_name(pid); } if (rd_check_is_filtered(rd, "pid", pid)) { free(comm); continue; } if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]) /* discard const from mnl_attr_get_str */ comm = (char *)mnl_attr_get_str( nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]); if (rd->json_output) jsonw_start_array(rd->jw); print_dev(rd, idx, name); if (nla_line[RDMA_NLDEV_ATTR_RES_RKEY]) print_key(rd, "rkey", rkey); if (nla_line[RDMA_NLDEV_ATTR_RES_LKEY]) print_key(rd, "lkey", lkey); if (nla_line[RDMA_NLDEV_ATTR_RES_IOVA]) print_iova(rd, iova); print_mrlen(rd, mrlen); print_pid(rd, pid); print_comm(rd, comm, nla_line); if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) free(comm); print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]); newline(rd); } return MNL_CB_OK; }
static int res_cq_parse_cb(const struct nlmsghdr *nlh, void *data) { struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {}; struct nlattr *nla_table, *nla_entry; struct rd *rd = data; const char *name; uint32_t idx; mnl_attr_parse(nlh, 0, rd_attr_cb, tb); if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME] || !tb[RDMA_NLDEV_ATTR_RES_CQ]) return MNL_CB_ERROR; name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]); idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); nla_table = tb[RDMA_NLDEV_ATTR_RES_CQ]; mnl_attr_for_each_nested(nla_entry, nla_table) { struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {}; char *comm = NULL; uint32_t pid = 0; uint8_t poll_ctx = 0; uint64_t users; uint32_t cqe; int err; err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line); if (err != MNL_CB_OK) return MNL_CB_ERROR; if (!nla_line[RDMA_NLDEV_ATTR_RES_CQE] || !nla_line[RDMA_NLDEV_ATTR_RES_USECNT] || (!nla_line[RDMA_NLDEV_ATTR_RES_PID] && !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) { return MNL_CB_ERROR; } cqe = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_CQE]); users = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_USECNT]); if (rd_check_is_filtered(rd, "users", users)) continue; if (nla_line[RDMA_NLDEV_ATTR_RES_POLL_CTX]) { poll_ctx = mnl_attr_get_u8( nla_line[RDMA_NLDEV_ATTR_RES_POLL_CTX]); if (rd_check_is_string_filtered(rd, "poll-ctx", poll_ctx_to_str(poll_ctx))) continue; } if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) { pid = mnl_attr_get_u32( nla_line[RDMA_NLDEV_ATTR_RES_PID]); comm = get_task_name(pid); } if (rd_check_is_filtered(rd, "pid", pid)) { free(comm); continue; } if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]) /* discard const from mnl_attr_get_str */ comm = (char *)mnl_attr_get_str( nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]); if (rd->json_output) jsonw_start_array(rd->jw); print_dev(rd, idx, name); print_cqe(rd, cqe); print_users(rd, users); if (nla_line[RDMA_NLDEV_ATTR_RES_POLL_CTX]) print_poll_ctx(rd, poll_ctx); print_pid(rd, pid); print_comm(rd, comm, nla_line); if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) free(comm); print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]); newline(rd); } return MNL_CB_OK; }
/* returns negative on error * or returns remainded nlmsghdr length */ static int _unpack_nlmsg(const struct nlmsghdr *nlh, const char *format, va_list ap) { struct nlattr *attr = mnl_nlmsg_get_payload(nlh); int remains = (int)mnl_nlmsg_get_payload_len(nlh); size_t len; uint16_t atype, alen; void *p; while (*format != '\0' ) { if (!mnl_attr_ok(attr, remains)) { errno = EOVERFLOW; return -1; } remains -= MY_NLATTR_HDRLEN; atype = mnl_attr_get_type(attr); alen = mnl_attr_get_payload_len(attr); switch (*format) { case 'B': /* byte */ if (atype != MNL_TYPE_U8 || alen != sizeof(uint8_t)) { errno =EINVAL; return -1; } *(va_arg(ap, uint8_t *)) = mnl_attr_get_u8(attr); break; case 'H': /* 2byte */ if (atype != MNL_TYPE_U16 || alen != sizeof(uint16_t)) { errno = EINVAL; return -1; } *(va_arg(ap, uint16_t *)) = mnl_attr_get_u16(attr); break; case 'I': /* 4byte */ if (atype != MNL_TYPE_U32 || alen != sizeof(uint32_t)) { errno = EINVAL; return -1; } *(va_arg(ap, uint32_t *)) = mnl_attr_get_u32(attr); break; case 'K': /* 8byte */ if (atype != MNL_TYPE_U64 || alen != sizeof(uint64_t)) { errno = EINVAL; return -1; } *(va_arg(ap, uint64_t *)) = mnl_attr_get_u64(attr); break; case 'p': /* pointer */ if (atype != MNL_TYPE_BINARY || alen != sizeof(void *)) { errno = EINVAL; return -1; } *(va_arg(ap, void **)) = *((void **)mnl_attr_get_payload(attr)); break; case 'z': /* null string */ if (atype != MNL_TYPE_NUL_STRING) { errno = EINVAL; return -1; } p = va_arg(ap, void *); if (*(format + 1) == '#') { format++; len = va_arg(ap, size_t); if (alen > len) { errno = EINVAL; return -1; } } strncpy(p, mnl_attr_get_payload(attr), alen); break; case 'y': /* bytes with size */ format++; if (*format != '#') { errno = EINVAL; return -1; } p = va_arg(ap, void *); len = va_arg(ap, size_t); if (alen > len) return -EINVAL; memcpy(p, mnl_attr_get_payload(attr), alen); break; default: errno =EINVAL; return -1; } remains -= MY_ATTR_ALIGN(alen); format++; attr = mnl_attr_next(attr); } if (remains) { errno = EMSGSIZE; nurs_log(NURS_NOTICE, "unpack remains: %d\n", remains); } return remains; }