diff --git a/src/include/switch_core.h b/src/include/switch_core.h index e2dfa57afc..4f172a928e 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -2843,7 +2843,7 @@ SWITCH_DECLARE(int) switch_stream_system_fork(const char *cmd, switch_stream_han SWITCH_DECLARE(int) switch_stream_system(const char *cmd, switch_stream_handle_t *stream); SWITCH_DECLARE(int) switch_spawn(const char *cmd, switch_bool_t wait); -SWITCH_DECLARE(int) switch_stream_spawn(const char *cmd, switch_bool_t wait, switch_stream_handle_t *stream); +SWITCH_DECLARE(int) switch_stream_spawn(const char *cmd, switch_bool_t shell, switch_bool_t wait, switch_stream_handle_t *stream); SWITCH_DECLARE(void) switch_core_session_debug_pool(switch_stream_handle_t *stream); diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index 6c36d26d2a..ad5bd51ce9 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -6530,7 +6530,7 @@ SWITCH_STANDARD_API(spawn_stream_function) return SWITCH_STATUS_SUCCESS; } - if (switch_stream_spawn(cmd, SWITCH_TRUE, stream) < 0) { + if (switch_stream_spawn(cmd, SWITCH_FALSE, SWITCH_TRUE, stream) < 0) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Failed to execute command: %s\n", cmd); } diff --git a/src/switch_core.c b/src/switch_core.c index 617b623753..2589d276a4 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -3361,17 +3361,21 @@ static int switch_system_fork(const char *cmd, switch_bool_t wait) SWITCH_DECLARE(int) switch_system(const char *cmd, switch_bool_t wait) { + int retval = 0; #ifdef __linux__ switch_bool_t spawn_instead_of_system = switch_true(switch_core_get_variable("spawn_instead_of_system")); #else switch_bool_t spawn_instead_of_system = SWITCH_FALSE; #endif - int (*sys_p)(const char *cmd, switch_bool_t wait); - - sys_p = spawn_instead_of_system ? switch_spawn : switch_test_flag((&runtime), SCF_THREADED_SYSTEM_EXEC) ? switch_system_thread : switch_system_fork; - - return sys_p(cmd, wait); - + + if (spawn_instead_of_system) { + retval = switch_stream_spawn(cmd, SWITCH_TRUE, wait, NULL); + } else if (switch_test_flag((&runtime), SCF_THREADED_SYSTEM_EXEC)) { + retval = switch_system_thread(cmd, wait); + } else { + retval = switch_system_fork(cmd, wait); + } + return retval; } @@ -3385,7 +3389,7 @@ SWITCH_DECLARE(int) switch_stream_system_fork(const char *cmd, switch_stream_han extern char **environ; #endif -SWITCH_DECLARE(int) switch_stream_spawn(const char *cmd, switch_bool_t wait, switch_stream_handle_t *stream) +SWITCH_DECLARE(int) switch_stream_spawn(const char *cmd, switch_bool_t shell, switch_bool_t wait, switch_stream_handle_t *stream) { #ifndef __linux__ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "posix_spawn is unsupported on current platform\n"); @@ -3406,18 +3410,27 @@ SWITCH_DECLARE(int) switch_stream_spawn(const char *cmd, switch_bool_t wait, swi return 1; } - if (!(pdata = strdup(cmd))) { - return 1; - } - - if (!switch_separate_string(pdata, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) { - free(pdata); - return 1; + if (shell) { + argv[0] = switch_core_get_variable("spawn_system_shell"); + argv[1] = "-c"; + argv[2] = (char *)cmd; + argv[3] = NULL; + if (zstr(argv[0])) { + argv[0] = "/bin/sh"; + } + } else { + if (!(pdata = strdup(cmd))) { + return 1; + } + if (!switch_separate_string(pdata, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) { + free(pdata); + return 1; + } } if (!(attr = malloc(sizeof(posix_spawnattr_t)))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to execute switch_spawn_stream because of a memory error: %s\n", cmd); - free(pdata); + switch_safe_free(pdata); return 1; } @@ -3425,7 +3438,7 @@ SWITCH_DECLARE(int) switch_stream_spawn(const char *cmd, switch_bool_t wait, swi if (pipe(cout_pipe)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to execute switch_spawn_stream because of a pipe error: %s\n", cmd); free(attr); - free(pdata); + switch_safe_free(pdata); return 1; } @@ -3434,7 +3447,7 @@ SWITCH_DECLARE(int) switch_stream_spawn(const char *cmd, switch_bool_t wait, swi close(cout_pipe[0]); close(cout_pipe[1]); free(attr); - free(pdata); + switch_safe_free(pdata); return 1; } } @@ -3505,7 +3518,7 @@ SWITCH_DECLARE(int) switch_stream_spawn(const char *cmd, switch_bool_t wait, swi posix_spawnattr_destroy(attr); free(attr); posix_spawn_file_actions_destroy(&action); - free(pdata); + switch_safe_free(pdata); return status; #endif @@ -3513,7 +3526,7 @@ SWITCH_DECLARE(int) switch_stream_spawn(const char *cmd, switch_bool_t wait, swi SWITCH_DECLARE(int) switch_spawn(const char *cmd, switch_bool_t wait) { - return switch_stream_spawn(cmd, wait, NULL); + return switch_stream_spawn(cmd, SWITCH_FALSE, wait, NULL); } SWITCH_DECLARE(switch_status_t) switch_core_get_stacksizes(switch_size_t *cur, switch_size_t *max) @@ -3549,7 +3562,7 @@ SWITCH_DECLARE(int) switch_stream_system(const char *cmd, switch_stream_handle_t #endif if (spawn_instead_of_system){ - return switch_stream_spawn(cmd, SWITCH_TRUE, stream); + return switch_stream_spawn(cmd, SWITCH_TRUE, SWITCH_TRUE, stream); } else { char buffer[128]; size_t bytes; diff --git a/tests/unit/conf/freeswitch.xml b/tests/unit/conf/freeswitch.xml index 578a4fe2b7..3dcb33198b 100644 --- a/tests/unit/conf/freeswitch.xml +++ b/tests/unit/conf/freeswitch.xml @@ -1,6 +1,9 @@ + + +
diff --git a/tests/unit/switch_core.c b/tests/unit/switch_core.c index 44cfe148bf..bba7272cac 100644 --- a/tests/unit/switch_core.c +++ b/tests/unit/switch_core.c @@ -40,10 +40,11 @@ FST_CORE_BEGIN("./conf") { - FST_SUITE_BEGIN(switch_ivr_originate) + FST_SUITE_BEGIN(switch_core) { FST_SETUP_BEGIN() { + switch_core_set_variable("spawn_instead_of_system", "false"); } FST_SETUP_END() @@ -101,17 +102,17 @@ FST_CORE_BEGIN("./conf") #ifndef WIN32 FST_TEST_BEGIN(test_fork) { - switch_stream_handle_t exec_result = { 0 }; - SWITCH_STANDARD_STREAM(exec_result); - fst_requires(switch_stream_system_fork("ip ad sh", &exec_result) == 0); - fst_requires(!zstr(exec_result.data)); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s\n", (char *)exec_result.data); + switch_stream_handle_t exec_result = { 0 }; + SWITCH_STANDARD_STREAM(exec_result); + fst_requires(switch_stream_system_fork("ip ad sh", &exec_result) == 0); + fst_requires(!zstr(exec_result.data)); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s\n", (char *)exec_result.data); - fst_requires(switch_stream_system_fork("ip ad sh | grep link", &exec_result) == 0); - fst_requires(!zstr(exec_result.data)); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s\n", (char *)exec_result.data); + fst_requires(switch_stream_system_fork("ip ad sh | grep link", &exec_result) == 0); + fst_requires(!zstr(exec_result.data)); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s\n", (char *)exec_result.data); - switch_safe_free(exec_result.data); + switch_safe_free(exec_result.data); } FST_TEST_END() #endif @@ -171,13 +172,13 @@ FST_CORE_BEGIN("./conf") fst_check_int_equals(status, 0); SWITCH_STANDARD_STREAM(stream); - status = switch_stream_spawn("echo DEADBEEF", SWITCH_TRUE, &stream); + status = switch_stream_spawn("echo DEADBEEF", SWITCH_FALSE, SWITCH_TRUE, &stream); fst_check_int_equals(status, 0); fst_check_string_equals(stream.data, "DEADBEEF\n"); switch_safe_free(stream.data); SWITCH_STANDARD_STREAM(stream); - status = switch_stream_spawn("echo DEADBEEF", SWITCH_FALSE, &stream); + status = switch_stream_spawn("echo DEADBEEF", SWITCH_FALSE, SWITCH_FALSE, &stream); fst_check_int_equals(status, 0); fst_check_string_equals(stream.data, "DEADBEEF\n"); switch_safe_free(stream.data); @@ -191,6 +192,34 @@ FST_CORE_BEGIN("./conf") status = switch_spawn("true", SWITCH_TRUE); fct_chk_eq_int(status, 0); +#endif + } + FST_TEST_END() + + FST_TEST_BEGIN(test_switch_spawn_instead_of_system) + { +#ifdef __linux__ + int status; + char file_uuid[SWITCH_UUID_FORMATTED_LENGTH + 1] = { 0 }; + const char *filename = NULL; + const char *cmd = NULL; + + // tell FS core to use posix_spawn() instead of popen() and friends + switch_core_set_variable("spawn_instead_of_system", "true"); + + // echo text to a file using shell redirection- this will ensure the command was executed in a shell, as expected + switch_uuid_str(file_uuid, sizeof(file_uuid)); + filename = switch_core_sprintf(fst_pool, "%s" SWITCH_PATH_SEPARATOR "%s", SWITCH_GLOBAL_dirs.temp_dir, file_uuid); + cmd = switch_core_sprintf(fst_pool, "echo test_switch_spawn_instead_of_system with spaces > %s", filename); + status = switch_system(cmd, SWITCH_TRUE); + + fst_check_int_equals(status, 0); + fst_xcheck(status == 0, "Expect switch_system() command to return 0"); + fst_xcheck(switch_file_exists(filename, fst_pool) == SWITCH_STATUS_SUCCESS, "Expect switch_system() to use shell to create file via > redirection"); + unlink(filename); + + // verify exec-set works- see conf/freeswitch.xml for test setup of shell_exec_set_test global variable + fst_check_string_equals(switch_core_get_variable("shell_exec_set_test"), "usr"); #endif } FST_TEST_END()