libzypp  17.31.31
IOTools.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
13 #include <errno.h>
14 #include <fcntl.h>
15 #include <iostream>
16 #include <glib.h>
17 
18 #include <zypp-core/AutoDispose.h>
19 #include <zypp-core/base/IOTools.h>
20 #include <zypp-core/base/LogTools.h>
21 #include <zypp-core/zyppng/base/private/linuxhelpers_p.h>
22 
23 namespace zypp::io {
24 
25  BlockingMode setFILEBlocking (FILE * file, bool mode )
26  {
27  if ( !file ) return BlockingMode::FailedToSetMode;
28  return setFDBlocking( ::fileno( file ), mode );
29  }
30 
31  BlockingMode setFDBlocking(int fd, bool mode)
32  {
33  if ( fd == -1 )
34  { ERR << strerror( errno ) << std::endl; return BlockingMode::FailedToSetMode; }
35 
36  int flags = ::fcntl( fd, F_GETFL );
37 
38  if ( flags == -1 )
39  { ERR << strerror( errno ) << std::endl; return BlockingMode::FailedToSetMode; }
40 
41  BlockingMode oldMode = ( flags & O_NONBLOCK ) == O_NONBLOCK ? BlockingMode::WasNonBlocking : BlockingMode::WasBlocking;
42  if ( !mode )
43  flags = flags | O_NONBLOCK;
44  else if ( flags & O_NONBLOCK )
45  flags = flags ^ O_NONBLOCK;
46 
47  flags = ::fcntl( fd,F_SETFL,flags );
48 
49  if ( flags == -1 )
50  { ERR << strerror(errno) << std::endl; return BlockingMode::FailedToSetMode; }
51 
52  return oldMode;
53  }
54 
55  bool writeAll(int fd, void *buf, size_t size)
56  {
57  char *tmpBuf = ( char *) buf;
58 
59  size_t written = 0;
60  while ( written < size ) {
61  const auto res = zyppng::eintrSafeCall( ::write, fd, tmpBuf+written, size-written );
62  if ( res < 0 ) // error
63  return false;
64  written += res;
65  }
66  return true;
67  }
68 
69  ReadAllResult readAll (int fd, void *buf, size_t size )
70  {
71  char *tmpBuf = (char *)buf;
72  size_t read = 0;
73  while ( read != size ) {
74  const auto r = zyppng::eintrSafeCall( ::read, fd, tmpBuf+read, size - read );
75  if ( r == 0 )
76  return ReadAllResult::Eof;
77  if ( r < 0 )
78  return ReadAllResult::Error;
79 
80  read += r;
81  }
82  return ReadAllResult::Ok;
83  }
84 
85  std::pair<ReceiveUpToResult, std::string> receiveUpto(FILE *file, char c, timeout_type timeout, bool failOnUnblockError )
86  {
87  FILE * inputfile = file;
88  if ( !file )
89  return std::make_pair( ReceiveUpToResult::Error, std::string() );
90 
91  int inputfileFd = ::fileno( inputfile );
92 
93  size_t linebuffer_size = 0;
94  zypp::AutoFREE<char> linebuf;
95 
96  const auto prevMode = setFILEBlocking( file, false );
97  if ( prevMode == BlockingMode::FailedToSetMode && failOnUnblockError )
98  return std::make_pair( ReceiveUpToResult::Error, std::string() );
99 
100  // reset the blocking mode when we are done
101  zypp::OnScopeExit resetMode([ prevMode, fd = file ]( ){
102  if ( prevMode == BlockingMode::WasBlocking )
103  setFILEBlocking( fd, true );
104  });
105 
106  bool haveTimeout = (timeout != no_timeout);
107  int remainingTimeout = static_cast<int>( timeout );
108  zypp::AutoDispose<GTimer *> timer( nullptr );
109  if ( haveTimeout )
110  timer = zypp::AutoDispose<GTimer *>( g_timer_new(), &g_free );
111 
112  std::string line;
113  do
114  {
115  /* Watch inputFile to see when it has input. */
116 
117  GPollFD fd;
118  fd.fd = inputfileFd;
119  fd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
120  fd.revents = 0;
121 
122  if ( timer )
123  g_timer_start( timer );
124 
125  clearerr( inputfile );
126 
127  int retval = zyppng::eintrSafeCall( g_poll, &fd, 1, remainingTimeout );
128  if ( retval == -1 )
129  {
130  ERR << "select error: " << zyppng::strerr_cxx() << std::endl;
131  return std::make_pair( ReceiveUpToResult::Error, std::string() );
132  }
133  else if ( retval )
134  {
135  // Data is available now.
136  ssize_t nread = zyppng::eintrSafeCallEx( ::getdelim, [&](){ clearerr( inputfile ); }, &linebuf.value(), &linebuffer_size, c, inputfile );
137  if ( nread == -1 ) {
138  if ( ::feof( inputfile ) ) {
139  return std::make_pair( ReceiveUpToResult::EndOfFile, std::move(line) );
140  }
141  if ( errno != EAGAIN && ( ::ferror( inputfile ) || errno != 0 ) ) {
142  if ( errno ) ERR << "getdelim error: " << zyppng::strerr_cxx() << std::endl;
143  else ERR << "Unknown getdelim error." << std::endl;
144  return std::make_pair( ReceiveUpToResult::Error, std::string() );
145  }
146  }
147  else
148  {
149  if ( nread > 0 )
150  line += std::string( linebuf, nread );
151 
152  if ( ! ::ferror( inputfile ) || ::feof( inputfile ) ) {
153  return std::make_pair( ReceiveUpToResult::Success, std::move(line) ); // complete line
154  }
155  }
156  }
157 
158  // we timed out, or were interrupted for some reason
159  // check if we can wait more
160  if ( timer ) {
161  remainingTimeout -= g_timer_elapsed( timer, nullptr ) * 1000;
162  if ( remainingTimeout <= 0 )
163  return std::make_pair( ReceiveUpToResult::Timeout, std::move(line) );
164  }
165  } while ( true );
166  }
167 
169  { }
170 
171  std::vector<char> peek_data_fd( FILE *fd, off_t offset, size_t count )
172  {
173  if ( !fd )
174  return {};
175 
176  fflush( fd );
177 
178  std::vector<char> data( count + 1 , '\0' );
179 
180  ssize_t l = -1;
181  while ((l = pread( fileno( fd ), data.data(), count, offset ) ) == -1 && errno == EINTR)
182  ;
183  if (l == -1)
184  return {};
185 
186  return data;
187  }
188 
189 }
ReadAllResult
Definition: IOTools.h:44
struct _GPollFD GPollFD
Definition: ZYppImpl.h:26
std::map< std::string, std::string > read(const Pathname &_path)
Read sysconfig file path_r and return (key,valye) pairs.
Definition: sysconfig.cc:34
BlockingMode setFILEBlocking(FILE *file, bool mode)
Enables or disabled non blocking mode on a file descriptor.
Definition: IOTools.cc:25
#define ERR
Definition: Logger.h:98
bool write(const Pathname &path_r, const std::string &key_r, const std::string &val_r, const std::string &newcomment_r)
Add or change a value in sysconfig file path_r.
Definition: sysconfig.cc:80
size_t timeout_type
Definition: IOTools.h:77
Failed to block or unblock the fd.
std::vector< char > peek_data_fd(FILE *fd, off_t offset, size_t count)
Definition: IOTools.cc:171
BlockingMode
Definition: IOTools.h:22
bool writeAll(int fd, void *buf, size_t size)
Definition: IOTools.cc:55
std::pair< ReceiveUpToResult, std::string > receiveUpto(FILE *file, char c, timeout_type timeout, bool failOnUnblockError)
Definition: IOTools.cc:85
reference value() const
Reference to the Tp object.
Definition: AutoDispose.h:147
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition: AutoDispose.h:93
static constexpr timeout_type no_timeout
Definition: IOTools.h:78
FD was blocking before.
FD was non blocking before.
std::string strerror(int errno_r)
Return string describing the error_r code.
Definition: String.cc:53
virtual ~TimeoutException() noexcept override
Dtor.
Definition: IOTools.cc:168
ReadAllResult readAll(int fd, void *buf, size_t size)
Definition: IOTools.cc:69
BlockingMode setFDBlocking(int fd, bool mode)
Definition: IOTools.cc:31