--- fam-2.6.8/fam/DNotify.c++.kernel-work-around 2006-03-21 11:19:27.000000000 -0500 +++ fam-2.6.8/fam/DNotify.c++.kernel-work-around 2006-03-21 12:26:51.000000000 -0500 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include "DNotify.h" @@ -77,8 +78,64 @@ struct DNotify::ChangeEventData ino_t file_ino; }; +volatile sig_atomic_t kernel_and_libc_siginfo_mismatch = false; +static int pipe_fds[2]; + +void +detection_signal_handler(int sig, siginfo_t *si, void *data) +{ + if (si->si_fd != pipe_fds[0]) + kernel_and_libc_siginfo_mismatch = true; +} + +void +detect_kernel_and_libc_siginfo_mismatch (void) +{ + struct sigaction action = { 0 }, old_action; + pid_t child_pid; + + if (socketpair (AF_UNIX, SOCK_DGRAM, 0, pipe_fds) == 0) + { + sigemptyset (&action.sa_mask); + action.sa_sigaction = detection_signal_handler; + action.sa_flags = SA_SIGINFO; + + sigaction (SIGIO, &action, &old_action); + + fcntl(pipe_fds[0], F_SETSIG, SIGIO); + fcntl(pipe_fds[0], F_SETOWN, getpid ()); + fcntl(pipe_fds[0], F_SETFL, + fcntl (pipe_fds[0], F_GETFL) | O_ASYNC | O_NONBLOCK); + + fcntl(pipe_fds[1], F_SETFL, + fcntl (pipe_fds[1], F_GETFL) | O_NONBLOCK); + + child_pid = fork(); + + if (child_pid == 0) + { + close (pipe_fds[0]); + write (pipe_fds[1], "", 1); + close (pipe_fds[1]); + _exit (0); + } + close(pipe_fds[1]); + + if (child_pid > 0) + waitpid (child_pid, NULL, 0); + + sigaction(SIGIO, &old_action, NULL); + + close(pipe_fds[0]); + } +} + DNotify::DNotify(EventHandler h) { + static bool run_before = false; + + if (!run_before) + detect_kernel_and_libc_siginfo_mismatch (); assert(ehandler == NULL); ehandler = h; } @@ -130,6 +187,16 @@ DNotify::signal_handler(int sig, siginfo { int left; char c = 'x'; + int my_si_fd; + + /* Some kernels used int for si_band, but libc uses long. This + means we get the wrong si_fd. This is a fix, but only works + for such kernels. + */ + if (kernel_and_libc_siginfo_mismatch) + my_si_fd = *( ((int *)&si->si_band) + 1); + else + my_si_fd = si->si_fd; if (queue_head <= queue_tail) left = (QUEUESIZE + queue_head) - queue_tail; @@ -148,7 +215,7 @@ DNotify::signal_handler(int sig, siginfo } else { - change_queue[queue_tail] = si->si_fd; + change_queue[queue_tail] = my_si_fd; queue_tail = (queue_tail + 1) % QUEUESIZE; }