Here are two test (example) programs.

task_diag - request information for two processes.
test_diag_all - request information about all processes

Signed-off-by: Andrey Vagin <ava...@openvz.org>
---
 tools/testing/selftests/Makefile                   |   1 +
 tools/testing/selftests/task_diag/Makefile         |  16 ++
 tools/testing/selftests/task_diag/task_diag.c      |  56 ++++++
 tools/testing/selftests/task_diag/task_diag_all.c  |  82 ++++++++
 tools/testing/selftests/task_diag/task_diag_comm.c | 206 +++++++++++++++++++++
 tools/testing/selftests/task_diag/task_diag_comm.h |  47 +++++
 tools/testing/selftests/task_diag/taskdiag.h       |   1 +
 7 files changed, 409 insertions(+)
 create mode 100644 tools/testing/selftests/task_diag/Makefile
 create mode 100644 tools/testing/selftests/task_diag/task_diag.c
 create mode 100644 tools/testing/selftests/task_diag/task_diag_all.c
 create mode 100644 tools/testing/selftests/task_diag/task_diag_comm.c
 create mode 100644 tools/testing/selftests/task_diag/task_diag_comm.h
 create mode 120000 tools/testing/selftests/task_diag/taskdiag.h

diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 4e51122..c73d888 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -17,6 +17,7 @@ TARGETS += sysctl
 TARGETS += timers
 TARGETS += user
 TARGETS += vm
+TARGETS += task_diag
 #Please keep the TARGETS list alphabetically sorted
 
 TARGETS_HOTPLUG = cpu-hotplug
