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
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
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
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()
00192 << _sep << HistoryActionID::INSTALL.asString(true)
00193 << _sep << p->name()
00194 << _sep << p->edition()
00195 << _sep << p->arch();
00196
00197
00198 if (pi.status().isByUser() || pi.status().isByApplLow() )
00199 _log << _sep << userAtHostname();
00200 else if (pi.status().isByApplHigh())
00201 _log << _sep << pidAndAppname();
00202 else
00203 _log << _sep;
00204
00205 _log
00206 << _sep << p->repoInfo().alias()
00207 << _sep << p->checksum().checksum();
00208
00209 _log << endl;
00210
00211
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()
00223 << _sep << HistoryActionID::REMOVE.asString(true)
00224 << _sep << p->name()
00225 << _sep << p->edition()
00226 << _sep << p->arch();
00227
00228
00229 if ( pi.status().isByUser() || pi.status().isByApplLow() )
00230 _log << _sep << userAtHostname();
00231 else if (pi.status().isByApplHigh())
00232 _log << _sep << pidAndAppname();
00233 else
00234 _log << _sep;
00235
00236
00237
00238
00239 _log << endl;
00240
00241
00242 }
00243
00245
00246 void HistoryLog::addRepository(const RepoInfo & repo)
00247 {
00248 _log
00249 << timestamp()
00250 << _sep << HistoryActionID::REPO_ADD.asString(true)
00251 << _sep << str::escape(repo.alias(), _sep)
00252
00253 << _sep << *repo.baseUrlsBegin()
00254 << endl;
00255 }
00256
00257
00258 void HistoryLog::removeRepository(const RepoInfo & repo)
00259 {
00260 _log
00261 << timestamp()
00262 << _sep << HistoryActionID::REPO_REMOVE.asString(true)
00263 << _sep << str::escape(repo.alias(), _sep)
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()
00275 << _sep << HistoryActionID::REPO_CHANGE_ALIAS.asString(true)
00276 << _sep << str::escape(oldrepo.alias(), _sep)
00277 << _sep << str::escape(newrepo.alias(), _sep)
00278 << endl;
00279 }
00280
00281 if (*oldrepo.baseUrlsBegin() != *newrepo.baseUrlsBegin())
00282 {
00283 _log
00284 << timestamp()
00285 << _sep << HistoryActionID::REPO_CHANGE_URL.asString(true)
00286 << _sep << str::escape(oldrepo.alias(), _sep)
00287 << _sep << *newrepo.baseUrlsBegin()
00288 << endl;
00289 }
00290 }
00291
00293
00294 }