libzypp  10.5.0
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 
00213     _log << endl;
00214 
00215     //_log << pi << endl;
00216   }
00217 
00218 
00219   void HistoryLog::remove( const PoolItem & pi )
00220   {
00221     const Package::constPtr p = asKind<Package>(pi.resolvable());
00222     if (!p)
00223       return;
00224 
00225     _log
00226       << timestamp()                                   // 1 timestamp
00227       << _sep << HistoryActionID::REMOVE.asString(true) // 2 action
00228       << _sep << p->name()                             // 3 name
00229       << _sep << p->edition()                          // 4 evr
00230       << _sep << p->arch();                            // 5 arch
00231 
00232     // ApplLow is what the solver selected on behalf of the user.
00233     if ( pi.status().isByUser() || pi.status().isByApplLow() )
00234       _log << _sep << userAtHostname();                // 6 reqested by
00235     else if (pi.status().isByApplHigh())
00236       _log << _sep << pidAndAppname();
00237     else
00238       _log << _sep;
00239 
00240     // we don't have checksum in rpm db
00241     //  << _sep << p->checksum().checksum();           // x checksum
00242 
00243     _log << endl;
00244 
00245     //_log << pi << endl;
00246   }
00247 
00249 
00250   void HistoryLog::addRepository(const RepoInfo & repo)
00251   {
00252     _log
00253       << timestamp()                                   // 1 timestamp
00254       << _sep << HistoryActionID::REPO_ADD.asString(true) // 2 action
00255       << _sep << str::escape(repo.alias(), _sep)       // 3 alias
00256       // what about the rest of the URLs??
00257       << _sep << *repo.baseUrlsBegin()                 // 4 primary URL
00258       << endl;
00259   }
00260 
00261 
00262   void HistoryLog::removeRepository(const RepoInfo & repo)
00263   {
00264     _log
00265       << timestamp()                                   // 1 timestamp
00266       << _sep << HistoryActionID::REPO_REMOVE.asString(true) // 2 action
00267       << _sep << str::escape(repo.alias(), _sep)       // 3 alias
00268       << endl;
00269   }
00270 
00271 
00272   void HistoryLog::modifyRepository(
00273       const RepoInfo & oldrepo, const RepoInfo & newrepo)
00274   {
00275     if (oldrepo.alias() != newrepo.alias())
00276     {
00277       _log
00278         << timestamp()                                    // 1 timestamp
00279         << _sep << HistoryActionID::REPO_CHANGE_ALIAS.asString(true) // 2 action
00280         << _sep << str::escape(oldrepo.alias(), _sep)     // 3 old alias
00281         << _sep << str::escape(newrepo.alias(), _sep)     // 4 new alias
00282         << endl;
00283     }
00284 
00285     if (*oldrepo.baseUrlsBegin() != *newrepo.baseUrlsBegin())
00286     {
00287       _log
00288         << timestamp()                                             //1 timestamp
00289         << _sep << HistoryActionID::REPO_CHANGE_URL.asString(true) // 2 action
00290         << _sep << str::escape(oldrepo.alias(), _sep)              // 3 old url
00291         << _sep << *newrepo.baseUrlsBegin()                        // 4 new url
00292         << endl;
00293     }
00294   }
00295 
00297 
00298 } // namespace zypp