| 728 | #endif |
| 729 | |
| 730 | void TShellCommand::TImpl::Run() { |
| 731 | Y_ENSURE(ExecutionStatus.load(std::memory_order_acquire) != SHELL_RUNNING, TStringBuf("Process is already running")); |
| 732 | // Prepare I/O streams |
| 733 | CollectedOutput.clear(); |
| 734 | CollectedError.clear(); |
| 735 | TPipes pipes; |
| 736 | |
| 737 | if (Options_.OutputMode != TShellCommandOptions::HANDLE_INHERIT) { |
| 738 | TRealPipeHandle::Pipe(pipes.OutputPipeFd[0], pipes.OutputPipeFd[1], CloseOnExec); |
| 739 | } |
| 740 | if (Options_.ErrorMode != TShellCommandOptions::HANDLE_INHERIT) { |
| 741 | TRealPipeHandle::Pipe(pipes.ErrorPipeFd[0], pipes.ErrorPipeFd[1], CloseOnExec); |
| 742 | } |
| 743 | if (InputMode != TShellCommandOptions::HANDLE_INHERIT) { |
| 744 | TRealPipeHandle::Pipe(pipes.InputPipeFd[0], pipes.InputPipeFd[1], CloseOnExec); |
| 745 | } |
| 746 | |
| 747 | ExecutionStatus.store(SHELL_RUNNING, std::memory_order_release); |
| 748 | |
| 749 | #if defined(_unix_) |
| 750 | // block all signals to avoid signal handler race after fork() |
| 751 | sigset_t oldmask, newmask; |
| 752 | SigFillSet(&newmask); |
| 753 | if (SigProcMask(SIG_SETMASK, &newmask, &oldmask) != 0) { |
| 754 | ythrow TSystemError() << "Cannot block all signals in parent"; |
| 755 | } |
| 756 | |
| 757 | /* arguments holders */ |
| 758 | TString shellArg; |
| 759 | TVector<char*> qargv; |
| 760 | /* |
| 761 | Following "const_cast"s are safe: |
| 762 | http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html |
| 763 | */ |
| 764 | if (Options_.UseShell) { |
| 765 | shellArg = GetQuotedCommand(); |
| 766 | qargv.reserve(4); |
| 767 | qargv.push_back(const_cast<char*>("/bin/sh")); |
| 768 | qargv.push_back(const_cast<char*>("-c")); |
| 769 | // two args for 'sh -c -- ', |
| 770 | // one for program name, and one for NULL at the end |
| 771 | qargv.push_back(const_cast<char*>(shellArg.data())); |
| 772 | } else { |
| 773 | qargv.reserve(Arguments.size() + 2); |
| 774 | qargv.push_back(const_cast<char*>(Command.data())); |
| 775 | for (auto& i : Arguments) { |
| 776 | qargv.push_back(const_cast<char*>(i.data())); |
| 777 | } |
| 778 | } |
| 779 | |
| 780 | qargv.push_back(nullptr); |
| 781 | |
| 782 | TVector<TString> envHolder; |
| 783 | TVector<char*> envp; |
| 784 | if (!Options_.Environment.empty()) { |
| 785 | for (auto& env : Options_.Environment) { |
| 786 | envHolder.emplace_back(env.first + '=' + env.second); |
| 787 | envp.push_back(const_cast<char*>(envHolder.back().data())); |
no test coverage detected