1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/base/IOTools.cc
18 #include <zypp/AutoDispose.h>
19 #include <zypp/base/IOTools.h>
20 #include <zypp/base/LogTools.h>
24 BlockingMode setFILEBlocking (FILE * file, bool mode )
26 if ( !file ) return BlockingMode::FailedToSetMode;
28 int fd = ::fileno( file );
31 { ERR << strerror( errno ) << std::endl; return BlockingMode::FailedToSetMode; }
33 int flags = ::fcntl( fd, F_GETFL );
36 { ERR << strerror( errno ) << std::endl; return BlockingMode::FailedToSetMode; }
38 BlockingMode oldMode = ( flags & O_NONBLOCK ) == O_NONBLOCK ? BlockingMode::WasNonBlocking : BlockingMode::WasBlocking;
40 flags = flags | O_NONBLOCK;
41 else if ( flags & O_NONBLOCK )
42 flags = flags ^ O_NONBLOCK;
44 flags = ::fcntl( fd,F_SETFL,flags );
47 { ERR << strerror(errno) << std::endl; return BlockingMode::FailedToSetMode; }
52 std::pair<ReceiveUpToResult, std::string> receiveUpto(FILE *file, char c, timeout_type timeout, bool failOnUnblockError )
54 FILE * inputfile = file;
56 return std::make_pair( ReceiveUpToResult::Error, std::string() );
58 int inputfileFd = ::fileno( inputfile );
60 size_t linebuffer_size = 0;
61 zypp::AutoFREE<char> linebuf;
63 const auto prevMode = setFILEBlocking( file, false );
64 if ( prevMode == BlockingMode::FailedToSetMode && failOnUnblockError )
65 return std::make_pair( ReceiveUpToResult::Error, std::string() );
67 // reset the blocking mode when we are done
68 zypp::OnScopeExit resetMode([ prevMode, fd = file ]( ){
69 if ( prevMode == BlockingMode::WasBlocking )
70 setFILEBlocking( fd, true );
73 bool haveTimeout = (timeout != no_timeout);
74 int remainingTimeout = static_cast<int>( timeout );
75 zypp::AutoDispose<GTimer *> timer( nullptr );
77 timer = zypp::AutoDispose<GTimer *>( g_timer_new(), &g_free );
82 /* Watch inputFile to see when it has input. */
86 fd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
90 g_timer_start( timer );
92 clearerr( inputfile );
94 int retval = g_poll( &fd, 1, timeout );
97 if ( errno != EINTR ) {
98 ERR << "select error: " << strerror(errno) << std::endl;
99 return std::make_pair( ReceiveUpToResult::Error, std::string() );
104 // Data is available now.
105 ssize_t nread = getdelim( &linebuf.value(), &linebuffer_size, c, inputfile );
107 if ( ::feof( inputfile ) )
108 return std::make_pair( ReceiveUpToResult::EndOfFile, line );
113 line += std::string( linebuf, nread );
115 if ( ! ::ferror( inputfile ) || ::feof( inputfile ) ) {
116 return std::make_pair( ReceiveUpToResult::Success, line ); // complete line
121 // we timed out, or were interrupted for some reason
122 // check if we can wait more
124 remainingTimeout -= g_timer_elapsed( timer, nullptr );
125 if ( remainingTimeout <= 0 )
126 return std::make_pair( ReceiveUpToResult::Timeout, line );
131 TimeoutException::~TimeoutException() noexcept