NCBI C++ ToolKit
ncbi_pipe.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: ncbi_pipe.cpp 99228 2023-03-01 05:54:36Z lavr $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors: Anton Lavrentiev, Mike DiCuccio, Vladimir Ivanov
27  *
28  * File Description:
29  * Inter-process pipe with a spawned process.
30  *
31  */
32 
33 #include <ncbi_pch.hpp>
34 /* Cancel __wur (warn unused result) ill effects in GCC */
35 #ifdef _FORTIFY_SOURCE
36 # undef _FORTIFY_SOURCE
37 #endif /*_FORTIFY_SOURCE*/
38 #define _FORTIFY_SOURCE 0
39 #include "ncbi_priv.h"
40 #include <corelib/ncbiexec.hpp>
41 #include <corelib/ncbi_param.hpp>
42 #include <corelib/ncbi_system.hpp>
43 #include <corelib/stream_utils.hpp>
44 #include <connect/error_codes.hpp>
45 #include <connect/ncbi_pipe.hpp>
46 
47 #ifdef NCBI_OS_MSWIN
48 
49 # include <windows.h>
50 
51 #elif defined NCBI_OS_UNIX
52 
53 # include <errno.h>
54 # include <fcntl.h>
55 # include <poll.h>
56 # include <signal.h>
57 # include <unistd.h>
58 # include <sys/time.h>
59 # include <sys/types.h>
60 # include <sys/wait.h>
61 
62 #else
63 # error "The CPipe class is supported only on Windows and Unix"
64 #endif
65 
66 #define NCBI_USE_ERRCODE_X Connect_Pipe
67 
68 
69 #define IS_SET(flags, mask) (((flags) & (mask)) == (mask))
70 
71 
72 #define PIPE_THROW(err, errtxt) \
73  THROW0_TRACE(x_FormatError(int(err), errtxt))
74 
75 
77 
78 
79 //////////////////////////////////////////////////////////////////////////////
80 //
81 // Auxiliary functions
82 //
83 
84 static const STimeout* s_SetTimeout(const STimeout* from, STimeout* to)
85 {
86  if (!from) {
87  return kInfiniteTimeout;
88  }
89  to->sec = from->usec / kMicroSecondsPerSecond+ from->sec;
90  to->usec = from->usec % kMicroSecondsPerSecond;
91  return to;
92 }
93 
94 
96 
97 
98 static string x_FormatError(int error, const string& message)
99 {
100  const char* errstr;
101 
102 #ifdef NCBI_OS_MSWIN
103  string errmsg;
104  if (error) {
105  TCHAR* tmpstr = NULL;
106  DWORD rv = ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
107  FORMAT_MESSAGE_FROM_SYSTEM |
108  FORMAT_MESSAGE_MAX_WIDTH_MASK |
109  FORMAT_MESSAGE_IGNORE_INSERTS,
110  NULL, (DWORD) error,
111  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
112  (LPTSTR) &tmpstr, 0, NULL);
113  if (rv && tmpstr) {
114  errmsg = _T_CSTRING(tmpstr);
115  errstr = errmsg.c_str();
116  } else {
117  errstr = "";
118  }
119  if (tmpstr) {
120  ::LocalFree((HLOCAL) tmpstr);
121  }
122  } else
123 #endif // NCBI_OS_MSWIN
124  errstr = 0;
125 
126  int dynamic = 0/*false*/;
127  const char* result = ::NcbiMessagePlusError(&dynamic, message.c_str(),
128  error, errstr);
129  TTempCharPtr retval(const_cast<char*> (result),
130  dynamic ? eTakeOwnership : eNoOwnership);
131  return retval.get() ? retval.get() : message;
132 }
133 
134 
135 static string s_FormatErrorMessage(const string& where, const string& what)
136 {
137  return "[CPipe::" + where + "] " + what;
138 }
139 
140 
142  const STimeout* timeout, int* exitcode)
143 {
144  CProcess::CExitInfo exitinfo;
145  int x_exitcode = process.Wait(NcbiTimeoutToMs(timeout), &exitinfo);
146 
147  EIO_Status status;
148  if (x_exitcode < 0) {
149  if (!exitinfo.IsPresent()) {
150  status = eIO_Unknown;
151  } else if (!exitinfo.IsAlive()) {
152  status = eIO_Unknown;
153 #ifdef NCBI_OS_UNIX
154  if (exitinfo.IsSignaled()) {
155  x_exitcode = -(exitinfo.GetSignal() + 1000);
156  }
157 #endif // NCBI_OS_UNIX
158  } else {
159  status = eIO_Timeout;
162  unsigned long x_timeout;
163  if (!timeout || (timeout->sec | timeout->usec)) {
164  x_timeout = CProcess::kDefaultKillTimeout;
165  } else {
166  x_timeout = 0/*fast but unsafe*/;
167  }
168  bool killed;
169  if (IS_SET(flags, CPipe::fNewGroup)) {
170  killed = process.KillGroup(x_timeout);
171  } else {
172  killed = process.Kill (x_timeout);
173  }
174  status = killed ? eIO_Success : eIO_Unknown;
175  } else {
176  status = eIO_Success;
177  }
178  }
179  }
180  } else {
181  _ASSERT(exitinfo.IsPresent());
182  _ASSERT(exitinfo.IsExited());
183  _ASSERT(exitinfo.GetExitCode() == x_exitcode);
184  status = eIO_Success;
185  }
186 
187  if (exitcode) {
188  *exitcode = x_exitcode;
189  }
190  return status;
191 }
192 
193 
195 {
196  switch (handle) {
197  case CPipe::eStdIn:
198  return "eStdIn";
199  case CPipe::eStdOut:
200  return "eStdOut";
201  case CPipe::eStdErr:
202  return "eStdErr";
203  default:
204  _TROUBLE;
205  break;
206  }
207  return "<Invalid handle " + NStr::NumericToString(int(handle)) + '>';
208 }
209 
210 
211 static string x_CommandLine(const string& cmd,
212  const vector<string>& args)
213 {
214  // Enclose command elements in quotes if necessary.
215  string cmd_line(CExec::QuoteArg(cmd));
216  for (auto&& arg : args) {
217  cmd_line += ' ';
218  cmd_line += CExec::QuoteArg(arg);
219  }
220  return cmd_line;
221 }
222 
223 
224 
225 //////////////////////////////////////////////////////////////////////////////
226 //
227 // Class CPipeHandle handles forwarded requests from CPipe.
228 // This class is reimplemented in a platform-specific fashion where needed.
229 //
230 
231 #if defined(NCBI_OS_MSWIN)
232 
233 
234 const unsigned long kWaitPrecision = 100; // Timeout time slice (milliseconds)
235 
236 
237 static inline bool x_IsDisconnectError(DWORD error)
238 {
239  return (error == ERROR_NO_DATA ||
240  error == ERROR_BROKEN_PIPE ||
241  error == ERROR_PIPE_NOT_CONNECTED ? true : false);
242 }
243 
244 
245 //////////////////////////////////////////////////////////////////////////////
246 //
247 // CPipeHandle -- MS Windows version
248 //
249 
251 {
252 public:
253  CPipeHandle(void);
254  ~CPipeHandle();
255  EIO_Status Open(const string& cmd, const vector<string>& args,
256  CPipe::TCreateFlags create_flags,
257  const string& current_dir,
258  const char* const env[],
259  size_t pipe_size);
260  void OpenSelf(void);
261  EIO_Status Close(int* exitcode, const STimeout* timeout);
263  EIO_Status Read(void* buf, size_t count, size_t* n_read,
264  const CPipe::EChildIOHandle from_handle,
265  const STimeout* timeout) const;
266  EIO_Status Write(const void* data, size_t count, size_t* written,
267  const STimeout* timeout) const;
269  const STimeout* timeout) const;
271  void Release(void) { x_Clear(); }
272 
273 private:
274  // Clear object state.
275  void x_Clear(void);
276  // Get child's I/O handle.
277  HANDLE x_GetHandle(CPipe::EChildIOHandle from_handle) const;
278  // Trigger blocking mode on specified I/O handle.
279  void x_SetNonBlockingMode(HANDLE fd) const;
280  // Wait on the file descriptors for I/O.
282  const STimeout* timeout) const;
283 private:
284  // I/O handles for child process.
288 
289  // Child process descriptor.
291 
292  // Pipe flags
294 
295  // Flag that indicates whether the m_ChildStd* and m_ProcHandle
296  // member variables contain the relevant handles of the
297  // current process, in which case they won't be closed.
299 };
300 
301 
303  : m_ChildStdIn (INVALID_HANDLE_VALUE),
304  m_ChildStdOut(INVALID_HANDLE_VALUE),
305  m_ChildStdErr(INVALID_HANDLE_VALUE),
306  m_ProcHandle (INVALID_HANDLE_VALUE),
307  m_Flags(0), m_SelfHandles(false)
308 {
309  return;
310 }
311 
312 
314 {
315  static const STimeout kZeroTimeout = {0, 0};
316  Close(0, &kZeroTimeout);
317  x_Clear();
318 }
319 
320 
322  const vector<string>& args,
323  CPipe::TCreateFlags create_flags,
324  const string& current_dir,
325  const char* const env[],
326  size_t pipe_size)
327 {
328  DEFINE_STATIC_FAST_MUTEX(s_Mutex);
329  CFastMutexGuard guard_mutex(s_Mutex);
330 
332  ERR_POST_X(1, s_FormatErrorMessage("Open", "Pipe busy"));
333  return eIO_Unknown;
334  }
335  m_Flags = create_flags;
336 
337  HANDLE child_stdin = INVALID_HANDLE_VALUE;
338  HANDLE child_stdout = INVALID_HANDLE_VALUE;
339  HANDLE child_stderr = INVALID_HANDLE_VALUE;
340 
341  EIO_Status status = eIO_Unknown;
342 
343  try {
344  // Prepare command line to run
345  string cmd_line = x_CommandLine(cmd, args);
346 
347  // Convert environment array to block form
349  if (env) {
350  // Count block size:
351  // it should have one zero char at least
352  size_t size = 1;
353  int count = 0;
354  while (env[count]) {
355  size += strlen(env[count++]) + 1/*'\0'*/;
356  }
357  // Allocate memory
358  TXChar* block = new TXChar[size];
359  env_block.reset(block);
360 
361  // Copy environment strings
362  for (int i = 0; i < count; ++i) {
363 #if defined(NCBI_OS_MSWIN) && defined(_UNICODE)
365  size_t n = tmp.size();
366  memcpy(block, tmp.data(), n * sizeof(TXChar));
367  block[n++] = _TX('\0');
368 #else
369  size_t n = strlen(env[i]) + 1;
370  memcpy(block, env[i], n);
371 #endif // NCBI_OS_MSWIN && _UNICODE
372  block += n;
373  }
374  *block = _TX('\0');
375  }
376 
377  HANDLE stdout_handle = ::GetStdHandle(STD_OUTPUT_HANDLE);
378  if (stdout_handle == NULL) {
379  stdout_handle = INVALID_HANDLE_VALUE;
380  }
381  HANDLE stderr_handle = ::GetStdHandle(STD_ERROR_HANDLE);
382  if (stderr_handle == NULL) {
383  stderr_handle = INVALID_HANDLE_VALUE;
384  }
385 
386  // Flush stdio buffers before remap
387  NcbiCout.flush();
388  NcbiCerr.flush();
389  ::fflush(NULL);
390  if (stdout_handle != INVALID_HANDLE_VALUE) {
391  ::FlushFileBuffers(stdout_handle);
392  }
393  if (stderr_handle != INVALID_HANDLE_VALUE) {
394  ::FlushFileBuffers(stderr_handle);
395  }
396 
397  // Set base security attributes
398  SECURITY_ATTRIBUTES attr;
399  attr.nLength = sizeof(attr);
400  attr.bInheritHandle = TRUE;
401  attr.lpSecurityDescriptor = NULL;
402 
403  // Create pipe for child's stdin
405  if (!IS_SET(create_flags, CPipe::fStdIn_Close)) {
406  if (!::CreatePipe(&child_stdin, &m_ChildStdIn,
407  &attr, (DWORD) pipe_size)) {
408  PIPE_THROW(::GetLastError(),
409  "Failed CreatePipe(stdin)");
410  }
411  ::SetHandleInformation(m_ChildStdIn, HANDLE_FLAG_INHERIT, 0);
413  }
414 
415  // Create pipe for child's stdout
417  if (!IS_SET(create_flags, CPipe::fStdOut_Close)) {
418  if (!::CreatePipe(&m_ChildStdOut, &child_stdout, &attr, 0)) {
419  PIPE_THROW(::GetLastError(),
420  "Failed CreatePipe(stdout)");
421  }
422  ::SetHandleInformation(m_ChildStdOut, HANDLE_FLAG_INHERIT, 0);
424  }
425 
426  // Create pipe for child's stderr
428  if (IS_SET(create_flags, CPipe::fStdErr_Open)) {
429  if (!::CreatePipe(&m_ChildStdErr, &child_stderr, &attr, 0)) {
430  PIPE_THROW(::GetLastError(),
431  "Failed CreatePipe(stderr)");
432  }
433  ::SetHandleInformation(m_ChildStdErr, HANDLE_FLAG_INHERIT, 0);
435  } else if (IS_SET(create_flags, CPipe::fStdErr_Share)) {
436  if (stderr_handle != INVALID_HANDLE_VALUE) {
437  HANDLE current_process = ::GetCurrentProcess();
438  if (!::DuplicateHandle(current_process, stderr_handle,
439  current_process, &child_stderr,
440  0, TRUE, DUPLICATE_SAME_ACCESS)) {
441  PIPE_THROW(::GetLastError(),
442  "Failed DuplicateHandle(stderr)");
443  }
444  }
445  } else if (IS_SET(create_flags, CPipe::fStdErr_StdOut)) {
446  child_stderr = child_stdout;
447  }
448 
449  // Create child process
450  STARTUPINFO sinfo;
451  PROCESS_INFORMATION pinfo;
452  ::ZeroMemory(&pinfo, sizeof(pinfo));
453  ::ZeroMemory(&sinfo, sizeof(sinfo));
454  sinfo.cb = sizeof(sinfo);
455  sinfo.hStdError = child_stderr;
456  sinfo.hStdOutput = child_stdout;
457  sinfo.hStdInput = child_stdin;
458  sinfo.dwFlags = STARTF_USESTDHANDLES;
459 # if defined(_UNICODE)
460  DWORD dwCreationFlags = CREATE_UNICODE_ENVIRONMENT;
461 # else
462  DWORD dwCreationFlags = 0;
463 # endif // _UNICODE
464  if (!::CreateProcess(NULL,
465  (LPTSTR)(_T_XCSTRING(cmd_line)),
466  NULL, NULL, TRUE,
467  dwCreationFlags, env_block.get(),
468  current_dir.empty()
469  ? 0 : _T_XCSTRING(current_dir),
470  &sinfo, &pinfo)) {
471  status = eIO_Closed;
472  PIPE_THROW(::GetLastError(),
473  "Failed CreateProcess('" + cmd_line + "')");
474  }
475  ::CloseHandle(pinfo.hThread);
476  m_ProcHandle = pinfo.hProcess;
477 
479 
480  status = eIO_Success;
481  }
482  catch (string& what) {
483  static const STimeout kZeroZimeout = {0, 0};
484  Close(0, &kZeroZimeout);
485  ERR_POST_X(1, s_FormatErrorMessage("Open", what));
486  x_Clear();
487  }
488  if (child_stdin != INVALID_HANDLE_VALUE) {
489  ::CloseHandle(child_stdin);
490  }
491  if (child_stdout != INVALID_HANDLE_VALUE) {
492  ::CloseHandle(child_stdout);
493  }
494  if (child_stderr != INVALID_HANDLE_VALUE
495  && child_stderr != child_stdout) {
496  ::CloseHandle(child_stderr);
497  }
498 
499  return status;
500 }
501 
502 
504 {
506  PIPE_THROW(0,
507  "Pipe busy");
508  }
509 
510  NcbiCout.flush();
511  ::fflush(stdout);
513  && !::FlushFileBuffers(m_ChildStdIn)) {
514  PIPE_THROW(::GetLastError(),
515  "Failed FlushFileBuffers(stdout)");
516  }
517  if ((m_ChildStdIn = ::GetStdHandle(STD_OUTPUT_HANDLE))
519  PIPE_THROW(::GetLastError(),
520  "Failed GetStdHandle(stdout)");
521  }
522  if ((m_ChildStdOut = ::GetStdHandle(STD_INPUT_HANDLE))
524  PIPE_THROW(::GetLastError(),
525  "Failed GetStdHandle(stdin)");
526  }
527  // NB: GetCurrentProcess() returns HANDLE(-1) which is INVALID_HANDLE_VALUE
528  m_ProcHandle = GetCurrentProcess();
529 
530  m_SelfHandles = true;
531 }
532 
533 
535 {
537  if (m_SelfHandles) {
540  m_SelfHandles = false;
541  } else {
545  }
546 }
547 
548 
549 EIO_Status CPipeHandle::Close(int* exitcode, const STimeout* timeout)
550 {
551  EIO_Status status;
552 
553  if (!m_SelfHandles) {
557 
559  if (exitcode) {
560  *exitcode = -1;
561  }
562  status = eIO_Closed;
563  } else {
565  status = s_Close(process, m_Flags, timeout, exitcode);
566  }
567  } else {
568  if (exitcode) {
569  *exitcode = 0;
570  }
571  status = eIO_Success;
572  }
573 
574  if (status != eIO_Timeout) {
575  x_Clear();
576  }
577  return status;
578 }
579 
580 
582 {
583  switch (handle) {
584  case CPipe::eStdIn:
586  return eIO_Closed;
587  }
590  break;
591  case CPipe::eStdOut:
593  return eIO_Closed;
594  }
597  break;
598  case CPipe::eStdErr:
600  return eIO_Closed;
601  }
604  break;
605  default:
606  _TROUBLE;
607  return eIO_InvalidArg;
608  }
609  return eIO_Success;
610 }
611 
612 
613 EIO_Status CPipeHandle::Read(void* buf, size_t count, size_t* n_read,
614  const CPipe::EChildIOHandle from_handle,
615  const STimeout* timeout) const
616 {
617  _ASSERT(!n_read || !*n_read);
618  _ASSERT(!(from_handle & (from_handle - 1)));
619 
620  EIO_Status status = eIO_Unknown;
621 
622  try {
624  PIPE_THROW(0,
625  "Pipe closed");
626  }
627  HANDLE fd = x_GetHandle(from_handle);
628  if (fd == INVALID_HANDLE_VALUE) {
629  PIPE_THROW(0,
630  "Pipe I/O handle "
631  + x_GetHandleName(from_handle) + " closed");
632  }
633  if (!count) {
634  return eIO_Success;
635  }
636 
637  DWORD x_timeout = timeout ? NcbiTimeoutToMs(timeout) : INFINITE;
638  DWORD bytes_avail = 0;
639 
640  // Wait for data from the pipe with a timeout.
641  // Using a loop and periodically try PeekNamedPipe is inefficient,
642  // but Windows doesn't have asynchronous mechanism to read from a pipe.
643  // NOTE: WaitForSingleObject() doesn't work with anonymous pipes.
644  // See CPipe::Poll() for more details.
645 
646  unsigned long x_sleep = 1;
647  for (;;) {
648  BOOL ok = ::PeekNamedPipe(fd, NULL, 0, NULL, &bytes_avail, NULL);
649  if (bytes_avail) {
650  break;
651  }
652  if (!ok) {
653  // Has peer closed the connection?
654  DWORD error = ::GetLastError();
655  if (!x_IsDisconnectError(error)) {
656  // NB: status == eIO_Unknown
658  "Failed PeekNamedPipe("
659  + x_GetHandleName(from_handle) + ')');
660  }
661  return eIO_Closed;
662  }
663 
664  if (!x_timeout) {
665  return eIO_Timeout;
666  }
667  if (x_timeout != INFINITE) {
668  if (x_sleep > x_timeout) {
669  x_sleep = x_timeout;
670  }
671  x_timeout -= x_sleep;
672  }
673  SleepMilliSec(x_sleep);
674  x_sleep <<= 1;
675  if (x_sleep > kWaitPrecision) {
676  x_sleep = kWaitPrecision;
677  }
678  }
679  _ASSERT(bytes_avail);
680 
681  // We must read only "count" bytes of data regardless of
682  // the amount available to read
683  if (bytes_avail > count) {
684  bytes_avail = (DWORD) count;
685  }
686  BOOL ok = ::ReadFile(fd, buf, bytes_avail, &bytes_avail, NULL);
687  if (!bytes_avail) {
688  // NB: status == eIO_Unknown
689  PIPE_THROW(!ok ? ::GetLastError() : 0,
690  "Failed to read data from pipe I/O handle "
691  + x_GetHandleName(from_handle));
692  } else {
693  if (n_read) {
694  *n_read = (size_t) bytes_avail;
695  }
696  status = eIO_Success;
697  }
698  }
699  catch (string& what) {
700  ERR_POST_X(2, s_FormatErrorMessage("Read", what));
701  }
702 
703  return status;
704 }
705 
706 
707 EIO_Status CPipeHandle::Write(const void* data, size_t count,
708  size_t* n_written, const STimeout* timeout) const
709 
710 {
711  _ASSERT(!n_written || !*n_written);
712 
713  EIO_Status status = eIO_Unknown;
714 
715  try {
717  PIPE_THROW(0,
718  "Pipe closed");
719  }
721  status = eIO_Closed;
722  PIPE_THROW(0,
723  "Pipe I/O handle "
724  + x_GetHandleName(CPipe::eStdIn) + " closed");
725  }
726  if (!count) {
727  return eIO_Success;
728  }
729 
730  DWORD x_timeout = timeout ? NcbiTimeoutToMs(timeout) : INFINITE;
731  DWORD to_write = (count > numeric_limits<DWORD>::max()
733  : (DWORD) count);
734  DWORD bytes_written = 0;
735 
736  unsigned long x_sleep = 1;
737  for (;;) {
738  BOOL ok = ::WriteFile(m_ChildStdIn, (char*) data, to_write,
739  &bytes_written, NULL);
740  if (bytes_written) {
741  break;
742  }
743  if (!ok) {
744  DWORD error = ::GetLastError();
745  if (x_IsDisconnectError(error)) {
746  status = eIO_Closed;
747  } // NB: status == eIO_Unknown
749  "Failed to write data to pipe I/O handle "
751  }
752 
753  if (!x_timeout) {
754  return eIO_Timeout;
755  }
756  if (x_timeout != INFINITE) {
757  if (x_sleep > x_timeout) {
758  x_sleep = x_timeout;
759  }
760  x_timeout -= x_sleep;
761  }
762  SleepMilliSec(x_sleep);
763  x_sleep <<= 1;
764  if (x_sleep > kWaitPrecision) {
765  x_sleep = kWaitPrecision;
766  }
767  }
768  _ASSERT(bytes_written);
769 
770  if (n_written) {
771  *n_written = bytes_written;
772  }
773  status = eIO_Success;
774  }
775  catch (string& what) {
776  ERR_POST_X(3, s_FormatErrorMessage("Write", what));
777  }
778 
779  return status;
780 }
781 
782 
784  const STimeout* timeout) const
785 {
787 
788  try {
790  PIPE_THROW(0,
791  "Pipe closed");
792  }
796  PIPE_THROW(0,
797  "All pipe I/O handles closed");
798  }
799  poll = x_Poll(mask, timeout);
800  }
801  catch (string& what) {
802  ERR_POST_X(4, s_FormatErrorMessage("Poll", what));
803  }
804 
805  return poll;
806 }
807 
808 
810 {
811  switch (from_handle) {
812  case CPipe::eStdIn:
813  return m_ChildStdIn;
814  case CPipe::eStdOut:
815  return m_ChildStdOut;
816  case CPipe::eStdErr:
817  return m_ChildStdErr;
818  default:
819  _TROUBLE;
820  break;
821  }
822  return INVALID_HANDLE_VALUE;
823 }
824 
825 
827 {
828  // NB: Pipe is in byte-mode.
829  // NOTE: We cannot get a state of a pipe handle opened for writing.
830  // We cannot set a state of a pipe handle opened for reading.
831  DWORD state = PIPE_READMODE_BYTE | PIPE_NOWAIT;
832  if (!::SetNamedPipeHandleState(fd, &state, NULL, NULL)) {
833  PIPE_THROW(::GetLastError(),
834  "Failed to set pipe I/O handle non-blocking");
835  }
836 }
837 
838 
840  const STimeout* timeout) const
841 {
842  DWORD x_timeout = timeout ? NcbiTimeoutToMs(timeout) : INFINITE;
843 
844  // We cannot poll child's stdin, so just copy corresponding flag
846 
847  // Wait for data from the pipe with timeout.
848  // Using a loop and periodically try PeekNamedPipe is inefficient,
849  // but Windows doesn't have asynchronous mechanism to read from a pipe.
850  // NOTE: WaitForSingleObject() doesn't work with anonymous pipes.
851 
852  unsigned long x_sleep = 1;
853  for (;;) {
854  if ((mask & CPipe::fStdOut)
856  DWORD bytes_avail = 0;
857  if (!::PeekNamedPipe(m_ChildStdOut, NULL, 0, NULL,
858  &bytes_avail, NULL)) {
859  DWORD error = ::GetLastError();
860  // Has peer closed connection?
861  if (!x_IsDisconnectError(error)) {
863  "Failed PeekNamedPipe(stdout)");
864  }
865  poll |= CPipe::fStdOut;
866  } else if (bytes_avail) {
867  poll |= CPipe::fStdOut;
868  }
869  }
870  if ((mask & CPipe::fStdErr)
872  DWORD bytes_avail = 0;
873  if (!::PeekNamedPipe(m_ChildStdErr, NULL, 0, NULL,
874  &bytes_avail, NULL)) {
875  DWORD error = ::GetLastError();
876  // Has peer closed connection?
877  if (!x_IsDisconnectError(error)) {
879  "Failed PeekNamedPipe(stderr)");
880  }
881  poll |= CPipe::fStdErr;
882  } else if (bytes_avail) {
883  poll |= CPipe::fStdErr;
884  }
885  }
886  if (poll) {
887  break;
888  }
889 
890  if (!x_timeout) {
891  break;
892  }
893  if (x_timeout != INFINITE) {
894  if (x_sleep > x_timeout) {
895  x_sleep = x_timeout;
896  }
897  x_timeout -= x_sleep;
898  }
899  SleepMilliSec(x_sleep);
900  x_sleep <<= 1;
901  if (x_sleep > kWaitPrecision) {
902  x_sleep = kWaitPrecision;
903  }
904  }
905 
906  _ASSERT(!(poll ^ (poll & mask)));
907  return poll;
908 }
909 
910 
911 #elif defined(NCBI_OS_UNIX)
912 
913 
914 //////////////////////////////////////////////////////////////////////////////
915 //
916 // CPipeHandle -- Unix version
917 //
918 
919 NCBI_PARAM_DECL (bool, CONN, PIPE_USE_POLL);
920 NCBI_PARAM_DEF_EX(bool, CONN, PIPE_USE_POLL,
921  true, eParam_Default, CONN_PIPE_USE_POLL);
922 
923 class CPipeHandle
924 {
925 public:
926  CPipeHandle(void);
927  ~CPipeHandle();
928  EIO_Status Open(const string& cmd,
929  const vector<string>& args,
930  CPipe::TCreateFlags create_flags,
931  const string& current_dir,
932  const char* const env[],
933  size_t /*pipe_size*/);
934  void OpenSelf(void);
935  EIO_Status Close(int* exitcode, const STimeout* timeout);
937  EIO_Status Read(void* buf, size_t count, size_t* read,
938  const CPipe::EChildIOHandle from_handle,
939  const STimeout* timeout) const;
940  EIO_Status Write(const void* data, size_t count, size_t* written,
941  const STimeout* timeout) const;
943  const STimeout* timeout) const;
944  TProcessHandle GetProcessHandle(void) const { return m_Pid; }
945  void Release(void) { x_Clear(); }
946 
947 private:
948  // Clear object state.
949  void x_Clear(void);
950  // Get child's I/O handle.
951  int x_GetHandle(CPipe::EChildIOHandle from_handle) const;
952  // Trigger blocking mode on specified I/O handle.
953  void x_SetNonBlockingMode(int fd) const;
954  // Wait on the file descriptors for I/O.
956  const STimeout* timeout) const;
957 
958 private:
959  // I/O handles for child process.
960  int m_ChildStdIn;
961  int m_ChildStdOut;
962  int m_ChildStdErr;
963 
964  // Child process PID.
965  TPid m_Pid;
966 
967  // Pipe flags
969 
970  // Flag that indicates whether the m_ChildStd* and m_Pid
971  // member variables contain the relevant handles of the
972  // current process, in which case they won't be closed.
973  bool m_SelfHandles;
974 
975  // Use poll(2) (now default) instead of select(2) (formerly)
976  bool m_UsePoll;
977 };
978 
979 
981  : m_ChildStdIn(-1), m_ChildStdOut(-1), m_ChildStdErr(-1),
982  m_Pid((TPid)(-1)), m_Flags(0), m_SelfHandles(false)
983 {
984  static NCBI_PARAM_TYPE(CONN, PIPE_USE_POLL) use_poll_param;
985 
986  m_UsePoll = use_poll_param.Get();
987  ERR_POST_ONCE(Trace << "CPipeHandle using poll(): "
988  + NStr::BoolToString(m_UsePoll));
989 }
990 
991 
993 {
994  static const STimeout kZeroTimeout = {0, 0};
995  Close(0, &kZeroTimeout);
996  x_Clear();
997 }
998 
999 
1000 // Auxiliary function to exit from forked process with reporting errno
1001 // on errors into the specified file descriptor
1002 static void s_Exit(int status, int fd)
1003 {
1004  int errcode = errno;
1005  (void) ::write(fd, &errcode, sizeof(errcode));
1006  (void) ::close(fd);
1007  ::_exit(status);
1008 }
1009 
1010 
1011 #ifndef HAVE_EXECVPE
1012 
1013 // Emulate the nonexistent execvpe() call.
1014 // On success, execve() does not return; on error -1 is returned,
1015 // and errno is set appropriately.
1016 
1017 static int s_ExecShell(const char* command,
1018  char *const argv[], char *const envp[])
1019 {
1020  static const char kShell[] = "/bin/sh";
1021 
1022  // Count number of arguments
1023  size_t i;
1024  for (i = 0; argv[i]; ++i);
1025  ++i; // last NULL element
1026  _ASSERT(i > 1);
1027 
1028  // Construct argument list for the shell
1029  const char** args = new const char*[i + 1];
1031 
1032  args[0] = kShell;
1033  args[1] = command;
1034  // NB: skip argv[0]
1035  for (; i > 1; --i) {
1036  args[i] = argv[i - 1];
1037  }
1038 
1039  // Execute the shell
1040  return ::execve(kShell, (char**) args, envp);
1041 }
1042 
1043 
1044 // Note this is executing in a separate process: no environment locks necessary
1045 static int s_ExecVPE(const char* file, char* const argv[], char* const envp[])
1046 {
1047  // CAUTION (security): the current directory is in the path on purpose
1048  // (see man execlp), and also to be in-sync with the
1049  // default behavior on MS-Win.
1050  static const char* kPathDefault = ":/bin:/usr/bin";
1051 
1052  // If file name is not specified
1053  if (!file || *file == '\0') {
1054  errno = ENOENT;
1055  return -1;
1056  }
1057 
1058  // If the file name contains path
1059  if (strchr(file, '/')) {
1060  ::execve(file, argv, envp);
1061  return errno == ENOEXEC ? s_ExecShell(file, argv, envp) : -1;
1062  }
1063 
1064  // Get the PATH environment variable
1065  const char* path = getenv("PATH");
1066  if (!path) {
1067  path = kPathDefault;
1068  }
1069  size_t file_len = strlen(file) + 1/*'\0'*/;
1070  char* buf = new char[strlen(path) + 1/*'/'*/ + file_len];
1072 
1073  bool eacces_err = false;
1074  for (;;) {
1075  const char* next = strchr(path, ':');
1076  size_t len = next ? (size_t)(next - path) : strlen(path)/*last part*/;
1077  if (len) {
1078  // Copy directory name into the buffer
1079  memmove(buf, path, len);
1080  // Add slash if needed
1081  if (buf[len - 1] != '/') {
1082  buf[len++] = '/';
1083  }
1084  } else {
1085  // Empty PATH element (e.g.":...","::","...:") -- current directory
1086  buf[0] = '.';
1087  buf[1] = '/';
1088  len = 2;
1089  }
1090  // Add file name
1091  memcpy(buf + len, file, file_len);
1092 
1093  // Try to execute file with the generated name
1094  int error;
1095  ::execve(buf, argv, envp);
1096  if ((error = errno) == ENOEXEC) {
1097  return s_ExecShell(buf, argv, envp);
1098  }
1099  switch (error) {
1100  case EACCES:
1101  // Permission denied. Memorize this fact and try next path.
1102  eacces_err = true;
1103  /*FALLTHRU*/
1104  case ENOENT:
1105  case ENOTDIR:
1106  // Try next path element
1107  break;
1108  default:
1109  // We found an executable file, but could not execute it
1110  _ASSERT(error);
1111  return -1;
1112  }
1113  if (!next) {
1114  break;
1115  }
1116  path = next + 1;
1117  }
1118 
1119  if (eacces_err) {
1120  errno = EACCES;
1121  }
1122  return -1;
1123 }
1124 
1125 # define execvpe s_ExecVPE
1126 #endif // !HAVE_EXECVPE
1127 
1128 
1129 static int x_SafeFD(int fd, int safe)
1130 {
1131  if (fd == safe || fd > STDERR_FILENO) {
1132  return fd;
1133  }
1134  int temp = ::fcntl(fd, F_DUPFD, STDERR_FILENO + 1);
1135  ::close(fd);
1136  return temp;
1137 }
1138 
1139 
1140 static bool x_SafePipe(int pipe[2], int n, int safe)
1141 {
1142  bool retval = true;
1143  if ((pipe[0] = x_SafeFD(pipe[0], n == 0 ? safe : -1)) == -1) {
1144  ::close(pipe[1]);
1145  retval = false;
1146  } else if ((pipe[1] = x_SafeFD(pipe[1], n == 1 ? safe : -1)) == -1) {
1147  ::close(pipe[0]);
1148  retval = false;
1149  }
1150  return retval;
1151 }
1152 
1153 
1154 EIO_Status CPipeHandle::Open(const string& cmd,
1155  const vector<string>& args,
1156  CPipe::TCreateFlags create_flags,
1157  const string& current_dir,
1158  const char* const env[],
1159  size_t /*unused*/)
1160 
1161 {
1162  DEFINE_STATIC_FAST_MUTEX(s_Mutex);
1163  CFastMutexGuard guard_mutex(s_Mutex);
1164 
1165  if (m_Pid != (TPid)(-1)) {
1166  ERR_POST_X(1, s_FormatErrorMessage("Open", "Pipe busy"));
1167  return eIO_Unknown;
1168  }
1169  m_Flags = create_flags;
1170 
1171  // Child process I/O handles: init "our" ends of the pipes
1172  int pipe_in[2], pipe_out[2], pipe_err[2];
1173  pipe_in[0] = -1;
1174  pipe_out[1] = -1;
1175  pipe_err[1] = -1;
1176 
1177  EIO_Status status = eIO_Unknown;
1178 
1179  int status_pipe[2] = {-1, -1};
1180  try {
1181  // Flush stdio
1182  NcbiCout.flush();
1183  NcbiCerr.flush();
1184  ::fflush(NULL);
1185 
1186  // Create pipe for child's stdin
1188  if (!IS_SET(create_flags, CPipe::fStdIn_Close)) {
1189  if (::pipe(pipe_in) < 0
1190  || !x_SafePipe(pipe_in, 0, STDIN_FILENO)) {
1191  pipe_in[0] = -1;
1192  PIPE_THROW(errno,
1193  "Failed to create pipe for stdin");
1194  }
1195  m_ChildStdIn = pipe_in[1];
1197  }
1198 
1199  // Create pipe for child's stdout
1201  if (!IS_SET(create_flags, CPipe::fStdOut_Close)) {
1202  if (::pipe(pipe_out) < 0
1203  || !x_SafePipe(pipe_out, 1, STDOUT_FILENO)) {
1204  pipe_out[1] = -1;
1205  PIPE_THROW(errno,
1206  "Failed to create pipe for stdout");
1207  }
1208  m_ChildStdOut = pipe_out[0];
1210  }
1211 
1212  // Create pipe for child's stderr
1214  if (IS_SET(create_flags, CPipe::fStdErr_Open)) {
1215  if (::pipe(pipe_err) < 0
1216  || !x_SafePipe(pipe_err, 1, STDERR_FILENO)) {
1217  pipe_err[1] = -1;
1218  PIPE_THROW(errno,
1219  "Failed to create pipe for stderr");
1220  }
1221  m_ChildStdErr = pipe_err[0];
1223  }
1224 
1225  // Create temporary pipe to get status of execution
1226  // of the child process
1227  if (::pipe(status_pipe) < 0
1228  || !x_SafePipe(status_pipe, -1, -1)) {
1229  PIPE_THROW(errno,
1230  "Failed to create status pipe");
1231  }
1232  ::fcntl(status_pipe[1], F_SETFD,
1233  ::fcntl(status_pipe[1], F_GETFD, 0) | FD_CLOEXEC);
1234 
1235  // Fork off a child process
1236  switch (m_Pid = ::fork()) {
1237  case (TPid)(-1):
1238  PIPE_THROW(errno,
1239  "Failed fork()");
1240  /*NOTREACHED*/
1241  break;
1242 
1243  case 0:
1244  // *** CHILD PROCESS CONTINUES HERE ***
1245 
1246  // Create new process group if needed
1247  if (IS_SET(create_flags, CPipe::fNewGroup)) {
1248  ::setpgid(0, 0);
1249  }
1250 
1251  // Close unused pipe handle
1252  ::close(status_pipe[0]);
1253 
1254  // Bind child's standard I/O file handles to pipes
1255  if (!IS_SET(create_flags, CPipe::fStdIn_Close)) {
1256  if (pipe_in[0] != STDIN_FILENO) {
1257  if (::dup2(pipe_in[0], STDIN_FILENO) < 0) {
1258  s_Exit(-1, status_pipe[1]);
1259  }
1260  ::close(pipe_in[0]);
1261  }
1262  ::close(pipe_in[1]);
1263  ::fflush(stdin);
1264  } else {
1265  (void) ::freopen("/dev/null", "r", stdin);
1266  }
1267  if (!IS_SET(create_flags, CPipe::fStdOut_Close)) {
1268  if (pipe_out[1] != STDOUT_FILENO) {
1269  if (::dup2(pipe_out[1], STDOUT_FILENO) < 0) {
1270  s_Exit(-1, status_pipe[1]);
1271  }
1272  ::close(pipe_out[1]);
1273  }
1274  ::close(pipe_out[0]);
1275  } else {
1276  (void) ::freopen("/dev/null", "w", stdout);
1277  }
1278  if (IS_SET(create_flags, CPipe::fStdErr_Open)) {
1279  if (pipe_err[1] != STDERR_FILENO) {
1280  if (::dup2(pipe_err[1], STDERR_FILENO) < 0) {
1281  s_Exit(-1, status_pipe[1]);
1282  }
1283  ::close(pipe_err[1]);
1284  }
1285  ::close(pipe_err[0]);
1286  } else if (IS_SET(create_flags, CPipe::fStdErr_Share)) {
1287  /*nothing to do*/;
1288  } else if (IS_SET(create_flags, CPipe::fStdErr_StdOut)) {
1289  _ASSERT(STDOUT_FILENO != STDERR_FILENO);
1290  if (::dup2(STDOUT_FILENO, STDERR_FILENO) < 0) {
1291  s_Exit(-1, status_pipe[1]);
1292  }
1293  } else {
1294  (void) ::freopen("/dev/null", "a", stderr);
1295  }
1296 
1297  // Restore SIGPIPE signal processing
1298  if (IS_SET(create_flags, CPipe::fSigPipe_Restore)) {
1299  ::signal(SIGPIPE, SIG_DFL);
1300  }
1301 
1302  // Prepare program arguments
1303  size_t i;
1304  const char** x_args = new const char*[args.size() + 2];
1306  x_args[i = 0] = cmd.c_str();
1307  for (auto&& arg : args) {
1308  x_args[++i] = arg.c_str();
1309  }
1310  x_args[++i] = 0;
1311 
1312  // Change current working directory if specified
1313  if (!current_dir.empty() && current_dir != ".") {
1314  (void) ::chdir(current_dir.c_str());
1315  }
1316  // Execute the program
1317  int status;
1318  if (env) {
1319  status = execvpe(cmd.c_str(),
1320  const_cast<char**>(x_args),
1321  const_cast<char**>(env));
1322  } else {
1323  status = ::execvp(cmd.c_str(),
1324  const_cast<char**>(x_args));
1325  }
1326  s_Exit(status, status_pipe[1]);
1327 
1328  // *** CHILD PROCESS DOES NOT CONTINUE BEYOND THIS LINE ***
1329  }
1330 
1331  // Close unused pipes' ends
1332  if (!IS_SET(create_flags, CPipe::fStdIn_Close)) {
1333  ::close(pipe_in[0]);
1334  pipe_in[0] = -1;
1335  }
1336  if (!IS_SET(create_flags, CPipe::fStdOut_Close)) {
1337  ::close(pipe_out[1]);
1338  pipe_out[1] = -1;
1339  }
1340  if (IS_SET(create_flags, CPipe::fStdErr_Open)) {
1341  ::close(pipe_err[1]);
1342  pipe_err[1] = -1;
1343  }
1344  ::close(status_pipe[1]);
1345  status_pipe[1] = -1;
1346 
1347  // Check status pipe:
1348  // if it has some data, this is an errno from the child process;
1349  // if there is an EOF, then the child exec()'d successfully.
1350  // Retry if either blocked or interrupted
1351 
1352  // Try to read errno the from forked process
1353  ssize_t n;
1354  int errcode;
1355  while ((n = ::read(status_pipe[0], &errcode, sizeof(errcode))) < 0) {
1356  if (errno != EINTR)
1357  break;
1358  }
1359  ::close(status_pipe[0]);
1360  status_pipe[0] = -1;
1361 
1362  if (n > 0) {
1363  // Child could not run -- reap it and exit with an error
1364  status = eIO_Closed;
1365  ::waitpid(m_Pid, NULL, 0);
1366  PIPE_THROW((size_t) n < sizeof(errcode) ? 0 : errcode,
1367  "Failed to execute '" + x_CommandLine(cmd, args) +'\'');
1368  }
1369 
1370  return eIO_Success;
1371  }
1372  catch (string& what) {
1373  // Close all open file descriptors
1374  if (pipe_in[0] != -1) {
1375  ::close(pipe_in[0]);
1376  }
1377  if (pipe_out[1] != -1) {
1378  ::close(pipe_out[1]);
1379  }
1380  if (pipe_err[1] != -1) {
1381  ::close(pipe_err[1]);
1382  }
1383  if (status_pipe[0] != -1) {
1384  ::close(status_pipe[0]);
1385  }
1386  if (status_pipe[1] != -1) {
1387  ::close(status_pipe[1]);
1388  }
1389  static const STimeout kZeroTimeout = {0, 0};
1390  Close(0, &kZeroTimeout);
1391  ERR_POST_X(1, s_FormatErrorMessage("Open", what));
1392  x_Clear();
1393  }
1394 
1395  return status;
1396 }
1397 
1398 
1399 void CPipeHandle::OpenSelf(void)
1400 {
1401  if (m_Pid != (TPid)(-1)) {
1402  PIPE_THROW(0,
1403  "Pipe busy");
1404  }
1405 
1406  NcbiCout.flush();
1407  ::fflush(stdout);
1408  m_ChildStdIn = fileno(stdout); // NB: a macro on BSD, so no "::" scope
1409  m_ChildStdOut = fileno(stdin);
1410  m_Pid = ::getpid();
1411 
1412  m_SelfHandles = true;
1413 }
1414 
1415 
1416 void CPipeHandle::x_Clear(void)
1417 {
1418  m_Pid = (TPid)(-1);
1419  if (m_SelfHandles) {
1420  m_ChildStdIn = -1;
1421  m_ChildStdOut = -1;
1422  m_SelfHandles = false;
1423  } else {
1427  }
1428 }
1429 
1430 
1431 EIO_Status CPipeHandle::Close(int* exitcode, const STimeout* timeout)
1432 {
1433  EIO_Status status;
1434 
1435  if (!m_SelfHandles) {
1439 
1440  if (m_Pid == (TPid)(-1)) {
1441  if (exitcode) {
1442  *exitcode = -1;
1443  }
1444  status = eIO_Closed;
1445  } else {
1446  CProcess process(m_Pid, CProcess::ePid);
1447  status = s_Close(process, m_Flags, timeout, exitcode);
1448  }
1449  } else {
1450  if (exitcode) {
1451  *exitcode = 0;
1452  }
1453  status = eIO_Success;
1454  }
1455 
1456  if (status != eIO_Timeout) {
1457  x_Clear();
1458  }
1459  return status;
1460 }
1461 
1462 
1464 {
1465  switch (handle) {
1466  case CPipe::eStdIn:
1467  if (m_ChildStdIn == -1) {
1468  return eIO_Closed;
1469  }
1471  m_ChildStdIn = -1;
1472  break;
1473  case CPipe::eStdOut:
1474  if (m_ChildStdOut == -1) {
1475  return eIO_Closed;
1476  }
1478  m_ChildStdOut = -1;
1479  break;
1480  case CPipe::eStdErr:
1481  if (m_ChildStdErr == -1) {
1482  return eIO_Closed;
1483  }
1485  m_ChildStdErr = -1;
1486  break;
1487  default:
1488  _TROUBLE;
1489  return eIO_InvalidArg;
1490  }
1491  return eIO_Success;
1492 }
1493 
1494 
1495 EIO_Status CPipeHandle::Read(void* buf, size_t count, size_t* n_read,
1496  const CPipe::EChildIOHandle from_handle,
1497  const STimeout* timeout) const
1498 {
1499  _ASSERT(!n_read || !*n_read);
1500  _ASSERT(!(from_handle & (from_handle - 1)));
1501 
1502  EIO_Status status = eIO_Unknown;
1503 
1504  try {
1505  if (m_Pid == (TPid)(-1)) {
1506  PIPE_THROW(0,
1507  "Pipe closed");
1508  }
1509  int fd = x_GetHandle(from_handle);
1510  if (fd == -1) {
1511  PIPE_THROW(0,
1512  "Pipe I/O handle "
1513  + x_GetHandleName(from_handle) + " closed");
1514  }
1515  if (!count) {
1516  return eIO_Success;
1517  }
1518 
1519  // Retry if either blocked or interrupted
1520  for (;;) {
1521  // Try to read
1522  ssize_t bytes_read = ::read(fd, buf, count);
1523  if (bytes_read >= 0) {
1524  if (n_read) {
1525  *n_read = (size_t) bytes_read;
1526  }
1527  status = bytes_read ? eIO_Success : eIO_Closed;
1528  break;
1529  }
1530  int error = errno;
1531 
1532  if (error == EAGAIN || error == EWOULDBLOCK) {
1533  // Blocked -- wait for data to come; exit if timeout/error
1534  if ((timeout && !(timeout->sec | timeout->usec))
1535  || !x_Poll(from_handle, timeout)) {
1536  status = eIO_Timeout;
1537  break;
1538  }
1539  continue;
1540  }
1541  if (error != EINTR) {
1542  PIPE_THROW(error,
1543  "Failed to read data from pipe I/O handle "
1544  + x_GetHandleName(from_handle));
1545  }
1547  status = eIO_Interrupt;
1548  break;
1549  }
1550  // Interrupted read -- restart
1551  }
1552  }
1553  catch (string& what) {
1554  ERR_POST_X(2, s_FormatErrorMessage("Read", what));
1555  }
1556 
1557  return status;
1558 }
1559 
1560 
1561 EIO_Status CPipeHandle::Write(const void* data, size_t count,
1562  size_t* n_written, const STimeout* timeout) const
1563 
1564 {
1565  _ASSERT(!n_written || !*n_written);
1566 
1567  EIO_Status status = eIO_Unknown;
1568 
1569  try {
1570  if (m_Pid == (TPid)(-1)) {
1571  PIPE_THROW(0,
1572  "Pipe closed");
1573  }
1574  if (m_ChildStdIn == -1) {
1575  status = eIO_Closed;
1576  PIPE_THROW(0,
1577  "Pipe I/O handle "
1578  + x_GetHandleName(CPipe::eStdIn) + " closed");
1579  }
1580  if (!count) {
1581  return eIO_Success;
1582  }
1583 
1584  // Retry if either blocked or interrupted
1585  for (;;) {
1586  // Try to write
1587  ssize_t bytes_written = ::write(m_ChildStdIn, data, count);
1588  if (bytes_written >= 0) {
1589  if (n_written) {
1590  *n_written = (size_t) bytes_written;
1591  }
1592  status = bytes_written ? eIO_Success : eIO_Unknown;
1593  break;
1594  }
1595  int error = errno;
1596 
1597  if (errno == EAGAIN || errno == EWOULDBLOCK) {
1598  // Blocked -- wait for write readiness; exit if timeout/error
1599  if ((timeout && !(timeout->sec | timeout->usec))
1600  || !x_Poll(CPipe::fStdIn, timeout)) {
1601  status = eIO_Timeout;
1602  break;
1603  }
1604  continue;
1605  }
1606  if (errno != EINTR) {
1607  if (error == EPIPE) {
1608  // Peer has closed its end
1609  status = eIO_Closed;
1610  } // NB: status == eIO_Unknown
1611  PIPE_THROW(errno,
1612  "Failed to write data to pipe I/O handle "
1614  }
1616  status = eIO_Interrupt;
1617  break;
1618  }
1619  // Interrupted write -- restart
1620  }
1621  }
1622  catch (string& what) {
1623  ERR_POST_X(3, s_FormatErrorMessage("Write", what));
1624  }
1625 
1626  return status;
1627 }
1628 
1629 
1631  const STimeout* timeout) const
1632 {
1634 
1635  try {
1636  if (m_Pid == (TPid)(-1)) {
1637  PIPE_THROW(0,
1638  "Pipe closed");
1639  }
1640  if (m_ChildStdIn == -1 &&
1641  m_ChildStdOut == -1 &&
1642  m_ChildStdErr == -1) {
1643  PIPE_THROW(0,
1644  "All pipe I/O handles closed");
1645  }
1646  poll = x_Poll(mask, timeout);
1647  }
1648  catch (string& what) {
1649  ERR_POST_X(4, s_FormatErrorMessage("Poll", what));
1650  }
1651 
1652  return poll;
1653 }
1654 
1655 
1656 int CPipeHandle::x_GetHandle(CPipe::EChildIOHandle from_handle) const
1657 {
1658  switch (from_handle) {
1659  case CPipe::eStdIn:
1660  return m_ChildStdIn;
1661  case CPipe::eStdOut:
1662  return m_ChildStdOut;
1663  case CPipe::eStdErr:
1664  return m_ChildStdErr;
1665  default:
1666  _TROUBLE;
1667  break;
1668  }
1669  return -1;
1670 }
1671 
1672 
1673 void CPipeHandle::x_SetNonBlockingMode(int fd) const
1674 {
1675  if (::fcntl(fd, F_SETFL, ::fcntl(fd, F_GETFL, 0) | O_NONBLOCK) < 0) {
1676  PIPE_THROW(errno,
1677  "Failed to set pipe I/O handle non-blocking");
1678  }
1679 }
1680 
1681 
1683  const STimeout* timeout) const
1684 {
1686 
1687  if (m_UsePoll) {
1688  struct pollfd poll_fds[3] = {
1689  { m_ChildStdIn, POLLOUT },
1690  { m_ChildStdOut, POLLIN },
1691  { m_ChildStdErr, POLLIN }
1692  };
1693  int timeout_msec(timeout
1694  ? timeout->sec * 1000 + (timeout->usec + 500) / 1000
1695  : -1/*infinite*/);
1696 
1697  // Negative FDs OK, poll ignores them
1698  // Check the mask
1699  if (!(mask & CPipe::fStdIn))
1700  poll_fds[0].fd = -1;
1701  if (!(mask & CPipe::fStdOut))
1702  poll_fds[1].fd = -1;
1703  if (!(mask & CPipe::fStdErr))
1704  poll_fds[2].fd = -1;
1705 
1706  for (;;) { // Auto-resume if interrupted by a signal
1707  int n = ::poll(poll_fds, 3, timeout_msec);
1708 
1709  if (n == 0) {
1710  // timeout
1711  break;
1712  }
1713  if (n > 0) {
1714  // no need to check mask here
1715  if (poll_fds[0].revents) {
1716  poll |= CPipe::fStdIn;
1717  }
1718  if (poll_fds[1].revents) {
1719  poll |= CPipe::fStdOut;
1720  }
1721  if (poll_fds[2].revents) {
1722  poll |= CPipe::fStdErr;
1723  }
1724  break;
1725  }
1726  // n < 0
1727  if ((n = errno) != EINTR) {
1728  PIPE_THROW(n,
1729  "Failed poll()");
1730  }
1732  break;
1733  }
1734  // continue, no need to recreate either timeout or poll_fds
1735  }
1736  } else { // Using select(2), as before
1737  for (;;) { // Auto-resume if interrupted by a signal
1738  struct timeval* tmp;
1739  struct timeval tmo;
1740 
1741  if (timeout) {
1742  // NB: Timeout has already been normalized
1743  tmo.tv_sec = timeout->sec;
1744  tmo.tv_usec = timeout->usec;
1745  tmp = &tmo;
1746  } else {
1747  tmp = 0;
1748  }
1749 
1750  fd_set rfds;
1751  fd_set wfds;
1752  fd_set efds;
1753 
1754  int max = -1;
1755  bool rd = false;
1756  bool wr = false;
1757 
1758  FD_ZERO(&efds);
1759 
1760  if ((mask & CPipe::fStdIn) && m_ChildStdIn != -1) {
1761  wr = true;
1762  FD_ZERO(&wfds);
1763  if (m_ChildStdIn < FD_SETSIZE) {
1764  FD_SET(m_ChildStdIn, &wfds);
1765  FD_SET(m_ChildStdIn, &efds);
1766  }
1767  if (max < m_ChildStdIn) {
1768  max = m_ChildStdIn;
1769  }
1770  }
1771  if ((mask & CPipe::fStdOut) && m_ChildStdOut != -1) {
1772  rd = true;
1773  FD_ZERO(&rfds);
1774  if (m_ChildStdOut < FD_SETSIZE) {
1775  FD_SET(m_ChildStdOut, &rfds);
1776  FD_SET(m_ChildStdOut, &efds);
1777  }
1778  if (max < m_ChildStdOut) {
1779  max = m_ChildStdOut;
1780  }
1781  }
1782  if ((mask & CPipe::fStdErr) && m_ChildStdErr != -1) {
1783  if (!rd) {
1784  rd = true;
1785  FD_ZERO(&rfds);
1786  }
1787  if (m_ChildStdErr < FD_SETSIZE) {
1788  FD_SET(m_ChildStdErr, &rfds);
1789  FD_SET(m_ChildStdErr, &efds);
1790  }
1791  if (max < m_ChildStdErr) {
1792  max = m_ChildStdErr;
1793  }
1794  }
1795  _ASSERT(rd || wr);
1796 
1797  if (max >= FD_SETSIZE) {
1798  PIPE_THROW(0,
1799  "File descriptor " + NStr::NumericToString(max)
1800  + " too large (maximum allowed "
1801  + string(NCBI_AS_STRING(FD_SETSIZE)) + ')');
1802  }
1803 
1804  int n = ::select(max + 1,
1805  rd ? &rfds : 0,
1806  wr ? &wfds : 0, &efds, tmp);
1807 
1808  if (n == 0) {
1809  // timeout
1810  break;
1811  }
1812  if (n > 0) {
1813  if (wr
1814  && (FD_ISSET(m_ChildStdIn, &wfds) ||
1815  FD_ISSET(m_ChildStdIn, &efds))) {
1816  poll |= CPipe::fStdIn;
1817  }
1818  if ((mask & CPipe::fStdOut) && m_ChildStdOut != -1
1819  && (FD_ISSET(m_ChildStdOut, &rfds) ||
1820  FD_ISSET(m_ChildStdOut, &efds))) {
1821  poll |= CPipe::fStdOut;
1822  }
1823  if ((mask & CPipe::fStdErr) && m_ChildStdErr != -1
1824  && (FD_ISSET(m_ChildStdErr, &rfds) ||
1825  FD_ISSET(m_ChildStdErr, &efds))) {
1826  poll |= CPipe::fStdErr;
1827  }
1828  break;
1829  }
1830  if ((n = errno) != EINTR) {
1831  PIPE_THROW(n,
1832  "Failed select()");
1833  }
1835  break;
1836  }
1837  // continue
1838  }
1839  }
1840 
1841  _ASSERT(!(poll ^ (poll & mask)));
1842  return poll;
1843 }
1844 
1845 
1846 #endif // NCBI_OS_UNIX | NCBI_OS_MSWIN
1847 
1848 
1849 //////////////////////////////////////////////////////////////////////////////
1850 //
1851 // CPipe
1852 //
1853 
1854 CPipe::CPipe(size_t pipe_size)
1855  : m_PipeSize(pipe_size),
1856  m_PipeHandle(new CPipeHandle), m_ReadHandle(eStdOut),
1857  m_ReadStatus(eIO_Closed), m_WriteStatus(eIO_Closed),
1858  m_ReadTimeout(0), m_WriteTimeout(0), m_CloseTimeout(0)
1859 {
1860  return;
1861 }
1862 
1863 
1864 CPipe::CPipe(const string& cmd,
1865  const vector<string>& args,
1866  TCreateFlags create_flags,
1867  const string& current_dir,
1868  const char* const env[],
1869  size_t pipe_size)
1870  : m_PipeSize(pipe_size),
1871  m_PipeHandle(0), m_ReadHandle(eStdOut),
1872  m_ReadStatus(eIO_Closed), m_WriteStatus(eIO_Closed),
1873  m_ReadTimeout(0), m_WriteTimeout(0), m_CloseTimeout(0)
1874 {
1875  unique_ptr<CPipeHandle> pipe_handle_ptr(new CPipeHandle);
1876  EIO_Status status = pipe_handle_ptr->Open(cmd, args, create_flags,
1877  current_dir, env, pipe_size);
1878  if (status != eIO_Success) {
1879  NCBI_THROW(CPipeException, eOpen,
1880  "[CPipe::CPipe] Failed: " + string(IO_StatusStr(status)));
1881  }
1882  m_PipeHandle = pipe_handle_ptr.release();
1883 }
1884 
1885 
1887 {
1888  Close();
1889  delete m_PipeHandle;
1890 }
1891 
1892 
1894  const vector<string>& args,
1895  TCreateFlags create_flags,
1896  const string& current_dir,
1897  const char* const env[],
1898  size_t pipe_size)
1899 {
1901  if (pipe_size) {
1902  m_PipeSize = pipe_size;
1903  }
1904 
1906  EIO_Status status = m_PipeHandle->Open(cmd, args, create_flags,
1907  current_dir, env, m_PipeSize);
1908  m_ReadStatus = status;
1909  m_WriteStatus = status;
1910  return status;
1911 }
1912 
1913 
1915 {
1918  try {
1920  }
1921  catch (string& err) {
1924  NCBI_THROW(CPipeException, eOpen, err);
1925  }
1928 }
1929 
1930 
1931 EIO_Status CPipe::Close(int* exitcode)
1932 {
1934  EIO_Status status = m_PipeHandle->Close(exitcode, m_CloseTimeout);
1935  m_ReadStatus = status == eIO_Timeout ? eIO_Timeout : eIO_Closed;
1936  m_WriteStatus = status == eIO_Timeout ? eIO_Timeout : eIO_Closed;
1937  return status;
1938 }
1939 
1940 
1942 {
1944  if (handle == eDefault) {
1945  handle = m_ReadHandle;
1946  }
1947  EIO_Status status = m_PipeHandle->CloseHandle(handle);
1948  if (handle != eStdIn) {
1949  m_ReadStatus = status;
1950  } else {
1951  m_WriteStatus = status;
1952  }
1953  return status;
1954 }
1955 
1956 
1958 {
1960  if (from_handle == eStdIn) {
1961  return eIO_InvalidArg;
1962  }
1963  m_ReadHandle = from_handle == eDefault ? eStdOut : from_handle;
1964  return eIO_Success;
1965 }
1966 
1967 
1968 EIO_Status CPipe::Read(void* buf, size_t count, size_t* n_read,
1969  EChildIOHandle from_handle)
1970 {
1972  if (n_read) {
1973  *n_read = 0;
1974  }
1975  if (from_handle == eStdIn) {
1976  return eIO_InvalidArg;
1977  }
1978  if (from_handle == eDefault) {
1979  from_handle = m_ReadHandle;
1980  }
1982  if (count && !buf) {
1983  return eIO_InvalidArg;
1984  }
1985  m_ReadStatus = m_PipeHandle->Read(buf, count, n_read, from_handle,
1986  m_ReadTimeout);
1987  return m_ReadStatus;
1988 }
1989 
1990 
1991 EIO_Status CPipe::Write(const void* data, size_t count, size_t* n_written)
1992 {
1994  if (n_written) {
1995  *n_written = 0;
1996  }
1997  if (count && !data) {
1998  return eIO_InvalidArg;
1999  }
2000  m_WriteStatus = m_PipeHandle->Write(data, count, n_written,
2001  m_WriteTimeout);
2002  return m_WriteStatus;
2003 }
2004 
2005 
2007  const STimeout* timeout)
2008 {
2009  _ASSERT(m_PipeHandle && timeout != kDefaultTimeout);
2010  if (!mask || timeout == kDefaultTimeout) {
2011  return 0;
2012  }
2013  TChildPollMask x_mask = mask;
2014  if (mask & fDefault) {
2016  x_mask |= m_ReadHandle;
2017  }
2018  TChildPollMask poll = m_PipeHandle->Poll(x_mask, timeout);
2019  if (mask & fDefault) {
2020  if (poll & m_ReadHandle) {
2021  poll |= fDefault;
2022  }
2023  poll &= mask;
2024  }
2025  // Result may not be a bigger set
2026  _ASSERT(!(poll ^ (poll & mask)));
2027  return poll;
2028 }
2029 
2030 
2032 {
2034  switch (direction) {
2035  case eIO_Read:
2036  return m_ReadStatus;
2037  case eIO_Write:
2038  return m_WriteStatus;
2039  default:
2040  _TROUBLE;
2041  break;
2042  }
2043  return eIO_InvalidArg;
2044 }
2045 
2046 
2048 {
2050  if (timeout == kDefaultTimeout) {
2051  return eIO_Success;
2052  }
2053  switch (event) {
2054  case eIO_Close:
2056  break;
2057  case eIO_Read:
2059  break;
2060  case eIO_Write:
2062  break;
2063  case eIO_ReadWrite:
2066  break;
2067  default:
2068  _TROUBLE;
2069  return eIO_InvalidArg;
2070  }
2071  return eIO_Success;
2072 }
2073 
2074 
2076 {
2078  switch (event) {
2079  case eIO_Close:
2080  return m_CloseTimeout;
2081  case eIO_Read:
2082  return m_ReadTimeout;
2083  case eIO_Write:
2084  return m_WriteTimeout;
2085  default:
2086  _TROUBLE;
2087  break;
2088  }
2089  return kDefaultTimeout;
2090 }
2091 
2092 
2094 {
2096  return m_PipeHandle->GetProcessHandle();
2097 }
2098 
2099 
2101 {
2102 }
2103 
2104 
2105 /* static */
2107  const vector<string>& args,
2108  CNcbiIstream& in,
2109  CNcbiOstream& out,
2110  CNcbiOstream& err,
2111  int& exit_code,
2112  const string& current_dir,
2113  const char* const env[],
2114  CPipe::IProcessWatcher* watcher,
2115  const STimeout* kill_timeout,
2116  size_t pipe_size)
2117 {
2118  STimeout ktm;
2119 
2120  if (kill_timeout) {
2121  ktm = *kill_timeout;
2122  } else {
2124  }
2125 
2126  CPipe pipe(pipe_size);
2127  EIO_Status status = pipe.Open(cmd, args,
2129  | fNewGroup | fKillOnClose,
2130  current_dir, env);
2131  if (status != eIO_Success) {
2132  NCBI_THROW(CPipeException, eOpen,
2133  "[CPipe::ExecWait] Cannot execute '"
2134  + x_CommandLine(cmd, args) + '\'');
2135  }
2136  _ASSERT(pipe.m_PipeHandle);
2137 
2138  TProcessHandle pid = pipe.GetProcessHandle();
2139 
2140  if (watcher && watcher->OnStart(pid) != IProcessWatcher::eContinue) {
2141  pipe.SetTimeout(eIO_Close, &ktm);
2142  pipe.Close(&exit_code);
2143  return eCanceled;
2144  }
2145 
2146  EFinish finish = eDone;
2147  try {
2148 #ifndef NCBI_OS_LINUX
2149  const size_t buf_size = 16 * 1024;
2150 #else
2151  const size_t buf_size = 192 * 1024;
2152 #endif // NCBI_OS_LINUX
2153  AutoPtr< char, ArrayDeleter<char> > inbuf(new char[buf_size]);
2154  AutoPtr< char, ArrayDeleter<char> > buf(new char[buf_size]);
2155 
2156  size_t bytes_in_inbuf = 0;
2157  size_t bytes_written = 0;
2158  bool load_in = true;
2159 
2161 
2162  while (mask) {
2163  static const STimeout kNoWait = {0, 0};
2164  static const STimeout kWait = {1, 0};
2165 
2166  TChildPollMask rmask = pipe.Poll(mask, load_in? &kNoWait : &kWait);
2167 
2168  if ((rmask & fStdIn) || load_in) {
2169  bool done_in = false;
2170  if (!bytes_in_inbuf) {
2171  if (!in.good()) {
2172  done_in = true;
2173  } else if ((bytes_in_inbuf =
2174  (size_t) CStreamUtils::Readsome
2175  (in, inbuf.get(), buf_size)) != 0) {
2176  bytes_written = 0;
2177  load_in = false;
2178  } else if (!in.good()) {
2179  done_in = true;
2180  } else if (!(rmask & ~fStdIn)) {
2181  SleepMilliSec(NcbiTimeoutToMs(&kWait) / 100);
2182  }
2183  }
2184  if (bytes_in_inbuf && (rmask & fStdIn)) {
2185  size_t x_written;
2186  status = pipe.Write(inbuf.get() + bytes_written,
2187  bytes_in_inbuf, &x_written);
2188  bytes_in_inbuf -= x_written;
2189  if (status != eIO_Success) {
2190  if (bytes_in_inbuf) {
2191  ERR_POST_X(5,
2193  ("ExecWait",
2194  "Cannot pass input data to '"
2195  + x_CommandLine(cmd, args) + "': "
2196  + string(IO_StatusStr(status))));
2197  }
2198  done_in = true;
2199  } else if (!bytes_in_inbuf) {
2200  load_in = true;
2201  } else {
2202  bytes_written += x_written;
2203  }
2204  }
2205  if (done_in) {
2206  pipe.CloseHandle(eStdIn);
2207  mask &= ~fStdIn;
2208  load_in = false;
2209  }
2210  }
2211 
2212  size_t x_read;
2213  if (rmask & fStdOut) {
2214  status = pipe.Read(buf.get(), buf_size, &x_read);
2215  if (x_read) {
2216  out.write(buf.get(), x_read);
2217  }
2218  if (status != eIO_Success) {
2219  mask &= ~fStdOut;
2220  }
2221  }
2222 
2223  if (rmask & fStdErr) {
2224  status = pipe.Read(buf.get(), buf_size, &x_read, eStdErr);
2225  if (x_read) {
2226  err.write(buf.get(), x_read);
2227  }
2228  if (status != eIO_Success) {
2229  mask &= ~fStdErr;
2230  }
2231  }
2232 
2233  if (!CProcess(pid).IsAlive())
2234  break;
2235  if (watcher) {
2236  switch (watcher->Watch(pid)) {
2238  continue;
2240  break;
2242  pipe.m_PipeHandle->Release();
2243  return eCanceled;
2244  }
2245  // IProcessWatcher::eStop
2246  pipe.SetTimeout(eIO_Close, &ktm);
2247  finish = eCanceled;
2248  break;
2249  }
2250  }
2251  } catch (...) {
2252  pipe.SetTimeout(eIO_Close, &ktm);
2253  pipe.Close(&exit_code);
2254  throw;
2255  }
2256  pipe.Close(&exit_code);
2257  return finish;
2258 }
2259 
2260 
2261 const char* CPipeException::GetErrCodeString(void) const
2262 {
2263  switch (GetErrCode()) {
2264  case eOpen: return "eOpen";
2265  default: break;
2266  }
2268 }
2269 
2270 
ncbi::TMaskedQueryRegions mask
#define false
Definition: bool.h:36
AutoPtr –.
Definition: ncbimisc.hpp:401
CPipeException –.
Definition: ncbi_pipe.hpp:534
EIO_Status CloseHandle(CPipe::EChildIOHandle handle)
Definition: ncbi_pipe.cpp:581
CPipe::TChildPollMask Poll(CPipe::TChildPollMask mask, const STimeout *timeout) const
Definition: ncbi_pipe.cpp:783
EIO_Status Write(const void *data, size_t count, size_t *written, const STimeout *timeout) const
Definition: ncbi_pipe.cpp:707
void x_SetNonBlockingMode(HANDLE fd) const
Definition: ncbi_pipe.cpp:826
HANDLE m_ChildStdOut
Definition: ncbi_pipe.cpp:286
EIO_Status Open(const string &cmd, const vector< string > &args, CPipe::TCreateFlags create_flags, const string &current_dir, const char *const env[], size_t pipe_size)
Definition: ncbi_pipe.cpp:321
void OpenSelf(void)
Definition: ncbi_pipe.cpp:503
CPipe::TCreateFlags m_Flags
Definition: ncbi_pipe.cpp:293
HANDLE m_ChildStdErr
Definition: ncbi_pipe.cpp:287
HANDLE m_ChildStdIn
Definition: ncbi_pipe.cpp:285
EIO_Status Read(void *buf, size_t count, size_t *n_read, const CPipe::EChildIOHandle from_handle, const STimeout *timeout) const
Definition: ncbi_pipe.cpp:613
bool m_SelfHandles
Definition: ncbi_pipe.cpp:298
CPipe::TChildPollMask x_Poll(CPipe::TChildPollMask mask, const STimeout *timeout) const
Definition: ncbi_pipe.cpp:839
TProcessHandle GetProcessHandle(void) const
Definition: ncbi_pipe.cpp:270
HANDLE x_GetHandle(CPipe::EChildIOHandle from_handle) const
Definition: ncbi_pipe.cpp:809
void Release(void)
Definition: ncbi_pipe.cpp:271
void x_Clear(void)
Definition: ncbi_pipe.cpp:534
HANDLE m_ProcHandle
Definition: ncbi_pipe.cpp:290
CPipeHandle(void)
Definition: ncbi_pipe.cpp:302
EIO_Status Close(int *exitcode, const STimeout *timeout)
Definition: ncbi_pipe.cpp:549
Callback interface for ExecWait()
Definition: ncbi_pipe.hpp:403
CPipe –.
Definition: ncbi_pipe.hpp:76
Extended exit information for waited process.
CProcess –.
static CS_COMMAND * cmd
Definition: ct_dynamic.c:26
static uch flags
int close(int fd)
Definition: connection.cpp:45
static DLIST_TYPE *DLIST_NAME() next(DLIST_LIST_TYPE *list, DLIST_TYPE *item)
Definition: dlist.tmpl.h:56
std::ofstream out("events_result.xml")
main entry point for tests
void reset(element_type *p=0, EOwnership ownership=eTakeOwnership)
Reset will delete the old pointer (if owned), set content to the new value, and assume the ownership ...
Definition: ncbimisc.hpp:480
element_type * get(void) const
Get pointer.
Definition: ncbimisc.hpp:469
@ eOn
Definition: ncbi_types.h:111
@ eTakeOwnership
An object can take ownership of another.
Definition: ncbi_types.h:136
@ eNoOwnership
No ownership is assumed.
Definition: ncbi_types.h:135
#define NULL
Definition: ncbistd.hpp:225
#define ERR_POST_ONCE(message)
Error posting only once during program execution.
Definition: ncbidiag.hpp:602
#define ERR_POST_X(err_subcode, message)
Error posting with default error code and given error subcode.
Definition: ncbidiag.hpp:550
#define NCBI_THROW(exception_class, err_code, message)
Generic macro to throw an exception, given the exception class, error code and message string.
Definition: ncbiexpt.hpp:704
void Trace(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1179
virtual const char * GetErrCodeString(void) const override
Translate from the error code value to its string representation.
Definition: ncbiexpt.cpp:757
static string QuoteArg(const string &arg)
Quote argument.
Definition: ncbiexec.cpp:230
#define NCBI_PARAM_TYPE(section, name)
Generate typename for a parameter from its {section, name} attributes.
Definition: ncbi_param.hpp:149
#define NCBI_PARAM_DECL(type, section, name)
Parameter declaration.
Definition: ncbi_param.hpp:157
#define NCBI_PARAM_DEF_EX(type, section, name, default_value, flags, env)
Definition of a parameter with additional flags.
Definition: ncbi_param.hpp:228
@ eParam_Default
Default flags.
Definition: ncbi_param.hpp:416
virtual EAction Watch(TProcessHandle)=0
This method is getting called periodically during the process execution by the ExecWait() method.
EIO_Status m_ReadStatus
Last read status.
Definition: ncbi_pipe.hpp:505
EIO_Status Write(const void *data, size_t count, size_t *written=0)
Write data to pipe (data always goes to the child's eStdIn handle).
Definition: ncbi_pipe.cpp:1991
EChildIOHandle m_ReadHandle
Default handle used for read.
Definition: ncbi_pipe.hpp:502
EChildIOHandle
Which of the child I/O handles to use.
Definition: ncbi_pipe.hpp:114
~CPipe(void)
Destructor.
Definition: ncbi_pipe.cpp:1886
TChildPollMask Poll(TChildPollMask mask, const STimeout *timeout=0)
Wait for I/O event(s).
Definition: ncbi_pipe.cpp:2006
EFinish
ExecWait return code.
Definition: ncbi_pipe.hpp:437
TProcessHandle GetProcessHandle(void) const
Get the process handle for the piped child.
Definition: ncbi_pipe.cpp:2093
unsigned int TChildPollMask
bitwise OR of "EChildIOHandle"
Definition: ncbi_pipe.hpp:124
void OpenSelf(void)
Open the standard streams of the current process.
Definition: ncbi_pipe.cpp:1914
EIO_Status SetReadHandle(EChildIOHandle from_handle)
Set standard output handle to read data from.
Definition: ncbi_pipe.cpp:1957
virtual EAction OnStart(TProcessHandle)
This method is called when the process has just been started by the ExecWait() method.
Definition: ncbi_pipe.hpp:422
const STimeout * m_ReadTimeout
eIO_Read timeout
Definition: ncbi_pipe.hpp:509
size_t m_PipeSize
Pipe size.
Definition: ncbi_pipe.hpp:499
CPipe(size_t pipe_size=0)
Constructor.
Definition: ncbi_pipe.cpp:1854
STimeout m_CloseTimeoutValue
Storage for m_CloseTimeout.
Definition: ncbi_pipe.hpp:514
EIO_Status SetTimeout(EIO_Event event, const STimeout *timeout)
Specify timeout for the pipe I/O.
Definition: ncbi_pipe.cpp:2047
STimeout m_WriteTimeoutValue
Storage for m_WriteTimeout.
Definition: ncbi_pipe.hpp:513
CPipeHandle * m_PipeHandle
Internal OS-specific pipe handle.
Definition: ncbi_pipe.hpp:501
EIO_Status Read(void *buf, size_t count, size_t *read=0, EChildIOHandle from_handle=eDefault)
Read data from the pipe's default read handle.
Definition: ncbi_pipe.cpp:1968
STimeout m_ReadTimeoutValue
Storage for m_ReadTimeout.
Definition: ncbi_pipe.hpp:512
EIO_Status Open(const string &cmd, const vector< string > &args, TCreateFlags create_flags=0, const string &current_dir=kEmptyStr, const char *const env[]=0, size_t pipe_size=0)
Open pipe.
Definition: ncbi_pipe.cpp:1893
const STimeout * m_CloseTimeout
eIO_Close timeout
Definition: ncbi_pipe.hpp:511
unsigned int TCreateFlags
bitwise OR of "ECreateFlag"
Definition: ncbi_pipe.hpp:111
const STimeout * GetTimeout(EIO_Event event) const
Get pipe I/O timeout.
Definition: ncbi_pipe.cpp:2075
EIO_Status CloseHandle(EChildIOHandle handle)
Close the specified child's pipe handle (even for CPipe opened with OpenSelf()).
Definition: ncbi_pipe.cpp:1941
EIO_Status m_WriteStatus
Last write status.
Definition: ncbi_pipe.hpp:506
virtual const char * GetErrCodeString(void) const override
Translate from an error code value to its string representation.
Definition: ncbi_pipe.cpp:2261
EIO_Status Close(int *exitcode=0)
Close pipe.
Definition: ncbi_pipe.cpp:1931
static EFinish ExecWait(const string &cmd, const vector< string > &args, CNcbiIstream &in, CNcbiOstream &out, CNcbiOstream &err, int &exit_code, const string &current_dir=kEmptyStr, const char *const env[]=0, IProcessWatcher *watcher=0, const STimeout *kill_timeout=0, size_t pipe_size=0)
Execute a command with a vector of arguments, and wait for its completion.
Definition: ncbi_pipe.cpp:2106
const STimeout * m_WriteTimeout
eIO_Write timeout
Definition: ncbi_pipe.hpp:510
EIO_Status Status(EIO_Event direction) const
Return a status of the last I/O operation.
Definition: ncbi_pipe.cpp:2031
@ eDefault
see SetReadHandle()
Definition: ncbi_pipe.hpp:122
@ eStdOut
Definition: ncbi_pipe.hpp:120
@ eStdIn
Definition: ncbi_pipe.hpp:119
@ eStdErr
Definition: ncbi_pipe.hpp:121
@ fStdIn
Definition: ncbi_pipe.hpp:115
@ fDefault
see Wait()
Definition: ncbi_pipe.hpp:118
@ fStdOut
Definition: ncbi_pipe.hpp:116
@ fStdErr
Definition: ncbi_pipe.hpp:117
@ eDone
Process finished normally.
Definition: ncbi_pipe.hpp:438
@ eCanceled
Watcher requested to bail out.
Definition: ncbi_pipe.hpp:439
@ fKillOnClose
Close(): kill child process if it hasn't terminated within the allotted time.
Definition: ncbi_pipe.hpp:100
@ fNewGroup
UNIX: new process group will be created, and the child process will become the leader of the new proc...
Definition: ncbi_pipe.hpp:107
@ fKeepOnClose
Close(): just return eIO_Timeout if Close() cannot complete within the allotted time; don't close any...
Definition: ncbi_pipe.hpp:93
@ fSigPipe_Restore
Restore SIGPIPE processing for child process to system default.
Definition: ncbi_pipe.hpp:105
@ fStdErr_Open
Do open child's stderr.
Definition: ncbi_pipe.hpp:89
@ fStdIn_Close
Do not open child's stdin.
Definition: ncbi_pipe.hpp:86
@ fStdOut_Close
Do not open child's stdout.
Definition: ncbi_pipe.hpp:88
@ fStdErr_Share
Keep stderr (share it with child)
Definition: ncbi_pipe.hpp:91
@ fStdErr_StdOut
Redirect stderr to whatever stdout goes.
Definition: ncbi_pipe.hpp:92
@ eContinue
Continue running.
Definition: ncbi_pipe.hpp:408
@ eStop
Kill the child process and exit.
Definition: ncbi_pipe.hpp:409
@ eExit
Exit without waiting for the child process.
Definition: ncbi_pipe.hpp:410
bool IsPresent(void) const
TRUE if the object contains information about the process state.
bool KillGroup(unsigned long timeout=kDefaultKillTimeout) const
Terminate a group of processes.
TPid TProcessHandle
bool IsExited(void) const
TRUE if the process terminated normally.
int GetSignal(void) const
Get the signal number that has caused the process to terminate (UNIX only).
bool Kill(unsigned long timeout=kDefaultKillTimeout)
Terminate process.
int Wait(unsigned long timeout=kInfiniteTimeoutMs, CExitInfo *info=0) const
Wait until process terminates.
static const unsigned long kDefaultKillTimeout
Default wait time (milliseconds) between "soft" and "hard" attempts to terminate a process.
pid_t TPid
Process identifier (PID) and process handle.
bool IsAlive(void) const
TRUE if the process is still alive.
bool IsSignaled(void) const
TRUE if the process terminated by a signal (UNIX only).
int GetExitCode(void) const
Get process exit code.
@ ePid
A real process identifier (pid).
@ eHandle
A process handle (MS Windows).
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
#define NCBI_AS_STRING(value)
Convert some value to string even if this value is macro itself.
Definition: ncbistl.hpp:146
ESwitch SOCK_SetInterruptOnSignalAPI(ESwitch on_off)
Control restartability of I/O interrupted by signals.
Definition: ncbi_socket.c:8536
IO_PREFIX::ostream CNcbiOstream
Portable alias for ostream.
Definition: ncbistre.hpp:149
#define NcbiCout
Definition: ncbistre.hpp:543
IO_PREFIX::istream CNcbiIstream
Portable alias for istream.
Definition: ncbistre.hpp:146
static streamsize Readsome(CNcbiIstream &is, CT_CHAR_TYPE *buf, streamsize buf_size)
#define NcbiCerr
Definition: ncbistre.hpp:544
char TXChar
Definition: ncbistr.hpp:172
string TXString
Definition: ncbistr.hpp:173
static const string BoolToString(bool value)
Convert bool to string.
Definition: ncbistr.cpp:2813
#define _T_CSTRING(x)
Definition: ncbistr.hpp:182
#define _T_XCSTRING(x)
Definition: ncbistr.hpp:181
#define _TX(x)
Definition: ncbistr.hpp:176
#define _T_XSTRING(x)
Definition: ncbistr.hpp:179
static enable_if< is_arithmetic< TNumeric >::value||is_convertible< TNumeric, Int8 >::value, string >::type NumericToString(TNumeric value, TNumToStringFlags flags=0, int base=10)
Convert numeric value to string.
Definition: ncbistr.hpp:673
#define DEFINE_STATIC_FAST_MUTEX(id)
Define static fast mutex and initialize it.
Definition: ncbimtx.hpp:496
const long kMicroSecondsPerSecond
Number of microseconds in one second.
Definition: ncbitime.hpp:91
#define kInfiniteTimeout
Definition: ncbi_types.h:82
unsigned long NcbiTimeoutToMs(const STimeout *timeout)
Definition: ncbi_types.c:40
EIO_Status
I/O status.
Definition: ncbi_core.h:132
unsigned int usec
microseconds (modulo 1,000,000)
Definition: ncbi_types.h:78
const char * IO_StatusStr(EIO_Status status)
Get the text form of an enum status value.
Definition: ncbi_core.c:56
STimeout * NcbiMsToTimeout(STimeout *timeout, unsigned long ms)
Definition: ncbi_types.c:48
unsigned int sec
seconds
Definition: ncbi_types.h:77
const char * NcbiMessagePlusError(int *dynamic, const char *message, int error, const char *descr)
Add current "error" (and maybe its description) to the message: <message>[ {error=[[<error>][,...
Definition: ncbi_util.c:335
EIO_Event
I/O event (or direction).
Definition: ncbi_core.h:118
#define kDefaultTimeout
Definition: ncbi_types.h:81
@ eIO_Timeout
timeout expired before any I/O succeeded
Definition: ncbi_core.h:134
@ eIO_Interrupt
signal arrival prevented any I/O to succeed
Definition: ncbi_core.h:136
@ eIO_Success
everything is fine, no error occurred
Definition: ncbi_core.h:133
@ eIO_Unknown
unknown I/O error (likely fatal but can retry)
Definition: ncbi_core.h:139
@ eIO_InvalidArg
bad argument / parameter value(s) supplied
Definition: ncbi_core.h:137
@ eIO_Write
write
Definition: ncbi_core.h:121
@ eIO_ReadWrite
eIO_Read | eIO_Write (also, eCONN_OnFlush)
Definition: ncbi_core.h:122
@ eIO_Close
also serves as an error indicator in SOCK_Poll
Definition: ncbi_core.h:123
@ eIO_Read
read
Definition: ncbi_core.h:120
#define INVALID_HANDLE_VALUE
A value for an invalid file handle.
Definition: mdb.c:389
#define HANDLE
An abstraction for a file handle.
Definition: mdb.c:383
Definition of all error codes used in connect library (xconnect.lib, xconnext.lib etc).
FILE * file
char * buf
int i
yy_size_t n
int len
const struct ncbi::grid::netcache::search::fields::SIZE size
static const STimeout kZeroTimeout
static string x_FormatError(int error, const string &message)
Definition: ncbi_pipe.cpp:98
AutoPtr< char, CDeleter< char > > TTempCharPtr
Definition: ncbi_pipe.cpp:95
static string s_FormatErrorMessage(const string &where, const string &what)
Definition: ncbi_pipe.cpp:135
const unsigned long kWaitPrecision
Definition: ncbi_pipe.cpp:234
static const STimeout * s_SetTimeout(const STimeout *from, STimeout *to)
Definition: ncbi_pipe.cpp:84
#define IS_SET(flags, mask)
Definition: ncbi_pipe.cpp:69
static string x_GetHandleName(CPipe::EChildIOHandle handle)
Definition: ncbi_pipe.cpp:194
#define PIPE_THROW(err, errtxt)
Definition: ncbi_pipe.cpp:72
static bool x_IsDisconnectError(DWORD error)
Definition: ncbi_pipe.cpp:237
static string x_CommandLine(const string &cmd, const vector< string > &args)
Definition: ncbi_pipe.cpp:211
static EIO_Status s_Close(CProcess &process, CPipe::TCreateFlags flags, const STimeout *timeout, int *exitcode)
Definition: ncbi_pipe.cpp:141
Portable class to work with a spawned process via pipes.
void SleepMilliSec(unsigned long ml_sec, EInterruptOnSignal onsignal=eRestartOnSignal)
#define STDIN_FILENO
Definition: ncbicgi.cpp:61
#define STDOUT_FILENO
Definition: ncbicgir.cpp:48
int ssize_t
Definition: ncbiconf_msvc.h:92
Defines a portable execute class.
const char * command
T max(T x_, T y_)
std::istream & in(std::istream &in_, double &x_)
static char tmp[2048]
Definition: utf8.c:42
#define memmove(a, b, c)
Provide poll call where missing.
#define POLLIN
Definition: poll.h:37
#define poll(fds, nfds, timeout)
Definition: poll.h:81
#define FD_SETSIZE
Definition: poll.h:30
#define POLLOUT
Definition: poll.h:38
char TCHAR
Definition: sqltypes.h:91
TCHAR * LPTSTR
Definition: sqltypes.h:111
unsigned int DWORD
Definition: sqltypes.h:98
Timeout structure.
Definition: ncbi_types.h:76
Definition: poll.h:52
int fd
Definition: poll.h:53
short revents
Definition: poll.h:55
int BOOL
Definition: sybdb.h:150
#define _TROUBLE
#define _ASSERT
@ TRUE
Definition: testodbc.c:27
else result
Definition: token2.c:20
static HENV env
Definition: transaction2.c:38
uchar inbuf[1000000]
Definition: unzcrash.c:40
Modified on Wed Nov 29 02:15:11 2023 by modify_doxy.py rev. 669887