1 | // This is free and unencumbered software released into the public domain. |
---|
2 | #define _GNU_SOURCE // make dlfcn.h define RTLD_NEXT |
---|
3 | #include <dirent.h> |
---|
4 | #include <dlfcn.h> |
---|
5 | #include <errno.h> |
---|
6 | #include <signal.h> |
---|
7 | #include <stdio.h> // perror() |
---|
8 | #include <stdlib.h> // abort() |
---|
9 | #include <unistd.h> // read() |
---|
10 | |
---|
11 | |
---|
12 | static void |
---|
13 | die_perror(const char *str) |
---|
14 | { |
---|
15 | perror(str); |
---|
16 | exit(1); |
---|
17 | } |
---|
18 | |
---|
19 | static void |
---|
20 | mc_test_wait(void) |
---|
21 | { |
---|
22 | sigset_t orig_mask, sigwinch; |
---|
23 | static int done = 0; |
---|
24 | const int test_fd = 3; |
---|
25 | |
---|
26 | if (done) return; |
---|
27 | done = 1; |
---|
28 | |
---|
29 | sigemptyset(&sigwinch); |
---|
30 | sigaddset(&sigwinch, SIGWINCH); |
---|
31 | errno = pthread_sigmask(SIG_BLOCK, &sigwinch, &orig_mask); |
---|
32 | if (errno) { |
---|
33 | die_perror("pthread_sigmask"); |
---|
34 | } |
---|
35 | |
---|
36 | // test the parent process we're ready for our SIGWINCH |
---|
37 | do {} while (write(test_fd, "", 1) < 0 && errno == EINTR); |
---|
38 | |
---|
39 | // wait for SIGWINCH |
---|
40 | sigsuspend(&orig_mask); |
---|
41 | do {} while (close(test_fd) < 0 && errno == EINTR); |
---|
42 | |
---|
43 | errno = pthread_sigmask(SIG_SETMASK, &orig_mask, NULL); |
---|
44 | if (errno) { |
---|
45 | die_perror("pthread_sigmask"); |
---|
46 | } |
---|
47 | } |
---|
48 | |
---|
49 | struct dirent * |
---|
50 | readdir(DIR *dirp) |
---|
51 | { |
---|
52 | struct dirent *ret = NULL; |
---|
53 | struct dirent *(*real_fn)(DIR*); |
---|
54 | |
---|
55 | mc_test_wait(); |
---|
56 | |
---|
57 | real_fn = dlsym(RTLD_NEXT, __func__); |
---|
58 | if (!real_fn) { |
---|
59 | errno = ELIBACC; |
---|
60 | goto out; |
---|
61 | } |
---|
62 | ret = real_fn(dirp); |
---|
63 | out: |
---|
64 | return ret; |
---|
65 | } |
---|