summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Nieder <jrnieder@gmail.com>2012-01-11 17:50:10 -0600
committerJunio C Hamano <gitster@pobox.com>2012-01-11 17:37:10 -0800
commit06121a0a8328c8aaa7a023cf6ebb142e9dc2b45c (patch)
treeb0900ae8c603123769707ea636cced6ea5998c7f
parent8ec6c8d79567a71ca3c6f1ec73eb453d371b1ade (diff)
downloadgit-06121a0a8328c8aaa7a023cf6ebb142e9dc2b45c.tar.gz
unix-socket: do not let close() or chdir() clobber errno during cleanup
unix_stream_connect and unix_stream_listen return -1 on error, with errno set by the failing underlying call to allow the caller to write a useful diagnosis. Unfortunately the error path involves a few system calls itself, such as close(), that can themselves touch errno. This is not as worrisome as it might sound. If close() fails, this just means substituting one meaningful error message for another, which is perfectly fine. However, when the call _succeeds_, it is allowed to (and sometimes might) clobber errno along the way with some undefined value, so it is good higiene to save errno and restore it immediately before returning to the caller. Do so. Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r--unix-socket.c39
1 files changed, 22 insertions, 17 deletions
diff --git a/unix-socket.c b/unix-socket.c
index 7d8bec6158..01f119f970 100644
--- a/unix-socket.c
+++ b/unix-socket.c
@@ -73,25 +73,29 @@ static int unix_sockaddr_init(struct sockaddr_un *sa, const char *path,
int unix_stream_connect(const char *path)
{
- int fd;
+ int fd, saved_errno;
struct sockaddr_un sa;
struct unix_sockaddr_context ctx;
if (unix_sockaddr_init(&sa, path, &ctx) < 0)
return -1;
fd = unix_stream_socket();
- if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
- unix_sockaddr_cleanup(&ctx);
- close(fd);
- return -1;
- }
+ if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0)
+ goto fail;
unix_sockaddr_cleanup(&ctx);
return fd;
+
+fail:
+ saved_errno = errno;
+ unix_sockaddr_cleanup(&ctx);
+ close(fd);
+ errno = saved_errno;
+ return -1;
}
int unix_stream_listen(const char *path)
{
- int fd;
+ int fd, saved_errno;
struct sockaddr_un sa;
struct unix_sockaddr_context ctx;
@@ -100,18 +104,19 @@ int unix_stream_listen(const char *path)
fd = unix_stream_socket();
unlink(path);
- if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
- unix_sockaddr_cleanup(&ctx);
- close(fd);
- return -1;
- }
+ if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0)
+ goto fail;
- if (listen(fd, 5) < 0) {
- unix_sockaddr_cleanup(&ctx);
- close(fd);
- return -1;
- }
+ if (listen(fd, 5) < 0)
+ goto fail;
unix_sockaddr_cleanup(&ctx);
return fd;
+
+fail:
+ saved_errno = errno;
+ unix_sockaddr_cleanup(&ctx);
+ close(fd);
+ errno = saved_errno;
+ return -1;
}