Mercurial > hg > octave-shane > gnulib-hg
view lib/passfd.c @ 14421:f23a6a383241
passfd module, part 3.
* lib/passfd.h (recvfd): Add a flags argument.
* lib/passfd.c: Include <fcntl.h>, cloexec.h.
(recvfd): Add a flags argument.
* m4/afunix.m4 (gl_SOCKET_AFUNIX): Test whether MSG_CMSG_CLOEXEC
exists.
* modules/passfd (Depends-on): Add cloexec.
Suggested by Eric Blake.
author | Bastien Roucariès <roucaries.bastien@gmail.com> |
---|---|
date | Sun, 13 Mar 2011 16:36:30 +0100 |
parents | 08622275f761 |
children | 4c39cf933978 |
line wrap: on
line source
/* Copyright (C) 2011 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <config.h> /* Specification. */ #include "passfd.h" #include <errno.h> #include <fcntl.h> #include <stddef.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <unistd.h> #include <sys/socket.h> #if HAVE_SYS_UN_H # include <sys/un.h> #endif #include "cloexec.h" /* sendfd sends the file descriptor fd along the socket to a process calling recvfd on the other end. Return 0 on success, or -1 with errno set in case of error. */ int sendfd (int sock, int fd) { char send = 0; struct iovec iov[1]; struct msghdr msg; /* send at least one char */ iov[0].iov_base = &send; iov[0].iov_len = 1; msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_name = 0; msg.msg_namelen = 0; { #if HAVE_UNIXSOCKET_SCM_RIGHTS_BSD44_WAY struct cmsghdr *cmsg; char buf[CMSG_SPACE (sizeof (fd))]; msg.msg_control = buf; msg.msg_controllen = sizeof (buf); cmsg = CMSG_FIRSTHDR (&msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN (sizeof (int)); /* Initialize the payload: */ memcpy (CMSG_DATA (cmsg), &fd, sizeof (fd)); msg.msg_controllen = cmsg->cmsg_len; #elif HAVE_UNIXSOCKET_SCM_RIGHTS_BSD43_WAY msg.msg_accrights = &fd; msg.msg_accrightslen = sizeof (fd); #else errno = ENOSYS; return -1; #endif } if (sendmsg (sock, &msg, 0) != iov[0].iov_len) return -1; return 0; } /* recvfd receives a file descriptor through the socket. The flags are a bitmask, possibly including O_CLOEXEC (defined in <fcntl.h>). Return 0 on success, or -1 with errno set in case of error. */ int recvfd (int sock, int flags) { char recv = 0; struct iovec iov[1]; struct msghdr msg; if ((flags & ~O_CLOEXEC) != 0) { errno = EINVAL; return -1; } /* send at least one char */ iov[0].iov_base = &recv; iov[0].iov_len = 1; msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_name = 0; msg.msg_namelen = 0; { #if HAVE_UNIXSOCKET_SCM_RIGHTS_BSD44_WAY int fd; struct cmsghdr *cmsg; char buf[CMSG_SPACE (sizeof (fd))]; const int mone = -1; # if HAVE_MSG_CMSG_CLOEXEC int flags_recvmsg = (flags & O_CLOEXEC ? MSG_CMSG_CLOEXEC : 0); # else int flags_recvmsg = 0; # endif msg.msg_control = buf; msg.msg_controllen = sizeof (buf); cmsg = CMSG_FIRSTHDR (&msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN (sizeof (int)); /* Initialize the payload: */ memcpy (CMSG_DATA (cmsg), &mone, sizeof (mone)); msg.msg_controllen = cmsg->cmsg_len; if (recvmsg (sock, &msg, flags_recvmsg) < 0) return -1; cmsg = CMSG_FIRSTHDR (&msg); /* be paranoiac */ if (cmsg == NULL || cmsg->cmsg_len != CMSG_LEN (sizeof (int)) || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { /* fake errno: at end the file is not available */ errno = EACCES; return -1; } memcpy (&fd, CMSG_DATA (cmsg), sizeof (fd)); # if !HAVE_MSG_CMSG_CLOEXEC /* set close-on-exec flag */ if (flags & O_CLOEXEC) { if (set_cloexec_flag (fd, true) < 0) { int saved_errno = errno; (void) close (fd); errno = saved_errno; return -1; } } # endif return fd; #elif HAVE_UNIXSOCKET_SCM_RIGHTS_BSD43_WAY int fd; msg.msg_accrights = &fd; msg.msg_accrightslen = sizeof (fd); if (recvmsg (sock, &msg, 0) < 0) return -1; /* set close-on-exec flag */ if (flags & O_CLOEXEC) { if (set_cloexec_flag (fd, true) < 0) { int saved_errno = errno; (void) close (fd); errno = saved_errno; return -1; } } return fd; #else errno = ENOSYS; return -1; #endif } }