| /* |
| * SCM_RIGHTS with unix socket help program for test |
| * |
| * Copyright IBM, Inc. 2013 |
| * |
| * Authors: |
| * Wenchao Xia <xiawenc@linux.vnet.ibm.com> |
| * |
| * This work is licensed under the terms of the GNU LGPL, version 2 or later. |
| * See the COPYING.LIB file in the top-level directory. |
| */ |
| |
| #include "qemu/osdep.h" |
| #include <sys/socket.h> |
| #include <sys/un.h> |
| |
| /* #define SOCKET_SCM_DEBUG */ |
| |
| /* |
| * @fd and @fd_to_send will not be checked for validation in this function, |
| * a blank will be sent as iov data to notify qemu. |
| */ |
| static int send_fd(int fd, int fd_to_send) |
| { |
| struct msghdr msg; |
| struct iovec iov[1]; |
| int ret; |
| char control[CMSG_SPACE(sizeof(int))]; |
| struct cmsghdr *cmsg; |
| |
| memset(&msg, 0, sizeof(msg)); |
| memset(control, 0, sizeof(control)); |
| |
| /* Send a blank to notify qemu */ |
| iov[0].iov_base = (void *)" "; |
| iov[0].iov_len = 1; |
| |
| msg.msg_iov = iov; |
| msg.msg_iovlen = 1; |
| |
| msg.msg_control = control; |
| msg.msg_controllen = sizeof(control); |
| |
| cmsg = CMSG_FIRSTHDR(&msg); |
| |
| cmsg->cmsg_len = CMSG_LEN(sizeof(int)); |
| cmsg->cmsg_level = SOL_SOCKET; |
| cmsg->cmsg_type = SCM_RIGHTS; |
| memcpy(CMSG_DATA(cmsg), &fd_to_send, sizeof(int)); |
| |
| do { |
| ret = sendmsg(fd, &msg, 0); |
| } while (ret < 0 && errno == EINTR); |
| |
| if (ret < 0) { |
| fprintf(stderr, "Failed to send msg, reason: %s\n", strerror(errno)); |
| } |
| |
| return ret; |
| } |
| |
| /* Convert string to fd number. */ |
| static int get_fd_num(const char *fd_str, bool silent) |
| { |
| int sock; |
| char *err; |
| |
| errno = 0; |
| sock = strtol(fd_str, &err, 10); |
| if (errno) { |
| if (!silent) { |
| fprintf(stderr, "Failed in strtol for socket fd, reason: %s\n", |
| strerror(errno)); |
| } |
| return -1; |
| } |
| if (!*fd_str || *err || sock < 0) { |
| if (!silent) { |
| fprintf(stderr, "bad numerical value for socket fd '%s'\n", fd_str); |
| } |
| return -1; |
| } |
| |
| return sock; |
| } |
| |
| /* |
| * To make things simple, the caller needs to specify: |
| * 1. socket fd. |
| * 2. path of the file to be sent. |
| */ |
| int main(int argc, char **argv, char **envp) |
| { |
| int sock, fd, ret; |
| |
| #ifdef SOCKET_SCM_DEBUG |
| int i; |
| for (i = 0; i < argc; i++) { |
| fprintf(stderr, "Parameter %d: %s\n", i, argv[i]); |
| } |
| #endif |
| |
| if (argc != 3) { |
| fprintf(stderr, |
| "Usage: %s < socket-fd > < file-path >\n", |
| argv[0]); |
| return EXIT_FAILURE; |
| } |
| |
| |
| sock = get_fd_num(argv[1], false); |
| if (sock < 0) { |
| return EXIT_FAILURE; |
| } |
| |
| fd = get_fd_num(argv[2], true); |
| if (fd < 0) { |
| /* Now only open a file in readonly mode for test purpose. If more |
| precise control is needed, use python script in file operation, which |
| is supposed to fork and exec this program. */ |
| fd = open(argv[2], O_RDONLY); |
| if (fd < 0) { |
| fprintf(stderr, "Failed to open file '%s'\n", argv[2]); |
| return EXIT_FAILURE; |
| } |
| } |
| |
| ret = send_fd(sock, fd); |
| if (ret < 0) { |
| close(fd); |
| return EXIT_FAILURE; |
| } |
| |
| close(fd); |
| return EXIT_SUCCESS; |
| } |