Imported Upstream version 17.25.4
[platform/upstream/libzypp.git] / zypp / target / rpm / RpmDb.cc
index 1a231fd..c7bb912 100644 (file)
@@ -51,6 +51,7 @@ extern "C"
 #include <zypp/KeyRing.h>
 #include <zypp/ZYppFactory.h>
 #include <zypp/ZConfig.h>
+#include <zypp/base/IOTools.h>
 
 using std::endl;
 using namespace zypp::filesystem;
@@ -270,44 +271,39 @@ void RpmDb::initDatabase( Pathname root_r, bool doRebuild_r )
   if ( root_r.empty() )
     root_r = "/";
 
-  // NOTE: Former argument, but now locked to "/var/lib/rpm".
-  // A custom dbPath is not actually needed and would only work
-  // reliably if libsolv also supports it. By now no further
-  // cleanup in the code.
-  const Pathname & dbPath_r { librpmDb::defaultDbPath() };
+  const Pathname & dbPath_r { librpmDb::suggestedDbPath( root_r ) };   // also asserts root_r is absolute
 
-  if ( ! root_r.absolute() )
+  // The rpmdb compat symlink.
+  // Required at least until rpmdb2solv takes a dppath argument.
+  // Otherwise it creates a db at "/var/lib/rpm".
+  if ( dbPath_r != "/var/lib/rpm" && ! PathInfo( root_r/"/var/lib/rpm" ).isExist() )
   {
-    ERR << "Illegal root or dbPath: " << stringPath( root_r, dbPath_r ) << endl;
-    ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
+    WAR << "Inject missing /var/lib/rpm compat symlink to " << dbPath_r << endl;
+    filesystem::assert_dir( root_r/"/var/lib" );
+    filesystem::symlink( "../../"/dbPath_r, root_r/"/var/lib/rpm" );
   }
 
-  if ( ! PathInfo( root_r/"/var/lib/rpm" ).isExist()
-    && PathInfo( root_r/"/usr/lib/sysimage/rpm" ).isDir() )
-  {
-    WAR << "Rpm package was deleted? Injecting missing rpmdb compat symlink." << endl;
-    filesystem::symlink( "../../usr/lib/sysimage/rpm", root_r/"/var/lib/rpm" );
-  }
-
-  MIL << "Calling initDatabase: " << stringPath( root_r, dbPath_r )
-      << ( doRebuild_r ? " (rebuilddb)" : "" )
-      << ( quickinit ? " (quickinit)" : "" ) << endl;
-
   ///////////////////////////////////////////////////////////////////
   // Check whether already initialized
   ///////////////////////////////////////////////////////////////////
   if ( initialized() )
   {
-    if ( root_r == _root && dbPath_r == _dbPath )
-    {
+    // Just check for a changing root because the librpmDb::suggestedDbPath
+    // may indeed change: rpm %post moving the db from /var/lib/rpm
+    // to /usr/lib/sysimage/rpm. We continue to use the old dbpath
+    // (via the compat symlink) until a re-init.
+    if ( root_r == _root ) {
+      MIL << "Calling initDatabase: already initialized at " << stringPath( _root, _dbPath ) << endl;
       return;
     }
     else
-    {
       ZYPP_THROW(RpmDbAlreadyOpenException(_root, _dbPath, root_r, dbPath_r));
-    }
   }
 
+  MIL << "Calling initDatabase: " << stringPath( root_r, dbPath_r )
+      << ( doRebuild_r ? " (rebuilddb)" : "" )
+      << ( quickinit ? " (quickinit)" : "" ) << endl;
+
   ///////////////////////////////////////////////////////////////////
   // init database
   ///////////////////////////////////////////////////////////////////
@@ -1221,6 +1217,8 @@ namespace
       { lineres = RpmDb::CHK_NOTFOUND; }
       else if ( line.find( ": NOTRUSTED" ) != std::string::npos )
       { lineres = RpmDb::CHK_NOTTRUSTED; }
+      else if ( line.find( ": NOTFOUND" ) != std::string::npos )
+      { continue; } // just collect details for signatures found (#229)
 
       ++count[lineres];
       detail_r.push_back( RpmDb::CheckPackageDetail::value_type( lineres, std::move(line) ) );
@@ -1400,65 +1398,39 @@ bool RpmDb::systemReadLine( std::string & line )
   {
     process->setBlocking( false );
     FILE * inputfile = process->inputFile();
-    int    inputfileFd = ::fileno( inputfile );
-    do
-    {
-      /* Watch inputFile to see when it has input. */
-      fd_set rfds;
-      FD_ZERO( &rfds );
-      FD_SET( inputfileFd, &rfds );
-
-      /* Wait up to 5 seconds. */
-      struct timeval tv;
-      tv.tv_sec = 5;
-      tv.tv_usec = 0;
+    do {
+      // Check every 5 seconds if the process is still running to prevent against
+      // daemons launched in rpm %post that do not close their filedescriptors,
+      // causing us to block for infinity. (bnc#174548)
+      const auto &readResult = io::receiveUpto( inputfile, '\n', 5 * 1000, false );
+      switch ( readResult.first ) {
+        case io::ReceiveUpToResult::Timeout: {
+          if ( !process->running() )
+            return false;
+
+          // we might have received a partial line, lets not forget about it
+          line += readResult.second;
+        }
+        case io::ReceiveUpToResult::Error:
+        case io::ReceiveUpToResult::EndOfFile: {
+          line += readResult.second;
+          if ( line.size() && line.back() == '\n')
+            line.pop_back();
+          return line.size(); // in case of pending output
+        }
+        case io::ReceiveUpToResult::Success: {
+          line += readResult.second;
 
-      int retval = select( inputfileFd+1, &rfds, NULL, NULL, &tv );
+          if ( line.size() && line.back() == '\n')
+            line.pop_back();
 
-      if ( retval == -1 )
-      {
-       ERR << "select error: " << strerror(errno) << endl;
-       if ( errno != EINTR )
-         return false;
-      }
-      else if ( retval )
-      {
-       // Data is available now.
-       static size_t linebuffer_size = 0;      // static because getline allocs
-       static char * linebuffer = 0;           // and reallocs if buffer is too small
-       ssize_t nread = getline( &linebuffer, &linebuffer_size, inputfile );
-       if ( nread == -1 )
-       {
-         if ( ::feof( inputfile ) )
-           return line.size(); // in case of pending output
-       }
-       else
-       {
-         if ( nread > 0 )
-         {
-           if ( linebuffer[nread-1] == '\n' )
-             --nread;
-           line += std::string( linebuffer, nread );
-         }
-
-         if ( ! ::ferror( inputfile ) || ::feof( inputfile ) )
-         {
-           if ( env::ZYPP_RPM_DEBUG() )
-             L_DBG("RPM_DEBUG") << line << endl;
-           return true; // complete line
-         }
-       }
-       clearerr( inputfile );
-      }
-      else
-      {
-       // No data within time.
-       if ( ! process->running() )
-         return false;
+          if ( env::ZYPP_RPM_DEBUG() )
+            L_DBG("RPM_DEBUG") << line << endl;
+          return true; // complete line
+        }
       }
-    } while ( true );
+    } while( true );
   }
-
   return false;
 }