From 9d5b769d78c846bf5da3712050cb3a51d94ddd25 Mon Sep 17 00:00:00 2001 From: Jari Sundell Date: Mon, 5 May 2025 09:55:38 +0200 Subject: [PATCH] Removed/replaced deprecated commands (execute/schedule/schedule_remove) and removed global lock in ExecFile. --- configure.ac | 2 +- src/command_dynamic.cc | 9 +-- src/command_events.cc | 126 +++++++++++++++++---------------------- src/command_local.cc | 3 +- src/command_scheduler.cc | 44 +------------- src/main.cc | 31 +++++----- src/rpc/exec_file.cc | 63 ++++++++------------ src/rpc/exec_file.h | 61 ++++--------------- 8 files changed, 121 insertions(+), 218 deletions(-) diff --git a/configure.ac b/configure.ac index dc4b9b26..53842054 100644 --- a/configure.ac +++ b/configure.ac @@ -10,7 +10,7 @@ AM_PROG_AR LT_INIT AC_PROG_CXX -AC_DEFINE([API_VERSION], [12], [api version]) +AC_DEFINE([API_VERSION], [13], [api version]) # Filter out unwanted flags added by autoconf on some systems, e.g. MacOS. TORRENT_REMOVE_UNWANTED(CXX, $CXX, -std=c++11 -std=gnu++11) diff --git a/src/command_dynamic.cc b/src/command_dynamic.cc index a8231a9d..8e39e847 100644 --- a/src/command_dynamic.cc +++ b/src/command_dynamic.cc @@ -407,12 +407,13 @@ cmd_catch(rpc::target_type target, const torrent::Object& args) { void initialize_command_dynamic() { // clang-format off - #ifdef HAVE_XMLRPC_TINYXML2 +#ifdef HAVE_XMLRPC_TINYXML2 CMD2_ANY ("system.listMethods", std::bind(&system_listMethods)); // only used by tinyxml2 - #endif +#endif - CMD2_VAR_BOOL ("method.use_deprecated", true); - CMD2_VAR_VALUE ("method.use_intermediate", 1); + // Keep these for future use when we deprecate more commands. + CMD2_VAR_BOOL ("method.use_deprecated", false); + CMD2_VAR_VALUE ("method.use_intermediate", 0); CMD2_ANY_LIST ("method.insert", std::bind(&system_method_insert, std::placeholders::_2)); CMD2_ANY_LIST ("method.insert.value", std::bind(&system_method_insert_object, std::placeholders::_2, rpc::object_storage::flag_value_type)); diff --git a/src/command_events.cc b/src/command_events.cc index f8fc1c03..488cb58c 100644 --- a/src/command_events.cc +++ b/src/command_events.cc @@ -11,6 +11,9 @@ #include #include +#include "globals.h" +#include "control.h" +#include "command_helpers.h" #include "core/download.h" #include "core/download_list.h" #include "core/manager.h" @@ -19,74 +22,55 @@ #include "rpc/parse.h" #include "rpc/parse_commands.h" -#include "globals.h" -#include "control.h" -#include "command_helpers.h" - -#include "thread_worker.h" - torrent::Object apply_on_ratio(const torrent::Object& rawArgs) { - const std::string& groupName = rawArgs.as_string(); + auto& group_name = rawArgs.as_string(); + auto view_itr = control->view_manager()->find(rpc::commands.call("group2." + group_name + ".view", rpc::make_target()).as_string()); - char buffer[32 + groupName.size()]; - snprintf(buffer, sizeof(buffer), "group2.%s.view", groupName.c_str()); - - core::ViewManager::iterator viewItr = control->view_manager()->find(rpc::commands.call(buffer, rpc::make_target()).as_string()); - - if (viewItr == control->view_manager()->end()) + if (view_itr == control->view_manager()->end()) throw torrent::input_error("Could not find view."); - char* bufferStart = buffer + snprintf(buffer, sizeof(buffer), "group2.%s.ratio.", groupName.c_str()); - // first argument: minimum ratio to reach // second argument: minimum upload amount to reach [optional] // third argument: maximum ratio to reach [optional] - std::strcpy(bufferStart, "min"); - int64_t minRatio = rpc::commands.call(buffer, rpc::make_target()).as_value(); - std::strcpy(bufferStart, "max"); - int64_t maxRatio = rpc::commands.call(buffer, rpc::make_target()).as_value(); - std::strcpy(bufferStart, "upload"); - int64_t minUpload = rpc::commands.call(buffer, rpc::make_target()).as_value(); + int64_t min_ratio = rpc::commands.call("group2." + group_name + ".ratio.min", rpc::make_target()).as_value(); + int64_t max_ratio = rpc::commands.call("group2." + group_name + ".ratio.max", rpc::make_target()).as_value(); + int64_t min_upload = rpc::commands.call("group2." + group_name + ".ratio.upload", rpc::make_target()).as_value(); std::vector downloads; - for (core::View::iterator itr = (*viewItr)->begin_visible(), last = (*viewItr)->end_visible(); itr != last; itr++) { + for (auto itr = (*view_itr)->begin_visible(), last = (*view_itr)->end_visible(); itr != last; itr++) { if (!(*itr)->is_seeding() || rpc::call_command_value("d.ignore_commands", rpc::make_target(*itr)) != 0) continue; - // rpc::parse_command_single(rpc::make_target(*itr), "print={Checked ratio of download.}"); + int64_t total_done = (*itr)->download()->bytes_done(); + int64_t total_upload = (*itr)->info()->up_rate()->total(); - int64_t totalDone = (*itr)->download()->bytes_done(); - int64_t totalUpload = (*itr)->info()->up_rate()->total(); - - if (!(totalUpload >= minUpload && totalUpload * 100 >= totalDone * minRatio) && - !(maxRatio > 0 && totalUpload * 100 > totalDone * maxRatio)) + if (!(total_upload >= min_upload && total_upload * 100 >= total_done * min_ratio) && + !(max_ratio > 0 && total_upload * 100 > total_done * max_ratio)) continue; downloads.push_back(*itr); } - snprintf(buffer, sizeof(buffer), "group.%s.ratio.command", groupName.c_str()); + auto ratio_command = "group." + group_name + ".ratio.command"; - for (std::vector::iterator itr = downloads.begin(), last = downloads.end(); itr != last; itr++) { - // rpc::commands.call("print", rpc::make_target(*itr), "Calling ratio command."); - rpc::commands.call_catch(buffer, rpc::make_target(*itr), torrent::Object(), "Ratio reached, but command failed: "); - } + for (std::vector::iterator itr = downloads.begin(), last = downloads.end(); itr != last; itr++) + rpc::commands.call_catch(ratio_command, rpc::make_target(*itr), torrent::Object(), "Ratio reached, but command failed: "); return torrent::Object(); } torrent::Object apply_start_tied() { - for (core::DownloadList::iterator itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ++itr) { + for (auto itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ++itr) { if (rpc::call_command_value("d.state", rpc::make_target(*itr)) == 1) continue; rak::file_stat fs; - const std::string& tiedToFile = rpc::call_command_string("d.tied_to_file", rpc::make_target(*itr)); + const std::string& tied_to_file = rpc::call_command_string("d.tied_to_file", rpc::make_target(*itr)); - if (!tiedToFile.empty() && fs.update(rak::path_expand(tiedToFile))) + if (!tied_to_file.empty() && fs.update(rak::path_expand(tied_to_file))) rpc::parse_command_single(rpc::make_target(*itr), "d.try_start="); } @@ -95,14 +79,14 @@ apply_start_tied() { torrent::Object apply_stop_untied() { - for (core::DownloadList::iterator itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ++itr) { + for (auto itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ++itr) { if (rpc::call_command_value("d.state", rpc::make_target(*itr)) == 0) continue; rak::file_stat fs; - const std::string& tiedToFile = rpc::call_command_string("d.tied_to_file", rpc::make_target(*itr)); + const std::string& tied_to_file = rpc::call_command_string("d.tied_to_file", rpc::make_target(*itr)); - if (!tiedToFile.empty() && !fs.update(rak::path_expand(tiedToFile))) + if (!tied_to_file.empty() && !fs.update(rak::path_expand(tied_to_file))) rpc::parse_command_single(rpc::make_target(*itr), "d.try_stop="); } @@ -111,11 +95,11 @@ apply_stop_untied() { torrent::Object apply_close_untied() { - for (core::DownloadList::iterator itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ++itr) { + for (auto itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ++itr) { rak::file_stat fs; - const std::string& tiedToFile = rpc::call_command_string("d.tied_to_file", rpc::make_target(*itr)); + const std::string& tied_to_file = rpc::call_command_string("d.tied_to_file", rpc::make_target(*itr)); - if (rpc::call_command_value("d.ignore_commands", rpc::make_target(*itr)) == 0 && !tiedToFile.empty() && !fs.update(rak::path_expand(tiedToFile))) + if (rpc::call_command_value("d.ignore_commands", rpc::make_target(*itr)) == 0 && !tied_to_file.empty() && !fs.update(rak::path_expand(tied_to_file))) rpc::parse_command_single(rpc::make_target(*itr), "d.try_close="); } @@ -124,11 +108,11 @@ apply_close_untied() { torrent::Object apply_remove_untied() { - for (core::DownloadList::iterator itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ) { + for (auto itr = control->core()->download_list()->begin(); itr != control->core()->download_list()->end(); ) { rak::file_stat fs; - const std::string& tiedToFile = rpc::call_command_string("d.tied_to_file", rpc::make_target(*itr)); + const std::string& tied_to_file = rpc::call_command_string("d.tied_to_file", rpc::make_target(*itr)); - if (!tiedToFile.empty() && !fs.update(rak::path_expand(tiedToFile))) { + if (!tied_to_file.empty() && !fs.update(rak::path_expand(tied_to_file))) { // Need to clear tied_to_file so it doesn't try to delete it. rpc::call_command("d.tied_to_file.set", std::string(), rpc::make_target(*itr)); @@ -149,9 +133,9 @@ apply_schedule(const torrent::Object::list_type& args) { torrent::Object::list_const_iterator itr = args.begin(); - const std::string& arg1 = (itr++)->as_string(); - const std::string& arg2 = (itr++)->as_string(); - const std::string& arg3 = (itr++)->as_string(); + auto& arg1 = (itr++)->as_string(); + auto& arg2 = (itr++)->as_string(); + auto& arg3 = (itr++)->as_string(); control->command_scheduler()->parse(arg1, arg2, arg3, *itr); @@ -165,7 +149,7 @@ apply_load(const torrent::Object::list_type& args, int flags) { if (argsItr == args.end()) throw torrent::input_error("Too few arguments."); - const std::string& filename = argsItr->as_string(); + auto& filename = argsItr->as_string(); core::Manager::command_list_type commands; while (++argsItr != args.end()) @@ -210,20 +194,20 @@ apply_download_list(const torrent::Object::list_type& args) { torrent::Object::list_const_iterator argsItr = args.begin(); core::ViewManager* viewManager = control->view_manager(); - core::ViewManager::iterator viewItr; + core::ViewManager::iterator view_itr; if (argsItr != args.end() && !argsItr->as_string().empty()) - viewItr = viewManager->find((argsItr++)->as_string()); + view_itr = viewManager->find((argsItr++)->as_string()); else - viewItr = viewManager->find("default"); + view_itr = viewManager->find("default"); - if (viewItr == viewManager->end()) + if (view_itr == viewManager->end()) throw torrent::input_error("Could not find view."); torrent::Object result = torrent::Object::create_list(); torrent::Object::list_type& resultList = result.as_list(); - for (core::View::const_iterator itr = (*viewItr)->begin_visible(), last = (*viewItr)->end_visible(); itr != last; itr++) { + for (core::View::const_iterator itr = (*view_itr)->begin_visible(), last = (*view_itr)->end_visible(); itr != last; itr++) { const torrent::HashString* hashString = &(*itr)->info()->hash(); resultList.push_back(rak::transform_hex(hashString->begin(), hashString->end())); @@ -238,32 +222,31 @@ d_multicall(const torrent::Object::list_type& args) { throw torrent::input_error("Too few arguments."); core::ViewManager* viewManager = control->view_manager(); - core::ViewManager::iterator viewItr; + core::ViewManager::iterator view_itr; if (!args.front().as_string().empty()) - viewItr = viewManager->find(args.front().as_string()); + view_itr = viewManager->find(args.front().as_string()); else - viewItr = viewManager->find("default"); + view_itr = viewManager->find("default"); - if (viewItr == viewManager->end()) + if (view_itr == viewManager->end()) throw torrent::input_error("Could not find view."); // Add some pre-parsing of the commands, so we don't spend time // parsing and searching command map for every single call. - unsigned int dlist_size = (*viewItr)->size_visible(); - core::Download* dlist[dlist_size]; + std::vector dlist((*view_itr)->size_visible()); - std::copy((*viewItr)->begin_visible(), (*viewItr)->end_visible(), dlist); + std::copy((*view_itr)->begin_visible(), (*view_itr)->end_visible(), dlist.data()); torrent::Object resultRaw = torrent::Object::create_list(); torrent::Object::list_type& result = resultRaw.as_list(); - for (core::Download** vItr = dlist; vItr != dlist + dlist_size; vItr++) { + for (auto download : dlist) { torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list(); for (torrent::Object::list_const_iterator cItr = ++args.begin(); cItr != args.end(); cItr++) { - const std::string& cmd = cItr->as_string(); - row.push_back(rpc::parse_command(rpc::make_target(*vItr), cmd.c_str(), cmd.c_str() + cmd.size()).first); + auto& cmd = cItr->as_string(); + row.push_back(rpc::parse_command(rpc::make_target(download), cmd.c_str(), cmd.c_str() + cmd.size()).first); } } @@ -278,14 +261,14 @@ d_multicall_filtered(const torrent::Object::list_type& args) { // Find the given view core::ViewManager* viewManager = control->view_manager(); - core::ViewManager::iterator viewItr = viewManager->find(arg->as_string().empty() ? "default" : arg->as_string()); + core::ViewManager::iterator view_itr = viewManager->find(arg->as_string().empty() ? "default" : arg->as_string()); - if (viewItr == viewManager->end()) + if (view_itr == viewManager->end()) throw torrent::input_error("Could not find view '" + arg->as_string() + "'."); // Make a filtered copy of the current item list core::View::base_type dlist; - (*viewItr)->filter_by(*++arg, dlist); + (*view_itr)->filter_by(*++arg, dlist); // Generate result by iterating over all items torrent::Object resultRaw = torrent::Object::create_list(); @@ -298,7 +281,7 @@ d_multicall_filtered(const torrent::Object::list_type& args) { // Call the provided commands and assemble their results for (torrent::Object::list_const_iterator command = arg; command != args.end(); command++) { - const std::string& cmdstr = command->as_string(); + auto& cmdstr = command->as_string(); row.push_back(rpc::parse_command(rpc::make_target(*item), cmdstr.c_str(), cmdstr.c_str() + cmdstr.size()).first); } } @@ -316,8 +299,8 @@ directory_watch_added(const torrent::Object::list_type& args) { if (args.size() != 2) throw torrent::input_error("Too few arguments."); - const std::string& path = args.front().as_string(); - const std::string& command = args.back().as_string(); + auto& path = args.front().as_string(); + auto& command = args.back().as_string(); if (!control->directory_events()->open()) throw torrent::input_error("Could not open inotify:" + std::string(rak::error_number::current().c_str())); @@ -337,7 +320,10 @@ initialize_command_events() { CMD2_ANY ("close_untied", std::bind(&apply_close_untied)); CMD2_ANY ("remove_untied", std::bind(&apply_remove_untied)); + // TODO: Deprecate schedule2 in the future. + CMD2_ANY_LIST ("schedule", std::bind(&apply_schedule, std::placeholders::_2)); CMD2_ANY_LIST ("schedule2", std::bind(&apply_schedule, std::placeholders::_2)); + CMD2_ANY_STRING_V("schedule.remove", std::bind(&rpc::CommandScheduler::erase_str, control->command_scheduler(), std::placeholders::_2)); CMD2_ANY_STRING_V("schedule_remove2", std::bind(&rpc::CommandScheduler::erase_str, control->command_scheduler(), std::placeholders::_2)); CMD2_ANY_STRING_V("import", std::bind(&apply_import, std::placeholders::_2)); diff --git a/src/command_local.cc b/src/command_local.cc index f411d72d..c1220443 100644 --- a/src/command_local.cc +++ b/src/command_local.cc @@ -300,9 +300,10 @@ initialize_command_local() { CMD2_ANY ("lua.execute.str", std::bind(&rpc::execute_lua, lua_engine, std::placeholders::_1, std::placeholders::_2, rpc::LuaEngine::flag_string)); #endif -#define CMD2_EXECUTE(key, flags) \ +#define CMD2_EXECUTE(key, flags) \ CMD2_ANY(key, std::bind(&rpc::ExecFile::execute_object, &rpc::execFile, std::placeholders::_2, flags)); + CMD2_EXECUTE ("execute", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw); CMD2_EXECUTE ("execute2", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw); CMD2_EXECUTE ("execute.throw", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw); CMD2_EXECUTE ("execute.throw.bg", rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_throw | rpc::ExecFile::flag_background); diff --git a/src/command_scheduler.cc b/src/command_scheduler.cc index a2c92684..4de7ae48 100644 --- a/src/command_scheduler.cc +++ b/src/command_scheduler.cc @@ -1,39 +1,3 @@ -// rTorrent - BitTorrent client -// Copyright (C) 2005-2011, Jari Sundell -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// In addition, as a special exception, the copyright holders give -// permission to link the code of portions of this program with the -// OpenSSL library under certain conditions as described in each -// individual source file, and distribute linked combinations -// including the two. -// -// You must obey the GNU General Public License in all respects for -// all of the code used other than OpenSSL. If you modify file(s) -// with this exception, you may extend this exception to your version -// of the file(s), but you are not obligated to do so. If you do not -// wish to do so, delete this exception statement from your version. -// If you delete this exception statement from all source files in the -// program, then also delete it here. -// -// Contact: Jari Sundell -// -// Skomakerveien 33 -// 3185 Skoppum, NORWAY - #include "config.h" #include @@ -52,7 +16,7 @@ torrent::Object cmd_scheduler_simple_added(core::Download* download) { unsigned int numActive = (*control->view_manager()->find("active"))->size_visible(); int64_t maxActive = rpc::call_command("scheduler.max_active", torrent::Object()).as_value(); - + if (numActive < (uint64_t)maxActive) control->core()->download_list()->resume(download); @@ -83,7 +47,7 @@ cmd_scheduler_simple_removed(core::Download* download) { } torrent::Object -cmd_scheduler_simple_update(core::Download* download) { +cmd_scheduler_simple_update([[maybe_unused]] core::Download* download) { core::View* viewActive = *control->view_manager()->find("active"); core::View* viewStarted = *control->view_manager()->find("started"); @@ -91,7 +55,6 @@ cmd_scheduler_simple_update(core::Download* download) { uint64_t maxActive = rpc::call_command("scheduler.max_active", torrent::Object()).as_value(); if (viewActive->size_visible() < maxActive) { - for (core::View::iterator itr = viewStarted->begin_visible(), last = viewStarted->end_visible(); itr != last; itr++) { if ((*itr)->is_active()) continue; @@ -102,8 +65,7 @@ cmd_scheduler_simple_update(core::Download* download) { break; } - } else if (viewActive->size_visible() > maxActive) { - + } else { while (viewActive->size_visible() > maxActive) control->core()->download_list()->pause(*viewActive->begin_visible()); } diff --git a/src/main.cc b/src/main.cc index ee77359c..15706ade 100644 --- a/src/main.cc +++ b/src/main.cc @@ -395,25 +395,26 @@ main(int argc, char** argv) { CMD2_REDIRECT ("torrent_list_layout", "ui.torrent_list.layout.set"); // Deprecated commands. Don't use these anymore. + // + // It has been so long that we now re-create these commands with the new (old by now) command + // call style, where the first argument is the target. - if (rpc::call_command_value("method.use_intermediate") == 1) { - CMD2_REDIRECT_GENERIC("execute", "execute2"); + // if (rpc::call_command_value("method.use_intermediate") == 1) { + // CMD2_REDIRECT_GENERIC("execute", "execute2"); - CMD2_REDIRECT_GENERIC("schedule", "schedule2"); - CMD2_REDIRECT_GENERIC("schedule_remove", "schedule_remove2"); + // CMD2_REDIRECT_GENERIC("schedule", "schedule2"); + // CMD2_REDIRECT_GENERIC("schedule_remove", "schedule_remove2"); - } else if (rpc::call_command_value("method.use_intermediate") == 2) { - // Allow for use in config files, etc, just don't export it. - CMD2_REDIRECT_GENERIC_NO_EXPORT("execute", "execute2"); + // } else if (rpc::call_command_value("method.use_intermediate") == 2) { + // Allow for use in config files, etc, just don't export it. + // CMD2_REDIRECT_GENERIC_NO_EXPORT("execute", "execute2"); - CMD2_REDIRECT_GENERIC_NO_EXPORT("schedule", "schedule2"); - CMD2_REDIRECT_GENERIC_NO_EXPORT("schedule_remove", "schedule_remove2"); - } + // CMD2_REDIRECT_GENERIC_NO_EXPORT("schedule", "schedule2"); + // CMD2_REDIRECT_GENERIC_NO_EXPORT("schedule_remove", "schedule_remove2"); + // } -#if LT_SLIM_VERSION != 1 - if (rpc::call_command_value("method.use_deprecated")) { - } -#endif + // if (rpc::call_command_value("method.use_deprecated") == 1) { + // } int firstArg = parse_options(argc, argv); @@ -607,6 +608,8 @@ print_help() { std::cout << std::endl; std::cout << "Usage: rtorrent [OPTIONS]... [FILE]... [URL]..." << std::endl; std::cout << " -D Enable deprecated commands" << std::endl; + std::cout << " -I Disable intermediate commands" << std::endl; + std::cout << " -K Allow intermediate commands without xmlrpc" << std::endl; std::cout << " -h Display this very helpful text" << std::endl; std::cout << " -n Don't try to load rtorrent.rc on startup" << std::endl; std::cout << " -b Bind the listening socket to this IP" << std::endl; diff --git a/src/rpc/exec_file.cc b/src/rpc/exec_file.cc index d97f582c..a2142f3c 100644 --- a/src/rpc/exec_file.cc +++ b/src/rpc/exec_file.cc @@ -1,9 +1,9 @@ #include "config.h" +#include #include #include #include -#include #include #include #include @@ -14,32 +14,24 @@ namespace rpc { -const unsigned int ExecFile::max_args; -const unsigned int ExecFile::buffer_size; - -const int ExecFile::flag_expand_tilde; -const int ExecFile::flag_throw; -const int ExecFile::flag_capture; -const int ExecFile::flag_background; - -// Close m_logFd. +// TODO: Access fd through torrent logging? int ExecFile::execute(const char* file, char* const* argv, int flags) { // Write the execued command and its parameters to the log fd. int __UNUSED result; - if (m_logFd != -1) { + if (m_log_fd != -1) { for (char* const* itr = argv; *itr != NULL; itr++) { if (itr == argv) - result = write(m_logFd, "\n---\n", sizeof("\n---\n")); + result = write(m_log_fd, "\n---\n", sizeof("\n---\n")); else - result = write(m_logFd, " ", 1); + result = write(m_log_fd, " ", 1); - result = write(m_logFd, *itr, std::strlen(*itr)); + result = write(m_log_fd, *itr, std::strlen(*itr)); } - result = write(m_logFd, "\n---\n", sizeof("\n---\n")); + result = write(m_log_fd, "\n---\n", sizeof("\n---\n")); } int pipeFd[2]; @@ -60,17 +52,18 @@ ExecFile::execute(const char* file, char* const* argv, int flags) { _exit(-1); if (detached_pid != 0) { - if (m_logFd != -1) - result = write(m_logFd, "\n--- Background task ---\n", sizeof("\n--- Background task ---\n")); + if (m_log_fd != -1) + result = write(m_log_fd, "\n--- Background task ---\n", sizeof("\n--- Background task ---\n")); _exit(0); } - m_logFd = -1; + m_log_fd = -1; flags &= ~flag_capture; } int devNull = open("/dev/null", O_RDWR); + if (devNull != -1) dup2(devNull, 0); else @@ -78,15 +71,15 @@ ExecFile::execute(const char* file, char* const* argv, int flags) { if (flags & flag_capture) dup2(pipeFd[1], 1); - else if (m_logFd != -1) - dup2(m_logFd, 1); + else if (m_log_fd != -1) + dup2(m_log_fd, 1); else if (devNull != -1) dup2(devNull, 1); else ::close(1); - if (m_logFd != -1) - dup2(m_logFd, 2); + if (m_log_fd != -1) + dup2(m_log_fd, 2); else if (devNull != -1) dup2(devNull, 2); else @@ -101,10 +94,6 @@ ExecFile::execute(const char* file, char* const* argv, int flags) { _exit(result); } - // We yield the global lock when waiting for the executed command to - // finish so that XMLRPC and other threads can continue working. - torrent::utils::Thread::release_global_lock(); - if (flags & flag_capture) { m_capture = std::string(); ::close(pipeFd[1]); @@ -121,9 +110,9 @@ ExecFile::execute(const char* file, char* const* argv, int flags) { ::close(pipeFd[0]); - if (m_logFd != -1) { - result = write(m_logFd, "Captured output:\n", sizeof("Captured output:\n")); - result = write(m_logFd, m_capture.data(), m_capture.length()); + if (m_log_fd != -1) { + result = write(m_log_fd, "Captured output:\n", sizeof("Captured output:\n")); + result = write(m_log_fd, m_capture.data(), m_capture.length()); } } @@ -132,19 +121,17 @@ ExecFile::execute(const char* file, char* const* argv, int flags) { do { wpid = waitpid(childPid, &status, 0); - } while (wpid == -1 && rak::error_number::current().value() == rak::error_number::e_intr); - - torrent::utils::Thread::acquire_global_lock(); + } while (wpid == -1 && WIFEXITED(status) == 0); if (wpid != childPid) throw torrent::internal_error("ExecFile::execute(...) waitpid failed."); // Check return value? - if (m_logFd != -1) { + if (m_log_fd != -1) { if (status == 0) - result = write(m_logFd, "\n--- Success ---\n", sizeof("\n--- Success ---\n")); + result = write(m_log_fd, "\n--- Success ---\n", sizeof("\n--- Success ---\n")); else - result = write(m_logFd, "\n--- Error ---\n", sizeof("\n--- Error ---\n")); + result = write(m_log_fd, "\n--- Error ---\n", sizeof("\n--- Error ---\n")); } return status; @@ -156,7 +143,7 @@ ExecFile::execute_object(const torrent::Object& rawArgs, int flags) { char** argsCurrent = argsBuffer; // Size of value strings are less than 24. - char valueBuffer[buffer_size]; + char valueBuffer[buffer_size+1]; char* valueCurrent = valueBuffer; if (rawArgs.is_list()) { @@ -178,12 +165,12 @@ ExecFile::execute_object(const torrent::Object& rawArgs, int flags) { if (valueCurrent >= valueBuffer + buffer_size) throw torrent::input_error("Overflowed execute arg buffer."); - } + } } } else { const torrent::Object::string_type& args = rawArgs.as_string(); - + if ((flags & flag_expand_tilde) && args.c_str()[0] == '~') { *argsCurrent = valueCurrent; valueCurrent = print_object(valueCurrent, valueBuffer + buffer_size, &rawArgs, flags) + 1; diff --git a/src/rpc/exec_file.h b/src/rpc/exec_file.h index 6e70a07d..6b3e0fd2 100644 --- a/src/rpc/exec_file.h +++ b/src/rpc/exec_file.h @@ -1,39 +1,3 @@ -// rTorrent - BitTorrent client -// Copyright (C) 2005-2011, Jari Sundell -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// In addition, as a special exception, the copyright holders give -// permission to link the code of portions of this program with the -// OpenSSL library under certain conditions as described in each -// individual source file, and distribute linked combinations -// including the two. -// -// You must obey the GNU General Public License in all respects for -// all of the code used other than OpenSSL. If you modify file(s) -// with this exception, you may extend this exception to your version -// of the file(s), but you are not obligated to do so. If you do not -// wish to do so, delete this exception statement from your version. -// If you delete this exception statement from all source files in the -// program, then also delete it here. -// -// Contact: Jari Sundell -// -// Skomakerveien 33 -// 3185 Skoppum, NORWAY - #ifndef RTORRENT_RPC_EXEC_FILE_H #define RTORRENT_RPC_EXEC_FILE_H @@ -43,25 +7,24 @@ namespace rpc { class ExecFile { public: - static const unsigned int max_args = 128; - static const unsigned int buffer_size = 4096; - - static const int flag_expand_tilde = 0x1; - static const int flag_throw = 0x2; - static const int flag_capture = 0x4; - static const int flag_background = 0x8; + static constexpr unsigned int max_args = 128; + static constexpr unsigned int buffer_size = 4096; - ExecFile() : m_logFd(-1) {} + static constexpr int flag_expand_tilde = 0x1; + static constexpr int flag_throw = 0x2; + static constexpr int flag_capture = 0x4; + static constexpr int flag_background = 0x8; - int log_fd() const { return m_logFd; } - void set_log_fd(int fd) { m_logFd = fd; } + ExecFile() : m_log_fd(-1) {} + + int log_fd() const { return m_log_fd; } + void set_log_fd(int fd) { m_log_fd = fd; } int execute(const char* file, char* const* argv, int flags); - torrent::Object execute_object(const torrent::Object& rawArgs, int flags); - + private: - int m_logFd; + int m_log_fd; std::string m_capture; };