libzypp 9.41.1

HistoryLog.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <iostream>
00013 #include <fstream>
00014 #include <unistd.h>
00015 
00016 #include "zypp/ZConfig.h"
00017 #include "zypp/base/String.h"
00018 #include "zypp/base/Logger.h"
00019 
00020 #include "zypp/PathInfo.h"
00021 #include "zypp/Date.h"
00022 
00023 #include "zypp/PoolItem.h"
00024 #include "zypp/Package.h"
00025 #include "zypp/RepoInfo.h"
00026 
00027 #include "zypp/HistoryLog.h"
00028 #include "zypp/HistoryLogData.h"
00029 
00030 using std::endl;
00031 using std::string;
00032 
00033 namespace
00034 {
00035   inline string timestamp()
00036   { return zypp::Date::now().form( HISTORY_LOG_DATE_FORMAT ); }
00037 
00038   inline string userAtHostname()
00039   {
00040     static char buf[256];
00041     string result;
00042     char * tmp = ::cuserid(buf);
00043     if (tmp)
00044     {
00045       result = string(tmp);
00046       if (!::gethostname(buf, 255))
00047         result += "@" + string(buf);
00048     }
00049     return result;
00050   }
00051 
00052   static std::string pidAndAppname()
00053   {
00054     static std::string _val;
00055     if ( _val.empty() )
00056     {
00057       pid_t mypid = getpid();
00058       zypp::Pathname p( "/proc/"+zypp::str::numstring(mypid)+"/exe" );
00059       zypp::Pathname myname( zypp::filesystem::readlink( p ) );
00060 
00061       _val += zypp::str::numstring(mypid);
00062       _val += ":";
00063       _val += myname.basename();
00064     }
00065     return _val;
00066   }
00067 }
00068 
00069 namespace zypp
00070 {
00071   namespace
00072   {
00073     const char          _sep = '|';
00074     std::ofstream       _log;
00075     unsigned            _refcnt = 0;
00076     Pathname            _fname;
00077     Pathname            _fnameLastFail;
00078 
00079     inline void openLog()
00080     {
00081       if ( _fname.empty() )
00082         _fname = ZConfig::instance().historyLogFile();
00083 
00084       _log.clear();
00085       _log.open( _fname.asString().c_str(), std::ios::out|std::ios::app );
00086       if( !_log && _fnameLastFail != _fname )
00087       {
00088         ERR << "Could not open logfile '" << _fname << "'" << endl;
00089         _fnameLastFail = _fname;
00090       }
00091     }
00092 
00093     inline void closeLog()
00094     {
00095       _log.clear();
00096       _log.close();
00097     }
00098 
00099     inline void refUp()
00100     {
00101       if ( !_refcnt )
00102         openLog();
00103       ++_refcnt;
00104     }
00105 
00106     inline void refDown()
00107     {
00108       --_refcnt;
00109       if ( !_refcnt )
00110         closeLog();
00111     }
00112   }
00113 
00115   //
00116   //    CLASS NAME : HistoryLog
00117   //
00119 
00120   HistoryLog::HistoryLog( const Pathname & rootdir )
00121   {
00122     setRoot( rootdir );
00123     refUp();
00124   }
00125 
00126   HistoryLog::~HistoryLog()
00127   {
00128     refDown();
00129   }
00130 
00131   void HistoryLog::setRoot( const Pathname & rootdir )
00132   {
00133     if ( ! rootdir.absolute() )
00134       return;
00135 
00136     if ( _refcnt )
00137       closeLog();
00138 
00139     _fname = rootdir / ZConfig::instance().historyLogFile();
00140     filesystem::assert_dir( _fname.dirname() );
00141     MIL << "installation log file " << _fname << endl;
00142 
00143     if ( _refcnt )
00144       openLog();
00145   }
00146 
00147   const Pathname & HistoryLog::fname()
00148   {
00149     if ( _fname.empty() )
00150       _fname = ZConfig::instance().historyLogFile();
00151     return _fname;
00152   }
00153 
00155 
00156   void HistoryLog::comment( const string & comment, bool timestamp )
00157   {
00158     if (comment.empty())
00159       return;
00160 
00161     _log << "# ";
00162     if ( timestamp )
00163       _log << ::timestamp() << " ";
00164 
00165     const char * s = comment.c_str();
00166     const char * c = s;
00167     unsigned size = comment.size();
00168 
00169     // ignore the last newline
00170     if (comment[size-1] == '\n')
00171       --size;
00172 
00173     for ( unsigned i = 0; i < size; ++i, ++c )
00174       if ( *c == '\n' )
00175       {
00176         _log << string( s, c + 1 - s ) << "# ";
00177         s = c + 1;
00178       }
00179 
00180     if ( s < c )
00181       _log << std::string( s, c-s );
00182 
00183     _log << endl;
00184   }
00185 
00187 
00188   void HistoryLog::install( const PoolItem & pi )
00189   {
00190     const Package::constPtr p = asKind<Package>(pi.resolvable());
00191     if (!p)
00192       return;
00193 
00194     _log
00195       << timestamp()                                                    // 1 timestamp
00196       << _sep << HistoryActionID::INSTALL.asString(true)                // 2 action
00197       << _sep << p->name()                                              // 3 name
00198       << _sep << p->edition()                                           // 4 evr
00199       << _sep << p->arch();                                             // 5 arch
00200 
00201     // ApplLow is what the solver selected on behalf of the user.
00202     if (pi.status().isByUser() || pi.status().isByApplLow() )
00203       _log << _sep << userAtHostname();                                 // 6 reqested by
00204     else if (pi.status().isByApplHigh())
00205       _log << _sep << pidAndAppname();
00206     else
00207       _log << _sep;
00208 
00209     _log
00210       << _sep << p->repoInfo().alias()                                  // 7 repo alias
00211       << _sep << p->checksum().checksum()                               // 8 checksum
00212       << _sep << str::escape(ZConfig::instance().userData(), _sep)      // 9 userdata
00213       << endl;
00214   }
00215 
00216 
00217   void HistoryLog::remove( const PoolItem & pi )
00218   {
00219     const Package::constPtr p = asKind<Package>(pi.resolvable());
00220     if (!p)
00221       return;
00222 
00223     _log
00224       << timestamp()                                                    // 1 timestamp
00225       << _sep << HistoryActionID::REMOVE.asString(true)                 // 2 action
00226       << _sep << p->name()                                              // 3 name
00227       << _sep << p->edition()                                           // 4 evr
00228       << _sep << p->arch();                                             // 5 arch
00229 
00230     // ApplLow is what the solver selected on behalf of the user.
00231     if ( pi.status().isByUser() || pi.status().isByApplLow() )
00232       _log << _sep << userAtHostname();                                 // 6 reqested by
00233     else if (pi.status().isByApplHigh())
00234       _log << _sep << pidAndAppname();
00235     else
00236       _log << _sep;
00237 
00238     _log
00239       << _sep << str::escape(ZConfig::instance().userData(), _sep)      // 7 userdata
00240       << endl;
00241   }
00242 
00244 
00245   void HistoryLog::addRepository(const RepoInfo & repo)
00246   {
00247     _log
00248       << timestamp()                                                    // 1 timestamp
00249       << _sep << HistoryActionID::REPO_ADD.asString(true)               // 2 action
00250       << _sep << str::escape(repo.alias(), _sep)                        // 3 alias
00251       << _sep << *repo.baseUrlsBegin()                                  // 4 primary URL
00252       << _sep << str::escape(ZConfig::instance().userData(), _sep)      // 5 userdata
00253       << endl;
00254   }
00255 
00256 
00257   void HistoryLog::removeRepository(const RepoInfo & repo)
00258   {
00259     _log
00260       << timestamp()                                                    // 1 timestamp
00261       << _sep << HistoryActionID::REPO_REMOVE.asString(true)            // 2 action
00262       << _sep << str::escape(repo.alias(), _sep)                        // 3 alias
00263       << _sep << str::escape(ZConfig::instance().userData(), _sep)      // 4 userdata
00264       << endl;
00265   }
00266 
00267 
00268   void HistoryLog::modifyRepository(
00269       const RepoInfo & oldrepo, const RepoInfo & newrepo)
00270   {
00271     if (oldrepo.alias() != newrepo.alias())
00272     {
00273       _log
00274         << timestamp()                                                  // 1 timestamp
00275         << _sep << HistoryActionID::REPO_CHANGE_ALIAS.asString(true)    // 2 action
00276         << _sep << str::escape(oldrepo.alias(), _sep)                   // 3 old alias
00277         << _sep << str::escape(newrepo.alias(), _sep)                   // 4 new alias
00278         << _sep << str::escape(ZConfig::instance().userData(), _sep)    // 5 userdata
00279         << endl;
00280     }
00281     if (*oldrepo.baseUrlsBegin() != *newrepo.baseUrlsBegin())
00282     {
00283       _log
00284         << timestamp()                                                  // 1 timestamp
00285         << _sep << HistoryActionID::REPO_CHANGE_URL.asString(true)      // 2 action
00286         << _sep << str::escape(oldrepo.alias(), _sep)                   // 3 old url
00287         << _sep << *newrepo.baseUrlsBegin()                             // 4 new url
00288         << _sep << str::escape(ZConfig::instance().userData(), _sep)    // 5 userdata
00289         << endl;
00290     }
00291   }
00292 
00294 
00295 } // namespace zypp