mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-10-21 08:36:18 +00:00
Use posix_spawn for execute commands.
This commit is contained in:
@@ -251,7 +251,9 @@ initialize_command_network() {
|
|||||||
CMD2_ANY ("network.http.max_host_connections", [http_stack](auto, auto) { return http_stack->max_host_connections(); });
|
CMD2_ANY ("network.http.max_host_connections", [http_stack](auto, auto) { return http_stack->max_host_connections(); });
|
||||||
CMD2_ANY_VALUE_V ("network.http.max_host_connections.set", [http_stack](auto, auto& value) { return http_stack->set_max_host_connections(value); });
|
CMD2_ANY_VALUE_V ("network.http.max_host_connections.set", [http_stack](auto, auto& value) { return http_stack->set_max_host_connections(value); });
|
||||||
CMD2_ANY ("network.http.max_total_connections", [http_stack](auto, auto) { return http_stack->max_total_connections(); });
|
CMD2_ANY ("network.http.max_total_connections", [http_stack](auto, auto) { return http_stack->max_total_connections(); });
|
||||||
|
|
||||||
CMD2_ANY_VALUE_V ("network.http.max_total_connections.set", [http_stack](auto, auto& value) { return http_stack->set_max_total_connections(value); });
|
CMD2_ANY_VALUE_V ("network.http.max_total_connections.set", [http_stack](auto, auto& value) { return http_stack->set_max_total_connections(value); });
|
||||||
|
|
||||||
CMD2_ANY ("network.http.proxy_address", [http_stack](auto, auto) { return http_stack->http_proxy(); });
|
CMD2_ANY ("network.http.proxy_address", [http_stack](auto, auto) { return http_stack->http_proxy(); });
|
||||||
CMD2_ANY_STRING_V("network.http.proxy_address.set", [http_stack](auto, auto& str) { return http_stack->set_http_proxy(str); });
|
CMD2_ANY_STRING_V("network.http.proxy_address.set", [http_stack](auto, auto& str) { return http_stack->set_http_proxy(str); });
|
||||||
CMD2_ANY ("network.http.ssl_verify_host", [http_stack](auto, auto) { return http_stack->ssl_verify_host(); });
|
CMD2_ANY ("network.http.ssl_verify_host", [http_stack](auto, auto) { return http_stack->ssl_verify_host(); });
|
||||||
@@ -284,7 +286,9 @@ initialize_command_network() {
|
|||||||
|
|
||||||
CMD2_ANY ("network.open_files", [file_manager](auto, auto) { return file_manager->open_files(); });
|
CMD2_ANY ("network.open_files", [file_manager](auto, auto) { return file_manager->open_files(); });
|
||||||
CMD2_ANY ("network.max_open_files", [file_manager](auto, auto) { return file_manager->max_open_files(); });
|
CMD2_ANY ("network.max_open_files", [file_manager](auto, auto) { return file_manager->max_open_files(); });
|
||||||
|
|
||||||
CMD2_ANY_VALUE_V ("network.max_open_files.set", [file_manager](auto, auto& value) { return file_manager->set_max_open_files(value); });
|
CMD2_ANY_VALUE_V ("network.max_open_files.set", [file_manager](auto, auto& value) { return file_manager->set_max_open_files(value); });
|
||||||
|
|
||||||
CMD2_ANY ("network.total_handshakes", [](auto, auto) { return torrent::runtime::total_handshakes(); });
|
CMD2_ANY ("network.total_handshakes", [](auto, auto) { return torrent::runtime::total_handshakes(); });
|
||||||
|
|
||||||
CMD2_ANY_STRING ("network.scgi.open_port", std::bind(&apply_scgi, std::placeholders::_2, 1));
|
CMD2_ANY_STRING ("network.scgi.open_port", std::bind(&apply_scgi, std::placeholders::_2, 1));
|
||||||
|
|||||||
+60
-50
@@ -3,6 +3,7 @@
|
|||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <spawn.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
@@ -12,6 +13,9 @@
|
|||||||
#include "exec_file.h"
|
#include "exec_file.h"
|
||||||
#include "parse.h"
|
#include "parse.h"
|
||||||
|
|
||||||
|
// Standard POSIX environment pointer
|
||||||
|
extern char** environ;
|
||||||
|
|
||||||
namespace rpc {
|
namespace rpc {
|
||||||
|
|
||||||
// TODO: Access fd through torrent logging?
|
// TODO: Access fd through torrent logging?
|
||||||
@@ -34,86 +38,92 @@ ExecFile::execute(const char* file, char* const* argv, int flags) {
|
|||||||
result = write(m_log_fd, "\n---\n", sizeof("\n---\n"));
|
result = write(m_log_fd, "\n---\n", sizeof("\n---\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
int pipeFd[2];
|
int pipe_fd[2];
|
||||||
|
|
||||||
if ((flags & flag_capture) && pipe(pipeFd))
|
if ((flags & flag_capture) && pipe(pipe_fd))
|
||||||
throw torrent::input_error("ExecFile::execute(...) Pipe creation failed.");
|
throw torrent::input_error("ExecFile::execute(...) Pipe creation failed.");
|
||||||
|
|
||||||
pid_t childPid = fork();
|
auto clean_fn = [pipe_fd, flags]() {
|
||||||
|
|
||||||
if (childPid == -1) {
|
|
||||||
if (flags & flag_capture) {
|
if (flags & flag_capture) {
|
||||||
::close(pipeFd[0]);
|
::close(pipe_fd[0]);
|
||||||
::close(pipeFd[1]);
|
::close(pipe_fd[1]);
|
||||||
}
|
}
|
||||||
throw torrent::input_error("ExecFile::execute(...) Fork failed.");
|
};
|
||||||
|
|
||||||
|
posix_spawn_file_actions_t actions{};
|
||||||
|
|
||||||
|
if (posix_spawn_file_actions_init(&actions) != 0) {
|
||||||
|
clean_fn();
|
||||||
|
throw torrent::internal_error("ExecFile::execute(...) posix_spawn_file_actions_init failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (childPid == 0) {
|
// Handle standard input redirection (/dev/null), posix_spawn_file_actions_addopen handles opening
|
||||||
if (flags & flag_background) {
|
// and dup2 natively
|
||||||
pid_t detached_pid = fork();
|
if (posix_spawn_file_actions_addopen(&actions, 0, "/dev/null", O_RDWR, 0) != 0) {
|
||||||
|
// Fallback if open fails inside action setup
|
||||||
if (detached_pid == -1)
|
posix_spawn_file_actions_addclose(&actions, 0);
|
||||||
_exit(-1);
|
|
||||||
|
|
||||||
if (detached_pid != 0) {
|
|
||||||
if (m_log_fd != -1)
|
|
||||||
result = write(m_log_fd, "\n--- Background task ---\n", sizeof("\n--- Background task ---\n"));
|
|
||||||
|
|
||||||
_exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_log_fd = -1;
|
// Handle standard output redirection
|
||||||
flags &= ~flag_capture;
|
if (flags & flag_capture) {
|
||||||
|
posix_spawn_file_actions_adddup2(&actions, pipe_fd[1], 1);
|
||||||
|
|
||||||
|
// Ensure the write end of the pipe is closed in the child after duplicating.
|
||||||
|
posix_spawn_file_actions_addclose(&actions, pipe_fd[1]);
|
||||||
|
posix_spawn_file_actions_addclose(&actions, pipe_fd[0]);
|
||||||
|
|
||||||
|
} else if (m_log_fd != -1) {
|
||||||
|
posix_spawn_file_actions_adddup2(&actions, m_log_fd, 1);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
posix_spawn_file_actions_addopen(&actions, 1, "/dev/null", O_RDWR, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int devNull = open("/dev/null", O_RDWR);
|
if (m_log_fd != -1) {
|
||||||
|
posix_spawn_file_actions_adddup2(&actions, m_log_fd, 2);
|
||||||
|
} else {
|
||||||
|
posix_spawn_file_actions_addopen(&actions, 2, "/dev/null", O_RDWR, 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (devNull != -1)
|
posix_spawnattr_t attr;
|
||||||
dup2(devNull, 0);
|
posix_spawnattr_init(&attr);
|
||||||
else
|
|
||||||
::close(0);
|
|
||||||
|
|
||||||
if (flags & flag_capture)
|
// If you are using standard close-on-exec (O_CLOEXEC) across rtorrent, posix_spawn honors it
|
||||||
dup2(pipeFd[1], 1);
|
// automatically. If you want to explicitly enforce a clean slate, modern systems support
|
||||||
else if (m_log_fd != -1)
|
// POSIX_SPAWN_CLOEXEC_DEFAULT.
|
||||||
dup2(m_log_fd, 1);
|
|
||||||
else if (devNull != -1)
|
|
||||||
dup2(devNull, 1);
|
|
||||||
else
|
|
||||||
::close(1);
|
|
||||||
|
|
||||||
if (m_log_fd != -1)
|
#ifdef POSIX_SPAWN_CLOEXEC_DEFAULT
|
||||||
dup2(m_log_fd, 2);
|
posix_spawnattr_setflags(&attr, POSIX_SPAWN_CLOEXEC_DEFAULT);
|
||||||
else if (devNull != -1)
|
#endif
|
||||||
dup2(devNull, 2);
|
|
||||||
else
|
|
||||||
::close(2);
|
|
||||||
|
|
||||||
// Close all fd's.
|
pid_t child_pid{};
|
||||||
for (int i = 3, last = sysconf(_SC_OPEN_MAX); i != last; i++)
|
|
||||||
::close(i);
|
|
||||||
|
|
||||||
result = execvp(file, argv);
|
int spawn_status = posix_spawnp(&child_pid, file, &actions, &attr, argv, environ);
|
||||||
|
|
||||||
_exit(result);
|
posix_spawn_file_actions_destroy(&actions);
|
||||||
|
posix_spawnattr_destroy(&attr);
|
||||||
|
|
||||||
|
if (spawn_status != 0) {
|
||||||
|
clean_fn();
|
||||||
|
throw torrent::input_error("ExecFile::execute(...) posix_spawn failed: " + std::string(std::strerror(spawn_status)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & flag_capture) {
|
if (flags & flag_capture) {
|
||||||
m_capture = std::string();
|
m_capture = std::string();
|
||||||
::close(pipeFd[1]);
|
::close(pipe_fd[1]);
|
||||||
|
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
ssize_t length;
|
ssize_t length;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
length = read(pipeFd[0], buffer, sizeof(buffer));
|
length = read(pipe_fd[0], buffer, sizeof(buffer));
|
||||||
|
|
||||||
if (length > 0)
|
if (length > 0)
|
||||||
m_capture += std::string(buffer, length);
|
m_capture += std::string(buffer, length);
|
||||||
|
|
||||||
} while (length > 0);
|
} while (length > 0);
|
||||||
|
|
||||||
::close(pipeFd[0]);
|
::close(pipe_fd[0]);
|
||||||
|
|
||||||
if (m_log_fd != -1) {
|
if (m_log_fd != -1) {
|
||||||
result = write(m_log_fd, "Captured output:\n", sizeof("Captured output:\n"));
|
result = write(m_log_fd, "Captured output:\n", sizeof("Captured output:\n"));
|
||||||
@@ -123,7 +133,7 @@ ExecFile::execute(const char* file, char* const* argv, int flags) {
|
|||||||
|
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
while (waitpid(childPid, &status, 0) == -1) {
|
while (waitpid(child_pid, &status, 0) == -1) {
|
||||||
switch (errno) {
|
switch (errno) {
|
||||||
case EINTR:
|
case EINTR:
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
Reference in New Issue
Block a user