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 
00078     inline void openLog()
00079     {
00080       if ( _fname.empty() )
00081         _fname = ZConfig::instance().historyLogFile();
00082 
00083       _log.clear();
00084       _log.open( _fname.asString().c_str(), std::ios::out|std::ios::app );
00085       if( !_log )
00086         ERR << "Could not open logfile '" << _fname << "'" << endl;
00087     }
00088 
00089     inline void closeLog()
00090     {
00091       _log.clear();
00092       _log.close();
00093     }
00094 
00095     inline void refUp()
00096     {
00097       if ( !_refcnt )
00098         openLog();
00099       ++_refcnt;
00100     }
00101 
00102     inline void refDown()
00103     {
00104       --_refcnt;
00105       if ( !_refcnt )
00106         closeLog();
00107     }
00108   }
00109 
00111   //
00112   //    CLASS NAME : HistoryLog
00113   //
00115 
00116   HistoryLog::HistoryLog( const Pathname & rootdir )
00117   {
00118     setRoot( rootdir );
00119     refUp();
00120   }
00121 
00122   HistoryLog::~HistoryLog()
00123   {
00124     refDown();
00125   }
00126 
00127   void HistoryLog::setRoot( const Pathname & rootdir )
00128   {
00129     if ( ! rootdir.absolute() )
00130       return;
00131 
00132     if ( _refcnt )
00133       closeLog();
00134 
00135     _fname = rootdir / ZConfig::instance().historyLogFile();
00136     filesystem::assert_dir( _fname.dirname() );
00137     MIL << "installation log file " << _fname << endl;
00138 
00139     if ( _refcnt )
00140       openLog();
00141   }
00142 
00143   const Pathname & HistoryLog::fname()
00144   {
00145     if ( _fname.empty() )
00146       _fname = ZConfig::instance().historyLogFile();
00147     return _fname;
00148   }
00149 
00151 
00152   void HistoryLog::comment( const string & comment, bool timestamp )
00153   {
00154     if (comment.empty())
00155       return;
00156 
00157     _log << "# ";
00158     if ( timestamp )
00159       _log << ::timestamp() << " ";
00160 
00161     const char * s = comment.c_str();
00162     const char * c = s;
00163     unsigned size = comment.size();
00164 
00165     // ignore the last newline
00166     if (comment[size-1] == '\n')
00167       --size;
00168 
00169     for ( unsigned i = 0; i < size; ++i, ++c )
00170       if ( *c == '\n' )
00171       {
00172         _log << string( s, c + 1 - s ) << "# ";
00173         s = c + 1;
00174       }
00175 
00176     if ( s < c )
00177       _log << std::string( s, c-s );
00178 
00179     _log << endl;
00180   }
00181 
00183 
00184   void HistoryLog::install( const PoolItem & pi )
00185   {
00186     const Package::constPtr p = asKind<Package>(pi.resolvable());
00187     if (!p)
00188       return;
00189 
00190     _log
00191       << timestamp()                                   // 1 timestamp
00192       << _sep << HistoryActionID::INSTALL.asString(true) // 2 action
00193       << _sep << p->name()                             // 3 name
00194       << _sep << p->edition()                          // 4 evr
00195       << _sep << p->arch();                            // 5 arch
00196 
00197     // ApplLow is what the solver selected on behalf of the user.
00198     if (pi.status().isByUser() || pi.status().isByApplLow() )
00199       _log << _sep << userAtHostname();                // 6 reqested by
00200     else if (pi.status().isByApplHigh())
00201       _log << _sep << pidAndAppname();
00202     else
00203       _log << _sep;
00204 
00205     _log
00206       << _sep << p->repoInfo().alias()                 // 7 repo alias
00207       << _sep << p->checksum().checksum();             // 8 checksum
00208 
00209     _log << endl;
00210 
00211     //_log << pi << endl;
00212   }
00213 
00214 
00215   void HistoryLog::remove( const PoolItem & pi )
00216   {
00217     const Package::constPtr p = asKind<Package>(pi.resolvable());
00218     if (!p)
00219       return;
00220 
00221     _log
00222       << timestamp()                                   // 1 timestamp
00223       << _sep << HistoryActionID::REMOVE.asString(true) // 2 action
00224       << _sep << p->name()                             // 3 name
00225       << _sep << p->edition()                          // 4 evr
00226       << _sep << p->arch();                            // 5 arch
00227 
00228     // ApplLow is what the solver selected on behalf of the user.
00229     if ( pi.status().isByUser() || pi.status().isByApplLow() )
00230       _log << _sep << userAtHostname();                // 6 reqested by
00231     else if (pi.status().isByApplHigh())
00232       _log << _sep << pidAndAppname();
00233     else
00234       _log << _sep;
00235 
00236     // we don't have checksum in rpm db
00237     //  << _sep << p->checksum().checksum();           // x checksum
00238 
00239     _log << endl;
00240 
00241     //_log << pi << endl;
00242   }
00243 
00245 
00246   void HistoryLog::addRepository(const RepoInfo & repo)
00247   {
00248     _log
00249       << timestamp()                                   // 1 timestamp
00250       << _sep << HistoryActionID::REPO_ADD.asString(true) // 2 action
00251       << _sep << str::escape(repo.alias(), _sep)       // 3 alias
00252       // what about the rest of the URLs??
00253       << _sep << *repo.baseUrlsBegin()                 // 4 primary URL
00254       << endl;
00255   }
00256 
00257 
00258   void HistoryLog::removeRepository(const RepoInfo & repo)
00259   {
00260     _log
00261       << timestamp()                                   // 1 timestamp
00262       << _sep << HistoryActionID::REPO_REMOVE.asString(true) // 2 action
00263       << _sep << str::escape(repo.alias(), _sep)       // 3 alias
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         << endl;
00279     }
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         << endl;
00289     }
00290   }
00291 
00293 
00294 } // namespace zypp

doxygen