lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame^] | 1 | #include <netlink/cli/utils.h> |
| 2 | #include <linux/taskstats.h> |
| 3 | |
| 4 | static struct nla_policy attr_policy[TASKSTATS_TYPE_MAX+1] = { |
| 5 | [TASKSTATS_TYPE_PID] = { .type = NLA_U32 }, |
| 6 | [TASKSTATS_TYPE_TGID] = { .type = NLA_U32 }, |
| 7 | [TASKSTATS_TYPE_STATS] = { .minlen = sizeof(struct taskstats) }, |
| 8 | [TASKSTATS_TYPE_AGGR_PID] = { .type = NLA_NESTED }, |
| 9 | [TASKSTATS_TYPE_AGGR_TGID] = { .type = NLA_NESTED }, |
| 10 | }; |
| 11 | |
| 12 | |
| 13 | static int parse_cmd_new(struct nl_cache_ops *unused, struct genl_cmd *cmd, |
| 14 | struct genl_info *info, void *arg) |
| 15 | { |
| 16 | struct nlattr *attrs[TASKSTATS_TYPE_MAX+1]; |
| 17 | struct nlattr *nested; |
| 18 | int err; |
| 19 | |
| 20 | if (info->attrs[TASKSTATS_TYPE_AGGR_PID]) |
| 21 | nested = info->attrs[TASKSTATS_TYPE_AGGR_PID]; |
| 22 | else if (info->attrs[TASKSTATS_TYPE_AGGR_TGID]) |
| 23 | nested = info->attrs[TASKSTATS_TYPE_AGGR_TGID]; |
| 24 | else { |
| 25 | fprintf(stderr, "Invalid taskstats message: Unable to find " |
| 26 | "nested attribute/\n"); |
| 27 | return NL_SKIP; |
| 28 | } |
| 29 | |
| 30 | err = nla_parse_nested(attrs, TASKSTATS_TYPE_MAX, nested, attr_policy); |
| 31 | if (err < 0) { |
| 32 | nl_perror(err, "Error while parsing generic netlink message"); |
| 33 | return err; |
| 34 | } |
| 35 | |
| 36 | |
| 37 | if (attrs[TASKSTATS_TYPE_STATS]) { |
| 38 | struct taskstats *stats = nla_data(attrs[TASKSTATS_TYPE_STATS]); |
| 39 | |
| 40 | printf("%s pid %u uid %u gid %u parent %u\n", |
| 41 | stats->ac_comm, stats->ac_pid, stats->ac_uid, |
| 42 | stats->ac_gid, stats->ac_ppid); |
| 43 | } |
| 44 | |
| 45 | return 0; |
| 46 | } |
| 47 | |
| 48 | static int parse_cb(struct nl_msg *msg, void *arg) |
| 49 | { |
| 50 | return genl_handle_msg(msg, NULL); |
| 51 | } |
| 52 | |
| 53 | static struct genl_cmd cmds[] = { |
| 54 | { |
| 55 | .c_id = TASKSTATS_CMD_NEW, |
| 56 | .c_name = "taskstats_new()", |
| 57 | .c_maxattr = TASKSTATS_TYPE_MAX, |
| 58 | .c_attr_policy = attr_policy, |
| 59 | .c_msg_parser = &parse_cmd_new, |
| 60 | }, |
| 61 | }; |
| 62 | |
| 63 | #define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0])) |
| 64 | |
| 65 | static struct genl_ops ops = { |
| 66 | .o_name = TASKSTATS_GENL_NAME, |
| 67 | .o_cmds = cmds, |
| 68 | .o_ncmds = ARRAY_SIZE(cmds), |
| 69 | }; |
| 70 | |
| 71 | int main(int argc, char *argv[]) |
| 72 | { |
| 73 | struct nl_sock *sock; |
| 74 | struct nl_msg *msg; |
| 75 | void *hdr; |
| 76 | int err; |
| 77 | |
| 78 | sock = nl_cli_alloc_socket(); |
| 79 | nl_cli_connect(sock, NETLINK_GENERIC); |
| 80 | |
| 81 | if ((err = genl_register_family(&ops)) < 0) |
| 82 | nl_cli_fatal(err, "Unable to register Generic Netlink family"); |
| 83 | |
| 84 | if ((err = genl_ops_resolve(sock, &ops)) < 0) |
| 85 | nl_cli_fatal(err, "Unable to resolve family name"); |
| 86 | |
| 87 | if (genl_ctrl_resolve(sock, "nlctrl") != GENL_ID_CTRL) |
| 88 | nl_cli_fatal(NLE_INVAL, "Resolving of \"nlctrl\" failed"); |
| 89 | |
| 90 | msg = nlmsg_alloc(); |
| 91 | if (msg == NULL) |
| 92 | nl_cli_fatal(NLE_NOMEM, "Unable to allocate netlink message"); |
| 93 | |
| 94 | hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, ops.o_id, |
| 95 | 0, 0, TASKSTATS_CMD_GET, TASKSTATS_GENL_VERSION); |
| 96 | if (hdr == NULL) |
| 97 | nl_cli_fatal(ENOMEM, "Unable to write genl header"); |
| 98 | |
| 99 | if ((err = nla_put_u32(msg, TASKSTATS_CMD_ATTR_PID, 1)) < 0) |
| 100 | nl_cli_fatal(err, "Unable to add attribute: %s", nl_geterror(err)); |
| 101 | |
| 102 | if ((err = nl_send_auto_complete(sock, msg)) < 0) |
| 103 | nl_cli_fatal(err, "Unable to send message: %s", nl_geterror(err)); |
| 104 | |
| 105 | nlmsg_free(msg); |
| 106 | |
| 107 | if ((err = nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, |
| 108 | parse_cb, NULL)) < 0) |
| 109 | nl_cli_fatal(err, "Unable to modify valid message callback"); |
| 110 | |
| 111 | if ((err = nl_recvmsgs_default(sock)) < 0) |
| 112 | nl_cli_fatal(err, "Unable to receive message: %s", nl_geterror(err)); |
| 113 | |
| 114 | nl_close(sock); |
| 115 | nl_socket_free(sock); |
| 116 | |
| 117 | return 0; |
| 118 | } |