[PATCH 2/4] sock_diag.7: Add EXAMPLE program

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Signed-off-by: Dmitry V. Levin <ldv@xxxxxxxxxxxx>
Acked-by: Pavel Emelyanov <xemul@xxxxxxxxxxxxx>
---
 man7/sock_diag.7 | 188 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 188 insertions(+)

diff --git a/man7/sock_diag.7 b/man7/sock_diag.7
index d1be9cf..776e2c9 100644
--- a/man7/sock_diag.7
+++ b/man7/sock_diag.7
@@ -626,6 +626,194 @@ was introduced in Linux 3.3.
 and
 .BR INET_DIAG_SKMEMINFO
 were introduced in Linux 3.6.
+.SH EXAMPLE
+The following example program prints inode number, peer's inode number,
+and name of all UNIX domain sockets in the current namespace.
+
+.nf
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/sock_diag.h>
+#include <linux/unix_diag.h>
+
+static int
+send_query(int fd)
+{
+    struct sockaddr_nl nladdr = {
+        .nl_family = AF_NETLINK
+    };
+    struct
+    {
+        struct nlmsghdr nlh;
+        struct unix_diag_req udr;
+    } req = {
+        .nlh = {
+            .nlmsg_len = sizeof(req),
+            .nlmsg_type = SOCK_DIAG_BY_FAMILY,
+            .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP
+        },
+        .udr = {
+            .sdiag_family = PF_UNIX,
+            .udiag_states = \-1,
+            .udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER
+        }
+    };
+    struct iovec iov = {
+        .iov_base = &req,
+        .iov_len = sizeof(req)
+    };
+    struct msghdr msg = {
+        .msg_name = (void *) &nladdr,
+        .msg_namelen = sizeof(nladdr),
+        .msg_iov = &iov,
+        .msg_iovlen = 1
+    };
+
+    for (;;) {
+        if (sendmsg(fd, &msg, 0) < 0) {
+            if (errno == EINTR)
+                continue;
+            perror("sendmsg");
+            return \-1;
+        }
+        return 0;
+    }
+}
+
+static int
+print_diag(const struct unix_diag_msg *diag, unsigned int len)
+{
+    if (len < NLMSG_LENGTH(sizeof(*diag))) {
+        fputs("short response\\n", stderr);
+        return \-1;
+    }
+    if (diag\->udiag_family != PF_UNIX) {
+        fprintf(stderr, "unexpected family %u\\n", diag\->udiag_family);
+        return \-1;
+    }
+
+    struct rtattr *attr;
+    unsigned int rta_len = len \- NLMSG_LENGTH(sizeof(*diag));
+    unsigned int peer = 0;
+    size_t path_len = 0;
+    char path[sizeof(((struct sockaddr_un *) 0)\->sun_path) + 1];
+
+    for (attr = (struct rtattr *) (diag + 1);
+             RTA_OK(attr, rta_len); attr = RTA_NEXT(attr, rta_len)) {
+        switch (attr\->rta_type) {
+            case UNIX_DIAG_NAME:
+                if (!path_len) {
+                    path_len = RTA_PAYLOAD(attr);
+                    if (path_len > sizeof(path) \- 1)
+                        path_len = sizeof(path) \- 1;
+                    memcpy(path, RTA_DATA(attr), path_len);
+                    path[path_len] = '\\0';
+                }
+                break;
+            case UNIX_DIAG_PEER:
+                if (RTA_PAYLOAD(attr) >= sizeof(peer))
+                    peer = *(unsigned int *) RTA_DATA(attr);
+                break;
+        }
+    }
+
+    printf("inode=%u", diag->udiag_ino);
+
+    if (peer)
+        printf(", peer=%u", peer);
+
+    if (path_len)
+        printf(", name=%s%s", *path ? "" : "@", *path ? path : path + 1);
+
+    putchar('\\n');
+    return 0;
+}
+
+static int
+receive_responses(int fd)
+{
+    long buf[8192 / sizeof(long)];
+    struct sockaddr_nl nladdr = {
+        .nl_family = AF_NETLINK
+    };
+    struct iovec iov = {
+        .iov_base = buf,
+        .iov_len = sizeof(buf)
+    };
+    int flags = 0;
+
+    for (;;) {
+        struct msghdr msg = {
+            .msg_name = (void *) &nladdr,
+            .msg_namelen = sizeof(nladdr),
+            .msg_iov = &iov,
+            .msg_iovlen = 1
+        };
+
+        ssize_t ret = recvmsg(fd, &msg, flags);
+
+        if (ret < 0) {
+            if (errno == EINTR)
+                continue;
+            perror("recvmsg");
+            return \-1;
+        }
+        if (ret == 0)
+            return 0;
+
+        const struct nlmsghdr *h = (struct nlmsghdr *) buf;
+
+        if (!NLMSG_OK(h, ret)) {
+            fputs("!NLMSG_OK\\n", stderr);
+            return \-1;
+        }
+        for (; NLMSG_OK(h, ret); h = NLMSG_NEXT(h, ret)) {
+            if (h\->nlmsg_type == NLMSG_DONE)
+                return 0;
+            if (h\->nlmsg_type == NLMSG_ERROR) {
+                const struct nlmsgerr *err = NLMSG_DATA(h);
+
+                if (h\->nlmsg_len < NLMSG_LENGTH(sizeof(*err))) {
+                    fputs("NLMSG_ERROR\\n", stderr);
+                } else {
+                    errno = \-err\->error;
+                    perror("NLMSG_ERROR");
+                }
+                return \-1;
+            }
+            if (h\->nlmsg_type != SOCK_DIAG_BY_FAMILY) {
+                fprintf(stderr, "unexpected nlmsg_type %u\\n",
+                        (unsigned) h\->nlmsg_type);
+                return \-1;
+            }
+
+            if (print_diag(NLMSG_DATA(h), h\->nlmsg_len))
+                return \-1;
+        }
+    }
+}
+
+int
+main(void)
+{
+    int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG);
+
+    if (fd < 0) {
+        perror("socket");
+        return 1;
+    }
+
+    int ret = send_query(fd) || receive_responses(fd);
+
+    close(fd);
+    return ret;
+}
+.fi
 .SH SEE ALSO
 .BR netlink (3),
 .BR rtnetlink (3),
-- 
ldv

--
To unsubscribe from this list: send the line "unsubscribe linux-man" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Kernel Documentation]     [Netdev]     [Linux Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux