From d7a37e9754c5af1393d4b2477f7275b28b1c5bc8 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 20 Dec 2011 12:34:21 -0600 Subject: [PATCH] allow system API command to capture output from the executed command --- src/include/switch_core.h | 4 +- .../applications/mod_commands/mod_commands.c | 5 +- src/switch_core.c | 171 ++++++++++++++++-- src/switch_xml.c | 1 + 4 files changed, 157 insertions(+), 24 deletions(-) diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 9d0893565f..29c9cfc8c5 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -2115,6 +2115,7 @@ SWITCH_DECLARE(uint32_t) switch_core_default_dtmf_duration(uint32_t duration); SWITCH_DECLARE(switch_status_t) switch_console_set_complete(const char *string); SWITCH_DECLARE(switch_status_t) switch_console_set_alias(const char *string); SWITCH_DECLARE(int) switch_system(const char *cmd, switch_bool_t wait); +SWITCH_DECLARE(int) switch_stream_system(const char *cmd, switch_stream_handle_t *stream); SWITCH_DECLARE(void) switch_cond_yield(switch_interval_time_t t); SWITCH_DECLARE(void) switch_cond_next(void); SWITCH_DECLARE(switch_status_t) switch_core_chat_send_args(const char *dest_proto, const char *proto, const char *from, const char *to, @@ -2302,7 +2303,8 @@ SWITCH_DECLARE(char *) switch_say_file_handle_detach_path(switch_say_file_handle SWITCH_DECLARE(void) switch_say_file_handle_destroy(switch_say_file_handle_t **sh); SWITCH_DECLARE(switch_status_t) switch_say_file_handle_create(switch_say_file_handle_t **sh, const char *ext, switch_event_t **var_event); SWITCH_DECLARE(void) switch_say_file(switch_say_file_handle_t *sh, const char *fmt, ...); - +SWITCH_DECLARE(int) switch_max_file_desc(void); +SWITCH_DECLARE(void) switch_close_extra_files(void); SWITCH_END_EXTERN_C #endif diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index 03e2cb3faf..48cfebf8ca 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -4791,11 +4791,10 @@ SWITCH_STANDARD_API(system_function) return SWITCH_STATUS_SUCCESS; } - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Executing command: %s\n", cmd); - if (switch_system(cmd, SWITCH_TRUE) < 0) { + if (switch_stream_system(cmd, stream) < 0) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Failed to execute command: %s\n", cmd); } - stream->write_function(stream, "+OK\n"); + return SWITCH_STATUS_SUCCESS; } diff --git a/src/switch_core.c b/src/switch_core.c index e64c6156fb..85fd7bf5bd 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -2321,6 +2321,7 @@ struct system_thread_handle { switch_mutex_t *mutex; switch_memory_pool_t *pool; int ret; + int *fds; }; static void *SWITCH_THREAD_FUNC system_thread(switch_thread_t *thread, void *obj) @@ -2339,6 +2340,10 @@ static void *SWITCH_THREAD_FUNC system_thread(switch_thread_t *thread, void *obj #endif #endif + if (sth->fds) { + dup2(sth->fds[1], STDOUT_FILENO); + } + sth->ret = system(sth->cmd); #if 0 @@ -2400,6 +2405,33 @@ static int switch_system_thread(const char *cmd, switch_bool_t wait) return ret; } +SWITCH_DECLARE(int) switch_max_file_desc(void) +{ + int max = 0; + +#ifndef WIN32 +#if defined(HAVE_GETDTABLESIZE) + max = getdtablesize(); +#else + max = sysconf(_SC_OPEN_MAX); +#endif +#endif + + return max; + +} + +SWITCH_DECLARE(void) switch_close_extra_files(void) +{ + int open_max = switch_max_file_desc(); + int i; + + for (i = 3; i < open_max; i++) { + close(i); + } +} + + #ifdef WIN32 static int switch_system_fork(const char *cmd, switch_bool_t wait) @@ -2408,19 +2440,6 @@ static int switch_system_fork(const char *cmd, switch_bool_t wait) } #else -static int max_open(void) -{ - int max; - -#if defined(HAVE_GETDTABLESIZE) - max = getdtablesize(); -#else - max = sysconf(_SC_OPEN_MAX); -#endif - - return max; - -} static int switch_system_fork(const char *cmd, switch_bool_t wait) { @@ -2437,15 +2456,10 @@ static int switch_system_fork(const char *cmd, switch_bool_t wait) } free(dcmd); } else { - int open_max = max_open(); - int i; - - for (i = 3; i < open_max; i++) { - close(i); - } + switch_close_extra_files(); set_low_priority(); - i = system(dcmd); + system(dcmd); free(dcmd); exit(0); } @@ -2467,6 +2481,123 @@ SWITCH_DECLARE(int) switch_system(const char *cmd, switch_bool_t wait) } + +SWITCH_DECLARE(int) switch_stream_system_fork(const char *cmd, switch_stream_handle_t *stream) +{ +#ifdef WIN32 + return switch_system(cmd, SWITCH_TRUE); +#else + int fds[2], pid = 0; + + if (pipe(fds)) { + goto end; + } else { /* good to go */ + pid = fork(); + + if (pid < 0) { /* ok maybe not */ + close(fds[0]); + close(fds[1]); + goto end; + } else if (pid) { /* parent */ + char buf[1024] = ""; + int bytes; + close(fds[1]); + while ((bytes = read(fds[0], buf, sizeof(buf))) > 0) { + stream->raw_write_function(stream, (unsigned char *)buf, bytes); + } + close(fds[0]); + waitpid(pid, NULL, 0); + } else { /* child */ + switch_close_extra_files(); + close(fds[0]); + dup2(fds[1], STDOUT_FILENO); + switch_system(cmd, SWITCH_TRUE); + close(fds[1]); + exit(0); + } + } + + end: + + return 0; + +#endif + +} + +static int switch_stream_system_thread(const char *cmd, switch_stream_handle_t *stream) +{ +#ifdef WIN32 + return switch_system(cmd, SWITCH_TRUE); +#else + switch_thread_t *thread; + switch_threadattr_t *thd_attr; + int ret = 0; + struct system_thread_handle *sth; + switch_memory_pool_t *pool; + int fds[2] = {0}; + char buf[1024] = ""; + int bytes; + + if (pipe(fds)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Pipe Failure\n"); + return 1; + } + + if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Pool Failure\n"); + return 1; + } + + if (!(sth = switch_core_alloc(pool, sizeof(struct system_thread_handle)))) { + switch_core_destroy_memory_pool(&pool); + return 1; + } + + sth->pool = pool; + sth->cmd = switch_core_strdup(pool, cmd); + sth->fds = fds; + + switch_thread_cond_create(&sth->cond, sth->pool); + switch_mutex_init(&sth->mutex, SWITCH_MUTEX_NESTED, sth->pool); + switch_mutex_lock(sth->mutex); + + switch_threadattr_create(&thd_attr, sth->pool); + switch_threadattr_stacksize_set(thd_attr, SWITCH_SYSTEM_THREAD_STACKSIZE); + switch_threadattr_detach_set(thd_attr, 1); + switch_thread_create(&thread, thd_attr, system_thread, sth, sth->pool); + + close(fds[1]); + while ((bytes = read(fds[0], buf, sizeof(buf))) > 0) { + stream->raw_write_function(stream, (unsigned char *)buf, bytes); + } + close(fds[0]); + switch_thread_cond_wait(sth->cond, sth->mutex); + ret = sth->ret; + switch_mutex_unlock(sth->mutex); + + return ret; + +#endif + +} + + +SWITCH_DECLARE(int) switch_stream_system(const char *cmd, switch_stream_handle_t *stream) +{ +#ifdef WIN32 + stream->write_function(stream, "Capturing output not supported.\n"); + return switch_system(cmd, SWITCH_TRUE); +#else + int (*sys_p)(const char *cmd, switch_stream_handle_t *stream); + + sys_p = switch_test_flag((&runtime), SCF_THREADED_SYSTEM_EXEC) ? switch_stream_system_thread : switch_stream_system_fork; + + return sys_p(cmd, stream); +#endif + +} + /* For Emacs: * Local Variables: * mode:c diff --git a/src/switch_xml.c b/src/switch_xml.c index d9b28a312f..2c57620210 100644 --- a/src/switch_xml.c +++ b/src/switch_xml.c @@ -1256,6 +1256,7 @@ static int preprocess_exec(const char *cwd, const char *command, int write_fd, i close(fds[0]); waitpid(pid, NULL, 0); } else { /* child */ + switch_close_extra_files(); close(fds[0]); dup2(fds[1], STDOUT_FILENO); switch_system(command, SWITCH_TRUE);