123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- #include "pipe.h"
- #include <util/generic/yexception.h>
- #include <cstdio>
- #include <cerrno>
- class TPipeBase::TImpl {
- public:
- inline TImpl(const TString& command, const char* mode)
- : Pipe_(nullptr)
- {
- #ifndef _freebsd_
- if (strcmp(mode, "r+") == 0) {
- ythrow TSystemError(EINVAL) << "pipe \"r+\" mode is implemented only on FreeBSD";
- }
- #endif
- Pipe_ = ::popen(command.data(), mode);
- if (Pipe_ == nullptr) {
- ythrow TSystemError() << "failed to open pipe: " << command.Quote();
- }
- }
- inline ~TImpl() {
- if (Pipe_ != nullptr) {
- ::pclose(Pipe_);
- }
- }
- public:
- FILE* Pipe_;
- };
- TPipeBase::TPipeBase(const TString& command, const char* mode)
- : Impl_(new TImpl(command, mode))
- {
- }
- TPipeBase::~TPipeBase() = default;
- TPipeInput::TPipeInput(const TString& command)
- : TPipeBase(command, "r")
- {
- }
- size_t TPipeInput::DoRead(void* buf, size_t len) {
- if (Impl_->Pipe_ == nullptr) {
- return 0;
- }
- size_t bytesRead = ::fread(buf, 1, len, Impl_->Pipe_);
- if (bytesRead == 0) {
- int exitStatus = ::pclose(Impl_->Pipe_);
- Impl_->Pipe_ = nullptr;
- if (exitStatus == -1) {
- ythrow TSystemError() << "pclose() failed";
- } else if (exitStatus != 0) {
- ythrow yexception() << "subprocess exited with non-zero status(" << exitStatus << ")";
- }
- }
- return bytesRead;
- }
- TPipeOutput::TPipeOutput(const TString& command)
- : TPipeBase(command, "w")
- {
- }
- void TPipeOutput::DoWrite(const void* buf, size_t len) {
- if (Impl_->Pipe_ == nullptr || len != ::fwrite(buf, 1, len, Impl_->Pipe_)) {
- ythrow TSystemError() << "fwrite failed";
- }
- }
- void TPipeOutput::Close() {
- int exitStatus = ::pclose(Impl_->Pipe_);
- Impl_->Pipe_ = nullptr;
- if (exitStatus == -1) {
- ythrow TSystemError() << "pclose() failed";
- } else if (exitStatus != 0) {
- ythrow yexception() << "subprocess exited with non-zero status(" << exitStatus << ")";
- }
- }
- TPipedBase::TPipedBase(PIPEHANDLE fd)
- : Handle_(fd)
- {
- }
- TPipedBase::~TPipedBase() {
- if (Handle_.IsOpen()) {
- Handle_.Close();
- }
- }
- TPipedInput::TPipedInput(PIPEHANDLE fd)
- : TPipedBase(fd)
- {
- }
- TPipedInput::~TPipedInput() = default;
- size_t TPipedInput::DoRead(void* buf, size_t len) {
- if (!Handle_.IsOpen()) {
- return 0;
- }
- return Handle_.Read(buf, len);
- }
- TPipedOutput::TPipedOutput(PIPEHANDLE fd)
- : TPipedBase(fd)
- {
- }
- TPipedOutput::~TPipedOutput() = default;
- void TPipedOutput::DoWrite(const void* buf, size_t len) {
- if (!Handle_.IsOpen() || static_cast<ssize_t>(len) != Handle_.Write(buf, len)) {
- ythrow TSystemError() << "pipe writing failed";
- }
- }
|