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