libzypp  17.25.1
ExternalProgram.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
12 #define _GNU_SOURCE 1 // for ::getline
13 
14 #include <signal.h>
15 #include <errno.h>
16 #include <unistd.h>
17 #include <sys/wait.h>
18 #include <fcntl.h>
19 #include <pty.h> // openpty
20 #include <stdlib.h> // setenv
21 #include <sys/prctl.h> // prctl(), PR_SET_PDEATHSIG
22 
23 #include <cstring> // strsignal
24 #include <iostream>
25 #include <sstream>
26 
27 #include <zypp/base/Logger.h>
28 #include <zypp/base/String.h>
29 #include <zypp/base/Gettext.h>
30 #include <zypp/ExternalProgram.h>
32 
33 using std::endl;
34 
35 #undef ZYPP_BASE_LOGGER_LOGGROUP
36 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::exec"
37 
38 namespace zypp {
39 
41  : use_pty (false)
42  , pid( -1 )
43  {}
44 
45 
46  ExternalProgram::ExternalProgram( std::string commandline,
47  Stderr_Disposition stderr_disp,
48  bool use_pty,
49  int stderr_fd,
50  bool default_locale,
51  const Pathname & root )
52  : use_pty (use_pty)
53  , pid( -1 )
54  {
55  const char *argv[4];
56  argv[0] = "/bin/sh";
57  argv[1] = "-c";
58  argv[2] = commandline.c_str();
59  argv[3] = 0;
60 
61  start_program( argv, Environment(), stderr_disp, stderr_fd, default_locale, root.c_str() );
62  }
63 
64 
66  Stderr_Disposition stderr_disp,
67  bool use_pty,
68  int stderr_fd,
69  bool default_locale,
70  const Pathname & root )
71  : use_pty (use_pty)
72  , pid( -1 )
73  {
74  const char * argvp[argv.size() + 1];
75  unsigned c = 0;
76  for_( i, argv.begin(), argv.end() )
77  {
78  argvp[c] = i->c_str();
79  ++c;
80  }
81  argvp[c] = 0;
82 
83  start_program( argvp, Environment(), stderr_disp, stderr_fd, default_locale, root.c_str() );
84  }
85 
86 
88  const Environment & environment,
89  Stderr_Disposition stderr_disp,
90  bool use_pty,
91  int stderr_fd,
92  bool default_locale,
93  const Pathname & root )
94  : use_pty (use_pty)
95  , pid( -1 )
96  {
97  const char * argvp[argv.size() + 1];
98  unsigned c = 0;
99  for_( i, argv.begin(), argv.end() )
100  {
101  argvp[c] = i->c_str();
102  ++c;
103  }
104  argvp[c] = 0;
105 
106  start_program( argvp, environment, stderr_disp, stderr_fd, default_locale, root.c_str() );
107  }
108 
109 
110 
111  ExternalProgram::ExternalProgram( const char *const *argv,
112  Stderr_Disposition stderr_disp,
113  bool use_pty,
114  int stderr_fd,
115  bool default_locale,
116  const Pathname & root )
117  : use_pty (use_pty)
118  , pid( -1 )
119  {
120  start_program( argv, Environment(), stderr_disp, stderr_fd, default_locale, root.c_str() );
121  }
122 
123 
124  ExternalProgram::ExternalProgram( const char *const * argv,
125  const Environment & environment,
126  Stderr_Disposition stderr_disp,
127  bool use_pty,
128  int stderr_fd,
129  bool default_locale,
130  const Pathname & root )
131  : use_pty (use_pty)
132  , pid( -1 )
133  {
134  start_program( argv, environment, stderr_disp, stderr_fd, default_locale, root.c_str() );
135  }
136 
137 
138  ExternalProgram::ExternalProgram( const char *binpath,
139  const char *const *argv_1,
140  bool use_pty )
141  : use_pty (use_pty)
142  , pid( -1 )
143  {
144  int i = 0;
145  while (argv_1[i++])
146  ;
147  const char *argv[i + 1];
148  argv[0] = binpath;
149  memcpy( &argv[1], argv_1, (i - 1) * sizeof (char *) );
150  start_program( argv, Environment() );
151  }
152 
153 
154  ExternalProgram::ExternalProgram( const char *binpath,
155  const char *const *argv_1,
156  const Environment & environment,
157  bool use_pty )
158  : use_pty (use_pty)
159  , pid( -1 )
160  {
161  int i = 0;
162  while (argv_1[i++])
163  ;
164  const char *argv[i + 1];
165  argv[0] = binpath;
166  memcpy( &argv[1], argv_1, (i - 1) * sizeof (char *) );
167  start_program( argv, environment );
168  }
169 
170 
172  {
173  if ( running() ) {
174  // we got destructed while the external process is still alive
175  // make sure the zombie is cleaned up once it exits
177  }
178  }
179 
180 
181 
182  void ExternalProgram::start_program(const char *const *argv,
183  const Environment & environment,
184  Stderr_Disposition stderr_disp,
185  int stderr_fd,
186  bool default_locale,
187  const char * root , bool switch_pgid, bool die_with_parent )
188  {
189  pid = -1;
190  _exitStatus = 0;
191  int to_external[2], from_external[2]; // fds for pair of pipes
192  int master_tty, slave_tty; // fds for pair of ttys
193 
194  // retrieve options at beginning of arglist
195  const char * redirectStdin = nullptr; // <[file]
196  const char * redirectStdout = nullptr; // >[file]
197  const char * chdirTo = nullptr; // #/[path]
198 
199  if ( root )
200  {
201  if ( root[0] == '\0' )
202  {
203  root = nullptr; // ignore empty root
204  }
205  else if ( root[0] == '/' && root[1] == '\0' )
206  {
207  // If root is '/' do not chroot, but chdir to '/'
208  // unless arglist defines another dir.
209  chdirTo = "/";
210  root = nullptr;
211  }
212  }
213 
214  for ( bool strip = false; argv[0]; ++argv )
215  {
216  strip = false;
217  switch ( argv[0][0] )
218  {
219  case '<':
220  strip = true;
221  redirectStdin = argv[0]+1;
222  if ( *redirectStdin == '\0' )
223  redirectStdin = "/dev/null";
224  break;
225 
226  case '>':
227  strip = true;
228  redirectStdout = argv[0]+1;
229  if ( *redirectStdout == '\0' )
230  redirectStdout = "/dev/null";
231  break;
232 
233  case '#':
234  strip = true;
235  if ( argv[0][1] == '/' ) // #/[path]
236  chdirTo = argv[0]+1;
237  break;
238  }
239  if ( ! strip )
240  break;
241  }
242 
243  // do not remove the single quotes around every argument, copy&paste of
244  // command to shell will not work otherwise!
245  {
246  std::stringstream cmdstr;
247  for (int i = 0; argv[i]; i++)
248  {
249  if (i>0) cmdstr << ' ';
250  cmdstr << '\'';
251  cmdstr << argv[i];
252  cmdstr << '\'';
253  }
254  if ( redirectStdin )
255  cmdstr << " < '" << redirectStdin << "'";
256  if ( redirectStdout )
257  cmdstr << " > '" << redirectStdout << "'";
258  _command = cmdstr.str();
259  }
260  DBG << "Executing" << (default_locale?"[C] ":" ") << _command << endl;
261 
262 
263  if (use_pty)
264  {
265  // Create pair of ttys
266  DBG << "Using ttys for communication with " << argv[0] << endl;
267  if (openpty (&master_tty, &slave_tty, 0, 0, 0) != 0)
268  {
269  _execError = str::form( _("Can't open pty (%s)."), strerror(errno) );
270  _exitStatus = 126;
271  ERR << _execError << endl;
272  return;
273  }
274  }
275  else
276  {
277  // Create pair of pipes
278  if (pipe (to_external) != 0 || pipe (from_external) != 0)
279  {
280  _execError = str::form( _("Can't open pipe (%s)."), strerror(errno) );
281  _exitStatus = 126;
282  ERR << _execError << endl;
283  return;
284  }
285  }
286 
287  pid_t ppid_before_fork = ::getpid();
288 
289  // Create module process
290  if ((pid = fork()) == 0)
291  {
293  // Don't write to the logfile after fork!
295  if (use_pty)
296  {
297  setsid();
298  if(slave_tty != 1)
299  dup2 (slave_tty, 1); // set new stdout
300  renumber_fd (slave_tty, 0); // set new stdin
301  ::close(master_tty); // Belongs to father process
302 
303  // We currently have no controlling terminal (due to setsid).
304  // The first open call will also set the new ctty (due to historical
305  // unix guru knowledge ;-) )
306 
307  char name[512];
308  ttyname_r(slave_tty, name, sizeof(name));
309  ::close(open(name, O_RDONLY));
310  }
311  else
312  {
313  if ( switch_pgid )
314  setpgid( 0, 0);
315  renumber_fd (to_external[0], 0); // set new stdin
316  ::close(from_external[0]); // Belongs to father process
317 
318  renumber_fd (from_external[1], 1); // set new stdout
319  ::close(to_external [1]); // Belongs to father process
320  }
321 
322  if ( redirectStdin )
323  {
324  ::close( 0 );
325  int inp_fd = open( redirectStdin, O_RDONLY );
326  dup2( inp_fd, 0 );
327  }
328 
329  if ( redirectStdout )
330  {
331  ::close( 1 );
332  int inp_fd = open( redirectStdout, O_WRONLY|O_CREAT|O_APPEND, 0600 );
333  dup2( inp_fd, 1 );
334  }
335 
336  // Handle stderr
337  if (stderr_disp == Discard_Stderr)
338  {
339  int null_fd = open("/dev/null", O_WRONLY);
340  dup2(null_fd, 2);
341  ::close(null_fd);
342  }
343  else if (stderr_disp == Stderr_To_Stdout)
344  {
345  dup2(1, 2);
346  }
347  else if (stderr_disp == Stderr_To_FileDesc)
348  {
349  // Note: We don't have to close anything regarding stderr_fd.
350  // Our caller is responsible for that.
351  dup2 (stderr_fd, 2);
352  }
353 
354  for ( Environment::const_iterator it = environment.begin(); it != environment.end(); ++it ) {
355  setenv( it->first.c_str(), it->second.c_str(), 1 );
356  }
357 
358  if(default_locale)
359  setenv("LC_ALL","C",1);
360 
361  if(root)
362  {
363  if(chroot(root) == -1)
364  {
365  _execError = str::form( _("Can't chroot to '%s' (%s)."), root, strerror(errno) );
366  std::cerr << _execError << endl;// After fork log on stderr too
367  _exit (128); // No sense in returning! I am forked away!!
368  }
369  if ( ! chdirTo )
370  chdirTo = "/";
371  }
372 
373  if ( chdirTo && chdir( chdirTo ) == -1 )
374  {
375  _execError = root ? str::form( _("Can't chdir to '%s' inside chroot '%s' (%s)."), chdirTo, root, strerror(errno) )
376  : str::form( _("Can't chdir to '%s' (%s)."), chdirTo, strerror(errno) );
377  std::cerr << _execError << endl;// After fork log on stderr too
378  _exit (128); // No sense in returning! I am forked away!!
379  }
380 
381  // close all filedesctiptors above stderr
382  for ( int i = ::getdtablesize() - 1; i > 2; --i ) {
383  ::close( i );
384  }
385 
386  if ( die_with_parent ) {
387  // process dies with us
388  int r = prctl(PR_SET_PDEATHSIG, SIGTERM);
389  if (r == -1) {
390  //ignore if it did not work, worst case the process lives on after the parent dies
391  std::cerr << "Failed to set PR_SET_PDEATHSIG" << endl;// After fork log on stderr too
392  }
393 
394  // test in case the original parent exited just
395  // before the prctl() call
396  pid_t ppidNow = getppid();
397  if (ppidNow != ppid_before_fork) {
398  std::cerr << "PPID changed from "<<ppid_before_fork<<" to "<< ppidNow << endl;// After fork log on stderr too
399  _exit(128);
400  }
401  }
402 
403  execvp(argv[0], const_cast<char *const *>(argv));
404  // don't want to get here
405  _execError = str::form( _("Can't exec '%s' (%s)."), argv[0], strerror(errno) );
406  std::cerr << _execError << endl;// After fork log on stderr too
407  _exit (129); // No sense in returning! I am forked away!!
409  }
410 
411  else if (pid == -1) // Fork failed, close everything.
412  {
413  _execError = str::form( _("Can't fork (%s)."), strerror(errno) );
414  _exitStatus = 127;
415  ERR << _execError << endl;
416 
417  if (use_pty) {
418  ::close(master_tty);
419  ::close(slave_tty);
420  }
421  else {
422  ::close(to_external[0]);
423  ::close(to_external[1]);
424  ::close(from_external[0]);
425  ::close(from_external[1]);
426  }
427  }
428 
429  else {
430  if (use_pty)
431  {
432  ::close(slave_tty); // belongs to child process
433  inputfile = fdopen(master_tty, "r");
434  outputfile = fdopen(master_tty, "w");
435  }
436  else
437  {
438  ::close(to_external[0]); // belongs to child process
439  ::close(from_external[1]); // belongs to child process
440  inputfile = fdopen(from_external[0], "r");
441  outputfile = fdopen(to_external[1], "w");
442  }
443 
444  DBG << "pid " << pid << " launched" << endl;
445 
446  if (!inputfile || !outputfile)
447  {
448  ERR << "Cannot create streams to external program " << argv[0] << endl;
449  close();
450  }
451  }
452  }
453 
454 
455  int
457  {
458  if (pid > 0)
459  {
460  if ( inputFile() )
461  {
462  // Discard any output instead of closing the pipe,
463  // but watch out for the command exiting while some
464  // subprocess keeps the filedescriptor open.
465  setBlocking( false );
466  FILE * inputfile = inputFile();
467  int inputfileFd = ::fileno( inputfile );
468  long delay = 0;
469  do
470  {
471  /* Watch inputFile to see when it has input. */
472  fd_set rfds;
473  FD_ZERO( &rfds );
474  FD_SET( inputfileFd, &rfds );
475 
476  /* Wait up to 1 seconds. */
477  struct timeval tv;
478  tv.tv_sec = (delay < 0 ? 1 : 0);
479  tv.tv_usec = (delay < 0 ? 0 : delay*100000);
480  if ( delay >= 0 && ++delay > 9 )
481  delay = -1;
482  int retval = select( inputfileFd+1, &rfds, NULL, NULL, &tv );
483 
484  if ( retval == -1 )
485  {
486  ERR << "select error: " << strerror(errno) << endl;
487  if ( errno != EINTR )
488  break;
489  }
490  else if ( retval )
491  {
492  // Data is available now.
493  static size_t linebuffer_size = 0; // static because getline allocs
494  static char * linebuffer = 0; // and reallocs if buffer is too small
496  // ::feof check is important as select returns
497  // positive if the file was closed.
498  if ( ::feof( inputfile ) )
499  break;
500  clearerr( inputfile );
501  }
502  else
503  {
504  // No data within time.
505  if ( ! running() )
506  break;
507  }
508  } while ( true );
509  }
510 
511  if ( pid > 0 ) // bsc#1109877: must re-check! running() in the loop above may have already waited.
512  {
513  // Wait for child to exit
514  int ret;
515  int status = 0;
516  do
517  {
518  ret = waitpid(pid, &status, 0);
519  }
520  while (ret == -1 && errno == EINTR);
521 
522  if (ret != -1)
523  {
524  _exitStatus = checkStatus( status );
525  }
526  pid = -1;
527  }
528  }
529 
530  return _exitStatus;
531  }
532 
533 
535  {
536  if (WIFEXITED (status))
537  {
538  status = WEXITSTATUS (status);
539  if(status)
540  {
541  DBG << "Pid " << pid << " exited with status " << status << endl;
542  _execError = str::form( _("Command exited with status %d."), status );
543  }
544  else
545  {
546  // if 'launch' is logged, completion should be logged,
547  // even if successfull.
548  DBG << "Pid " << pid << " successfully completed" << endl;
549  _execError.clear(); // empty if running or successfully completed
550  }
551  }
552  else if (WIFSIGNALED (status))
553  {
554  status = WTERMSIG (status);
555  WAR << "Pid " << pid << " was killed by signal " << status
556  << " (" << strsignal(status);
557  if (WCOREDUMP (status))
558  {
559  WAR << ", core dumped";
560  }
561  WAR << ")" << endl;
562  _execError = str::form( _("Command was killed by signal %d (%s)."), status, strsignal(status) );
563  status+=128;
564  }
565  else {
566  ERR << "Pid " << pid << " exited with unknown error" << endl;
567  _execError = _("Command exited with unknown error.");
568  }
569 
570  return status;
571  }
572 
573  bool
575  {
576  if (pid > 0)
577  {
578  ::kill(pid, SIGKILL);
579  close();
580  }
581  return true;
582  }
583 
584  bool ExternalProgram::kill(int sig)
585  {
586  if (pid > 0)
587  {
588  ::kill(pid, sig);
589  }
590  return true;
591  }
592 
593  bool
595  {
596  if ( pid < 0 ) return false;
597 
598  int status = 0;
599  int p = waitpid( pid, &status, WNOHANG );
600  switch ( p )
601  {
602  case -1:
603  ERR << "waitpid( " << pid << ") returned error '" << strerror(errno) << "'" << endl;
604  return false;
605  break;
606  case 0:
607  return true; // still running
608  break;
609  }
610 
611  // Here: completed...
612  _exitStatus = checkStatus( status );
613  pid = -1;
614  return false;
615  }
616 
617  // origfd will be accessible as newfd and closed (unless they were equal)
618  void ExternalProgram::renumber_fd (int origfd, int newfd)
619  {
620  // It may happen that origfd is already the one we want
621  // (Although in our circumstances, that would mean somebody has closed
622  // our stdin or stdout... weird but has appened to Cray, #49797)
623  if (origfd != newfd)
624  {
625  dup2 (origfd, newfd);
626  ::close (origfd);
627  }
628  }
629 
630  std::ostream & ExternalProgram::operator>>( std::ostream & out_r )
631  {
632  setBlocking( true );
633  for ( std::string line = receiveLine(); line.length(); line = receiveLine() )
634  out_r << line;
635  return out_r;
636  }
637 
639  //
640  // class ExternalProgramWithStderr
641  //
643 
644  namespace externalprogram
645  {
647  {
648  _fds[R] = _fds[W] = -1;
649 #ifdef HAVE_PIPE2
650  ::pipe2( _fds, O_NONBLOCK );
651 #else
652  ::pipe( _fds );
653  ::fcntl(_fds[R], F_SETFD, O_NONBLOCK );
654  ::fcntl(_fds[W], F_SETFD, O_NONBLOCK );
655 #endif
656  _stderr = ::fdopen( _fds[R], "r" );
657  }
658 
660  {
661  closeW();
662  if ( _stderr )
663  ::fclose( _stderr );
664  }
665  } // namespace externalprogram
666 
667  bool ExternalProgramWithStderr::stderrGetUpTo( std::string & retval_r, const char delim_r, bool returnDelim_r )
668  {
669  if ( ! _stderr )
670  return false;
671  if ( delim_r && ! _buffer.empty() )
672  {
673  // check for delim already in buffer
674  std::string::size_type pos( _buffer.find( delim_r ) );
675  if ( pos != std::string::npos )
676  {
677  retval_r = _buffer.substr( 0, returnDelim_r ? pos+1 : pos );
678  _buffer.erase( 0, pos+1 );
679  return true;
680  }
681  }
682  ::clearerr( _stderr );
683  do {
684  int ch = fgetc( _stderr );
685  if ( ch != EOF )
686  {
687  if ( ch != delim_r || ! delim_r )
688  _buffer.push_back( ch );
689  else
690  {
691  if ( returnDelim_r )
692  _buffer.push_back( delim_r );
693  break;
694  }
695  }
696  else if ( ::feof( _stderr ) )
697  {
698  if ( _buffer.empty() )
699  return false;
700  break;
701  }
702  else if ( errno != EINTR )
703  return false;
704  } while ( true );
705  // HERE: we left after readig at least one char (\n)
706  retval_r.swap( _buffer );
707  _buffer.clear();
708  return true;
709  }
710 
711 
712 } // namespace zypp
zypp::ExternalProgram::operator>>
std::ostream & operator>>(std::ostream &out_r)
Redirect all command output to an ostream.
Definition: ExternalProgram.cc:630
ExternalProgram.h
zypp::ExternalProgram::Stderr_To_Stdout
Definition: ExternalProgram.h:73
zypp::ExternalProgram::start_program
void start_program(const char *const *argv, const Environment &environment, Stderr_Disposition stderr_disp=Normal_Stderr, int stderr_fd=-1, bool default_locale=false, const char *root=NULL, bool switch_pgid=false, bool die_with_parent=false)
Definition: ExternalProgram.cc:182
zypp::externalprogram::EarlyPipe::closeW
void closeW()
Definition: ExternalProgram.h:256
zypp::ExternalProgram::use_pty
bool use_pty
Set to true, if a pair of ttys is used for communication instead of a pair of pipes.
Definition: ExternalProgram.h:225
CleanerThread_p.h
zypp::ExternalProgram::kill
bool kill()
Kill the program.
Definition: ExternalProgram.cc:574
zypp::externalprogram::ExternalDataSource::linebuffer_size
size_t linebuffer_size
Definition: ExternalDataSource.h:35
zypp::ExternalProgram::running
bool running()
Return whether program is running.
Definition: ExternalProgram.cc:594
zypp::externalprogram::EarlyPipe::_stderr
FILE * _stderr
Definition: ExternalProgram.h:259
zypp::CleanerThread::watchPID
static void watchPID(pid_t pid_r)
Definition: CleanerThread.cc:69
zypp::externalprogram::EarlyPipe::_fds
int _fds[2]
Definition: ExternalProgram.h:260
zypp::str::strerror
std::string strerror(int errno_r)
Return string describing the error_r code.
Definition: String.cc:51
zypp::iostr::getline
std::string getline(std::istream &str)
Read one line from stream.
Definition: IOStream.cc:32
zypp::ExternalProgram::Arguments
std::vector< std::string > Arguments
Definition: ExternalProgram.h:64
zypp::ExternalProgramWithStderr::_buffer
std::string _buffer
Definition: ExternalProgram.h:307
zypp::filesystem::Pathname::c_str
const char * c_str() const
String representation.
Definition: Pathname.h:110
Logger.h
WAR
#define WAR
Definition: Logger.h:80
zypp::ExternalProgram::checkStatus
int checkStatus(int)
Definition: ExternalProgram.cc:534
zypp::ExternalProgram::~ExternalProgram
~ExternalProgram()
Definition: ExternalProgram.cc:171
_
#define _(MSG)
Definition: Gettext.h:37
zypp::str::form
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition: String.cc:35
zypp::externalprogram::EarlyPipe::~EarlyPipe
~EarlyPipe()
Definition: ExternalProgram.cc:659
zypp::externalprogram::EarlyPipe::EarlyPipe
EarlyPipe()
Definition: ExternalProgram.cc:646
zypp
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:1
zypp::ExternalProgram::Discard_Stderr
Definition: ExternalProgram.h:72
zypp::ExternalProgram::Stderr_Disposition
Stderr_Disposition
Define symbols for different policies on the handling of stderr.
Definition: ExternalProgram.h:70
zypp::ExternalProgram::close
int close()
Wait for the progamm to complete.
Definition: ExternalProgram.cc:456
zypp::ExternalProgram::_execError
std::string _execError
Remember execution errors like failed fork/exec.
Definition: ExternalProgram.h:232
zypp::ExternalProgram::Environment
std::map< std::string, std::string > Environment
For passing additional environment variables to set.
Definition: ExternalProgram.h:81
zypp::externalprogram::ExternalDataSource::inputfile
FILE * inputfile
Definition: ExternalDataSource.h:30
zypp::ExternalProgram::pid
pid_t pid
Definition: ExternalProgram.h:227
zypp::ExternalProgramWithStderr::stderrGetUpTo
bool stderrGetUpTo(std::string &retval_r, const char delim_r, bool returnDelim_r=false)
Read data up to delim_r from stderr (nonblocking).
Definition: ExternalProgram.cc:667
zypp::ExternalProgram::_exitStatus
int _exitStatus
Definition: ExternalProgram.h:228
zypp::ExternalProgram::_command
std::string _command
Store the command we're executing.
Definition: ExternalProgram.h:230
Gettext.h
for_
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:28
zypp::externalprogram::ExternalDataSource::setBlocking
void setBlocking(bool mode)
Set the blocking mode of the input stream.
Definition: ExternalDataSource.cc:109
zypp::ExternalProgram::getpid
pid_t getpid()
return pid
Definition: ExternalProgram.h:171
zypp::externalprogram::ExternalDataSource::receiveLine
std::string receiveLine()
Read one line from the input stream.
Definition: ExternalDataSource.cc:115
String.h
zypp::filesystem::Pathname
Pathname.
Definition: Pathname.h:44
zypp::sat::detail::size_type
SolvableIdType size_type
Definition: PoolMember.h:126
ERR
#define ERR
Definition: Logger.h:81
DBG
#define DBG
Definition: Logger.h:78
zypp::ExternalProgram::renumber_fd
static void renumber_fd(int origfd, int newfd)
origfd will be accessible as newfd and closed (unless they were equal)
Definition: ExternalProgram.cc:618
zypp::externalprogram::ExternalDataSource::outputfile
FILE * outputfile
Definition: ExternalDataSource.h:31
zypp::externalprogram::ExternalDataSource::linebuffer
char * linebuffer
Definition: ExternalDataSource.h:34
zypp::externalprogram::EarlyPipe::R
Definition: ExternalProgram.h:253
zypp::externalprogram::EarlyPipe::W
Definition: ExternalProgram.h:253
zypp::externalprogram::ExternalDataSource::inputFile
FILE * inputFile() const
Return the input stream.
Definition: ExternalDataSource.h:118
zypp::ExternalProgram::ExternalProgram
ExternalProgram()
Start an external program by giving the arguments as an arry of char *pointers.
Definition: ExternalProgram.cc:40
zypp::ExternalProgram::Stderr_To_FileDesc
Definition: ExternalProgram.h:74