Ticket #4630: readdir-wait.c

File readdir-wait.c, 1.2 KB (added by zaytsev, 8 hours ago)
Line 
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
12static void
13die_perror(const char *str)
14{
15        perror(str);
16        exit(1);
17}
18
19static void
20mc_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
49struct dirent *
50readdir(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);
63out:
64        return ret;
65}