summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/aio/aio.c6
-rw-r--r--src/internal/pthread_impl.h1
-rw-r--r--src/passwd/getspnam.c3
-rw-r--r--src/passwd/getspnam_r.c11
-rw-r--r--src/signal/sigaction.c6
-rw-r--r--src/thread/__timedwait.c8
-rw-r--r--src/thread/pthread_sigmask.c2
-rw-r--r--src/thread/sem_timedwait.c2
8 files changed, 32 insertions, 7 deletions
diff --git a/src/aio/aio.c b/src/aio/aio.c
index dae97cc6..6d34fa86 100644
--- a/src/aio/aio.c
+++ b/src/aio/aio.c
@@ -280,6 +280,8 @@ static int submit(struct aiocb *cb, int op)
if (!q) {
if (errno != EBADF) errno = EAGAIN;
+ cb->__ret = -1;
+ cb->__err = errno;
return -1;
}
q->ref++;
@@ -303,8 +305,8 @@ static int submit(struct aiocb *cb, int op)
if (pthread_create(&td, &a, io_thread_func, &args)) {
pthread_mutex_lock(&q->lock);
__aio_unref_queue(q);
- errno = EAGAIN;
- ret = -1;
+ cb->__err = errno = EAGAIN;
+ cb->__ret = ret = -1;
}
pthread_sigmask(SIG_SETMASK, &origmask, 0);
diff --git a/src/internal/pthread_impl.h b/src/internal/pthread_impl.h
index 7a25b88e..58ecce90 100644
--- a/src/internal/pthread_impl.h
+++ b/src/internal/pthread_impl.h
@@ -156,6 +156,7 @@ extern hidden volatile int __block_new_threads;
extern hidden volatile size_t __pthread_tsd_size;
extern hidden void *__pthread_tsd_main[];
extern hidden volatile int __aio_fut;
+extern hidden volatile int __eintr_valid_flag;
hidden int __clone(int (*)(void *), void *, int, void *, ...);
hidden int __set_thread_area(void *);
diff --git a/src/passwd/getspnam.c b/src/passwd/getspnam.c
index 041f8965..709b526d 100644
--- a/src/passwd/getspnam.c
+++ b/src/passwd/getspnam.c
@@ -8,10 +8,11 @@ struct spwd *getspnam(const char *name)
static char *line;
struct spwd *res;
int e;
+ int orig_errno = errno;
if (!line) line = malloc(LINE_LIM);
if (!line) return 0;
e = getspnam_r(name, &sp, line, LINE_LIM, &res);
- if (e) errno = e;
+ errno = e ? e : orig_errno;
return res;
}
diff --git a/src/passwd/getspnam_r.c b/src/passwd/getspnam_r.c
index 541206fa..541e8531 100644
--- a/src/passwd/getspnam_r.c
+++ b/src/passwd/getspnam_r.c
@@ -67,6 +67,7 @@ int getspnam_r(const char *name, struct spwd *sp, char *buf, size_t size, struct
size_t k, l = strlen(name);
int skip = 0;
int cs;
+ int orig_errno = errno;
*res = 0;
@@ -93,8 +94,14 @@ int getspnam_r(const char *name, struct spwd *sp, char *buf, size_t size, struct
return errno;
}
} else {
+ if (errno != ENOENT && errno != ENOTDIR)
+ return errno;
f = fopen("/etc/shadow", "rbe");
- if (!f) return errno;
+ if (!f) {
+ if (errno != ENOENT && errno != ENOTDIR)
+ return errno;
+ return 0;
+ }
}
pthread_cleanup_push(cleanup, f);
@@ -113,6 +120,6 @@ int getspnam_r(const char *name, struct spwd *sp, char *buf, size_t size, struct
break;
}
pthread_cleanup_pop(1);
- if (rv) errno = rv;
+ errno = rv ? rv : orig_errno;
return rv;
}
diff --git a/src/signal/sigaction.c b/src/signal/sigaction.c
index af47195e..05445089 100644
--- a/src/signal/sigaction.c
+++ b/src/signal/sigaction.c
@@ -21,6 +21,8 @@ void __get_handler_set(sigset_t *set)
memcpy(set, handler_set, sizeof handler_set);
}
+volatile int __eintr_valid_flag;
+
int __libc_sigaction(int sig, const struct sigaction *restrict sa, struct sigaction *restrict old)
{
struct k_sigaction ksa, ksa_old;
@@ -43,6 +45,10 @@ int __libc_sigaction(int sig, const struct sigaction *restrict sa, struct sigact
SIGPT_SET, 0, _NSIG/8);
unmask_done = 1;
}
+
+ if (!(sa->sa_flags & SA_RESTART)) {
+ a_store(&__eintr_valid_flag, 1);
+ }
}
/* Changing the disposition of SIGABRT to anything but
* SIG_DFL requires a lock, so that it cannot be changed
diff --git a/src/thread/__timedwait.c b/src/thread/__timedwait.c
index 229db313..ae19bd63 100644
--- a/src/thread/__timedwait.c
+++ b/src/thread/__timedwait.c
@@ -5,6 +5,9 @@
#include "syscall.h"
#include "pthread_impl.h"
+static volatile int dummy = 0;
+weak_alias(dummy, __eintr_valid_flag);
+
int __timedwait_cp(volatile int *addr, int val,
clockid_t clk, const struct timespec *at, int priv)
{
@@ -28,6 +31,11 @@ int __timedwait_cp(volatile int *addr, int val,
r = -__syscall_cp(SYS_futex, addr, FUTEX_WAIT|priv, val, top);
if (r == ENOSYS) r = -__syscall_cp(SYS_futex, addr, FUTEX_WAIT, val, top);
if (r != EINTR && r != ETIMEDOUT && r != ECANCELED) r = 0;
+ /* Mitigate bug in old kernels wrongly reporting EINTR for non-
+ * interrupting (SA_RESTART) signal handlers. This is only practical
+ * when NO interrupting signal handlers have been installed, and
+ * works by sigaction tracking whether that's the case. */
+ if (r == EINTR && !__eintr_valid_flag) r = 0;
return r;
}
diff --git a/src/thread/pthread_sigmask.c b/src/thread/pthread_sigmask.c
index 88c333f6..f188782a 100644
--- a/src/thread/pthread_sigmask.c
+++ b/src/thread/pthread_sigmask.c
@@ -5,7 +5,7 @@
int pthread_sigmask(int how, const sigset_t *restrict set, sigset_t *restrict old)
{
int ret;
- if ((unsigned)how - SIG_BLOCK > 2U) return EINVAL;
+ if (set && (unsigned)how - SIG_BLOCK > 2U) return EINVAL;
ret = -__syscall(SYS_rt_sigprocmask, how, set, old, _NSIG/8);
if (!ret && old) {
if (sizeof old->__bits[0] == 8) {
diff --git a/src/thread/sem_timedwait.c b/src/thread/sem_timedwait.c
index 8132eb1b..58d3ebfe 100644
--- a/src/thread/sem_timedwait.c
+++ b/src/thread/sem_timedwait.c
@@ -22,7 +22,7 @@ int sem_timedwait(sem_t *restrict sem, const struct timespec *restrict at)
pthread_cleanup_push(cleanup, (void *)(sem->__val+1));
r = __timedwait_cp(sem->__val, -1, CLOCK_REALTIME, at, sem->__val[2]);
pthread_cleanup_pop(1);
- if (r && r != EINTR) {
+ if (r) {
errno = r;
return -1;
}