]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
tests: (test_mkfds::sockdiag) new factory
authorMasatake YAMATO <yamato@redhat.com>
Sat, 16 Mar 2024 13:07:43 +0000 (22:07 +0900)
committerMasatake YAMATO <yamato@redhat.com>
Fri, 5 Apr 2024 09:31:14 +0000 (18:31 +0900)
The factory is for detecting whether a platform provides
NETLINK_SOCK_DIAG sockets for a given family.

Signed-off-by: Masatake YAMATO <yamato@redhat.com>
tests/helpers/test_mkfds.c
tests/ts/lsfd/lsfd-functions.bash

index bbce228fd51d792714fce46f2dc5c67c4bd26441..15e901696322f527dfc86ad4bcf5a5ee9ae4aa5f 100644 (file)
@@ -34,6 +34,8 @@
 #include <linux/if_packet.h>
 #include <linux/if_tun.h>
 #include <linux/netlink.h>
+#include <linux/sock_diag.h>
+# include <linux/unix_diag.h> /* for UNIX domain sockets */
 #include <linux/sockios.h>  /* SIOCGSKNS */
 #include <mqueue.h>
 #include <net/if.h>
@@ -70,6 +72,7 @@
 #define EXIT_ENOPROTOOPT 19
 #define EXIT_EPROTONOSUPPORT 20
 #define EXIT_EACCES 21
+#define EXIT_ENOENT 22
 
 #define _U_ __attribute__((__unused__))
 
@@ -3307,6 +3310,100 @@ static void free_mmap(const struct factory * factory _U_, void *data)
               ((struct mmap_data *)data)->len);
 }
 
+static int send_diag_request(int diagsd, void *req, size_t req_size)
+{
+       struct sockaddr_nl nladdr = {
+               .nl_family = AF_NETLINK,
+       };
+
+       struct nlmsghdr nlh = {
+               .nlmsg_len = sizeof(nlh) + req_size,
+               .nlmsg_type = SOCK_DIAG_BY_FAMILY,
+               .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
+       };
+
+       struct iovec iovecs[] = {
+               { &nlh, sizeof(nlh) },
+               { req, req_size },
+       };
+
+       const struct msghdr mhd = {
+               .msg_namelen = sizeof(nladdr),
+               .msg_name = &nladdr,
+               .msg_iovlen = ARRAY_SIZE(iovecs),
+               .msg_iov = iovecs,
+       };
+
+       if (sendmsg(diagsd, &mhd, 0) < 0)
+               return errno;
+
+       return 0;
+}
+
+static void *make_sockdiag(const struct factory *factory, struct fdesc fdescs[],
+                          int argc, char ** argv)
+{
+       struct arg family = decode_arg("family", factory->params, argc, argv);
+       const char *sfamily = ARG_STRING(family);
+       int ifamily;
+       int diagsd;
+       void *req = NULL;
+       size_t reqlen = 0;
+       int e;
+       struct unix_diag_req udr;
+
+       if (strcmp(sfamily, "unix") == 0)
+               ifamily = AF_UNIX;
+       else
+               errx(EXIT_FAILURE, "unknown/unsupported family: %s", sfamily);
+       free_arg(&family);
+
+       diagsd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_SOCK_DIAG);
+       if (diagsd < 0)
+               err(errno == EPROTONOSUPPORT? EXIT_EPROTONOSUPPORT: EXIT_FAILURE,
+                   "failed in sendmsg()");
+
+       if (ifamily == AF_UNIX) {
+               udr = (struct unix_diag_req) {
+                       .sdiag_family = AF_UNIX,
+                       .udiag_states = -1, /* set the all bits. */
+                       .udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER | UNIX_DIAG_SHUTDOWN,
+               };
+               req = &udr;
+               reqlen = sizeof(udr);
+       }
+
+       e = send_diag_request(diagsd, req, reqlen);
+       if (e) {
+               close (diagsd);
+               errno = e;
+               if (errno == EACCES)
+                       err(EXIT_EACCES, "failed in sendmsg()");
+               if (errno == ENOENT)
+                       err(EXIT_ENOENT, "failed in sendmsg()");
+               err(EXIT_FAILURE, "failed in sendmsg()");
+       }
+
+
+       if (diagsd != fdescs[0].fd) {
+               if (dup2(diagsd, fdescs[0].fd) < 0) {
+                       e = errno;
+                       close(diagsd);
+                       errno = e;
+                       err(EXIT_FAILURE, "failed to dup %d -> %d", diagsd, fdescs[0].fd);
+               }
+               close(diagsd);
+       }
+
+       fdescs[0] = (struct fdesc){
+               .fd    = fdescs[0].fd,
+               .close = close_fdesc,
+               .data  = NULL
+       };
+
+       return NULL;
+}
+
 #define PARAM_END { .name = NULL, }
 static const struct factory factories[] = {
        {
@@ -4168,6 +4265,24 @@ static const struct factory factories[] = {
                        PARAM_END
                }
        },
+       {
+               .name = "sockdiag",
+               .desc = "make a sockdiag netlink socket",
+               .priv = false,
+               .N = 1,
+               .EX_N = 0,
+               .make = make_sockdiag,
+               .params = (struct parameter []) {
+                       {
+                               .name = "family",
+                               .type = PTYPE_STRING,
+                               /* TODO: inet, inet6 */
+                               .desc = "name of a protocol family ([unix])",
+                               .defv.string = "unix",
+                       },
+                       PARAM_END
+               }
+       },
 };
 
 static int count_parameters(const struct factory *factory)
index d7eab146a70dac63314ac748d361c3361c16e167..3a3f58f0c890fd34718205a39986200b7c53455e 100644 (file)
@@ -20,6 +20,7 @@ readonly EPERM=18
 readonly ENOPROTOOPT=19
 readonly EPROTONOSUPPORT=20
 readonly EACCES=21
+readonly ENOENT=22
 
 function lsfd_wait_for_pausing {
        ts_check_prog "sleep"
@@ -92,3 +93,29 @@ function lsfd_check_mkfds_factory
                ts_skip "test_mkfds has no factory for $FACTORY"
        fi
 }
+
+function lsfd_check_sockdiag
+{
+       local family=$1
+
+       ts_check_test_command "$TS_HELPER_MKFDS"
+
+       local msg
+       local err
+
+       msg=$("$TS_HELPER_MKFDS" -c sockdiag 9 family=$family 2>&1)
+       err=$?
+
+       case $err in
+           0)
+               return;;
+           $EPROTONOSUPPORT)
+               ts_skip "NETLINK_SOCK_DIAG protocol is not supported in socket(2)";;
+           $EACCES)
+               ts_skip "sending a msg via a sockdiag netlink socket is not permitted";;
+           $ENOENT)
+               ts_skip "sockdiag netlink socket is not available";;
+           *)
+               ts_failed "failed to create a sockdiag netlink socket $family ($err): $msg";;
+       esac
+}