libzypp: zypp-core/ng/io/forkspawnengine.cc Source File

libzypp 17.38.14

forkspawnengine.cc
Go to the documentation of this file.
1#include "private/forkspawnengine_p.h"
2
3#include <sstream>
4#include <zypp-core/base/LogControl.h>
5#include <zypp-core/base/Gettext.h>
6#include <zypp-core/base/IOTools.h>
7#include <zypp-core/fs/PathInfo.h>
8#include <zypp-core/ng/core/String>
9#include <zypp-core/ng/base/EventDispatcher>
10#include <zypp-core/ng/base/Timer>
11#include <zypp-core/ng/base/private/linuxhelpers_p.h>
12#include <zypp-core/base/CleanerThread_p.h>
13#include <zypp-core/base/LogControl.h>
14
15#include <cstdint>
16#include <iostream>
17#include <signal.h>
18#include <errno.h>
19#include <unistd.h>
20#include <sys/wait.h>
21#include <fcntl.h>
22#include <pty.h> // openpty
23#include <stdlib.h> // setenv
24#include <sys/prctl.h> // prctl(), PR_SET_PDEATHSIG
25
26#include <sys/syscall.h>
27#ifdef SYS_pidfd_open
28#include <poll.h>
29#endif
30
31#undef ZYPP_BASE_LOGGER_LOGGROUP
32#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::exec"
33
34
35zyppng::AbstractDirectSpawnEngine::~AbstractDirectSpawnEngine()
36{
37 if ( AbstractDirectSpawnEngine::isRunning() ) {
38 // we got destructed while the external process is still alive
39 // make sure the zombie is cleaned up once it exits
40 zypp::CleanerThread::watchPID( _pid );
41 }
42}
43
44 bool zyppng::AbstractDirectSpawnEngine::isRunning( bool wait )
45{
46 if ( _pid < 0 ) return false;
47
48 int status = 0;
49 int p = zyppng::eintrSafeCall( ::waitpid, _pid, &status, wait ? 0 : WNOHANG );
50 switch ( p )
51 {
52 case -1:
53 ERR << "waitpid( " << _pid << ") returned error '" << strerror(errno) << "'" << std::endl;
54 return false;
55 break;
56 case 0:
57 return true; // still running
58 break;
59 }
60
61 // Here: completed...
62 _exitStatus = checkStatus( status );
63 _pid = -1;
64 return false;
65}
66
67 bool zyppng::AbstractDirectSpawnEngine::waitForExit( const std::optional<uint64_t> &timeout )
68{
69 if ( _pid < 0 ) return true;
70
71 // no timeout, wait forever
72 if ( !timeout.has_value () )
73 return !isRunning( true );
74
75 // busy loop polling in case pidfd is not available or fails, only called if we have a valid timout
76 const auto &fallbackPoll = [&]( uint64_t timeout ){
77 const auto start = Timer::now();
78 do {
79 if ( !isRunning(false) )
80 return true;
81 // give up the CPU, so we do not use 100% just to poll
82 std::this_thread::sleep_for( std::chrono::milliseconds(1) );
83 } while( Timer::elapsedSince ( start ) < timeout );
84
85 return !isRunning ( false );
86 };
87
88#ifdef SYS_pidfd_open
89 // we have pidfd support, but there is not yet a wrapper in glibc
90 const auto &zypp_pidfd_open = [](pid_t pid, unsigned int flags) -> int {
91 return syscall( SYS_pidfd_open, pid, flags );
92 };
93
94 zypp::AutoFD pidFd = zyppng::eintrSafeCall( zypp_pidfd_open, _pid, 0 );
95 if ( pidFd == -1 ) {
96 // fallback to manual polling
97 ERR << "pidfd_open failed, falling back to polling waidpid" << std::endl;
98 return fallbackPoll( *timeout );
99 }
100
101 struct pollfd pollfd;
102 pollfd.fd = pidFd;
103 pollfd.events = POLLIN;
104
105 // timeout always has a value set, we established that above
106 uint64_t tRemaining = *timeout;
107
108 const auto start = Timer::now();
109 do {
110 // posix using int as timeout, could in theory overflow so protect against it
111 int posixTimeout = tRemaining > INT_MAX ? INT_MAX : static_cast<int>(tRemaining);
112
113 int ready = poll(&pollfd, 1, posixTimeout );
114 tRemaining = *timeout - std::min<uint64_t>( Timer::elapsedSince( start ), *timeout );
115
116 if ( ready == -1 && errno != EINTR ) {
117 ERR << "Polling the pidfd failed with error: " << zypp::Errno() << std::endl;
118 if ( tRemaining > 0 ) {
119 ERR << "Falling back to manual polling for the remaining timeout." << std::endl;
120 return fallbackPoll( tRemaining );
121 }
122 break;
123 } else if ( pollfd.revents & POLLIN ) {
124 break;
125 }
126 } while( tRemaining > 0 );
127
128 // set exit status
129 return !isRunning ( false );
130#else
131 // we do not have pidfd support, need to busyloop on waitpid until timeout is over
132 return fallbackPoll( *timeout );
133#endif
134}
135
136 void zyppng::AbstractDirectSpawnEngine::mapExtraFds ( int controlFd )
137{
138 // we might have gotten other FDs to reuse, lets map them to STDERR_FILENO++
139 // BUT we need to make sure the fds are not already in the range we need to map them to
140 // so we first go over a list and collect those that are safe or move those that are not
141 int lastFdToKeep = STDERR_FILENO + _mapFds.size();
142 int nextBackupFd = lastFdToKeep + 1; //this we will use to count the fds upwards
143 std::vector<int> safeFds;
144 for ( auto fd : _mapFds ) {
145 // If the fds are larger than the last one we will map to, it is safe.
146 if ( fd > lastFdToKeep ) {
147 safeFds.push_back( fd );
148 } else {
149 // we need to map the fd after the set of those we want to keep, but also make sure
150 // that we do not close one of those we have already moved or might move
151 while (true) {
152
153 int backupTo = nextBackupFd;
154 nextBackupFd++;
155 const bool isSafe1 = std::find( _mapFds.begin(), _mapFds.end(), backupTo ) == _mapFds.end();
156 const bool isSafe2 = std::find( safeFds.begin(), safeFds.end(), backupTo ) == safeFds.end();
157 if ( isSafe1 && isSafe2 && ( controlFd == -1 || backupTo != controlFd) ) {
158 dup2( fd, backupTo );
159 safeFds.push_back( backupTo );
160 break;
161 }
162 }
163 }
164 }
165
166 // now we have a list of safe fds we need to map to the fd we want them to end up
167 int nextFd = STDERR_FILENO;
168 for ( auto fd : safeFds ) {
169 nextFd++;
170 dup2( fd, nextFd );
171 }
172
173 const auto &canCloseFd = [&]( int fd ){
174 // controlFD has O_CLOEXEC set so it will be cleaned up :)
175 if ( controlFd != -1 && controlFd == fd )
176 return false;
177 // make sure we don't close fd's still need
178 if ( fd <= lastFdToKeep )
179 return false;
180 return true;
181 };
182
183 const auto maxFds = ( ::getdtablesize() - 1 );
184 //If the rlimits are too high we need to use a different approach
185 // in detecting how many fds we need to close, or otherwise we are too slow (bsc#1191324)
186 if ( maxFds > 1024 && zypp::PathInfo( "/proc/self/fd" ).isExist() ) {
187
188 std::vector<int> fdsToClose;
189 fdsToClose.reserve (256);
190
191 zypp::filesystem::dirForEachExt( "/proc/self/fd", [&]( const zypp::Pathname &p, const zypp::filesystem::DirEntry &entry ){
192 if ( entry.type != zypp::filesystem::FT_LINK)
193 return true;
194
195 const auto &fdVal = zyppng::str::safe_strtonum<int>( entry.name );
196 if ( !fdVal || !canCloseFd(*fdVal) )
197 return true;
198
199 // we can not call close() directly here because zypp::filesystem::dirForEachExt actually has a fd open on
200 // /proc/self/fd that we would close as well. So we just remember which fd's we WOULD close and then do it
201 // after iterating
202 fdsToClose.push_back (*fdVal);
203 return true;
204 });
205 for ( int cFd : fdsToClose )
206 ::close( cFd );
207 } else {
208 // close all filedescriptors above the last we want to keep
209 for ( int i = maxFds; i > lastFdToKeep; --i ) {
210 if ( !canCloseFd(i) ) continue;
211 ::close( i );
212 }
213 }
214}
215
216 void zyppng::AbstractDirectSpawnEngine::resetSignals()
217{
218 // set all signal handers to their default
219 struct sigaction act;
220 memset (&act, 0, sizeof (struct sigaction));
221 act.sa_handler = SIG_DFL;
222 for ( int i = 1; i < NSIG; i++ ) {
223 // this might return -1 and set errno for unknown signals, but
224 // thats fine for us.
225 sigaction(i, &act, NULL);
226 }
227
228 // clear the sigmask
229 sigset_t sigMask;
230 sigemptyset ( &sigMask );
231 pthread_sigmask ( SIG_SETMASK, &sigMask, nullptr );
232}
233
234 bool zyppng::ForkSpawnEngine::start( const char * const *argv, int stdin_fd, int stdout_fd, int stderr_fd )
235{
236 _pid = -1;
237 _exitStatus = 0;
238 _execError.clear();
239 _executedCommand.clear();
240 _args.clear();
241
242 if ( !argv || !argv[0] ) {
243 _execError = _("Invalid spawn arguments given.");
244 _exitStatus = 128;
245 return false;
246 }
247
248 const char * chdirTo = nullptr;
249
250 if ( _chroot == "/" ) {
251 // If _chroot is '/' do not chroot, but chdir to '/'
252 // unless arglist defines another dir.
253 chdirTo = "/";
254 _chroot = zypp::Pathname();
255 }
256
257 if ( !_workingDirectory.empty() )
258 chdirTo = _workingDirectory.c_str();
259
260 // do not remove the single quotes around every argument, copy&paste of
261 // command to shell will not work otherwise!
262 {
263 _args.clear();
264 std::stringstream cmdstr;
265 for (int i = 0; argv[i]; i++) {
266 if ( i != 0 ) cmdstr << ' ';
267 cmdstr << '\'';
268 cmdstr << argv[i];
269 cmdstr << '\'';
270 _args.push_back( argv[i] );
271 }
272 _executedCommand = cmdstr.str();
273 }
274 DBG << "Executing" << ( _useDefaultLocale?"[C] ":" ") << _executedCommand << std::endl;
275
276 // we use a control pipe to figure out if the exec actually worked,
277 // this is the approach:
278 // - create a pipe before forking
279 // - block on the read end of the pipe in the parent process
280 // - in the child process we write a error tag + errno into the pipe if we encounter any error and exit
281 // - If child setup works out, the pipe is auto closed by exec() and the parent process knows from just receiving EOF
282 // that starting the child was successful, otherwise the blocking read in the parent will return with actual data read from the fd
283 // which will contain the error description
284
285 enum class ChildErrType : int8_t {
286 NO_ERR,
287 CHROOT_FAILED,
288 CHDIR_FAILED,
289 EXEC_FAILED
290 };
291
292 struct ChildErr {
293 int childErrno = 0;
294 ChildErrType type = ChildErrType::NO_ERR;
295 };
296
297 auto controlPipe = Pipe::create( O_CLOEXEC );
298 if ( !controlPipe ) {
299 _execError = _("Unable to create control pipe.");
300 _exitStatus = 128;
301 return false;
302 }
303
304 pid_t ppid_before_fork = ::getpid();
305
306 // Create module process
307 if ( ( _pid = fork() ) == 0 )
308 {
309
310 // child process
311 resetSignals();
312 controlPipe->unrefRead();
313
314 const auto &writeErrAndExit = [&]( int errCode, ChildErrType type ){
315 ChildErr buf {
316 errno,
317 type
318 };
319
320 zypp::io::writeAll( controlPipe->writeFd, &buf, sizeof(ChildErr) );
321 _exit ( errCode );
322 };
323
325 // Don't write to the logfile after fork!
327 if ( _use_pty )
328 {
329 setsid();
330 dup2 ( stdout_fd, 1); // set new stdout
331 dup2 ( stdin_fd , 0); // set new stdin
332
333 // We currently have no controlling terminal (due to setsid).
334 // The first open call will also set the new ctty (due to historical
335 // unix guru knowledge ;-) )
336
337 char name[512];
338 ttyname_r( stdout_fd , name, sizeof(name) );
339 ::close(open(name, O_RDONLY));
340 }
341 else
342 {
343 if ( _switchPgid )
344 setpgid( 0, 0);
345 if ( stdin_fd != -1 )
346 dup2 ( stdin_fd, 0); // set new stdin
347 if ( stdout_fd != -1 )
348 dup2 ( stdout_fd, 1); // set new stdout
349 }
350
351 // Handle stderr
352 if ( stderr_fd != -1 )
353 dup2 ( stderr_fd, 2); // set new stderr
354
355 for ( Environment::const_iterator it = _environment.begin(); it != _environment.end(); ++it ) {
356 setenv( it->first.c_str(), it->second.c_str(), 1 );
357 }
358
359 if( _useDefaultLocale )
360 setenv("LC_ALL","C",1);
361
362 if( !_chroot.empty() )
363 {
364 if( ::chroot(_chroot.c_str()) == -1)
365 {
366 _execError = zypp::str::form( _("Can't chroot to '%s' (%s)."), _chroot.c_str(), strerror(errno).c_str() );
367 std::cerr << _execError << std::endl; // After fork log on stderr too
368 writeErrAndExit( 128, ChildErrType::CHROOT_FAILED ); // No sense in returning! I am forked away!!
369 }
370 if ( ! chdirTo )
371 chdirTo = "/";
372 }
373
374 if ( chdirTo && chdir( chdirTo ) == -1 )
375 {
376 _execError = _chroot.empty() ? zypp::str::form( _("Can't chdir to '%s' (%s)."), chdirTo, strerror(errno).c_str() )
377 : zypp::str::form( _("Can't chdir to '%s' inside chroot '%s' (%s)."), chdirTo, _chroot.c_str(), strerror(errno).c_str() );
378
379 std::cerr << _execError << std::endl;// After fork log on stderr too
380 writeErrAndExit( 128, ChildErrType::CHDIR_FAILED ); // No sense in returning! I am forked away!!
381 }
382
383 // map the extra fds the user might have set
384 mapExtraFds( controlPipe->writeFd );
385
386 if ( _dieWithParent ) {
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" << std::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 // no sense to write to control pipe, parent is gone
399 std::cerr << "PPID changed from "<<ppid_before_fork<<" to "<< ppidNow << std::endl;// After fork log on stderr too
400 _exit(128);
401 }
402 }
403
404 execvp( argv[0], const_cast<char *const *>( argv ) );
405 // don't want to get here
406 _execError = zypp::str::form( _("Can't exec '%s' (%s)."), _args[0].c_str(), strerror(errno).c_str() );
407 std::cerr << _execError << std::endl;// After fork log on stderr too
408 writeErrAndExit( 129, ChildErrType::EXEC_FAILED ); // No sense in returning! I am forked away!!
410 }
411 else if ( _pid == -1 ) // Fork failed, close everything.
412 {
413 _execError = zypp::str::form( _("Can't fork (%s)."), strerror(errno).c_str() );
414 _exitStatus = 127;
415 ERR << _execError << std::endl;
416 return false;
417 }
418 else {
419
420 // parent process, fork worked lets wait for the exec to happen
421 controlPipe->unrefWrite();
422
423 ChildErr buf;
424 const auto res = zypp::io::readAll( controlPipe->readFd, &buf, sizeof(ChildErr) );
425 if ( res == zypp::io::ReadAllResult::Eof ) {
426 // success!!!!
427 DBG << "pid " << _pid << " launched" << std::endl;
428 return true;
429 } else if ( res == zypp::io::ReadAllResult::Ok ) {
430 switch( buf.type ) {
431 case ChildErrType::CHDIR_FAILED:
432 _execError = zypp::str::form( _("Can't exec '%s', chdir failed (%s)."), _args[0].c_str(), zypp::str::strerror(buf.childErrno).c_str() );
433 break;
434 case ChildErrType::CHROOT_FAILED:
435 _execError = zypp::str::form( _("Can't exec '%s', chroot failed (%s)."), _args[0].c_str(), zypp::str::strerror(buf.childErrno).c_str() );
436 break;
437 case ChildErrType::EXEC_FAILED:
438 _execError = zypp::str::form( _("Can't exec '%s', exec failed (%s)."), _args[0].c_str(), zypp::str::strerror(buf.childErrno).c_str() );
439 break;
440 // all other cases need to be some sort of error, because we only get data if the exec fails
441 default:
442 _execError = zypp::str::form( _("Can't exec '%s', unexpected error."), _args[0].c_str() );
443 break;
444 }
445 ERR << "pid " << _pid << " launch failed: " << _execError << std::endl;
446 _childExecDetail = _execError; //
447
448 // reap child and collect exit code
449 isRunning( true );
450 return false;
451 } else {
452 //reading from the fd failed, this should actually never happen
453 ERR << "Reading from the control pipe failed. " << errno << ". This is not supposed to happen ever." << std::endl;
454 return isRunning();
455 }
456 }
457 return true;
458}
459
460 bool zyppng::ForkSpawnEngine::usePty() const
461{
462 return _use_pty;
463}
464
465 void zyppng::ForkSpawnEngine::setUsePty( const bool set )
466{
467 _use_pty = set;
468}
469
470
471#if ZYPP_HAS_GLIBSPAWNENGINE
472
473struct GLibForkData {
474 zyppng::GlibSpawnEngine *that = nullptr;
475 pid_t pidParent = -1;
476};
477
478bool zyppng::GlibSpawnEngine::start( const char * const *argv, int stdin_fd, int stdout_fd, int stderr_fd )
479{
480 _pid = -1;
481 _exitStatus = 0;
482 _execError.clear();
483 _executedCommand.clear();
484 _args.clear();
485
486 if ( !argv || !argv[0] ) {
487 _execError = _("Invalid spawn arguments given.");
488 _exitStatus = 128;
489 return false;
490 }
491
492 const char * chdirTo = nullptr;
493
494 if ( _chroot == "/" ) {
495 // If _chroot is '/' do not chroot, but chdir to '/'
496 // unless arglist defines another dir.
497 chdirTo = "/";
498 _chroot = zypp::Pathname();
499 }
500
501 if ( !_workingDirectory.empty() )
502 chdirTo = _workingDirectory.c_str();
503
504 // do not remove the single quotes around every argument, copy&paste of
505 // command to shell will not work otherwise!
506 {
507 _args.clear();
508 std::stringstream cmdstr;
509 for (int i = 0; argv[i]; i++) {
510 if ( i != 0 ) cmdstr << ' ';
511 cmdstr << '\'';
512 cmdstr << argv[i];
513 cmdstr << '\'';
514 _args.push_back( argv[i] );
515 }
516 _executedCommand = cmdstr.str();
517 }
518 DBG << "Executing" << ( _useDefaultLocale?"[C] ":" ") << _executedCommand << std::endl;
519
520 // build the env var ptrs
521 std::vector<std::string> envStrs;
522 std::vector<gchar *> envPtrs;
523
524 for ( char **envPtr = environ; *envPtr != nullptr; envPtr++ )
525 envPtrs.push_back( *envPtr );
526
527 envStrs.reserve( _environment.size() );
528 envPtrs.reserve( envPtrs.size() + _environment.size() + ( _useDefaultLocale ? 2 : 1 ) );
529 for ( const auto &env : _environment ) {
530 envStrs.push_back( env.first + "=" + env.second );
531 envPtrs.push_back( envStrs.back().data() );
532 }
533 if ( _useDefaultLocale ) {
534 envStrs.push_back( "LC_ALL=C" );
535 envPtrs.push_back( envStrs.back().data() );
536 }
537 envPtrs.push_back( nullptr );
538
539 GLibForkData data;
540 data.that = this;
541 data.pidParent = ::getpid();
542
543 bool needCallback = !_chroot.empty() || _dieWithParent || _switchPgid || _mapFds.size();
544
545 auto spawnFlags = GSpawnFlags( G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH_FROM_ENVP );
546 if ( _mapFds.size() )
547 spawnFlags = GSpawnFlags( spawnFlags | G_SPAWN_LEAVE_DESCRIPTORS_OPEN );
548
549 GPid childPid = -1;
550 g_autoptr(GError) error = NULL;
551 g_spawn_async_with_fds(
552 chdirTo,
553 const_cast<gchar**>(argv),
554 envPtrs.data(),
555 spawnFlags,
556 needCallback ? &GlibSpawnEngine::glibSpawnCallback : nullptr,
557 needCallback ? &data : nullptr,
558 &childPid,
559 stdin_fd, //in
560 stdout_fd, //out
561 stderr_fd, //err
562 &error
563 );
564
565 if ( !error ) {
566 _pid = childPid;
567 } else {
568 _execError = zypp::str::form( _("Can't fork (%s)."), strerror(errno).c_str() );
569 _exitStatus = 127;
570 ERR << _execError << std::endl;
571 return false;
572 }
573 return true;
574}
575
576void zyppng::GlibSpawnEngine::glibSpawnCallback(void *data)
577{
578 GLibForkData *d = reinterpret_cast<GLibForkData *>(data);
579
580 d->that->resetSignals();
581 bool doChroot = !d->that->_chroot.empty();
582
583 if ( d->that->_switchPgid )
584 setpgid( 0, 0);
585
586 if ( doChroot ) {
587 std::string execError;
588
589 if ( ::chroot( d->that->_chroot.c_str() ) == -1 ) {
590 execError = zypp::str::form( "Can't chroot to '%s' (%s).", d->that->_chroot.c_str(), strerror(errno).c_str() );
591 std::cerr << execError << std::endl;// After fork log on stderr too
592 _exit (128); // No sense in returning! I am forked away!!
593 }
594
595 std::string chdir; //if we are in chroot we need to chdir again
596 if ( d->that->_workingDirectory.empty() ) {
597 chdir = "/";
598 } else {
599 chdir = d->that->_workingDirectory.asString();
600 }
601
602 if ( !chdir.empty() && ::chdir( chdir.data() ) == -1 )
603 {
604 execError = doChroot ? zypp::str::form( "Can't chdir to '%s' inside chroot '%s' (%s).", chdir.data(), d->that->_chroot.c_str(), strerror(errno).c_str() )
605 : zypp::str::form( "Can't chdir to '%s' (%s).", chdir.data(), strerror(errno).c_str() );
606 std::cerr << execError << std::endl; // After fork log on stderr too
607 _exit (128); // No sense in returning! I am forked away!!
608 }
609
610 }
611
612 if ( d->that->_dieWithParent ) {
613 // process dies with us
614 int r = prctl(PR_SET_PDEATHSIG, SIGTERM);
615 if (r == -1) {
616 //ignore if it did not work, worst case the process lives on after the parent dies
617 std::cerr << "Failed to set PR_SET_PDEATHSIG" << std::endl;// After fork log on stderr too
618 }
619
620 // test in case the original parent exited just
621 // before the prctl() call
622 pid_t ppidNow = getppid();
623 if (ppidNow != d->pidParent ) {
624 std::cerr << "PPID changed from "<<d->pidParent<<" to "<< ppidNow << std::endl;// After fork log on stderr too
625 _exit(128);
626 }
627 }
628
629 // map the extra fds the user might have set
630 d->that->mapExtraFds();
631}
632#endif
CleanerThread_p.h
Gettext.h
_
#define _(MSG)
Definition Gettext.h:39
IOTools.h
LogControl.h
DBG
#define DBG
Definition Logger.h:102
ERR
#define ERR
Definition Logger.h:105
zypp::CleanerThread::watchPID
static void watchPID(pid_t pid_r)
Definition CleanerThread.cc:76
zypp::Errno
Convenience errno wrapper.
Definition Errno.h:26
zypp::filesystem::PathInfo
Wrapper class for stat/lstat.
Definition PathInfo.h:226
zypp::filesystem::Pathname
Pathname.
Definition Pathname.h:48
zyppng::AbstractDirectSpawnEngine::~AbstractDirectSpawnEngine
~AbstractDirectSpawnEngine() override
Definition forkspawnengine.cc:35
zyppng::AbstractDirectSpawnEngine::resetSignals
void resetSignals()
Definition forkspawnengine.cc:216
zyppng::AbstractDirectSpawnEngine::isRunning
bool isRunning(bool wait=false) override
Definition forkspawnengine.cc:44
zyppng::AbstractDirectSpawnEngine::waitForExit
bool waitForExit(const std::optional< uint64_t > &timeout={}) override
Definition forkspawnengine.cc:67
zyppng::AbstractDirectSpawnEngine::mapExtraFds
void mapExtraFds(int controlFd=-1)
Definition forkspawnengine.cc:136
zyppng::AbstractSpawnEngine::pid
pid_t pid()
Definition abstractspawnengine.cc:170
zyppng::AbstractSpawnEngine::_chroot
zypp::Pathname _chroot
Path to chroot into.
Definition abstractspawnengine_p.h:106
zyppng::AbstractSpawnEngine::_workingDirectory
zypp::Pathname _workingDirectory
Working directory.
Definition abstractspawnengine_p.h:108
zyppng::AbstractSpawnEngine::_execError
std::string _execError
Remember execution errors like failed fork/exec.
Definition abstractspawnengine_p.h:96
zyppng::AbstractSpawnEngine::_executedCommand
std::string _executedCommand
Store the command we're executing.
Definition abstractspawnengine_p.h:100
zyppng::AbstractSpawnEngine::_exitStatus
int _exitStatus
Definition abstractspawnengine_p.h:94
zyppng::AbstractSpawnEngine::start
virtual bool start(const char *const *argv, int stdin_fd, int stdout_fd, int stderr_fd)=0
zyppng::AbstractSpawnEngine::_dieWithParent
bool _dieWithParent
Should the process die with the parent process.
Definition abstractspawnengine_p.h:89
zyppng::AbstractSpawnEngine::_switchPgid
bool _switchPgid
Definition abstractspawnengine_p.h:91
zyppng::AbstractSpawnEngine::_childExecDetail
std::optional< std::string > _childExecDetail
Error detail to remember if checkStatus sets an _execError.
Definition abstractspawnengine_p.h:98
zyppng::AbstractSpawnEngine::_useDefaultLocale
bool _useDefaultLocale
Definition abstractspawnengine_p.h:87
zyppng::AbstractSpawnEngine::_mapFds
std::vector< int > _mapFds
Additional file descriptors we want to map to the new process.
Definition abstractspawnengine_p.h:110
zyppng::AbstractSpawnEngine::_environment
Environment _environment
Environment variables to set in the new process.
Definition abstractspawnengine_p.h:104
zyppng::AbstractSpawnEngine::_pid
pid_t _pid
Definition abstractspawnengine_p.h:93
zyppng::AbstractSpawnEngine::checkStatus
int checkStatus(int status)
Definition abstractspawnengine.cc:175
zyppng::AbstractSpawnEngine::chroot
zypp::Pathname chroot() const
Definition abstractspawnengine.cc:140
zyppng::AbstractSpawnEngine::_args
std::vector< std::string > _args
The arguments we want to pass to the program.
Definition abstractspawnengine_p.h:102
zyppng::ForkSpawnEngine::_use_pty
bool _use_pty
Set to true, if a pair of ttys is used for communication instead of a pair of pipes.
Definition forkspawnengine_p.h:38
zyppng::ForkSpawnEngine::start
bool start(const char *const *argv, int stdin_fd, int stdout_fd, int stderr_fd) override
Definition forkspawnengine.cc:234
zyppng::ForkSpawnEngine::usePty
bool usePty() const
Definition forkspawnengine.cc:460
zyppng::ForkSpawnEngine::setUsePty
void setUsePty(const bool set=true)
Definition forkspawnengine.cc:465
zyppng::Timer::elapsedSince
static uint64_t elapsedSince(const uint64_t start)
Definition timer.cc:83
zyppng::Timer::now
static uint64_t now()
Definition timer.cc:70
forkspawnengine_p.h
linuxhelpers_p.h
form
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition String.cc:39
ztui::ProgressEnd::error
@ error
Definition Out.h:45
zypp::env
Namespace intended to collect all environment variables we use.
Definition RepoVariables.cc:34
zypp::filesystem::FT_LINK
@ FT_LINK
Definition PathInfo.h:68
zypp::filesystem::dirForEachExt
int dirForEachExt(const Pathname &dir_r, const function< bool(const Pathname &, const DirEntry &)> &fnc_r)
Simiar to.
Definition PathInfo.cc:612
zypp::io::ReadAllResult::Eof
@ Eof
Definition IOTools.h:46
zypp::io::ReadAllResult::Ok
@ Ok
Definition IOTools.h:47
zypp::io::writeAll
bool writeAll(int fd, void *buf, size_t size)
Definition IOTools.cc:55
zypp::io::readAll
ReadAllResult readAll(int fd, void *buf, size_t size)
Definition IOTools.cc:69
zypp::str::strerror
std::string strerror(int errno_r)
Return string describing the error_r code.
Definition String.cc:56
zypp::str::form
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition String.cc:39
zyppng::str
Definition string.h:18
zyppng::str::safe_strtonum
std::optional< T > safe_strtonum(const std::string_view &val)
Definition string.h:23
zyppng::strerror
std::string strerror(int errno_r) ZYPP_API
Return string describing the error_r code.
Definition String.cc:56
zyppng::eintrSafeCall
auto eintrSafeCall(Fun &&function, Args &&... args)
Definition linuxhelpers_p.h:50
zypp::AutoFD
AutoDispose<int> calling close
Definition AutoDispose.h:310
zypp::filesystem::DirEntry
Listentry returned by readdir.
Definition PathInfo.h:517
zypp::filesystem::DirEntry::name
std::string name
Definition PathInfo.h:518
zypp::filesystem::DirEntry::type
FileType type
Definition PathInfo.h:519
zyppng::Pipe::create
static std::optional< Pipe > create(int flags=0)
Definition linuxhelpers.cc:71
PathInfo.h