HistoryLog.cc
Go to the documentation of this file.00001
00002
00003
00004
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
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
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()
00196 << _sep << HistoryActionID::INSTALL.asString(true)
00197 << _sep << p->name()
00198 << _sep << p->edition()
00199 << _sep << p->arch();
00200
00201
00202 if (pi.status().isByUser() || pi.status().isByApplLow() )
00203 _log << _sep << userAtHostname();
00204 else if (pi.status().isByApplHigh())
00205 _log << _sep << pidAndAppname();
00206 else
00207 _log << _sep;
00208
00209 _log
00210 << _sep << p->repoInfo().alias()
00211 << _sep << p->checksum().checksum();
00212
00213 _log << endl;
00214
00215
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()
00227 << _sep << HistoryActionID::REMOVE.asString(true)
00228 << _sep << p->name()
00229 << _sep << p->edition()
00230 << _sep << p->arch();
00231
00232
00233 if ( pi.status().isByUser() || pi.status().isByApplLow() )
00234 _log << _sep << userAtHostname();
00235 else if (pi.status().isByApplHigh())
00236 _log << _sep << pidAndAppname();
00237 else
00238 _log << _sep;
00239
00240
00241
00242
00243 _log << endl;
00244
00245
00246 }
00247
00249
00250 void HistoryLog::addRepository(const RepoInfo & repo)
00251 {
00252 _log
00253 << timestamp()
00254 << _sep << HistoryActionID::REPO_ADD.asString(true)
00255 << _sep << str::escape(repo.alias(), _sep)
00256
00257 << _sep << *repo.baseUrlsBegin()
00258 << endl;
00259 }
00260
00261
00262 void HistoryLog::removeRepository(const RepoInfo & repo)
00263 {
00264 _log
00265 << timestamp()
00266 << _sep << HistoryActionID::REPO_REMOVE.asString(true)
00267 << _sep << str::escape(repo.alias(), _sep)
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()
00279 << _sep << HistoryActionID::REPO_CHANGE_ALIAS.asString(true)
00280 << _sep << str::escape(oldrepo.alias(), _sep)
00281 << _sep << str::escape(newrepo.alias(), _sep)
00282 << endl;
00283 }
00284
00285 if (*oldrepo.baseUrlsBegin() != *newrepo.baseUrlsBegin())
00286 {
00287 _log
00288 << timestamp()
00289 << _sep << HistoryActionID::REPO_CHANGE_URL.asString(true)
00290 << _sep << str::escape(oldrepo.alias(), _sep)
00291 << _sep << *newrepo.baseUrlsBegin()
00292 << endl;
00293 }
00294 }
00295
00297
00298 }