diff options
author | Daniel Wilhelm <shieldwed@outlook.com> | 2020-02-23 22:12:27 +0000 |
---|---|---|
committer | Daniel Wilhelm <shieldwed@outlook.com> | 2020-02-23 22:12:27 +0000 |
commit | 450f803dd75f831f8ee14072fe0eb664bbe518df (patch) | |
tree | b3e831d44df50348a20f3541b6062f7fbab6ff3d /zen/shell_execute.h | |
parent | Merge branch '10.19' into 'master' (diff) | |
parent | remove upstream deleted files (diff) | |
download | FreeFileSync-450f803dd75f831f8ee14072fe0eb664bbe518df.tar.gz FreeFileSync-450f803dd75f831f8ee14072fe0eb664bbe518df.tar.bz2 FreeFileSync-450f803dd75f831f8ee14072fe0eb664bbe518df.zip |
Merge branch '10.20' into 'master'10.20
add upstream 10.20
See merge request opensource-tracking/FreeFileSync!17
Diffstat (limited to 'zen/shell_execute.h')
-rw-r--r-- | zen/shell_execute.h | 48 |
1 files changed, 41 insertions, 7 deletions
diff --git a/zen/shell_execute.h b/zen/shell_execute.h index 56322236..580c4558 100644 --- a/zen/shell_execute.h +++ b/zen/shell_execute.h @@ -19,15 +19,15 @@ namespace zen //Windows: COM needs to be initialized before calling this function! enum class ExecutionType { - SYNC, - ASYNC + sync, + async }; namespace { -void shellExecute(const Zstring& command, ExecutionType type, bool hideConsole) //throw FileError +int shellExecute(const Zstring& command, ExecutionType type, bool hideConsole) //throw FileError { /* we cannot use wxExecute due to various issues: @@ -35,21 +35,23 @@ void shellExecute(const Zstring& command, ExecutionType type, bool hideConsole) - 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) + 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"\n" + utfTo<std::wstring>(command)); + 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"\n" + utfTo<std::wstring>(command), L"fork"); + THROW_LAST_FILE_ERROR(_("Incorrect command line:") + L' ' + utfTo<std::wstring>(command), L"fork"); if (pid == 0) //child process { @@ -64,7 +66,39 @@ void shellExecute(const Zstring& command, ExecutionType type, bool hideConsole) ::_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::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"); + + 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; } } @@ -72,7 +106,7 @@ void shellExecute(const Zstring& command, ExecutionType type, bool hideConsole) inline void openWithDefaultApplication(const Zstring& itemPath) //throw FileError { - shellExecute("xdg-open \"" + itemPath + '"', ExecutionType::ASYNC, false /*hideConsole*/); //throw FileError + shellExecute("xdg-open \"" + itemPath + '"', ExecutionType::async, false /*hideConsole*/); //throw FileError } } |