diff options
author | B Stack <bgstack15@gmail.com> | 2020-04-18 17:00:42 +0000 |
---|---|---|
committer | B Stack <bgstack15@gmail.com> | 2020-04-18 17:00:42 +0000 |
commit | b4ecf755bad016b0d7fbb277106887f405f6b600 (patch) | |
tree | 8cfcea5441be72ad92095a3887ded84d38f9ba11 /zen/shell_execute.h | |
parent | Merge branch '10.22' into 'master' (diff) | |
parent | add upstream 10.23 (diff) | |
download | FreeFileSync-b4ecf755bad016b0d7fbb277106887f405f6b600.tar.gz FreeFileSync-b4ecf755bad016b0d7fbb277106887f405f6b600.tar.bz2 FreeFileSync-b4ecf755bad016b0d7fbb277106887f405f6b600.zip |
Merge branch '10.23' into 'master'10.23
add upstream 10.23
See merge request opensource-tracking/FreeFileSync!20
Diffstat (limited to 'zen/shell_execute.h')
-rw-r--r-- | zen/shell_execute.h | 99 |
1 files changed, 6 insertions, 93 deletions
diff --git a/zen/shell_execute.h b/zen/shell_execute.h index faea4bd9..b80cf2ba 100644 --- a/zen/shell_execute.h +++ b/zen/shell_execute.h @@ -9,105 +9,18 @@ #include "file_error.h" - #include <unistd.h> //fork() - #include <stdlib.h> //::system() - namespace zen { -//launch commandline and report errors via popup dialog -//Windows: COM needs to be initialized before calling this function! -enum class ExecutionType -{ - sync, - async -}; - -namespace -{ - - -int shellExecute(const Zstring& command, ExecutionType type, bool hideConsole) //throw FileError -{ - /* - we cannot use wxExecute due to various issues: - - screws up encoding on OS X for non-ASCII characters - - does not provide any reasonable error information - - uses a zero-sized dummy window as a hack to keep focus which leaves a useless empty icon in ALT-TAB list in Windows - */ - if (type == ExecutionType::sync) - { - //Posix ::system() - execute a shell command - const int rv = ::system(command.c_str()); //do NOT use std::system as its documentation says nothing about "WEXITSTATUS(rv)", etc... - if (rv == -1 || WEXITSTATUS(rv) == 127) - throw FileError(_("Incorrect command line:") + L' ' + utfTo<std::wstring>(command)); - //https://linux.die.net/man/3/system "In case /bin/sh could not be executed, the exit status will be that of a command that does exit(127)" - //Bonus: For an incorrect command line /bin/sh also returns with 127! - - return /*int exitCode = */ WEXITSTATUS(rv); - } - else - { - //follow implemenation of ::system() except for waitpid(): - const pid_t pid = ::fork(); - if (pid < 0) //pids are never negative, empiric proof: https://linux.die.net/man/2/wait - THROW_LAST_FILE_ERROR(_("Incorrect command line:") + L' ' + utfTo<std::wstring>(command), L"fork"); - - if (pid == 0) //child process - { - const char* argv[] = { "sh", "-c", command.c_str(), nullptr }; - /*int rv =*/::execv("/bin/sh", const_cast<char**>(argv)); - //safe to cast away const: http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html - // "The statement about argv[] and envp[] being constants is included to make explicit to future - // writers of language bindings that these objects are completely constant. Due to a limitation of - // the ISO C standard, it is not possible to state that idea in standard C." - - //"execv() only returns if an error has occurred. The return value is -1, and errno is set to indicate the error." - ::_exit(127); //[!] avoid flushing I/O buffers or doing other clean up from child process like with "exit(127)"! - } - //else //parent process - return 0; - } -} - - -std::string getCommandOutput(const Zstring& command) //throw SysError -{ - //https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/popen.3.html - FILE* pipe = ::popen(command.c_str(), "r"); - if (!pipe) - THROW_LAST_SYS_ERROR(L"popen"); - ZEN_ON_SCOPE_EXIT(::pclose(pipe)); +std::vector<Zstring> parseCommandline(const Zstring& cmdLine); - std::string output; - const size_t blockSize = 64 * 1024; - do - { - output.resize(output.size() + blockSize); - //caveat: SIGCHLD is NOT ignored under macOS debugger => EINTR inside fread() => call ::siginterrupt(SIGCHLD, false) during startup - const size_t bytesRead = ::fread(&*(output.end() - blockSize), 1, blockSize, pipe); - if (::ferror(pipe)) - THROW_LAST_SYS_ERROR(L"fread"); +DEFINE_NEW_SYS_ERROR(SysErrorTimeOut) +[[nodiscard]] std::pair<int /*exit code*/, std::wstring> consoleExecute(const Zstring& cmdLine, std::optional<int> timeoutMs); //throw SysError, SysErrorTimeOut +/* limitations: Windows: cmd.exe returns exit code 1 if file not found (instead of throwing SysError) => nodiscard! + Linux/macOS: SysErrorTimeOut leaves zombie process behind */ - if (bytesRead > blockSize) - throw SysError(L"fread: buffer overflow"); - - if (bytesRead < blockSize) - output.resize(output.size() - (blockSize - bytesRead)); //caveat: unsigned arithmetics - } - while (!::feof(pipe)); - - return output; -} -} - - -inline -void openWithDefaultApplication(const Zstring& itemPath) //throw FileError -{ - shellExecute("xdg-open \"" + itemPath + '"', ExecutionType::async, false /*hideConsole*/); //throw FileError -} +void openWithDefaultApp(const Zstring& itemPath); //throw FileError } #endif //SHELL_EXECUTE_H_23482134578134134 |