riscv: Fix alignment-ignorant memcpy implementation
[glibc.git] / sysdeps / unix / sysv / linux / tst-scm_rights.c
blob23ccdad9f95c3a0c0c520c3480865c62f4dd14dc
1 /* Smoke test for SCM_RIGHTS.
2 Copyright (C) 2021-2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 /* This test passes a file descriptor from a subprocess to the parent
20 process, using recvmsg/sendmsg or recvmmsg/sendmmsg. */
22 #include <fcntl.h>
23 #include <signal.h>
24 #include <stdbool.h>
25 #include <string.h>
26 #include <support/check.h>
27 #include <support/xunistd.h>
28 #include <sys/socket.h>
29 #include <sys/wait.h>
30 #include <unistd.h>
32 /* String sent over the socket. */
33 static char DATA[] = "descriptor";
35 /* Path that is to be opened and sent over the socket. */
36 #define PATH "/etc"
38 /* True if sendmmsg/recvmmsg is to be used. */
39 static bool use_multi_call;
41 /* The pair of sockets used for coordination. The subprocess uses
42 sockets[1]. */
43 static int sockets[2];
45 /* Subprocess side of one send/receive test. */
46 _Noreturn static void
47 subprocess (void)
49 /* The file descriptor to send. */
50 int fd = xopen (PATH, O_RDONLY, 0);
52 struct iovec iov = { .iov_base = DATA, .iov_len = sizeof (DATA) };
53 union
55 struct cmsghdr header;
56 char bytes[CMSG_SPACE (sizeof (int))];
57 } cmsg_storage;
58 struct mmsghdr mmhdr =
60 .msg_hdr =
62 .msg_iov = &iov,
63 .msg_iovlen = 1,
64 .msg_control = cmsg_storage.bytes,
65 .msg_controllen = sizeof (cmsg_storage),
69 /* Configure the file descriptor for sending. */
70 struct cmsghdr *cmsg = CMSG_FIRSTHDR (&mmhdr.msg_hdr);
71 cmsg->cmsg_level = SOL_SOCKET;
72 cmsg->cmsg_type = SCM_RIGHTS;
73 cmsg->cmsg_len = CMSG_LEN (sizeof (int));
74 memcpy (CMSG_DATA (cmsg), &fd, sizeof (fd));
75 mmhdr.msg_hdr.msg_controllen = cmsg->cmsg_len;
77 /* Perform the send operation. */
78 int ret;
79 if (use_multi_call)
81 ret = sendmmsg (sockets[1], &mmhdr, 1, 0);
82 if (ret >= 0)
83 ret = mmhdr.msg_len;
85 else
86 ret = sendmsg (sockets[1], &mmhdr.msg_hdr, 0);
87 TEST_COMPARE (ret, sizeof (DATA));
89 xclose (fd);
91 /* Stop the process from exiting. */
92 while (true)
93 pause ();
96 /* Performs one send/receive test. */
97 static void
98 one_test (void)
100 TEST_COMPARE (socketpair (AF_UNIX, SOCK_STREAM, 0, sockets), 0);
102 pid_t pid = xfork ();
103 if (pid == 0)
104 subprocess ();
106 char data_storage[sizeof (DATA) + 1];
107 struct iovec iov =
109 .iov_base = data_storage,
110 .iov_len = sizeof (data_storage)
112 union
114 struct cmsghdr header;
115 char bytes[CMSG_SPACE (sizeof (int))];
116 } cmsg_storage;
117 struct mmsghdr mmhdr =
119 .msg_hdr =
121 .msg_iov = &iov,
122 .msg_iovlen = 1,
123 .msg_control = cmsg_storage.bytes,
124 .msg_controllen = sizeof (cmsg_storage),
128 /* Set up the space for receiving the file descriptor. */
129 struct cmsghdr *cmsg = CMSG_FIRSTHDR (&mmhdr.msg_hdr);
130 cmsg->cmsg_level = SOL_SOCKET;
131 cmsg->cmsg_type = SCM_RIGHTS;
132 cmsg->cmsg_len = CMSG_LEN (sizeof (int));
133 mmhdr.msg_hdr.msg_controllen = cmsg->cmsg_len;
135 /* Perform the receive operation. */
136 int ret;
137 if (use_multi_call)
139 ret = recvmmsg (sockets[0], &mmhdr, 1, 0, NULL);
140 if (ret >= 0)
141 ret = mmhdr.msg_len;
143 else
144 ret = recvmsg (sockets[0], &mmhdr.msg_hdr, 0);
145 TEST_COMPARE (ret, sizeof (DATA));
146 TEST_COMPARE_BLOB (data_storage, sizeof (DATA), DATA, sizeof (DATA));
148 /* Extract the file descriptor. */
149 TEST_VERIFY (CMSG_FIRSTHDR (&mmhdr.msg_hdr) != NULL);
150 TEST_COMPARE (CMSG_FIRSTHDR (&mmhdr.msg_hdr)->cmsg_len,
151 CMSG_LEN (sizeof (int)));
152 TEST_VERIFY (&cmsg_storage.header == CMSG_FIRSTHDR (&mmhdr.msg_hdr));
153 int fd;
154 memcpy (&fd, CMSG_DATA (CMSG_FIRSTHDR (&mmhdr.msg_hdr)), sizeof (fd));
156 /* Verify the received file descriptor. */
157 TEST_VERIFY (fd > 2);
158 struct stat64 st_fd;
159 TEST_COMPARE (fstat64 (fd, &st_fd), 0);
160 struct stat64 st_path;
161 TEST_COMPARE (stat64 (PATH, &st_path), 0);
162 TEST_COMPARE (st_fd.st_ino, st_path.st_ino);
163 TEST_COMPARE (st_fd.st_dev, st_path.st_dev);
164 xclose (fd);
166 /* Terminate the subprocess. */
167 TEST_COMPARE (kill (pid, SIGUSR1), 0);
168 int status;
169 TEST_COMPARE (xwaitpid (pid, &status, 0), pid);
170 TEST_VERIFY (WIFSIGNALED (status));
171 TEST_COMPARE (WTERMSIG (status), SIGUSR1);
173 xclose (sockets[0]);
174 xclose (sockets[1]);
177 static int
178 do_test (void)
180 one_test ();
181 use_multi_call = true;
182 one_test ();
183 return 0;
186 #include <support/test-driver.c>