diff options
author | Masatake YAMATO <yamato@redhat.com> | 2024-03-16 22:07:43 +0900 |
---|---|---|
committer | Masatake YAMATO <yamato@redhat.com> | 2024-04-05 18:31:14 +0900 |
commit | 6979e2a111ad0e1383b4b239042b12d35cd99ff6 (patch) | |
tree | 22f373c9db2a8939ad7c66103a8123a163557618 | |
parent | 5f77e0ffe653b82378d24da26979cd7493e45542 (diff) | |
download | util-linux-6979e2a111ad0e1383b4b239042b12d35cd99ff6.tar.gz |
tests: (test_mkfds::sockdiag) new factory
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>
-rw-r--r-- | tests/helpers/test_mkfds.c | 115 | ||||
-rw-r--r-- | tests/ts/lsfd/lsfd-functions.bash | 27 |
2 files changed, 142 insertions, 0 deletions
diff --git a/tests/helpers/test_mkfds.c b/tests/helpers/test_mkfds.c index bbce228fd5..15e9016963 100644 --- a/tests/helpers/test_mkfds.c +++ b/tests/helpers/test_mkfds.c @@ -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) diff --git a/tests/ts/lsfd/lsfd-functions.bash b/tests/ts/lsfd/lsfd-functions.bash index d7eab146a7..3a3f58f0c8 100644 --- a/tests/ts/lsfd/lsfd-functions.bash +++ b/tests/ts/lsfd/lsfd-functions.bash @@ -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 +} |