diff options
author | Sebastien Helleu <flashcode@flashtux.org> | 2009-03-06 18:22:34 +0100 |
---|---|---|
committer | Sebastien Helleu <flashcode@flashtux.org> | 2009-03-06 18:22:34 +0100 |
commit | 8e551473641151d1e5f043ac279eca399daff5fb (patch) | |
tree | 0374c21edec94e29b550c61819bff51c1381c16f /src/core | |
parent | 0fd8bbc2de94705d94b56966d681264f73b48dd2 (diff) | |
download | weechat-8e551473641151d1e5f043ac279eca399daff5fb.zip |
Add new hook type "process": launch command with fork and catch result (rc/stdout/stderr) via callback
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/wee-command.c | 46 | ||||
-rw-r--r-- | src/core/wee-config.c | 3 | ||||
-rw-r--r-- | src/core/wee-hook.c | 380 | ||||
-rw-r--r-- | src/core/wee-hook.h | 58 | ||||
-rw-r--r-- | src/core/wee-network.c | 5 |
5 files changed, 465 insertions, 27 deletions
diff --git a/src/core/wee-command.c b/src/core/wee-command.c index 10295959c..45734d590 100644 --- a/src/core/wee-command.c +++ b/src/core/wee-command.c @@ -2053,6 +2053,7 @@ command_plugin_list (const char *name, int full) plugins_found++; /* plugin info */ + gui_chat_printf (NULL, ""); gui_chat_printf (NULL, " %s%s%s v%s - %s (%s)", GUI_COLOR(GUI_COLOR_CHAT_BUFFER), @@ -2161,7 +2162,26 @@ command_plugin_list (const char *name, int full) _(" exception") : ""); } } - + + /* process hooked */ + hook_found = 0; + for (ptr_hook = weechat_hooks[HOOK_TYPE_PROCESS]; ptr_hook; + ptr_hook = ptr_hook->next_hook) + { + if (!ptr_hook->deleted && (ptr_hook->plugin == ptr_plugin)) + { + if (!hook_found) + gui_chat_printf (NULL, + _(" process hooked:")); + hook_found = 1; + gui_chat_printf (NULL, + _(" command: '%s', child " + "pid: %d"), + (HOOK_PROCESS(ptr_hook, command)), + HOOK_PROCESS(ptr_hook, child_pid)); + } + } + /* connect hooked */ hook_found = 0; for (ptr_hook = weechat_hooks[HOOK_TYPE_CONNECT]; ptr_hook; @@ -2175,10 +2195,11 @@ command_plugin_list (const char *name, int full) hook_found = 1; gui_chat_printf (NULL, _(" socket: %d, address: %s, " - "port: %d"), + "port: %d, child pid: %d"), HOOK_CONNECT(ptr_hook, sock), HOOK_CONNECT(ptr_hook, address), - HOOK_CONNECT(ptr_hook, port)); + HOOK_CONNECT(ptr_hook, port), + HOOK_CONNECT(ptr_hook, child_pid)); } } @@ -3079,6 +3100,17 @@ command_upgrade (void *data, struct t_gui_buffer *buffer, (void) data; (void) buffer; (void) argv; + + /* it's forbidden to upgrade while there are some background process + (hook type "process" or "connect") */ + if (weechat_hooks[HOOK_TYPE_PROCESS] || weechat_hooks[HOOK_TYPE_CONNECT]) + { + gui_chat_printf (NULL, + _("%sCan't upgrade: there is one or more background " + "process (hook type 'process' or 'connect')"), + gui_chat_prefix[GUI_CHAT_PREFIX_ERROR]); + return WEECHAT_RC_OK; + } if (argc > 1) { @@ -3096,7 +3128,7 @@ command_upgrade (void *data, struct t_gui_buffer *buffer, gui_chat_prefix[GUI_CHAT_PREFIX_ERROR], ptr_binary); free (ptr_binary); - return WEECHAT_RC_ERROR; + return WEECHAT_RC_OK; } if ((!(stat_buf.st_mode & S_IXUSR)) && (!(stat_buf.st_mode & S_IXGRP)) && (!(stat_buf.st_mode & S_IXOTH))) @@ -3107,7 +3139,7 @@ command_upgrade (void *data, struct t_gui_buffer *buffer, gui_chat_prefix[GUI_CHAT_PREFIX_ERROR], ptr_binary); free (ptr_binary); - return WEECHAT_RC_ERROR; + return WEECHAT_RC_OK; } } } @@ -3119,7 +3151,7 @@ command_upgrade (void *data, struct t_gui_buffer *buffer, gui_chat_printf (NULL, _("%sNot enough memory"), gui_chat_prefix[GUI_CHAT_PREFIX_ERROR]); - return WEECHAT_RC_ERROR; + return WEECHAT_RC_OK; } gui_chat_printf (NULL, @@ -3135,7 +3167,7 @@ command_upgrade (void *data, struct t_gui_buffer *buffer, _("%sError: unable to save session in file"), gui_chat_prefix[GUI_CHAT_PREFIX_ERROR]); free (ptr_binary); - return WEECHAT_RC_ERROR; + return WEECHAT_RC_OK; } exec_args[0] = ptr_binary; diff --git a/src/core/wee-config.c b/src/core/wee-config.c index df2eb12bb..43ccfced1 100644 --- a/src/core/wee-config.c +++ b/src/core/wee-config.c @@ -322,7 +322,7 @@ config_change_color (void *data, struct t_config_option *option) */ int -config_day_change_timer_cb (void *data) +config_day_change_timer_cb (void *data, int remaining_calls) { struct timeval tv_time; struct tm *local_time; @@ -331,6 +331,7 @@ config_day_change_timer_cb (void *data) /* make C compiler happy */ (void) data; + (void) remaining_calls; gettimeofday (&tv_time, NULL); local_time = localtime (&tv_time.tv_sec); diff --git a/src/core/wee-hook.c b/src/core/wee-hook.c index 9422850ed..41a38f245 100644 --- a/src/core/wee-hook.c +++ b/src/core/wee-hook.c @@ -47,8 +47,8 @@ char *hook_type_string[HOOK_NUM_TYPES] = -{ "command", "command_run", "timer", "fd", "connect", "print", "signal", - "config", "completion", "modifier", "info", "infolist" }; +{ "command", "command_run", "timer", "fd", "process", "connect", "print", + "signal", "config", "completion", "modifier", "info", "infolist" }; struct t_hook *weechat_hooks[HOOK_NUM_TYPES]; /* list of hooks */ struct t_hook *last_weechat_hook[HOOK_NUM_TYPES]; /* last hook */ int hook_exec_recursion = 0; /* 1 when a hook is executed */ @@ -56,6 +56,9 @@ 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 */ +void hook_process_run (struct t_hook *hook_process); + + /* * hook_init: init hooks lists */ @@ -797,7 +800,9 @@ hook_timer_exec () { ptr_hook->running = 1; (void) (HOOK_TIMER(ptr_hook, callback)) - (ptr_hook->callback_data); + (ptr_hook->callback_data, + (HOOK_TIMER(ptr_hook, remaining_calls) > 0) ? + HOOK_TIMER(ptr_hook, remaining_calls) - 1 : -1); ptr_hook->running = 0; if (!ptr_hook->deleted) { @@ -964,6 +969,294 @@ hook_fd_exec (fd_set *read_fds, fd_set *write_fds, fd_set *exception_fds) } /* + * hook_process: hook a process (using fork) + */ + +struct t_hook * +hook_process (struct t_weechat_plugin *plugin, + const char *command, int timeout, + t_hook_callback_process *callback, void *callback_data) +{ + struct t_hook *new_hook; + struct t_hook_process *new_hook_process; + + if (!command || !command[0]) + return NULL; + + new_hook = malloc (sizeof (*new_hook)); + if (!new_hook) + return NULL; + new_hook_process = malloc (sizeof (*new_hook_process)); + if (!new_hook_process) + { + free (new_hook); + return NULL; + } + + hook_init_data (new_hook, plugin, HOOK_TYPE_PROCESS, callback_data); + + new_hook->hook_data = new_hook_process; + new_hook_process->callback = callback; + new_hook_process->command = strdup (command); + new_hook_process->timeout = timeout; + new_hook_process->child_stdout_read = -1; + new_hook_process->child_stdout_write = -1; + new_hook_process->child_stderr_read = -1; + new_hook_process->child_stderr_write = -1; + new_hook_process->child_pid = 0; + new_hook_process->hook_fd_stdout = NULL; + new_hook_process->hook_fd_stderr = NULL; + new_hook_process->hook_timer = NULL; + + hook_add_to_list (new_hook); + + hook_process_run (new_hook); + + return new_hook; +} + +/* + * hook_process_child: child process for hook process: execute function and + * return string result into pipe for WeeChat process + */ + +void +hook_process_child (struct t_hook *hook_process) +{ + char *exec_args[4] = { "sh", "-c", NULL, NULL }; + + /* close stdin, so that process will fail to read stdin (process reading + stdin should not be run inside WeeChat!) */ + close (STDIN_FILENO); + + /* redirect stdout/stderr to pipe (so that father process can read them) */ + close (HOOK_PROCESS(hook_process, child_stdout_read)); + close (HOOK_PROCESS(hook_process, child_stderr_read)); + if (dup2 (HOOK_PROCESS(hook_process, child_stdout_write), + STDOUT_FILENO) < 0) + { + _exit (EXIT_FAILURE); + } + if (dup2 (HOOK_PROCESS(hook_process, child_stderr_write), + STDERR_FILENO) < 0) + { + _exit (EXIT_FAILURE); + } + + /* launch command */ + exec_args[2] = HOOK_PROCESS(hook_process, command); + execvp (exec_args[0], exec_args); + + /* should not be executed if execvp was ok */ + fprintf (stderr, "Error with command '%s'\n", + HOOK_PROCESS(hook_process, command)); + _exit (EXIT_FAILURE); +} + +/* + * hook_process_child_read: read process output (stdout or stderr) from child + * process + */ + +void +hook_process_child_read (struct t_hook *hook_process, int fd, + int stdout, struct t_hook **hook_fd) +{ + char buffer[4096]; + int num_read; + + num_read = read (fd, buffer, sizeof (buffer) - 1); + if (num_read > 0) + { + buffer[num_read] = '\0'; + (void) (HOOK_PROCESS(hook_process, callback)) + (hook_process->callback_data, + HOOK_PROCESS(hook_process, command), + WEECHAT_HOOK_PROCESS_RUNNING, + (stdout) ? buffer : NULL, + (stdout) ? NULL : buffer); + } + else if (num_read == 0) + { + unhook (*hook_fd); + *hook_fd = NULL; + } +} + +/* + * hook_process_child_read_stdout_cb: read process output (stdout) from child + * process + */ + +int +hook_process_child_read_stdout_cb (void *arg_hook_process, int fd) +{ + struct t_hook *hook_process; + + hook_process = (struct t_hook *)arg_hook_process; + hook_process_child_read (hook_process, fd, 1, + &(HOOK_PROCESS(hook_process, hook_fd_stdout))); + return WEECHAT_RC_OK; +} + +/* + * hook_process_child_read_stderr_cb: read process output (stderr) from child + * process + */ + +int +hook_process_child_read_stderr_cb (void *arg_hook_process, int fd) +{ + struct t_hook *hook_process; + + hook_process = (struct t_hook *)arg_hook_process; + hook_process_child_read (hook_process, fd, 0, + &(HOOK_PROCESS(hook_process, hook_fd_stderr))); + return WEECHAT_RC_OK; +} + +/* + * hook_process_timer_cb: timer to check if child is died or not + */ + +int +hook_process_timer_cb (void *arg_hook_process, int remaining_calls) +{ + struct t_hook *hook_process; + int status, rc; + + /* make C compiler happy */ + (void) remaining_calls; + + hook_process = (struct t_hook *)arg_hook_process; + + if (remaining_calls == 0) + { + gui_chat_printf (NULL, + _("End of command '%s', timeout reached (%.1fs)"), + HOOK_PROCESS(hook_process, command), + ((float)HOOK_PROCESS(hook_process, timeout)) / 1000); + kill (HOOK_PROCESS(hook_process, child_pid), SIGKILL); + usleep (1000); + } + + if (waitpid (HOOK_PROCESS(hook_process, child_pid), &status, WNOHANG) > 0) + { + rc = WEXITSTATUS(status); + (void) (HOOK_PROCESS(hook_process, callback)) + (hook_process->callback_data, + HOOK_PROCESS(hook_process, command), + rc, NULL, NULL); + unhook (hook_process); + } + + return WEECHAT_RC_OK; +} + +/* + * hook_process_run: fork, execute process function in child, and read data in + * current process, with fd hook + */ + +void +hook_process_run (struct t_hook *hook_process) +{ + int pipe_stdout[2], pipe_stderr[2], timeout, max_calls; + long interval; + pid_t pid; + + /* create pipe for child process (stdout) */ + if (pipe (pipe_stdout) < 0) + { + (void) (HOOK_PROCESS(hook_process, callback)) + (hook_process->callback_data, + HOOK_PROCESS(hook_process, command), + WEECHAT_HOOK_PROCESS_ERROR, + NULL, NULL); + unhook (hook_process); + return; + } + if (pipe (pipe_stderr) < 0) + { + close (pipe_stdout[0]); + close (pipe_stdout[1]); + (void) (HOOK_PROCESS(hook_process, callback)) + (hook_process->callback_data, + HOOK_PROCESS(hook_process, command), + WEECHAT_HOOK_PROCESS_ERROR, + NULL, NULL); + unhook (hook_process); + return; + } + + HOOK_PROCESS(hook_process, child_stdout_read) = pipe_stdout[0]; + HOOK_PROCESS(hook_process, child_stdout_write) = pipe_stdout[1]; + + HOOK_PROCESS(hook_process, child_stderr_read) = pipe_stderr[0]; + HOOK_PROCESS(hook_process, child_stderr_write) = pipe_stderr[1]; + + switch (pid = fork ()) + { + /* fork failed */ + case -1: + (void) (HOOK_PROCESS(hook_process, callback)) + (hook_process->callback_data, + HOOK_PROCESS(hook_process, command), + WEECHAT_HOOK_PROCESS_ERROR, + NULL, NULL); + unhook (hook_process); + return; + /* child process */ + case 0: + setuid (getuid ()); + hook_process_child (hook_process); + /* never executed */ + _exit (EXIT_SUCCESS); + break; + } + /* parent process */ + HOOK_PROCESS(hook_process, child_pid) = pid; + close (HOOK_PROCESS(hook_process, child_stdout_write)); + HOOK_PROCESS(hook_process, child_stdout_write) = -1; + close (HOOK_PROCESS(hook_process, child_stderr_write)); + HOOK_PROCESS(hook_process, child_stderr_write) = -1; + HOOK_PROCESS(hook_process, hook_fd_stdout) = hook_fd (hook_process->plugin, + HOOK_PROCESS(hook_process, child_stdout_read), + 1, 0, 0, + &hook_process_child_read_stdout_cb, + hook_process); + + HOOK_PROCESS(hook_process, hook_fd_stderr) = hook_fd (hook_process->plugin, + HOOK_PROCESS(hook_process, child_stderr_read), + 1, 0, 0, + &hook_process_child_read_stderr_cb, + hook_process); + + timeout = HOOK_PROCESS(hook_process, timeout); + interval = 100; + max_calls = 0; + if (timeout > 0) + { + if (timeout <= 100) + { + interval = timeout; + max_calls = 1; + } + else + { + interval = 100; + max_calls = timeout / 100; + if (timeout % 100 == 0) + max_calls++; + } + } + HOOK_PROCESS(hook_process, hook_timer) = hook_timer (hook_process->plugin, + interval, 0, max_calls, + &hook_process_timer_cb, + hook_process); +} + +/* * hook_connect: hook a connection to peer (using fork) */ @@ -1704,18 +1997,37 @@ unhook (struct t_hook *hook) free (HOOK_COMMAND(hook, args_description)); if (HOOK_COMMAND(hook, completion)) free (HOOK_COMMAND(hook, completion)); - free ((struct t_hook_command *)hook->hook_data); break; case HOOK_TYPE_COMMAND_RUN: if (HOOK_COMMAND_RUN(hook, command)) free (HOOK_COMMAND_RUN(hook, command)); - free ((struct t_hook_command *)hook->hook_data); break; case HOOK_TYPE_TIMER: - free ((struct t_hook_timer *)hook->hook_data); break; case HOOK_TYPE_FD: - free ((struct t_hook_fd *)hook->hook_data); + break; + case HOOK_TYPE_PROCESS: + if (HOOK_PROCESS(hook, command)) + free (HOOK_PROCESS(hook, command)); + if (HOOK_PROCESS(hook, hook_fd_stdout)) + unhook (HOOK_PROCESS(hook, hook_fd_stdout)); + if (HOOK_PROCESS(hook, hook_fd_stderr)) + unhook (HOOK_PROCESS(hook, hook_fd_stderr)); + if (HOOK_PROCESS(hook, hook_timer)) + unhook (HOOK_PROCESS(hook, hook_timer)); + if (HOOK_PROCESS(hook, child_pid) > 0) + { + kill (HOOK_PROCESS(hook, child_pid), SIGKILL); + waitpid (HOOK_PROCESS(hook, child_pid), NULL, 0); + } + if (HOOK_PROCESS(hook, child_stdout_read) != -1) + close (HOOK_PROCESS(hook, child_stdout_read)); + if (HOOK_PROCESS(hook, child_stdout_write) != -1) + close (HOOK_PROCESS(hook, child_stdout_write)); + if (HOOK_PROCESS(hook, child_stderr_read) != -1) + close (HOOK_PROCESS(hook, child_stderr_read)); + if (HOOK_PROCESS(hook, child_stderr_write) != -1) + close (HOOK_PROCESS(hook, child_stderr_write)); break; case HOOK_TYPE_CONNECT: if (HOOK_CONNECT(hook, proxy)) @@ -1735,52 +2047,45 @@ unhook (struct t_hook *hook) close (HOOK_CONNECT(hook, child_read)); if (HOOK_CONNECT(hook, child_write) != -1) close (HOOK_CONNECT(hook, child_write)); - free ((struct t_hook_connect *)hook->hook_data); break; case HOOK_TYPE_PRINT: if (HOOK_PRINT(hook, message)) free (HOOK_PRINT(hook, message)); - free ((struct t_hook_print *)hook->hook_data); break; case HOOK_TYPE_SIGNAL: if (HOOK_SIGNAL(hook, signal)) free (HOOK_SIGNAL(hook, signal)); - free ((struct t_hook_signal *)hook->hook_data); break; case HOOK_TYPE_CONFIG: if (HOOK_CONFIG(hook, option)) free (HOOK_CONFIG(hook, option)); - free ((struct t_hook_config *)hook->hook_data); break; case HOOK_TYPE_COMPLETION: if (HOOK_COMPLETION(hook, completion_item)) free (HOOK_COMPLETION(hook, completion_item)); - free ((struct t_hook_completion *)hook->hook_data); break; case HOOK_TYPE_MODIFIER: if (HOOK_MODIFIER(hook, modifier)) free (HOOK_MODIFIER(hook, modifier)); - free ((struct t_hook_modifier *)hook->hook_data); break; case HOOK_TYPE_INFO: if (HOOK_INFO(hook, info_name)) free (HOOK_INFO(hook, info_name)); if (HOOK_INFO(hook, description)) free (HOOK_INFO(hook, description)); - free ((struct t_hook_info *)hook->hook_data); break; case HOOK_TYPE_INFOLIST: if (HOOK_INFOLIST(hook, infolist_name)) free (HOOK_INFOLIST(hook, infolist_name)); if (HOOK_INFOLIST(hook, description)) free (HOOK_INFOLIST(hook, description)); - free ((struct t_hook_infolist *)hook->hook_data); break; case HOOK_NUM_TYPES: /* this constant is used to count types only, it is never used as type */ break; } + free (hook->hook_data); hook->hook_data = NULL; } @@ -1957,6 +2262,33 @@ hook_add_to_infolist_type (struct t_infolist *infolist, return 0; } break; + case HOOK_TYPE_PROCESS: + if (!ptr_hook->deleted) + { + if (!infolist_new_var_pointer (ptr_item, "callback", HOOK_PROCESS(ptr_hook, callback))) + return 0; + if (!infolist_new_var_string (ptr_item, "command", HOOK_PROCESS(ptr_hook, command))) + return 0; + if (!infolist_new_var_integer (ptr_item, "timeout", HOOK_PROCESS(ptr_hook, timeout))) + return 0; + if (!infolist_new_var_integer (ptr_item, "child_stdout_read", HOOK_PROCESS(ptr_hook, child_stdout_read))) + return 0; + if (!infolist_new_var_integer (ptr_item, "child_stdout_write", HOOK_PROCESS(ptr_hook, child_stdout_write))) + return 0; + if (!infolist_new_var_integer (ptr_item, "child_stderr_read", HOOK_PROCESS(ptr_hook, child_stderr_read))) + return 0; + if (!infolist_new_var_integer (ptr_item, "child_stderr_write", HOOK_PROCESS(ptr_hook, child_stderr_write))) + return 0; + if (!infolist_new_var_integer (ptr_item, "child_pid", HOOK_PROCESS(ptr_hook, child_pid))) + return 0; + if (!infolist_new_var_pointer (ptr_item, "hook_fd_stdout", HOOK_PROCESS(ptr_hook, hook_fd_stdout))) + return 0; + if (!infolist_new_var_pointer (ptr_item, "hook_fd_stderr", HOOK_PROCESS(ptr_hook, hook_fd_stderr))) + return 0; + if (!infolist_new_var_pointer (ptr_item, "hook_timer", HOOK_PROCESS(ptr_hook, hook_timer))) + return 0; + } + break; case HOOK_TYPE_CONNECT: if (!ptr_hook->deleted) { @@ -2189,6 +2521,23 @@ hook_print_log () log_printf (" flags. . . . . . . . : %d", HOOK_FD(ptr_hook, flags)); } break; + case HOOK_TYPE_PROCESS: + if (!ptr_hook->deleted) + { + log_printf (" process data:"); + log_printf (" callback . . . . . . : 0x%lx", HOOK_PROCESS(ptr_hook, callback)); + log_printf (" command. . . . . . . : '%s'", HOOK_PROCESS(ptr_hook, command)); + log_printf (" timeout. . . . . . . : %d", HOOK_PROCESS(ptr_hook, timeout)); + log_printf (" child_stdout_read. . : %d", HOOK_PROCESS(ptr_hook, child_stdout_read)); + log_printf (" child_stdout_write . : %d", HOOK_PROCESS(ptr_hook, child_stdout_write)); + log_printf (" child_stderr_read. . : %d", HOOK_PROCESS(ptr_hook, child_stderr_read)); + log_printf (" child_stderr_write . : %d", HOOK_PROCESS(ptr_hook, child_stderr_write)); + log_printf (" child_pid. . . . . . : %d", HOOK_PROCESS(ptr_hook, child_pid)); + log_printf (" hook_fd_stdout . . . : 0x%lx", HOOK_PROCESS(ptr_hook, hook_fd_stdout)); + log_printf (" hook_fd_stderr . . . : 0x%lx", HOOK_PROCESS(ptr_hook, hook_fd_stderr)); + log_printf (" hook_timer . . . . . : 0x%lx", HOOK_PROCESS(ptr_hook, hook_timer)); + } + break; case HOOK_TYPE_CONNECT: if (!ptr_hook->deleted) { @@ -2204,6 +2553,7 @@ hook_print_log () log_printf (" local_hostname . . . : '%s'", HOOK_CONNECT(ptr_hook, local_hostname)); log_printf (" child_read . . . . . : %d", HOOK_CONNECT(ptr_hook, child_read)); log_printf (" child_write. . . . . : %d", HOOK_CONNECT(ptr_hook, child_write)); + log_printf (" child_pid. . . . . . : %d", HOOK_CONNECT(ptr_hook, child_pid)); log_printf (" hook_fd. . . . . . . : 0x%lx", HOOK_CONNECT(ptr_hook, hook_fd)); } break; diff --git a/src/core/wee-hook.h b/src/core/wee-hook.h index 397156abf..833473684 100644 --- a/src/core/wee-hook.h +++ b/src/core/wee-hook.h @@ -38,6 +38,7 @@ enum t_hook_type HOOK_TYPE_COMMAND_RUN, /* when a command is executed */ HOOK_TYPE_TIMER, /* timer */ HOOK_TYPE_FD, /* socket of file descriptor */ + HOOK_TYPE_PROCESS, /* sub-process (fork) */ HOOK_TYPE_CONNECT, /* connect to peer with fork */ HOOK_TYPE_PRINT, /* printed message */ HOOK_TYPE_SIGNAL, /* signal */ @@ -63,6 +64,7 @@ enum t_hook_type #define HOOK_COMMAND_RUN(hook, var) (((struct t_hook_command_run *)hook->hook_data)->var) #define HOOK_TIMER(hook, var) (((struct t_hook_timer *)hook->hook_data)->var) #define HOOK_FD(hook, var) (((struct t_hook_fd *)hook->hook_data)->var) +#define HOOK_PROCESS(hook, var) (((struct t_hook_process *)hook->hook_data)->var) #define HOOK_CONNECT(hook, var) (((struct t_hook_connect *)hook->hook_data)->var) #define HOOK_PRINT(hook, var) (((struct t_hook_print *)hook->hook_data)->var) #define HOOK_SIGNAL(hook, var) (((struct t_hook_signal *)hook->hook_data)->var) @@ -88,6 +90,8 @@ struct t_hook struct t_hook *next_hook; /* link to next hook */ }; +/* hook command */ + typedef int (t_hook_callback_command)(void *data, struct t_gui_buffer *buffer, int argc, char **argv, char **argv_eol); @@ -103,6 +107,8 @@ struct t_hook_command char *completion; /* template for completion */ }; +/* hook command run */ + typedef int (t_hook_callback_command_run)(void *data, struct t_gui_buffer *buffer, const char *command); @@ -113,7 +119,9 @@ struct t_hook_command_run char *command; /* name of command (without '/') */ }; -typedef int (t_hook_callback_timer)(void *data); +/* hook timer */ + +typedef int (t_hook_callback_timer)(void *data, int remaining_calls); struct t_hook_timer { @@ -126,6 +134,8 @@ struct t_hook_timer struct timeval next_exec; /* next scheduled execution */ }; +/* hook fd */ + typedef int (t_hook_callback_fd)(void *data, int fd); struct t_hook_fd @@ -135,6 +145,29 @@ struct t_hook_fd int flags; /* fd flags (read,write,..) */ }; +/* hook process */ + +typedef int (t_hook_callback_process)(void *data, const char *command, + int return_code, const char *stdout, + const char *stderr); + +struct t_hook_process +{ + t_hook_callback_process *callback; /* process callback (after child end)*/ + char *command; /* command executed by child */ + long timeout; /* timeout (ms) (0 = no timeout) */ + int child_stdout_read; /* to read data in pipe from child */ + int child_stdout_write; /* to write data in pipe for child */ + int child_stderr_read; /* to read data in pipe from child */ + int child_stderr_write; /* to write data in pipe for child */ + pid_t child_pid; /* pid of child process */ + struct t_hook *hook_fd_stdout; /* hook fd for stdout */ + struct t_hook *hook_fd_stderr; /* hook fd for stderr */ + struct t_hook *hook_timer; /* timer to check if child has died */ +}; + +/* hook connect */ + typedef int (t_hook_callback_connect)(void *data, int status, const char *ip_address); @@ -150,12 +183,14 @@ struct t_hook_connect gnutls_session_t *gnutls_sess; /* GnuTLS session (SSL connection) */ #endif char *local_hostname; /* force local hostname (optional) */ - int child_read; /* to read into child pipe */ - int child_write; /* to write into child pipe */ + int child_read; /* to read data in pipe from child */ + int child_write; /* to write data in pipe for child */ pid_t child_pid; /* pid of child process (connecting) */ struct t_hook *hook_fd; /* pointer to fd hook */ }; +/* hook print */ + typedef int (t_hook_callback_print)(void *data, struct t_gui_buffer *buffer, time_t date, int tags_count, const char **tags, int displayed, @@ -172,6 +207,8 @@ struct t_hook_print int strip_colors; /* strip colors in msg for callback? */ }; +/* hook signal */ + typedef int (t_hook_callback_signal)(void *data, const char *signal, const char *type_data, void *signal_data); @@ -182,6 +219,8 @@ struct t_hook_signal /* with "*", "*" == any signal) */ }; +/* hook config */ + typedef int (t_hook_callback_config)(void *data, const char *option, const char *value); @@ -192,6 +231,8 @@ struct t_hook_config /* (NULL = hook for all options) */ }; +/* hook completion */ + typedef int (t_hook_callback_completion)(void *data, const char *completion_item, struct t_gui_buffer *buffer, @@ -203,6 +244,8 @@ struct t_hook_completion char *completion_item; /* name of completion */ }; +/* hook modifier */ + typedef char *(t_hook_callback_modifier)(void *data, const char *modifier, const char *modifier_data, const char *string); @@ -213,6 +256,8 @@ struct t_hook_modifier char *modifier; /* name of modifier */ }; +/* hook info */ + typedef const char *(t_hook_callback_info)(void *data, const char *info_name, const char *arguments); @@ -223,6 +268,8 @@ struct t_hook_info char *description; /* description */ }; +/* hook infolist */ + typedef struct t_infolist *(t_hook_callback_infolist)(void *data, const char *infolist_name, void *pointer, @@ -276,6 +323,11 @@ 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 struct t_hook *hook_process (struct t_weechat_plugin *plugin, + const char *command, + int timeout, + t_hook_callback_process *callback, + void *callback_data); extern struct t_hook *hook_connect (struct t_weechat_plugin *plugin, const char *proxy, const char *address, int port, int sock, int ipv6, diff --git a/src/core/wee-network.c b/src/core/wee-network.c index 10c8f12eb..d3468ab49 100644 --- a/src/core/wee-network.c +++ b/src/core/wee-network.c @@ -909,12 +909,15 @@ network_connect_with_fork (struct t_hook *hook_connect) /* child process */ case 0: setuid (getuid ()); + close (HOOK_CONNECT(hook_connect, child_read)); network_connect_child (hook_connect); _exit (EXIT_SUCCESS); } /* parent process */ HOOK_CONNECT(hook_connect, child_pid) = pid; - HOOK_CONNECT(hook_connect, hook_fd) = hook_fd (NULL, + close (HOOK_CONNECT(hook_connect, child_write)); + HOOK_CONNECT(hook_connect, child_write) = -1; + HOOK_CONNECT(hook_connect, hook_fd) = hook_fd (hook_connect->plugin, HOOK_CONNECT(hook_connect, child_read), 1, 0, 0, &network_connect_child_read_cb, |