summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSébastien Helleu <flashcode@flashtux.org>2015-07-18 20:03:34 +0200
committerSébastien Helleu <flashcode@flashtux.org>2015-07-18 20:03:34 +0200
commit3b2ee85b04f8cfabb10b42daf41f91dc95d368eb (patch)
tree8ae678e325b807da9c3b587a58b6e92c481ea895
parent23983b125aa37a87ee439cd9b6f7f417e8b2c079 (diff)
downloadweechat-3b2ee85b04f8cfabb10b42daf41f91dc95d368eb.zip
core: fix crash if a file descriptor used in hook_fd() is too high (> 1024 on Linux/BSD) (closes #465)
The calls to select() are replaced by poll(), which doesn't have limitation on file descriptor number.
-rw-r--r--ChangeLog.asciidoc2
-rw-r--r--doc/en/weechat_plugin_api.en.asciidoc3
-rw-r--r--doc/fr/weechat_plugin_api.fr.asciidoc3
-rw-r--r--doc/it/weechat_plugin_api.it.asciidoc5
-rw-r--r--doc/ja/weechat_plugin_api.ja.asciidoc4
-rw-r--r--src/core/wee-hook.c257
-rw-r--r--src/core/wee-hook.h6
-rw-r--r--src/core/wee-network.c13
-rw-r--r--src/gui/curses/gui-curses-main.c21
9 files changed, 182 insertions, 132 deletions
diff --git a/ChangeLog.asciidoc b/ChangeLog.asciidoc
index ae5315c33..62bb574ab 100644
--- a/ChangeLog.asciidoc
+++ b/ChangeLog.asciidoc
@@ -19,6 +19,8 @@ https://weechat.org/files/releasenotes/ReleaseNotes-devel.html[release notes]
=== New features
+* core: fix crash if a file descriptor used in hook_fd() is too high
+ (> 1024 on Linux/BSD) (closes #465)
* core: add option weechat.look.confirm_upgrade (closes #463)
* core: allow ctrl-C to exit WeeChat when the passphrase is asked on startup
(closes #452)
diff --git a/doc/en/weechat_plugin_api.en.asciidoc b/doc/en/weechat_plugin_api.en.asciidoc
index c9b12cb88..222153ffd 100644
--- a/doc/en/weechat_plugin_api.en.asciidoc
+++ b/doc/en/weechat_plugin_api.en.asciidoc
@@ -7228,6 +7228,8 @@ hook = weechat.hook_timer(20 * 1000, 0, 0, "my_timer_cb", "")
==== hook_fd
+_Updated in 1.3._
+
Hook a file descriptor (file or socket).
Prototype:
@@ -7249,6 +7251,7 @@ Arguments:
* 'flag_read': 1 = catch read event, 0 = ignore
* 'flag_write': 1 = catch write event, 0 = ignore
* 'flag_exception': 1 = catch exception event, 0 = ignore
+ (_WeeChat ≥ 1.3_: this argument is ignored and not used any more)
* 'callback': function called a selected event occurs for file (or socket),
arguments and return value:
** 'void *data': pointer
diff --git a/doc/fr/weechat_plugin_api.fr.asciidoc b/doc/fr/weechat_plugin_api.fr.asciidoc
index 79b5e7e64..d24c4f53e 100644
--- a/doc/fr/weechat_plugin_api.fr.asciidoc
+++ b/doc/fr/weechat_plugin_api.fr.asciidoc
@@ -7352,6 +7352,8 @@ hook = weechat.hook_timer(20 * 1000, 0, 0, "my_timer_cb", "")
==== hook_fd
+_Mis à jour dans la 1.3._
+
Accrocher un descripteur de fichier (fichier ou socket).
Prototype :
@@ -7373,6 +7375,7 @@ Paramètres :
* 'flag_read' : 1 = intercepter un évènement de lecture, 0 = ignorer
* 'flag_write' : 1 = intercepter un évènement d'écriture, 0 = ignorer
* 'flag_exception' : 1 = intercepter un évènement d'exception, 0 = ignorer
+ (_WeeChat ≥ 1.3_ : ce paramètre est ignoré et n'est plus utilisé)
* 'callback' : fonction appelée lorsqu'un des évènements sélectionnés se
produit pour le fichier (ou le socket), paramètres et valeur de retour :
** 'void *data' : pointeur
diff --git a/doc/it/weechat_plugin_api.it.asciidoc b/doc/it/weechat_plugin_api.it.asciidoc
index 46a547249..e14081dbb 100644
--- a/doc/it/weechat_plugin_api.it.asciidoc
+++ b/doc/it/weechat_plugin_api.it.asciidoc
@@ -7391,6 +7391,9 @@ hook = weechat.hook_timer(20 * 1000, 0, 0, "my_timer_cb", "")
==== hook_fd
+// TRANSLATION MISSING
+_Updated in 1.3._
+
Hook su un descrittore file (file oppure socket).
Prototipo:
@@ -7411,7 +7414,9 @@ Argomenti:
* 'fd': descrittore file
* 'flag_read': 1 = cattura l'evento lettura (read), 0 = ignora
* 'flag_write': 1 = cattura l'evento scrittura (write), 0 = ignora
+// TRANSLATION MISSING
* 'flag_exception': 1 = cattura l'eccezione evento (event), 0 = ignora
+ (_WeeChat ≥ 1.3_: this argument is ignored and not used any more)
* 'callback': funzione che chiama un evento selezionato che si verifica
per un file (o un socket), argomenti e valore restituito:
** 'void *data': puntatore
diff --git a/doc/ja/weechat_plugin_api.ja.asciidoc b/doc/ja/weechat_plugin_api.ja.asciidoc
index ff5d64ff0..df591c665 100644
--- a/doc/ja/weechat_plugin_api.ja.asciidoc
+++ b/doc/ja/weechat_plugin_api.ja.asciidoc
@@ -7227,6 +7227,8 @@ hook = weechat.hook_timer(20 * 1000, 0, 0, "my_timer_cb", "")
==== hook_fd
+_バージョン 1.3 で更新。_
+
ファイルディスクリプタ (ファイルやソケット) をフック。
プロトタイプ:
@@ -7247,7 +7249,9 @@ struct t_hook *weechat_hook_fd (int fd,
* 'fd': ファイルディスクリプタ
* 'flag_read': 1 = 読み込みイベントをキャッチ、0 = 無視
* 'flag_write': 1 = 書き込みイベントをキャッチ、0 = 無視
+// TRANSLATION MISSING
* 'flag_exception': 1 = 例外イベントをキャッチ、0 = 無視
+ (_WeeChat ≥ 1.3_: this argument is ignored and not used any more)
* 'callback': ファイル (またはソケット) に対してキャッチしたいイベントが発生した場合に実行する関数、
引数と戻り値:
** 'void *data': ポインタ
diff --git a/src/core/wee-hook.c b/src/core/wee-hook.c
index f6bbdc097..c0c195eef 100644
--- a/src/core/wee-hook.c
+++ b/src/core/wee-hook.c
@@ -32,7 +32,7 @@
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
-#include <sys/select.h>
+#include <poll.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
@@ -74,6 +74,9 @@ int hook_exec_recursion = 0; /* 1 when a hook is executed */
time_t hook_last_system_time = 0; /* used to detect system clock skew */
int real_delete_pending = 0; /* 1 if some hooks must be deleted */
+struct pollfd *hook_fd_pollfd = NULL; /* file descriptors for poll() */
+int hook_fd_pollfd_count = 0; /* number of file descriptors */
+
void hook_process_run (struct t_hook *hook_process);
@@ -122,6 +125,41 @@ hook_search_type (const char *type)
}
/*
+ * Reallocates the "struct pollfd" array for poll().
+ */
+
+void
+hook_fd_realloc_pollfd ()
+{
+ struct pollfd *ptr_pollfd;
+ int count;
+
+ if (hooks_count[HOOK_TYPE_FD] == hook_fd_pollfd_count)
+ return;
+
+ count = hooks_count[HOOK_TYPE_FD];
+
+ if (count == 0)
+ {
+ if (hook_fd_pollfd)
+ {
+ free (hook_fd_pollfd);
+ hook_fd_pollfd = NULL;
+ }
+ }
+ else
+ {
+ ptr_pollfd = realloc (hook_fd_pollfd,
+ count * sizeof (struct pollfd));
+ if (!ptr_pollfd)
+ return;
+ hook_fd_pollfd = ptr_pollfd;
+ }
+
+ hook_fd_pollfd_count = count;
+}
+
+/*
* Searches for position of hook in list (to keep hooks sorted).
*
* Hooks are sorted by priority, except commands which are sorted by command
@@ -208,6 +246,9 @@ hook_add_to_list (struct t_hook *new_hook)
hooks_count[new_hook->type]++;
hooks_count_total++;
+
+ if (new_hook->type == HOOK_TYPE_FD)
+ hook_fd_realloc_pollfd ();
}
/*
@@ -241,6 +282,9 @@ hook_remove_from_list (struct t_hook *hook)
hooks_count[type]--;
hooks_count_total--;
+
+ if (type == HOOK_TYPE_FD)
+ hook_fd_realloc_pollfd ();
}
/*
@@ -1087,73 +1131,81 @@ hook_timer_check_system_clock ()
}
/*
- * Sets time until next timeout.
+ * Returns time until next timeout (in milliseconds).
*/
-void
-hook_timer_time_to_next (struct timeval *tv_timeout)
+int
+hook_timer_get_time_to_next ()
{
struct t_hook *ptr_hook;
- int found;
- struct timeval tv_now;
+ int found, timeout;
+ struct timeval tv_now, tv_timeout;
long diff_usec;
hook_timer_check_system_clock ();
found = 0;
- tv_timeout->tv_sec = 0;
- tv_timeout->tv_usec = 0;
+ tv_timeout.tv_sec = 0;
+ tv_timeout.tv_usec = 0;
for (ptr_hook = weechat_hooks[HOOK_TYPE_TIMER]; ptr_hook;
ptr_hook = ptr_hook->next_hook)
{
if (!ptr_hook->deleted
&& (!found
- || (util_timeval_cmp (&HOOK_TIMER(ptr_hook, next_exec), tv_timeout) < 0)))
+ || (util_timeval_cmp (&HOOK_TIMER(ptr_hook, next_exec),
+ &tv_timeout) < 0)))
{
found = 1;
- tv_timeout->tv_sec = HOOK_TIMER(ptr_hook, next_exec).tv_sec;
- tv_timeout->tv_usec = HOOK_TIMER(ptr_hook, next_exec).tv_usec;
+ tv_timeout.tv_sec = HOOK_TIMER(ptr_hook, next_exec).tv_sec;
+ tv_timeout.tv_usec = HOOK_TIMER(ptr_hook, next_exec).tv_usec;
}
}
/* no timeout found, return 2 seconds by default */
if (!found)
{
- tv_timeout->tv_sec = 2;
- tv_timeout->tv_usec = 0;
- return;
+ tv_timeout.tv_sec = 2;
+ tv_timeout.tv_usec = 0;
+ goto end;
}
gettimeofday (&tv_now, NULL);
/* next timeout is past date! */
- if (util_timeval_cmp (tv_timeout, &tv_now) < 0)
+ if (util_timeval_cmp (&tv_timeout, &tv_now) < 0)
{
- tv_timeout->tv_sec = 0;
- tv_timeout->tv_usec = 0;
- return;
+ tv_timeout.tv_sec = 0;
+ tv_timeout.tv_usec = 0;
+ goto end;
}
- tv_timeout->tv_sec = tv_timeout->tv_sec - tv_now.tv_sec;
- diff_usec = tv_timeout->tv_usec - tv_now.tv_usec;
+ tv_timeout.tv_sec = tv_timeout.tv_sec - tv_now.tv_sec;
+ diff_usec = tv_timeout.tv_usec - tv_now.tv_usec;
if (diff_usec >= 0)
- tv_timeout->tv_usec = diff_usec;
+ {
+ tv_timeout.tv_usec = diff_usec;
+ }
else
{
- tv_timeout->tv_sec--;
- tv_timeout->tv_usec = 1000000 + diff_usec;
+ tv_timeout.tv_sec--;
+ tv_timeout.tv_usec = 1000000 + diff_usec;
}
/*
* to detect clock skew, we ensure there's a call to timers every
* 2 seconds max
*/
- if (tv_timeout->tv_sec > 2)
+ if (tv_timeout.tv_sec >= 2)
{
- tv_timeout->tv_sec = 2;
- tv_timeout->tv_usec = 0;
+ tv_timeout.tv_sec = 2;
+ tv_timeout.tv_usec = 0;
}
+
+end:
+ /* return a number of milliseconds */
+ timeout = (tv_timeout.tv_sec * 1000) + (tv_timeout.tv_usec / 1000);
+ return (timeout < 1) ? 1 : timeout;
}
/*
@@ -1282,18 +1334,19 @@ hook_fd (struct t_weechat_plugin *plugin, int fd, int flag_read,
}
/*
- * Fills sets according to fd hooked.
- *
- * Returns highest fd set.
+ * Executes fd hooks:
+ * - poll() on fie descriptors
+ * - call of hook fd callbacks if needed.
*/
-int
-hook_fd_set (fd_set *read_fds, fd_set *write_fds, fd_set *exception_fds)
+void
+hook_fd_exec ()
{
- struct t_hook *ptr_hook;
- int max_fd;
+ int i, num_fd, timeout, ready, found;
+ struct t_hook *ptr_hook, *next_hook;
- max_fd = 0;
+ /* build an array of "struct pollfd" for poll() */
+ num_fd = 0;
for (ptr_hook = weechat_hooks[HOOK_TYPE_FD]; ptr_hook;
ptr_hook = ptr_hook->next_hook)
{
@@ -1315,40 +1368,29 @@ hook_fd_set (fd_set *read_fds, fd_set *write_fds, fd_set *exception_fds)
}
else
{
+ if (num_fd > hook_fd_pollfd_count)
+ break;
+
+ hook_fd_pollfd[num_fd].fd = HOOK_FD(ptr_hook, fd);
+ hook_fd_pollfd[num_fd].events = 0;
+ hook_fd_pollfd[num_fd].revents = 0;
if (HOOK_FD(ptr_hook, flags) & HOOK_FD_FLAG_READ)
- {
- FD_SET (HOOK_FD(ptr_hook, fd), read_fds);
- if (HOOK_FD(ptr_hook, fd) > max_fd)
- max_fd = HOOK_FD(ptr_hook, fd);
- }
+ hook_fd_pollfd[num_fd].events |= POLLIN;
if (HOOK_FD(ptr_hook, flags) & HOOK_FD_FLAG_WRITE)
- {
- FD_SET (HOOK_FD(ptr_hook, fd), write_fds);
- if (HOOK_FD(ptr_hook, fd) > max_fd)
- max_fd = HOOK_FD(ptr_hook, fd);
- }
- if (HOOK_FD(ptr_hook, flags) & HOOK_FD_FLAG_EXCEPTION)
- {
- FD_SET (HOOK_FD(ptr_hook, fd), exception_fds);
- if (HOOK_FD(ptr_hook, fd) > max_fd)
- max_fd = HOOK_FD(ptr_hook, fd);
- }
+ hook_fd_pollfd[num_fd].events |= POLLOUT;
+
+ num_fd++;
}
}
}
- return max_fd;
-}
-
-/*
- * Executes fd callbacks with sets.
- */
-
-void
-hook_fd_exec (fd_set *read_fds, fd_set *write_fds, fd_set *exception_fds)
-{
- struct t_hook *ptr_hook, *next_hook;
+ /* perform the poll() */
+ timeout = hook_timer_get_time_to_next ();
+ ready = poll (hook_fd_pollfd, num_fd, timeout);
+ if (ready <= 0)
+ return;
+ /* execute callbacks for file descriptors with activity */
hook_exec_start ();
ptr_hook = weechat_hooks[HOOK_TYPE_FD];
@@ -1357,18 +1399,25 @@ hook_fd_exec (fd_set *read_fds, fd_set *write_fds, fd_set *exception_fds)
next_hook = ptr_hook->next_hook;
if (!ptr_hook->deleted
- && !ptr_hook->running
- && (((HOOK_FD(ptr_hook, flags) & HOOK_FD_FLAG_READ)
- && (FD_ISSET(HOOK_FD(ptr_hook, fd), read_fds)))
- || ((HOOK_FD(ptr_hook, flags) & HOOK_FD_FLAG_WRITE)
- && (FD_ISSET(HOOK_FD(ptr_hook, fd), write_fds)))
- || ((HOOK_FD(ptr_hook, flags) & HOOK_FD_FLAG_EXCEPTION)
- && (FD_ISSET(HOOK_FD(ptr_hook, fd), exception_fds)))))
+ && !ptr_hook->running)
{
- ptr_hook->running = 1;
- (void) (HOOK_FD(ptr_hook, callback)) (ptr_hook->callback_data,
- HOOK_FD(ptr_hook, fd));
- ptr_hook->running = 0;
+ found = 0;
+ for (i = 0; i < num_fd; i++)
+ {
+ if (hook_fd_pollfd[i].fd == HOOK_FD(ptr_hook, fd)
+ && hook_fd_pollfd[i].revents)
+ {
+ found = 1;
+ break;
+ }
+ }
+ if (found)
+ {
+ ptr_hook->running = 1;
+ (void) (HOOK_FD(ptr_hook, callback)) (ptr_hook->callback_data,
+ HOOK_FD(ptr_hook, fd));
+ ptr_hook->running = 0;
+ }
}
ptr_hook = next_hook;
@@ -1784,9 +1833,8 @@ hook_process_child_read_stderr_cb (void *arg_hook_process, int fd)
void
hook_process_child_read_until_eof (struct t_hook *hook_process)
{
- struct timeval tv_timeout;
- fd_set read_fds, write_fds, except_fds;
- int count, fd_stdout, fd_stderr, max_fd, ready;
+ struct pollfd poll_fd[2];
+ int count, fd_stdout, fd_stderr, num_fd, ready, i;
fd_stdout = HOOK_PROCESS(hook_process, child_read[HOOK_PROCESS_STDOUT]);
fd_stderr = HOOK_PROCESS(hook_process, child_read[HOOK_PROCESS_STDERR]);
@@ -1798,52 +1846,53 @@ hook_process_child_read_until_eof (struct t_hook *hook_process)
count = 0;
while (count < 1024)
{
- FD_ZERO (&read_fds);
- FD_ZERO (&write_fds);
- FD_ZERO (&except_fds);
+ num_fd = 0;
- max_fd = -1;
if (HOOK_PROCESS(hook_process, hook_fd[HOOK_PROCESS_STDOUT])
&& ((fcntl (fd_stdout, F_GETFD) != -1) || (errno != EBADF)))
{
- FD_SET (fd_stdout, &read_fds);
- if (fd_stdout > max_fd)
- max_fd = fd_stdout;
+ poll_fd[num_fd].fd = fd_stdout;
+ poll_fd[num_fd].events = POLLIN;
+ poll_fd[num_fd].revents = 0;
+ num_fd++;
}
+
if (HOOK_PROCESS(hook_process, hook_fd[HOOK_PROCESS_STDERR])
&& ((fcntl (fd_stderr, F_GETFD) != -1) || (errno != EBADF)))
{
- FD_SET (fd_stderr, &read_fds);
- if (fd_stderr > max_fd)
- max_fd = fd_stderr;
+ poll_fd[num_fd].fd = fd_stderr;
+ poll_fd[num_fd].events = POLLIN;
+ poll_fd[num_fd].revents = 0;
+ num_fd++;
}
- if (max_fd < 0)
+ if (num_fd == 0)
break;
- tv_timeout.tv_sec = 0;
- tv_timeout.tv_usec = 0;
-
- ready = select (max_fd + 1,
- &read_fds, &write_fds, &except_fds,
- &tv_timeout);
+ ready = poll (poll_fd, num_fd, 0);
if (ready <= 0)
break;
- if (FD_ISSET(fd_stdout, &read_fds))
- {
- (void) hook_process_child_read_stdout_cb (
- hook_process,
- HOOK_PROCESS(hook_process,
- child_read[HOOK_PROCESS_STDOUT]));
- }
- if (FD_ISSET(fd_stderr, &read_fds))
+ for (i = 0; i < num_fd; i++)
{
- (void) hook_process_child_read_stderr_cb (
- hook_process,
- HOOK_PROCESS(hook_process,
- child_read[HOOK_PROCESS_STDERR]));
+ if (poll_fd[i].revents & POLLIN)
+ {
+ if (poll_fd[i].fd == fd_stdout)
+ {
+ (void) hook_process_child_read_stdout_cb (
+ hook_process,
+ HOOK_PROCESS(hook_process,
+ child_read[HOOK_PROCESS_STDOUT]));
+ }
+ else
+ {
+ (void) hook_process_child_read_stderr_cb (
+ hook_process,
+ HOOK_PROCESS(hook_process,
+ child_read[HOOK_PROCESS_STDERR]));
+ }
+ }
}
count++;
diff --git a/src/core/wee-hook.h b/src/core/wee-hook.h
index f7ab9de62..82de5b7bd 100644
--- a/src/core/wee-hook.h
+++ b/src/core/wee-hook.h
@@ -467,17 +467,13 @@ extern struct t_hook *hook_timer (struct t_weechat_plugin *plugin,
int max_calls,
t_hook_callback_timer *callback,
void *callback_data);
-extern void hook_timer_time_to_next (struct timeval *tv_timeout);
extern void hook_timer_exec ();
extern struct t_hook *hook_fd (struct t_weechat_plugin *plugin, int fd,
int flag_read, int flag_write,
int flag_exception,
t_hook_callback_fd *callback,
void *callback_data);
-extern int hook_fd_set (fd_set *read_fds, fd_set *write_fds,
- fd_set *exception_fds);
-extern void hook_fd_exec (fd_set *read_fds, fd_set *write_fds,
- fd_set *exception_fds);
+extern void hook_fd_exec ();
extern struct t_hook *hook_process (struct t_weechat_plugin *plugin,
const char *command,
int timeout,
diff --git a/src/core/wee-network.c b/src/core/wee-network.c
index 92aa021ab..7eb94ca49 100644
--- a/src/core/wee-network.c
+++ b/src/core/wee-network.c
@@ -39,7 +39,7 @@
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
-#include <sys/select.h>
+#include <poll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
@@ -611,7 +611,7 @@ network_pass_proxy (const char *proxy, int sock, const char *address, int port)
int
network_connect (int sock, const struct sockaddr *addr, socklen_t addrlen)
{
- fd_set write_fds;
+ struct pollfd poll_fd;
int ready, value;
socklen_t len;
@@ -628,9 +628,12 @@ network_connect (int sock, const struct sockaddr *addr, socklen_t addrlen)
*/
while (1)
{
- FD_ZERO (&write_fds);
- FD_SET (sock, &write_fds);
- ready = select (sock + 1, NULL, &write_fds, NULL, NULL);
+ poll_fd.fd = sock;
+ poll_fd.events = POLLOUT;
+ poll_fd.revents = 0;
+ ready = poll (&poll_fd, 1, -1);
+ if (ready < 0)
+ break;
if (ready > 0)
{
len = sizeof (value);
diff --git a/src/gui/curses/gui-curses-main.c b/src/gui/curses/gui-curses-main.c
index f83d8324a..090c1ef04 100644
--- a/src/gui/curses/gui-curses-main.c
+++ b/src/gui/curses/gui-curses-main.c
@@ -29,7 +29,6 @@
#include <string.h>
#include <signal.h>
#include <time.h>
-#include <sys/select.h>
#include "../../core/weechat.h"
#include "../../core/wee-command.h"
@@ -383,10 +382,6 @@ void
gui_main_loop ()
{
struct t_hook *hook_fd_keyboard;
- struct timeval tv_timeout;
- fd_set read_fds, write_fds, except_fds;
- int max_fd;
- int ready;
/* catch SIGWINCH signal: redraw screen */
util_catch_signal (SIGWINCH, &gui_main_signal_sigwinch);
@@ -399,7 +394,7 @@ gui_main_loop ()
while (!weechat_quit)
{
- /* execute hook timers */
+ /* execute timer hooks */
hook_timer_exec ();
/* auto reset of color pairs */
@@ -424,18 +419,8 @@ gui_main_loop ()
gui_color_pairs_auto_reset_pending = 0;
- /* wait for keyboard or network activity */
- FD_ZERO (&read_fds);
- FD_ZERO (&write_fds);
- FD_ZERO (&except_fds);
- max_fd = hook_fd_set (&read_fds, &write_fds, &except_fds);
- hook_timer_time_to_next (&tv_timeout);
- ready = select (max_fd + 1, &read_fds, &write_fds, &except_fds,
- &tv_timeout);
- if (ready > 0)
- {
- hook_fd_exec (&read_fds, &write_fds, &except_fds);
- }
+ /* execute fd hooks */
+ hook_fd_exec ();
}
/* remove keyboard hook */