| 247 | } |
| 248 | |
| 249 | static int recvfd(int sockfd) { |
| 250 | int data, fd; |
| 251 | ssize_t nr; |
| 252 | struct iovec iov{}; |
| 253 | struct msghdr msgh{}; |
| 254 | |
| 255 | /* Allocate a char buffer for the ancillary data. See the comments |
| 256 | in sendfd() */ |
| 257 | union { |
| 258 | char buf[CMSG_SPACE(sizeof(int))]; |
| 259 | struct cmsghdr align; |
| 260 | } controlMsg{}; |
| 261 | struct cmsghdr *cmsgp; |
| 262 | |
| 263 | /* The 'msg_name' field can be used to obtain the address of the |
| 264 | sending socket. However, we do not need this information. */ |
| 265 | |
| 266 | msgh.msg_name = nullptr; |
| 267 | msgh.msg_namelen = 0; |
| 268 | |
| 269 | /* Specify buffer for receiving real data */ |
| 270 | |
| 271 | msgh.msg_iov = &iov; |
| 272 | msgh.msg_iovlen = 1; |
| 273 | iov.iov_base = &data; /* Real data is an 'int' */ |
| 274 | iov.iov_len = sizeof(int); |
| 275 | |
| 276 | /* Set 'msghdr' fields that describe ancillary data */ |
| 277 | |
| 278 | msgh.msg_control = controlMsg.buf; |
| 279 | msgh.msg_controllen = sizeof(controlMsg.buf); |
| 280 | |
| 281 | /* Receive real plus ancillary data; real data is ignored */ |
| 282 | |
| 283 | nr = recvmsg(sockfd, &msgh, 0); |
| 284 | if (nr == -1) return -1; |
| 285 | |
| 286 | cmsgp = CMSG_FIRSTHDR(&msgh); |
| 287 | |
| 288 | /* Check the validity of the 'cmsghdr' */ |
| 289 | |
| 290 | if (cmsgp == nullptr || cmsgp->cmsg_len != CMSG_LEN(sizeof(int)) || |
| 291 | cmsgp->cmsg_level != SOL_SOCKET || cmsgp->cmsg_type != SCM_RIGHTS) { |
| 292 | errno = EINVAL; |
| 293 | return -1; |
| 294 | } |
| 295 | |
| 296 | /* Return the received file descriptor to our caller */ |
| 297 | |
| 298 | memcpy(&fd, CMSG_DATA(cmsgp), sizeof(int)); |
| 299 | return fd; |
| 300 | } |
| 301 | |
| 302 | static int getKernelVersion() { |
| 303 | struct utsname un{}; |
nothing calls this directly
no outgoing calls
no test coverage detected