diff --git a/libs/ardour/ardour/system_exec.h b/libs/ardour/ardour/system_exec.h index 40e429720e..9f6b7dc1f5 100644 --- a/libs/ardour/ardour/system_exec.h +++ b/libs/ardour/ardour/system_exec.h @@ -32,6 +32,7 @@ class LIBARDOUR_API SystemExec public: SystemExec (std::string c, std::string a = ""); SystemExec (std::string c, char ** a); + SystemExec (std::string c, const std::map subs); ~SystemExec (); int start (int stderr_mode = 1) { diff --git a/libs/ardour/export_handler.cc b/libs/ardour/export_handler.cc index 7c5399a7ae..0eb7be6037 100644 --- a/libs/ardour/export_handler.cc +++ b/libs/ardour/export_handler.cc @@ -38,9 +38,7 @@ #include "ardour/export_filename.h" #include "ardour/session_metadata.h" #include "ardour/soundcloud_upload.h" -#include "pbd/openuri.h" -#include "pbd/basename.h" -#include "pbd/system_exec.h" +#include "ardour/system_exec.h" #include "i18n.h" @@ -297,18 +295,18 @@ ExportHandler::finish_timespan () while (config_map.begin() != timespan_bounds.second) { ExportFormatSpecPtr fmt = config_map.begin()->second.format; - std::string filepath = config_map.begin()->second.filename->get_path(fmt); + std::string filename = config_map.begin()->second.filename->get_path(fmt); if (fmt->with_cue()) { - export_cd_marker_file (current_timespan, fmt, filepath, CDMarkerCUE); + export_cd_marker_file (current_timespan, fmt, filename, CDMarkerCUE); } if (fmt->with_toc()) { - export_cd_marker_file (current_timespan, fmt, filepath, CDMarkerTOC); + export_cd_marker_file (current_timespan, fmt, filename, CDMarkerTOC); } if (fmt->tag()) { - AudiofileTagger::tag_file(filepath, *SessionMetadata::Metadata()); + AudiofileTagger::tag_file(filename, *SessionMetadata::Metadata()); } if (!fmt->command().empty()) { @@ -325,15 +323,14 @@ ExportHandler::finish_timespan () PBD::ScopedConnection command_connection; std::map subs; - subs.insert (std::pair ('f', filepath)); - subs.insert (std::pair ('d', Glib::path_get_dirname(filepath))); - subs.insert (std::pair ('b', PBD::basename_nosuffix(filepath))); - subs.insert (std::pair ('u', upload_username)); - subs.insert (std::pair ('p', upload_password)); - + subs.insert (std::pair ('f', filename)); + subs.insert (std::pair ('d', Glib::path_get_dirname(filename))); + subs.insert (std::pair ('b', PBD::basename_nosuffix(filename))); + subs.insert (std::pair ('s', session.path ())); + subs.insert (std::pair ('n', session.name ())); std::cerr << "running command: " << fmt->command() << "..." << std::endl; - SystemExec *se = new SystemExec(fmt->command(), subs); + ARDOUR::SystemExec *se = new SystemExec(fmt->command(), subs); se->ReadStdout.connect_same_thread(command_connection, boost::bind(&ExportHandler::command_output, this, _1, _2)); if (se->start (2) == 0) { @@ -357,8 +354,8 @@ ExportHandler::finish_timespan () "uploading %1 - username=%2, password=%3, token=%4", filename, soundcloud_username, soundcloud_password, token) ); std::string path = soundcloud_uploader->Upload ( - filepath, - PBD::basename_nosuffix(filepath), // title + filename, + PBD::basename_nosuffix(filename), // title token, soundcloud_make_public, soundcloud_downloadable, diff --git a/libs/pbd/pbd/system_exec.h b/libs/pbd/pbd/system_exec.h index 1232175fec..ce6e5a9c4f 100644 --- a/libs/pbd/pbd/system_exec.h +++ b/libs/pbd/pbd/system_exec.h @@ -42,6 +42,8 @@ #include #include #include +#include + #ifdef NOPBD /* unit-test outside ardour */ #include #include @@ -94,6 +96,23 @@ class LIBPBD_API SystemExec * */ SystemExec (std::string c, char ** a); + + /** similar to \ref SystemExec but expects a whole command line, and + * handles some simple escape sequences. + * + * @param command complete command-line to be executed + * @param subs a map of listing the % substitutions to + * be made. + * + * creates an argv array from the given command string, splitting into + * parameters at spaces. + * "\ " is non-splitting space, "\\" (and "\" at end of command) as "\", + * for "%", is looked up in subs and the corresponding string + * substituted. "%%" (and "%" at end of command) + * returns an argv array suitable for creating a new SystemExec with + */ + SystemExec (std::string command, const std::map subs); + virtual ~SystemExec (); /** fork and execute the given program @@ -182,6 +201,7 @@ class LIBPBD_API SystemExec int nicelevel; ///< process nice level - defaults to 0 void make_argp(std::string); + void make_argp_escaped(std::string command, const std::map subs); void make_envp(); char **argp; @@ -198,6 +218,7 @@ class LIBPBD_API SystemExec #else pid_t pid; #endif + void init (); pthread_mutex_t write_lock; int fdin; ///< file-descriptor for writing to child's STDIN. This variable is identical to pin[1] but also used as status check if the stdin pipe is open: <0 means closed. diff --git a/libs/pbd/system_exec.cc b/libs/pbd/system_exec.cc index 439135c564..ec01bd99fe 100644 --- a/libs/pbd/system_exec.cc +++ b/libs/pbd/system_exec.cc @@ -43,7 +43,12 @@ #include #endif +#include +#define USE_VFORK + +#include "pbd/file_utils.h" +#include "pbd/search_path.h" #include "pbd/system_exec.h" using namespace std; @@ -149,9 +154,8 @@ static int close_allv(const int except_fds[]) { } #endif /* not on windows, nor vfork */ - -SystemExec::SystemExec (std::string c, std::string a) - : cmd(c) +void +SystemExec::init () { pthread_mutex_init(&write_lock, NULL); thread_active=false; @@ -159,12 +163,19 @@ SystemExec::SystemExec (std::string c, std::string a) pin[1] = -1; nicelevel = 0; envp = NULL; - argp = NULL; #ifdef PLATFORM_WINDOWS stdinP[0] = stdinP[1] = INVALID_HANDLE_VALUE; stdoutP[0] = stdoutP[1] = INVALID_HANDLE_VALUE; stderrP[0] = stderrP[1] = INVALID_HANDLE_VALUE; #endif +} + +SystemExec::SystemExec (std::string c, std::string a) + : cmd(c) +{ + init (); + + argp = NULL; make_envp(); make_argp(a); } @@ -172,16 +183,9 @@ SystemExec::SystemExec (std::string c, std::string a) SystemExec::SystemExec (std::string c, char **a) : cmd(c) , argp(a) { - pthread_mutex_init(&write_lock, NULL); - thread_active=false; - pid = 0; - pin[1] = -1; - nicelevel = 0; - envp = NULL; + init (); + #ifdef PLATFORM_WINDOWS - stdinP[0] = stdinP[1] = INVALID_HANDLE_VALUE; - stdoutP[0] = stdoutP[1] = INVALID_HANDLE_VALUE; - stderrP[0] = stderrP[1] = INVALID_HANDLE_VALUE; make_wargs(a); #endif make_envp(); @@ -191,8 +195,17 @@ SystemExec::SystemExec (std::string command, const std::map s { init (); make_argp_escaped(command, subs); - cmd = argp[0]; - // cmd = strdup(argp[0]); + + if (find_file_in_search_path (Searchpath (Glib::getenv ("PATH")), argp[0], cmd)) { + // argp[0] exists in $PATH` - set it to the actual path where it was found + free (argp[0]); + argp[0] = strdup(cmd.c_str ()); + } + // else argp[0] not found in path - leave it as-is, it might be an absolute path + + // Glib::find_program_in_path () is only available in Glib >= 2.28 + // cmd = Glib::find_program_in_path (argp[0]); + make_envp(); } @@ -264,9 +277,6 @@ SystemExec::make_argp_escaped(std::string command, const std::maphProcess, INFINITE); - Sleep(20); + WaitForSingleObject(pid->hProcess, 40); } return 0; } @@ -412,7 +421,12 @@ SystemExec::wait (int options) bool SystemExec::is_running () { - return pid?true:false; + if (!pid) return false; + DWORD exit_code; + if (GetExitCodeProcess(pid->hProcess, &exit_code)) { + if (exit_code == STILL_ACTIVE) return true; + } + return false; } int @@ -602,7 +616,7 @@ SystemExec::make_argp(std::string args) { *cp2 = '\0'; argp[argn++] = strdup(cp1); cp1 = cp2 + 1; - argp = (char **) realloc(argp, (argn + 1) * sizeof(char *)); + argp = (char **) realloc(argp, (argn + 1) * sizeof(char *)); } } if (cp2 != cp1) { @@ -626,7 +640,7 @@ SystemExec::terminate () close_stdin(); if (pid) { - ::usleep(50000); + ::usleep(200000); sched_yield(); wait(WNOHANG); } @@ -637,7 +651,7 @@ SystemExec::terminate () if (pid) { ::kill(pid, SIGTERM); - usleep(50000); + ::usleep(250000); sched_yield(); wait(WNOHANG); } @@ -795,6 +809,10 @@ SystemExec::start (int stderr_mode, const char *vfork_exec_wrapper) #else signal(SIGPIPE, SIG_DFL); #endif + if (!vfork_exec_wrapper) { + error << _("Cannot start external process, no vfork wrapper") << endmsg; + return -1; + } int good_fds[2] = { pok[1], -1 }; close_allv(good_fds); @@ -857,7 +875,16 @@ SystemExec::output_interposer() for (;fcntl(rfd, F_GETFL)!=-1;) { r = read(rfd, buf, sizeof(buf)); if (r < 0 && (errno == EINTR || errno == EAGAIN)) { - ::usleep(1000); + fd_set rfds; + struct timeval tv; + FD_ZERO(&rfds); + FD_SET(rfd, &rfds); + tv.tv_sec = 0; + tv.tv_usec = 10000; + int rv = select(1, &rfds, NULL, NULL, &tv); + if (rv == -1) { + break; + } continue; } if (r <= 0) {