162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* getdelays.c
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Utility to get per-pid and per-tgid delay accounting statistics
562306a36Sopenharmony_ci * Also illustrates usage of the taskstats interface
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (C) Shailabh Nagar, IBM Corp. 2005
862306a36Sopenharmony_ci * Copyright (C) Balbir Singh, IBM Corp. 2006
962306a36Sopenharmony_ci * Copyright (c) Jay Lan, SGI. 2006
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * Compile with
1262306a36Sopenharmony_ci *	gcc -I/usr/src/linux/include getdelays.c -o getdelays
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <stdio.h>
1662306a36Sopenharmony_ci#include <stdlib.h>
1762306a36Sopenharmony_ci#include <errno.h>
1862306a36Sopenharmony_ci#include <unistd.h>
1962306a36Sopenharmony_ci#include <poll.h>
2062306a36Sopenharmony_ci#include <string.h>
2162306a36Sopenharmony_ci#include <fcntl.h>
2262306a36Sopenharmony_ci#include <sys/types.h>
2362306a36Sopenharmony_ci#include <sys/stat.h>
2462306a36Sopenharmony_ci#include <sys/socket.h>
2562306a36Sopenharmony_ci#include <sys/wait.h>
2662306a36Sopenharmony_ci#include <signal.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include <linux/genetlink.h>
2962306a36Sopenharmony_ci#include <linux/taskstats.h>
3062306a36Sopenharmony_ci#include <linux/cgroupstats.h>
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/*
3362306a36Sopenharmony_ci * Generic macros for dealing with netlink sockets. Might be duplicated
3462306a36Sopenharmony_ci * elsewhere. It is recommended that commercial grade applications use
3562306a36Sopenharmony_ci * libnl or libnetlink and use the interfaces provided by the library
3662306a36Sopenharmony_ci */
3762306a36Sopenharmony_ci#define GENLMSG_DATA(glh)	((void *)(NLMSG_DATA(glh) + GENL_HDRLEN))
3862306a36Sopenharmony_ci#define GENLMSG_PAYLOAD(glh)	(NLMSG_PAYLOAD(glh, 0) - GENL_HDRLEN)
3962306a36Sopenharmony_ci#define NLA_DATA(na)		((void *)((char*)(na) + NLA_HDRLEN))
4062306a36Sopenharmony_ci#define NLA_PAYLOAD(len)	(len - NLA_HDRLEN)
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#define err(code, fmt, arg...)			\
4362306a36Sopenharmony_ci	do {					\
4462306a36Sopenharmony_ci		fprintf(stderr, fmt, ##arg);	\
4562306a36Sopenharmony_ci		exit(code);			\
4662306a36Sopenharmony_ci	} while (0)
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ciint rcvbufsz;
4962306a36Sopenharmony_cichar name[100];
5062306a36Sopenharmony_ciint dbg;
5162306a36Sopenharmony_ciint print_delays;
5262306a36Sopenharmony_ciint print_io_accounting;
5362306a36Sopenharmony_ciint print_task_context_switch_counts;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#define PRINTF(fmt, arg...) {			\
5662306a36Sopenharmony_ci	    if (dbg) {				\
5762306a36Sopenharmony_ci		printf(fmt, ##arg);		\
5862306a36Sopenharmony_ci	    }					\
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci/* Maximum size of response requested or message sent */
6262306a36Sopenharmony_ci#define MAX_MSG_SIZE	1024
6362306a36Sopenharmony_ci/* Maximum number of cpus expected to be specified in a cpumask */
6462306a36Sopenharmony_ci#define MAX_CPUS	32
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistruct msgtemplate {
6762306a36Sopenharmony_ci	struct nlmsghdr n;
6862306a36Sopenharmony_ci	struct genlmsghdr g;
6962306a36Sopenharmony_ci	char buf[MAX_MSG_SIZE];
7062306a36Sopenharmony_ci};
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cichar cpumask[100+6*MAX_CPUS];
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic void usage(void)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	fprintf(stderr, "getdelays [-dilv] [-w logfile] [-r bufsize] "
7762306a36Sopenharmony_ci			"[-m cpumask] [-t tgid] [-p pid]\n");
7862306a36Sopenharmony_ci	fprintf(stderr, "  -d: print delayacct stats\n");
7962306a36Sopenharmony_ci	fprintf(stderr, "  -i: print IO accounting (works only with -p)\n");
8062306a36Sopenharmony_ci	fprintf(stderr, "  -l: listen forever\n");
8162306a36Sopenharmony_ci	fprintf(stderr, "  -v: debug on\n");
8262306a36Sopenharmony_ci	fprintf(stderr, "  -C: container path\n");
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci/*
8662306a36Sopenharmony_ci * Create a raw netlink socket and bind
8762306a36Sopenharmony_ci */
8862306a36Sopenharmony_cistatic int create_nl_socket(int protocol)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	int fd;
9162306a36Sopenharmony_ci	struct sockaddr_nl local;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	fd = socket(AF_NETLINK, SOCK_RAW, protocol);
9462306a36Sopenharmony_ci	if (fd < 0)
9562306a36Sopenharmony_ci		return -1;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	if (rcvbufsz)
9862306a36Sopenharmony_ci		if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF,
9962306a36Sopenharmony_ci				&rcvbufsz, sizeof(rcvbufsz)) < 0) {
10062306a36Sopenharmony_ci			fprintf(stderr, "Unable to set socket rcv buf size to %d\n",
10162306a36Sopenharmony_ci				rcvbufsz);
10262306a36Sopenharmony_ci			goto error;
10362306a36Sopenharmony_ci		}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	memset(&local, 0, sizeof(local));
10662306a36Sopenharmony_ci	local.nl_family = AF_NETLINK;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	if (bind(fd, (struct sockaddr *) &local, sizeof(local)) < 0)
10962306a36Sopenharmony_ci		goto error;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	return fd;
11262306a36Sopenharmony_cierror:
11362306a36Sopenharmony_ci	close(fd);
11462306a36Sopenharmony_ci	return -1;
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic int send_cmd(int sd, __u16 nlmsg_type, __u32 nlmsg_pid,
11962306a36Sopenharmony_ci	     __u8 genl_cmd, __u16 nla_type,
12062306a36Sopenharmony_ci	     void *nla_data, int nla_len)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	struct nlattr *na;
12362306a36Sopenharmony_ci	struct sockaddr_nl nladdr;
12462306a36Sopenharmony_ci	int r, buflen;
12562306a36Sopenharmony_ci	char *buf;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	struct msgtemplate msg;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	msg.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
13062306a36Sopenharmony_ci	msg.n.nlmsg_type = nlmsg_type;
13162306a36Sopenharmony_ci	msg.n.nlmsg_flags = NLM_F_REQUEST;
13262306a36Sopenharmony_ci	msg.n.nlmsg_seq = 0;
13362306a36Sopenharmony_ci	msg.n.nlmsg_pid = nlmsg_pid;
13462306a36Sopenharmony_ci	msg.g.cmd = genl_cmd;
13562306a36Sopenharmony_ci	msg.g.version = 0x1;
13662306a36Sopenharmony_ci	na = (struct nlattr *) GENLMSG_DATA(&msg);
13762306a36Sopenharmony_ci	na->nla_type = nla_type;
13862306a36Sopenharmony_ci	na->nla_len = nla_len + NLA_HDRLEN;
13962306a36Sopenharmony_ci	memcpy(NLA_DATA(na), nla_data, nla_len);
14062306a36Sopenharmony_ci	msg.n.nlmsg_len += NLMSG_ALIGN(na->nla_len);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	buf = (char *) &msg;
14362306a36Sopenharmony_ci	buflen = msg.n.nlmsg_len ;
14462306a36Sopenharmony_ci	memset(&nladdr, 0, sizeof(nladdr));
14562306a36Sopenharmony_ci	nladdr.nl_family = AF_NETLINK;
14662306a36Sopenharmony_ci	while ((r = sendto(sd, buf, buflen, 0, (struct sockaddr *) &nladdr,
14762306a36Sopenharmony_ci			   sizeof(nladdr))) < buflen) {
14862306a36Sopenharmony_ci		if (r > 0) {
14962306a36Sopenharmony_ci			buf += r;
15062306a36Sopenharmony_ci			buflen -= r;
15162306a36Sopenharmony_ci		} else if (errno != EAGAIN)
15262306a36Sopenharmony_ci			return -1;
15362306a36Sopenharmony_ci	}
15462306a36Sopenharmony_ci	return 0;
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci/*
15962306a36Sopenharmony_ci * Probe the controller in genetlink to find the family id
16062306a36Sopenharmony_ci * for the TASKSTATS family
16162306a36Sopenharmony_ci */
16262306a36Sopenharmony_cistatic int get_family_id(int sd)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	struct {
16562306a36Sopenharmony_ci		struct nlmsghdr n;
16662306a36Sopenharmony_ci		struct genlmsghdr g;
16762306a36Sopenharmony_ci		char buf[256];
16862306a36Sopenharmony_ci	} ans;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	int id = 0, rc;
17162306a36Sopenharmony_ci	struct nlattr *na;
17262306a36Sopenharmony_ci	int rep_len;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	strcpy(name, TASKSTATS_GENL_NAME);
17562306a36Sopenharmony_ci	rc = send_cmd(sd, GENL_ID_CTRL, getpid(), CTRL_CMD_GETFAMILY,
17662306a36Sopenharmony_ci			CTRL_ATTR_FAMILY_NAME, (void *)name,
17762306a36Sopenharmony_ci			strlen(TASKSTATS_GENL_NAME)+1);
17862306a36Sopenharmony_ci	if (rc < 0)
17962306a36Sopenharmony_ci		return 0;	/* sendto() failure? */
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	rep_len = recv(sd, &ans, sizeof(ans), 0);
18262306a36Sopenharmony_ci	if (ans.n.nlmsg_type == NLMSG_ERROR ||
18362306a36Sopenharmony_ci	    (rep_len < 0) || !NLMSG_OK((&ans.n), rep_len))
18462306a36Sopenharmony_ci		return 0;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	na = (struct nlattr *) GENLMSG_DATA(&ans);
18762306a36Sopenharmony_ci	na = (struct nlattr *) ((char *) na + NLA_ALIGN(na->nla_len));
18862306a36Sopenharmony_ci	if (na->nla_type == CTRL_ATTR_FAMILY_ID) {
18962306a36Sopenharmony_ci		id = *(__u16 *) NLA_DATA(na);
19062306a36Sopenharmony_ci	}
19162306a36Sopenharmony_ci	return id;
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci#define average_ms(t, c) (t / 1000000ULL / (c ? c : 1))
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_cistatic void print_delayacct(struct taskstats *t)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	printf("\n\nCPU   %15s%15s%15s%15s%15s\n"
19962306a36Sopenharmony_ci	       "      %15llu%15llu%15llu%15llu%15.3fms\n"
20062306a36Sopenharmony_ci	       "IO    %15s%15s%15s\n"
20162306a36Sopenharmony_ci	       "      %15llu%15llu%15.3fms\n"
20262306a36Sopenharmony_ci	       "SWAP  %15s%15s%15s\n"
20362306a36Sopenharmony_ci	       "      %15llu%15llu%15.3fms\n"
20462306a36Sopenharmony_ci	       "RECLAIM  %12s%15s%15s\n"
20562306a36Sopenharmony_ci	       "      %15llu%15llu%15.3fms\n"
20662306a36Sopenharmony_ci	       "THRASHING%12s%15s%15s\n"
20762306a36Sopenharmony_ci	       "      %15llu%15llu%15.3fms\n"
20862306a36Sopenharmony_ci	       "COMPACT  %12s%15s%15s\n"
20962306a36Sopenharmony_ci	       "      %15llu%15llu%15.3fms\n"
21062306a36Sopenharmony_ci	       "WPCOPY   %12s%15s%15s\n"
21162306a36Sopenharmony_ci	       "      %15llu%15llu%15.3fms\n"
21262306a36Sopenharmony_ci	       "IRQ   %15s%15s%15s\n"
21362306a36Sopenharmony_ci	       "      %15llu%15llu%15.3fms\n",
21462306a36Sopenharmony_ci	       "count", "real total", "virtual total",
21562306a36Sopenharmony_ci	       "delay total", "delay average",
21662306a36Sopenharmony_ci	       (unsigned long long)t->cpu_count,
21762306a36Sopenharmony_ci	       (unsigned long long)t->cpu_run_real_total,
21862306a36Sopenharmony_ci	       (unsigned long long)t->cpu_run_virtual_total,
21962306a36Sopenharmony_ci	       (unsigned long long)t->cpu_delay_total,
22062306a36Sopenharmony_ci	       average_ms((double)t->cpu_delay_total, t->cpu_count),
22162306a36Sopenharmony_ci	       "count", "delay total", "delay average",
22262306a36Sopenharmony_ci	       (unsigned long long)t->blkio_count,
22362306a36Sopenharmony_ci	       (unsigned long long)t->blkio_delay_total,
22462306a36Sopenharmony_ci	       average_ms((double)t->blkio_delay_total, t->blkio_count),
22562306a36Sopenharmony_ci	       "count", "delay total", "delay average",
22662306a36Sopenharmony_ci	       (unsigned long long)t->swapin_count,
22762306a36Sopenharmony_ci	       (unsigned long long)t->swapin_delay_total,
22862306a36Sopenharmony_ci	       average_ms((double)t->swapin_delay_total, t->swapin_count),
22962306a36Sopenharmony_ci	       "count", "delay total", "delay average",
23062306a36Sopenharmony_ci	       (unsigned long long)t->freepages_count,
23162306a36Sopenharmony_ci	       (unsigned long long)t->freepages_delay_total,
23262306a36Sopenharmony_ci	       average_ms((double)t->freepages_delay_total, t->freepages_count),
23362306a36Sopenharmony_ci	       "count", "delay total", "delay average",
23462306a36Sopenharmony_ci	       (unsigned long long)t->thrashing_count,
23562306a36Sopenharmony_ci	       (unsigned long long)t->thrashing_delay_total,
23662306a36Sopenharmony_ci	       average_ms((double)t->thrashing_delay_total, t->thrashing_count),
23762306a36Sopenharmony_ci	       "count", "delay total", "delay average",
23862306a36Sopenharmony_ci	       (unsigned long long)t->compact_count,
23962306a36Sopenharmony_ci	       (unsigned long long)t->compact_delay_total,
24062306a36Sopenharmony_ci	       average_ms((double)t->compact_delay_total, t->compact_count),
24162306a36Sopenharmony_ci	       "count", "delay total", "delay average",
24262306a36Sopenharmony_ci	       (unsigned long long)t->wpcopy_count,
24362306a36Sopenharmony_ci	       (unsigned long long)t->wpcopy_delay_total,
24462306a36Sopenharmony_ci	       average_ms((double)t->wpcopy_delay_total, t->wpcopy_count),
24562306a36Sopenharmony_ci	       "count", "delay total", "delay average",
24662306a36Sopenharmony_ci	       (unsigned long long)t->irq_count,
24762306a36Sopenharmony_ci	       (unsigned long long)t->irq_delay_total,
24862306a36Sopenharmony_ci	       average_ms((double)t->irq_delay_total, t->irq_count));
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic void task_context_switch_counts(struct taskstats *t)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	printf("\n\nTask   %15s%15s\n"
25462306a36Sopenharmony_ci	       "       %15llu%15llu\n",
25562306a36Sopenharmony_ci	       "voluntary", "nonvoluntary",
25662306a36Sopenharmony_ci	       (unsigned long long)t->nvcsw, (unsigned long long)t->nivcsw);
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistatic void print_cgroupstats(struct cgroupstats *c)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	printf("sleeping %llu, blocked %llu, running %llu, stopped %llu, "
26262306a36Sopenharmony_ci		"uninterruptible %llu\n", (unsigned long long)c->nr_sleeping,
26362306a36Sopenharmony_ci		(unsigned long long)c->nr_io_wait,
26462306a36Sopenharmony_ci		(unsigned long long)c->nr_running,
26562306a36Sopenharmony_ci		(unsigned long long)c->nr_stopped,
26662306a36Sopenharmony_ci		(unsigned long long)c->nr_uninterruptible);
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_cistatic void print_ioacct(struct taskstats *t)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	printf("%s: read=%llu, write=%llu, cancelled_write=%llu\n",
27362306a36Sopenharmony_ci		t->ac_comm,
27462306a36Sopenharmony_ci		(unsigned long long)t->read_bytes,
27562306a36Sopenharmony_ci		(unsigned long long)t->write_bytes,
27662306a36Sopenharmony_ci		(unsigned long long)t->cancelled_write_bytes);
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ciint main(int argc, char *argv[])
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	int c, rc, rep_len, aggr_len, len2;
28262306a36Sopenharmony_ci	int cmd_type = TASKSTATS_CMD_ATTR_UNSPEC;
28362306a36Sopenharmony_ci	__u16 id;
28462306a36Sopenharmony_ci	__u32 mypid;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	struct nlattr *na;
28762306a36Sopenharmony_ci	int nl_sd = -1;
28862306a36Sopenharmony_ci	int len = 0;
28962306a36Sopenharmony_ci	pid_t tid = 0;
29062306a36Sopenharmony_ci	pid_t rtid = 0;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	int fd = 0;
29362306a36Sopenharmony_ci	int write_file = 0;
29462306a36Sopenharmony_ci	int maskset = 0;
29562306a36Sopenharmony_ci	char *logfile = NULL;
29662306a36Sopenharmony_ci	int loop = 0;
29762306a36Sopenharmony_ci	int containerset = 0;
29862306a36Sopenharmony_ci	char *containerpath = NULL;
29962306a36Sopenharmony_ci	int cfd = 0;
30062306a36Sopenharmony_ci	int forking = 0;
30162306a36Sopenharmony_ci	sigset_t sigset;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	struct msgtemplate msg;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	while (!forking) {
30662306a36Sopenharmony_ci		c = getopt(argc, argv, "qdiw:r:m:t:p:vlC:c:");
30762306a36Sopenharmony_ci		if (c < 0)
30862306a36Sopenharmony_ci			break;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci		switch (c) {
31162306a36Sopenharmony_ci		case 'd':
31262306a36Sopenharmony_ci			printf("print delayacct stats ON\n");
31362306a36Sopenharmony_ci			print_delays = 1;
31462306a36Sopenharmony_ci			break;
31562306a36Sopenharmony_ci		case 'i':
31662306a36Sopenharmony_ci			printf("printing IO accounting\n");
31762306a36Sopenharmony_ci			print_io_accounting = 1;
31862306a36Sopenharmony_ci			break;
31962306a36Sopenharmony_ci		case 'q':
32062306a36Sopenharmony_ci			printf("printing task/process context switch rates\n");
32162306a36Sopenharmony_ci			print_task_context_switch_counts = 1;
32262306a36Sopenharmony_ci			break;
32362306a36Sopenharmony_ci		case 'C':
32462306a36Sopenharmony_ci			containerset = 1;
32562306a36Sopenharmony_ci			containerpath = optarg;
32662306a36Sopenharmony_ci			break;
32762306a36Sopenharmony_ci		case 'w':
32862306a36Sopenharmony_ci			logfile = strdup(optarg);
32962306a36Sopenharmony_ci			printf("write to file %s\n", logfile);
33062306a36Sopenharmony_ci			write_file = 1;
33162306a36Sopenharmony_ci			break;
33262306a36Sopenharmony_ci		case 'r':
33362306a36Sopenharmony_ci			rcvbufsz = atoi(optarg);
33462306a36Sopenharmony_ci			printf("receive buf size %d\n", rcvbufsz);
33562306a36Sopenharmony_ci			if (rcvbufsz < 0)
33662306a36Sopenharmony_ci				err(1, "Invalid rcv buf size\n");
33762306a36Sopenharmony_ci			break;
33862306a36Sopenharmony_ci		case 'm':
33962306a36Sopenharmony_ci			strncpy(cpumask, optarg, sizeof(cpumask));
34062306a36Sopenharmony_ci			cpumask[sizeof(cpumask) - 1] = '\0';
34162306a36Sopenharmony_ci			maskset = 1;
34262306a36Sopenharmony_ci			printf("cpumask %s maskset %d\n", cpumask, maskset);
34362306a36Sopenharmony_ci			break;
34462306a36Sopenharmony_ci		case 't':
34562306a36Sopenharmony_ci			tid = atoi(optarg);
34662306a36Sopenharmony_ci			if (!tid)
34762306a36Sopenharmony_ci				err(1, "Invalid tgid\n");
34862306a36Sopenharmony_ci			cmd_type = TASKSTATS_CMD_ATTR_TGID;
34962306a36Sopenharmony_ci			break;
35062306a36Sopenharmony_ci		case 'p':
35162306a36Sopenharmony_ci			tid = atoi(optarg);
35262306a36Sopenharmony_ci			if (!tid)
35362306a36Sopenharmony_ci				err(1, "Invalid pid\n");
35462306a36Sopenharmony_ci			cmd_type = TASKSTATS_CMD_ATTR_PID;
35562306a36Sopenharmony_ci			break;
35662306a36Sopenharmony_ci		case 'c':
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci			/* Block SIGCHLD for sigwait() later */
35962306a36Sopenharmony_ci			if (sigemptyset(&sigset) == -1)
36062306a36Sopenharmony_ci				err(1, "Failed to empty sigset");
36162306a36Sopenharmony_ci			if (sigaddset(&sigset, SIGCHLD))
36262306a36Sopenharmony_ci				err(1, "Failed to set sigchld in sigset");
36362306a36Sopenharmony_ci			sigprocmask(SIG_BLOCK, &sigset, NULL);
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci			/* fork/exec a child */
36662306a36Sopenharmony_ci			tid = fork();
36762306a36Sopenharmony_ci			if (tid < 0)
36862306a36Sopenharmony_ci				err(1, "Fork failed\n");
36962306a36Sopenharmony_ci			if (tid == 0)
37062306a36Sopenharmony_ci				if (execvp(argv[optind - 1],
37162306a36Sopenharmony_ci				    &argv[optind - 1]) < 0)
37262306a36Sopenharmony_ci					exit(-1);
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci			/* Set the command type and avoid further processing */
37562306a36Sopenharmony_ci			cmd_type = TASKSTATS_CMD_ATTR_PID;
37662306a36Sopenharmony_ci			forking = 1;
37762306a36Sopenharmony_ci			break;
37862306a36Sopenharmony_ci		case 'v':
37962306a36Sopenharmony_ci			printf("debug on\n");
38062306a36Sopenharmony_ci			dbg = 1;
38162306a36Sopenharmony_ci			break;
38262306a36Sopenharmony_ci		case 'l':
38362306a36Sopenharmony_ci			printf("listen forever\n");
38462306a36Sopenharmony_ci			loop = 1;
38562306a36Sopenharmony_ci			break;
38662306a36Sopenharmony_ci		default:
38762306a36Sopenharmony_ci			usage();
38862306a36Sopenharmony_ci			exit(-1);
38962306a36Sopenharmony_ci		}
39062306a36Sopenharmony_ci	}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	if (write_file) {
39362306a36Sopenharmony_ci		fd = open(logfile, O_WRONLY | O_CREAT | O_TRUNC,
39462306a36Sopenharmony_ci			  S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
39562306a36Sopenharmony_ci		if (fd == -1) {
39662306a36Sopenharmony_ci			perror("Cannot open output file\n");
39762306a36Sopenharmony_ci			exit(1);
39862306a36Sopenharmony_ci		}
39962306a36Sopenharmony_ci	}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	nl_sd = create_nl_socket(NETLINK_GENERIC);
40262306a36Sopenharmony_ci	if (nl_sd < 0)
40362306a36Sopenharmony_ci		err(1, "error creating Netlink socket\n");
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	mypid = getpid();
40762306a36Sopenharmony_ci	id = get_family_id(nl_sd);
40862306a36Sopenharmony_ci	if (!id) {
40962306a36Sopenharmony_ci		fprintf(stderr, "Error getting family id, errno %d\n", errno);
41062306a36Sopenharmony_ci		goto err;
41162306a36Sopenharmony_ci	}
41262306a36Sopenharmony_ci	PRINTF("family id %d\n", id);
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	if (maskset) {
41562306a36Sopenharmony_ci		rc = send_cmd(nl_sd, id, mypid, TASKSTATS_CMD_GET,
41662306a36Sopenharmony_ci			      TASKSTATS_CMD_ATTR_REGISTER_CPUMASK,
41762306a36Sopenharmony_ci			      &cpumask, strlen(cpumask) + 1);
41862306a36Sopenharmony_ci		PRINTF("Sent register cpumask, retval %d\n", rc);
41962306a36Sopenharmony_ci		if (rc < 0) {
42062306a36Sopenharmony_ci			fprintf(stderr, "error sending register cpumask\n");
42162306a36Sopenharmony_ci			goto err;
42262306a36Sopenharmony_ci		}
42362306a36Sopenharmony_ci	}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	if (tid && containerset) {
42662306a36Sopenharmony_ci		fprintf(stderr, "Select either -t or -C, not both\n");
42762306a36Sopenharmony_ci		goto err;
42862306a36Sopenharmony_ci	}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	/*
43162306a36Sopenharmony_ci	 * If we forked a child, wait for it to exit. Cannot use waitpid()
43262306a36Sopenharmony_ci	 * as all the delicious data would be reaped as part of the wait
43362306a36Sopenharmony_ci	 */
43462306a36Sopenharmony_ci	if (tid && forking) {
43562306a36Sopenharmony_ci		int sig_received;
43662306a36Sopenharmony_ci		sigwait(&sigset, &sig_received);
43762306a36Sopenharmony_ci	}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	if (tid) {
44062306a36Sopenharmony_ci		rc = send_cmd(nl_sd, id, mypid, TASKSTATS_CMD_GET,
44162306a36Sopenharmony_ci			      cmd_type, &tid, sizeof(__u32));
44262306a36Sopenharmony_ci		PRINTF("Sent pid/tgid, retval %d\n", rc);
44362306a36Sopenharmony_ci		if (rc < 0) {
44462306a36Sopenharmony_ci			fprintf(stderr, "error sending tid/tgid cmd\n");
44562306a36Sopenharmony_ci			goto done;
44662306a36Sopenharmony_ci		}
44762306a36Sopenharmony_ci	}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	if (containerset) {
45062306a36Sopenharmony_ci		cfd = open(containerpath, O_RDONLY);
45162306a36Sopenharmony_ci		if (cfd < 0) {
45262306a36Sopenharmony_ci			perror("error opening container file");
45362306a36Sopenharmony_ci			goto err;
45462306a36Sopenharmony_ci		}
45562306a36Sopenharmony_ci		rc = send_cmd(nl_sd, id, mypid, CGROUPSTATS_CMD_GET,
45662306a36Sopenharmony_ci			      CGROUPSTATS_CMD_ATTR_FD, &cfd, sizeof(__u32));
45762306a36Sopenharmony_ci		if (rc < 0) {
45862306a36Sopenharmony_ci			perror("error sending cgroupstats command");
45962306a36Sopenharmony_ci			goto err;
46062306a36Sopenharmony_ci		}
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ci	if (!maskset && !tid && !containerset) {
46362306a36Sopenharmony_ci		usage();
46462306a36Sopenharmony_ci		goto err;
46562306a36Sopenharmony_ci	}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	do {
46862306a36Sopenharmony_ci		rep_len = recv(nl_sd, &msg, sizeof(msg), 0);
46962306a36Sopenharmony_ci		PRINTF("received %d bytes\n", rep_len);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci		if (rep_len < 0) {
47262306a36Sopenharmony_ci			fprintf(stderr, "nonfatal reply error: errno %d\n",
47362306a36Sopenharmony_ci				errno);
47462306a36Sopenharmony_ci			continue;
47562306a36Sopenharmony_ci		}
47662306a36Sopenharmony_ci		if (msg.n.nlmsg_type == NLMSG_ERROR ||
47762306a36Sopenharmony_ci		    !NLMSG_OK((&msg.n), rep_len)) {
47862306a36Sopenharmony_ci			struct nlmsgerr *err = NLMSG_DATA(&msg);
47962306a36Sopenharmony_ci			fprintf(stderr, "fatal reply error,  errno %d\n",
48062306a36Sopenharmony_ci				err->error);
48162306a36Sopenharmony_ci			goto done;
48262306a36Sopenharmony_ci		}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci		PRINTF("nlmsghdr size=%zu, nlmsg_len=%d, rep_len=%d\n",
48562306a36Sopenharmony_ci		       sizeof(struct nlmsghdr), msg.n.nlmsg_len, rep_len);
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci		rep_len = GENLMSG_PAYLOAD(&msg.n);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci		na = (struct nlattr *) GENLMSG_DATA(&msg);
49162306a36Sopenharmony_ci		len = 0;
49262306a36Sopenharmony_ci		while (len < rep_len) {
49362306a36Sopenharmony_ci			len += NLA_ALIGN(na->nla_len);
49462306a36Sopenharmony_ci			switch (na->nla_type) {
49562306a36Sopenharmony_ci			case TASKSTATS_TYPE_AGGR_TGID:
49662306a36Sopenharmony_ci				/* Fall through */
49762306a36Sopenharmony_ci			case TASKSTATS_TYPE_AGGR_PID:
49862306a36Sopenharmony_ci				aggr_len = NLA_PAYLOAD(na->nla_len);
49962306a36Sopenharmony_ci				len2 = 0;
50062306a36Sopenharmony_ci				/* For nested attributes, na follows */
50162306a36Sopenharmony_ci				na = (struct nlattr *) NLA_DATA(na);
50262306a36Sopenharmony_ci				while (len2 < aggr_len) {
50362306a36Sopenharmony_ci					switch (na->nla_type) {
50462306a36Sopenharmony_ci					case TASKSTATS_TYPE_PID:
50562306a36Sopenharmony_ci						rtid = *(int *) NLA_DATA(na);
50662306a36Sopenharmony_ci						if (print_delays)
50762306a36Sopenharmony_ci							printf("PID\t%d\n", rtid);
50862306a36Sopenharmony_ci						break;
50962306a36Sopenharmony_ci					case TASKSTATS_TYPE_TGID:
51062306a36Sopenharmony_ci						rtid = *(int *) NLA_DATA(na);
51162306a36Sopenharmony_ci						if (print_delays)
51262306a36Sopenharmony_ci							printf("TGID\t%d\n", rtid);
51362306a36Sopenharmony_ci						break;
51462306a36Sopenharmony_ci					case TASKSTATS_TYPE_STATS:
51562306a36Sopenharmony_ci						if (print_delays)
51662306a36Sopenharmony_ci							print_delayacct((struct taskstats *) NLA_DATA(na));
51762306a36Sopenharmony_ci						if (print_io_accounting)
51862306a36Sopenharmony_ci							print_ioacct((struct taskstats *) NLA_DATA(na));
51962306a36Sopenharmony_ci						if (print_task_context_switch_counts)
52062306a36Sopenharmony_ci							task_context_switch_counts((struct taskstats *) NLA_DATA(na));
52162306a36Sopenharmony_ci						if (fd) {
52262306a36Sopenharmony_ci							if (write(fd, NLA_DATA(na), na->nla_len) < 0) {
52362306a36Sopenharmony_ci								err(1,"write error\n");
52462306a36Sopenharmony_ci							}
52562306a36Sopenharmony_ci						}
52662306a36Sopenharmony_ci						if (!loop)
52762306a36Sopenharmony_ci							goto done;
52862306a36Sopenharmony_ci						break;
52962306a36Sopenharmony_ci					case TASKSTATS_TYPE_NULL:
53062306a36Sopenharmony_ci						break;
53162306a36Sopenharmony_ci					default:
53262306a36Sopenharmony_ci						fprintf(stderr, "Unknown nested"
53362306a36Sopenharmony_ci							" nla_type %d\n",
53462306a36Sopenharmony_ci							na->nla_type);
53562306a36Sopenharmony_ci						break;
53662306a36Sopenharmony_ci					}
53762306a36Sopenharmony_ci					len2 += NLA_ALIGN(na->nla_len);
53862306a36Sopenharmony_ci					na = (struct nlattr *)((char *)na +
53962306a36Sopenharmony_ci							       NLA_ALIGN(na->nla_len));
54062306a36Sopenharmony_ci				}
54162306a36Sopenharmony_ci				break;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci			case CGROUPSTATS_TYPE_CGROUP_STATS:
54462306a36Sopenharmony_ci				print_cgroupstats(NLA_DATA(na));
54562306a36Sopenharmony_ci				break;
54662306a36Sopenharmony_ci			default:
54762306a36Sopenharmony_ci				fprintf(stderr, "Unknown nla_type %d\n",
54862306a36Sopenharmony_ci					na->nla_type);
54962306a36Sopenharmony_ci			case TASKSTATS_TYPE_NULL:
55062306a36Sopenharmony_ci				break;
55162306a36Sopenharmony_ci			}
55262306a36Sopenharmony_ci			na = (struct nlattr *) (GENLMSG_DATA(&msg) + len);
55362306a36Sopenharmony_ci		}
55462306a36Sopenharmony_ci	} while (loop);
55562306a36Sopenharmony_cidone:
55662306a36Sopenharmony_ci	if (maskset) {
55762306a36Sopenharmony_ci		rc = send_cmd(nl_sd, id, mypid, TASKSTATS_CMD_GET,
55862306a36Sopenharmony_ci			      TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK,
55962306a36Sopenharmony_ci			      &cpumask, strlen(cpumask) + 1);
56062306a36Sopenharmony_ci		printf("Sent deregister mask, retval %d\n", rc);
56162306a36Sopenharmony_ci		if (rc < 0)
56262306a36Sopenharmony_ci			err(rc, "error sending deregister cpumask\n");
56362306a36Sopenharmony_ci	}
56462306a36Sopenharmony_cierr:
56562306a36Sopenharmony_ci	close(nl_sd);
56662306a36Sopenharmony_ci	if (fd)
56762306a36Sopenharmony_ci		close(fd);
56862306a36Sopenharmony_ci	if (cfd)
56962306a36Sopenharmony_ci		close(cfd);
57062306a36Sopenharmony_ci	return 0;
57162306a36Sopenharmony_ci}
572