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