diff --git a/tools/testing/selftests/task_diag/Makefile 
b/tools/testing/selftests/task_diag/Makefile
new file mode 100644
index 0000000..d6583c4
--- /dev/null
+++ b/tools/testing/selftests/task_diag/Makefile
@@ -0,0 +1,16 @@
+all: task_diag task_diag_all
+
+run_tests: all
+       @./task_diag && ./task_diag_all && echo "task_diag: [PASS]" || echo 
"task_diag: [FAIL]"
+
+CFLAGS += -Wall -O2
+
+task_diag.o: task_diag.c task_diag_comm.h
+task_diag_all.o: task_diag_all.c task_diag_comm.h
+task_diag_comm.o: task_diag_comm.c task_diag_comm.h
+
+task_diag_all: task_diag_all.o task_diag_comm.o
+task_diag: task_diag.o task_diag_comm.o
+
+clean:
+       rm -rf task_diag task_diag_all task_diag_comm.o task_diag_all.o 
task_diag.o
diff --git a/tools/testing/selftests/task_diag/task_diag.c 
b/tools/testing/selftests/task_diag/task_diag.c
new file mode 100644
index 0000000..fafeeac
--- /dev/null
+++ b/tools/testing/selftests/task_diag/task_diag.c
@@ -0,0 +1,56 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <poll.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+#include <linux/genetlink.h>
+#include "taskdiag.h"
+#include "task_diag_comm.h"
+
+int main(int argc, char *argv[])
+{
+       int exit_status = 1;
+       int rc, rep_len, id;
+       int nl_sd = -1;
+       struct task_diag_pid req;
+       char buf[4096];
+
+       req.show_flags = TASK_DIAG_SHOW_CRED;
+       req.pid = getpid();
+
+       nl_sd = create_nl_socket(NETLINK_GENERIC);
+       if (nl_sd < 0)
+               return -1;
+
+       id = get_family_id(nl_sd);
+       if (!id)
+               goto err;
+
+       rc = send_cmd(nl_sd, id, getpid(), TASKDIAG_CMD_GET,
+                     TASKDIAG_CMD_ATTR_GET, &req, sizeof(req), 0);
+       pr_info("Sent pid/tgid, retval %d\n", rc);
+       if (rc < 0)
+               goto err;
+
+       rep_len = recv(nl_sd, buf, sizeof(buf), 0);
+       if (rep_len < 0) {
+               pr_perror("Unable to receive a response\n");
+               goto err;
+       }
+       pr_info("received %d bytes\n", rep_len);
+
+       nlmsg_receive(buf, rep_len, &show_task);
+
+       exit_status = 0;
+err:
+       close(nl_sd);
+       return exit_status;
+}
diff --git a/tools/testing/selftests/task_diag/task_diag_all.c 
b/tools/testing/selftests/task_diag/task_diag_all.c
new file mode 100644
index 0000000..85e1a0a
--- /dev/null
+++ b/tools/testing/selftests/task_diag/task_diag_all.c
@@ -0,0 +1,82 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <poll.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+#include "task_diag_comm.h"
+#include "taskdiag.h"
+
+int tasks;
+
+
+extern int _show_task(struct nlmsghdr *hdr)
+{
+       tasks++;
+       return show_task(hdr);
+}
+
+int main(int argc, char *argv[])
+{
+       int exit_status = 1;
+       int rc, rep_len, id;
+       int nl_sd = -1;
+       struct {
+               struct task_diag_pid req;
+       } pid_req;
+       char buf[4096];
+
+       quiet = 0;
+
+       pid_req.req.show_flags = 0;
+       pid_req.req.dump_stratagy = TASK_DIAG_DUMP_ALL;
+       pid_req.req.pid = 1;
+
+       nl_sd = create_nl_socket(NETLINK_GENERIC);
+       if (nl_sd < 0)
+               return -1;
+
+       id = get_family_id(nl_sd);
+       if (!id)
+               goto err;
+
+       rc = send_cmd(nl_sd, id, getpid(), TASKDIAG_CMD_GET,
+                     TASKDIAG_CMD_ATTR_GET, &pid_req, sizeof(pid_req), 1);
+       pr_info("Sent pid/tgid, retval %d\n", rc);
+       if (rc < 0)
+               goto err;
+
+       while (1) {
+               int err;
+
+               rep_len = recv(nl_sd, buf, sizeof(buf), 0);
+               pr_info("received %d bytes\n", rep_len);
+
+               if (rep_len < 0) {
+                       pr_perror("Unable to receive a response\n");
+                       goto err;
+               }
+
+               if (rep_len == 0)
+                       break;
+
+               err = nlmsg_receive(buf, rep_len, &_show_task);
+               if (err < 0)
+                       goto err;
+               if (err == 0)
+                       break;
+       }
+       printf("tasks: %d\n", tasks);
+
+       exit_status = 0;
+err:
+       close(nl_sd);
+       return exit_status;
+}
diff --git a/tools/testing/selftests/task_diag/task_diag_comm.c 
b/tools/testing/selftests/task_diag/task_diag_comm.c
new file mode 100644
index 0000000..df7780d
--- /dev/null
+++ b/tools/testing/selftests/task_diag/task_diag_comm.c
@@ -0,0 +1,206 @@
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/genetlink.h>
+
+#include "taskdiag.h"
+#include "task_diag_comm.h"
+
+int quiet = 0;
+
+/*
+ * Create a raw netlink socket and bind
+ */
+int create_nl_socket(int protocol)
+{
+       int fd;
+       struct sockaddr_nl local;
+
+       fd = socket(AF_NETLINK, SOCK_RAW, protocol);
+       if (fd < 0)
+               return -1;
+
+       memset(&local, 0, sizeof(local));
+       local.nl_family = AF_NETLINK;
+
+       if (bind(fd, (struct sockaddr *) &local, sizeof(local)) < 0)
+               goto error;
+
+       return fd;
+error:
+       close(fd);
+       return -1;
+}
+
+
+int send_cmd(int sd, __u16 nlmsg_type, __u32 nlmsg_pid,
+            __u8 genl_cmd, __u16 nla_type,
+            void *nla_data, int nla_len, int dump)
+{
+       struct nlattr *na;
+       struct sockaddr_nl nladdr;
+       int r, buflen;
+       char *buf;
+
+       struct msgtemplate msg;
+
+       msg.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+       msg.n.nlmsg_type = nlmsg_type;
+       msg.n.nlmsg_flags = NLM_F_REQUEST;
+       if (dump)
+               msg.n.nlmsg_flags |= NLM_F_DUMP;
+       msg.n.nlmsg_seq = 0;
+       msg.n.nlmsg_pid = nlmsg_pid;
+       msg.g.cmd = genl_cmd;
+       msg.g.version = 0x1;
+       na = (struct nlattr *) GENLMSG_DATA(&msg);
+       na->nla_type = nla_type;
+       na->nla_len = nla_len + 1 + NLA_HDRLEN;
+       memcpy(NLA_DATA(na), nla_data, nla_len);
+       msg.n.nlmsg_len += NLMSG_ALIGN(na->nla_len);
+
+       buf = (char *) &msg;
+       buflen = msg.n.nlmsg_len;
+       memset(&nladdr, 0, sizeof(nladdr));
+       nladdr.nl_family = AF_NETLINK;
+       r = sendto(sd, buf, buflen, 0, (struct sockaddr *) &nladdr,
+                          sizeof(nladdr));
+       if (r != buflen) {
+               pr_perror("Unable to send %d (%d)", r, buflen);
+               return -1;
+       }
+       return 0;
+}
+
+
+/*
+ * Probe the controller in genetlink to find the family id
+ * for the TASKDIAG family
+ */
+int get_family_id(int sd)
+{
+       char name[100];
+       struct msgtemplate ans;
+
+       int id = 0, rc;
+       struct nlattr *na;
+       int rep_len;
+
+       strcpy(name, TASKDIAG_GENL_NAME);
+       rc = send_cmd(sd, GENL_ID_CTRL, getpid(), CTRL_CMD_GETFAMILY,
+                       CTRL_ATTR_FAMILY_NAME, (void *)name,
+                       strlen(TASKDIAG_GENL_NAME) + 1, 0);
+       if (rc < 0)
+               return -1;
+
+       rep_len = recv(sd, &ans, sizeof(ans), 0);
+       if (ans.n.nlmsg_type == NLMSG_ERROR ||
+           (rep_len < 0) || !NLMSG_OK((&ans.n), rep_len))
+               return 0;
+
+       na = (struct nlattr *) GENLMSG_DATA(&ans);
+       na = (struct nlattr *) ((char *) na + NLA_ALIGN(na->nla_len));
+       if (na->nla_type == CTRL_ATTR_FAMILY_ID)
+               id = *(__u16 *) NLA_DATA(na);
+
+       return id;
+}
+
+int nlmsg_receive(void *buf, int len, int (*cb)(struct nlmsghdr *))
+{
+       struct nlmsghdr *hdr;
+
+       for (hdr = (struct nlmsghdr *)buf;
+                       NLMSG_OK(hdr, len); hdr = NLMSG_NEXT(hdr, len)) {
+
+               if (hdr->nlmsg_type == NLMSG_DONE) {
+                       int *len = (int *)NLMSG_DATA(hdr);
+
+                       if (*len < 0) {
+                               pr_err("ERROR %d reported by netlink (%s)\n",
+                                       *len, strerror(-*len));
+                               return *len;
+                       }
+
+                       return 0;
+               }
+
+               if (hdr->nlmsg_type == NLMSG_ERROR) {
+                       struct nlmsgerr *err = (struct nlmsgerr 
*)NLMSG_DATA(hdr);
+
+                       if (hdr->nlmsg_len - sizeof(*hdr) < sizeof(struct 
nlmsgerr)) {
+                               pr_err("ERROR truncated\n");
+                               return -1;
+                       }
+
+                       if (err->error == 0)
+                               return 0;
+
+                       return -1;
+               }
+               if (cb && cb(hdr))
+                       return -1;
+       }
+
+       return 1;
+}
+
+int show_task(struct nlmsghdr *hdr)
+{
+       int msg_len;
+       struct msgtemplate *msg;
+       struct nlattr *na;
+       int len;
+
+       msg_len = GENLMSG_PAYLOAD(hdr);
+
+       msg = (struct msgtemplate *)hdr;
+       na = (struct nlattr *) GENLMSG_DATA(msg);
+       len = 0;
+       while (len < msg_len) {
+               len += NLA_ALIGN(na->nla_len);
+               switch (na->nla_type) {
+               case TASK_DIAG_MSG:
+               {
+                       struct task_diag_msg *msg;
+
+                       /* For nested attributes, na follows */
+                       msg = (struct task_diag_msg *) NLA_DATA(na);
+                       pr_info("pid %d ppid %d comm %s\n", msg->pid, 
msg->ppid, msg->comm);
+                       break;
+               }
+               case TASK_DIAG_CRED:
+               {
+                       struct task_diag_creds *creds;
+
+                       creds = (struct task_diag_creds *) NLA_DATA(na);
+                       pr_info("uid: %d %d %d %d\n", creds->uid,
+                                       creds->euid, creds->suid, creds->fsuid);
+                       pr_info("gid: %d %d %d %d\n", creds->uid,
+                                       creds->euid, creds->suid, creds->fsuid);
+                       pr_info("CapInh: %08x%08x\n",
+                                               creds->cap_inheritable.cap[1],
+                                               creds->cap_inheritable.cap[0]);
+                       pr_info("CapPrm: %08x%08x\n",
+                                               creds->cap_permitted.cap[1],
+                                               creds->cap_permitted.cap[0]);
+                       pr_info("CapEff: %08x%08x\n",
+                                               creds->cap_effective.cap[1],
+                                               creds->cap_effective.cap[0]);
+                       pr_info("CapBnd: %08x%08x\n", creds->cap_bset.cap[1],
+                                               creds->cap_bset.cap[0]);
+                       break;
+               }
+               default:
+                       pr_err("Unknown nla_type %d\n",
+                               na->nla_type);
+                       return -1;
+               }
+               na = (struct nlattr *) (GENLMSG_DATA(msg) + len);
+       }
+
+       return 0;
+}
diff --git a/tools/testing/selftests/task_diag/task_diag_comm.h 
b/tools/testing/selftests/task_diag/task_diag_comm.h
new file mode 100644
index 0000000..42f2088
--- /dev/null
+++ b/tools/testing/selftests/task_diag/task_diag_comm.h
@@ -0,0 +1,47 @@
+#ifndef __TASK_DIAG_COMM__
+#define __TASK_DIAG_COMM__
+
+#include <stdio.h>
+
+#include <linux/genetlink.h>
+#include "taskdiag.h"
+
+/*
+ * Generic macros for dealing with netlink sockets. Might be duplicated
+ * elsewhere. It is recommended that commercial grade applications use
+ * libnl or libnetlink and use the interfaces provided by the library
+ */
+#define GENLMSG_DATA(glh)      ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN))
+#define GENLMSG_PAYLOAD(glh)   (NLMSG_PAYLOAD(glh, 0) - GENL_HDRLEN)
+#define NLA_DATA(na)           ((void *)((char *)(na) + NLA_HDRLEN))
+#define NLA_PAYLOAD(len)       (len - NLA_HDRLEN)
+
+#define pr_err(fmt, ...)                               \
+               fprintf(stderr, fmt, ##__VA_ARGS__)
+
+#define pr_perror(fmt, ...)                            \
+               fprintf(stderr, fmt " : %m\n", ##__VA_ARGS__)
+
+extern int quiet;
+#define pr_info(fmt, arg...)                   \
+       do {                                    \
+               if (!quiet)                     \
+                       printf(fmt, ##arg);     \
+       } while (0)                             \
+
+struct msgtemplate {
+       struct nlmsghdr n;
+       struct genlmsghdr g;
+       char body[4096];
+};
+
+extern int create_nl_socket(int protocol);
+extern int send_cmd(int sd, __u16 nlmsg_type, __u32 nlmsg_pid,
+            __u8 genl_cmd, __u16 nla_type,
+            void *nla_data, int nla_len, int dump);
+
+extern int get_family_id(int sd);
+extern int nlmsg_receive(void *buf, int len, int (*cb)(struct nlmsghdr *));
+extern int show_task(struct nlmsghdr *hdr);
+
+#endif /* __TASK_DIAG_COMM__ */
diff --git a/tools/testing/selftests/task_diag/taskdiag.h 
b/tools/testing/selftests/task_diag/taskdiag.h
new file mode 120000
index 0000000..83e857e
--- /dev/null
+++ b/tools/testing/selftests/task_diag/taskdiag.h
@@ -0,0 +1 @@
+../../../../include/uapi/linux/taskdiag.h
\ No newline at end of file
-- 
2.1.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to