I noticed that recvfd() fails with errno set to EACCES if the other end of the socket has closed (such as if it calls _exit()); but "Permission denied" as the strerror() message doesn't read very well. Any objections to a patch along these lines to give a nicer error message "Transport endpoint is not connected"? Or any better errno value to use? ECONNABORTED? ENOLINK?
diff --git i/ChangeLog w/ChangeLog index 25b59e3..f608556 100644 --- i/ChangeLog +++ w/ChangeLog @@ -1,3 +1,8 @@ +2013-12-21 Eric Blake <ebl...@redhat.com> + + passfd: give nicer error for recvfd at eof + * lib/passfd.c (recvfd): Fake ENOTCONN if other end closes early. + 2013-12-04 Eric Blake <ebl...@redhat.com> absolute-header: port to IBM Blue Gene compilers diff --git i/lib/passfd.c w/lib/passfd.c index 44a9de7..5388ca5 100644 --- i/lib/passfd.c +++ w/lib/passfd.c @@ -110,6 +110,7 @@ recvfd (int sock, int flags) struct iovec iov; struct msghdr msg; int fd = -1; + ssize_t len; # ifdef CMSG_FIRSTHDR struct cmsghdr *cmsg; char buf[CMSG_SPACE (sizeof fd)]; @@ -142,16 +143,17 @@ recvfd (int sock, int flags) memcpy (CMSG_DATA (cmsg), &fd, sizeof fd); msg.msg_controllen = cmsg->cmsg_len; - if (recvmsg (sock, &msg, flags_recvmsg) < 0) + len = recvmsg (sock, &msg, flags_recvmsg); + if (len < 0) return -1; cmsg = CMSG_FIRSTHDR (&msg); /* be paranoiac */ - if (cmsg == NULL || cmsg->cmsg_len != CMSG_LEN (sizeof fd) + if (len == 0 || cmsg == NULL || cmsg->cmsg_len != CMSG_LEN (sizeof fd) || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { /* fake errno: at end the file is not available */ - errno = EACCES; + errno = len ? EACCES : ENOTCONN; return -1; } Here's the crude program I tested with: $ cat foo.c #include <config.h> #include <stdlib.h> #include <errno.h> #include <stdio.h> #include <unistd.h> #include <sys/socket.h> #include <sys/wait.h> #include "passfd.h" int main(void) { int fds[2]; pid_t pid; int fd; int status; if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) exit(1); pid = fork(); if (pid < 0) exit(2); if (pid == 0) { sleep(3); _exit(127); } close(fds[1]); fd = recvfd(fds[0], 0); if (fd < 0) { perror("hi"); exit(3); } if (waitpid(pid, &status, 0) != pid) exit(4); if (status) exit(5); exit(0); } $ gcc -o foo -Wall -I. -Ignulib/lib foo.c -g gnulib/lib/.libs/libgnu.a for a project that was using the passlib module from gnulib. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
signature.asc
Description: OpenPGP digital signature