libzypp  13.10.6
HistoryLog.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
12 #include <iostream>
13 #include <fstream>
14 #include <unistd.h>
15 
16 #include "zypp/ZConfig.h"
17 #include "zypp/base/String.h"
18 #include "zypp/base/Logger.h"
19 
20 #include "zypp/PathInfo.h"
21 #include "zypp/Date.h"
22 
23 #include "zypp/PoolItem.h"
24 #include "zypp/Package.h"
25 #include "zypp/RepoInfo.h"
26 
27 #include "zypp/HistoryLog.h"
28 #include "zypp/HistoryLogData.h"
29 
30 using std::endl;
31 using std::string;
32 
33 namespace
34 {
35  inline string timestamp()
37 
38  inline string userAtHostname()
39  {
40  static char buf[256];
41  string result;
42  char * tmp = ::cuserid(buf);
43  if (tmp)
44  {
45  result = string(tmp);
46  if (!::gethostname(buf, 255))
47  result += "@" + string(buf);
48  }
49  return result;
50  }
51 
52  static std::string pidAndAppname()
53  {
54  static std::string _val;
55  if ( _val.empty() )
56  {
57  pid_t mypid = getpid();
58  zypp::Pathname p( "/proc/"+zypp::str::numstring(mypid)+"/exe" );
59  zypp::Pathname myname( zypp::filesystem::readlink( p ) );
60 
61  _val += zypp::str::numstring(mypid);
62  _val += ":";
63  _val += myname.basename();
64  }
65  return _val;
66  }
67 }
68 
69 namespace zypp
70 {
71  namespace
72  {
73  const char _sep = '|';
74  std::ofstream _log;
75  unsigned _refcnt = 0;
76  Pathname _fname;
77  Pathname _fnameLastFail;
78 
79  inline void openLog()
80  {
81  if ( _fname.empty() )
82  _fname = ZConfig::instance().historyLogFile();
83 
84  _log.clear();
85  _log.open( _fname.asString().c_str(), std::ios::out|std::ios::app );
86  if( !_log && _fnameLastFail != _fname )
87  {
88  ERR << "Could not open logfile '" << _fname << "'" << endl;
89  _fnameLastFail = _fname;
90  }
91  }
92 
93  inline void closeLog()
94  {
95  _log.clear();
96  _log.close();
97  }
98 
99  inline void refUp()
100  {
101  if ( !_refcnt )
102  openLog();
103  ++_refcnt;
104  }
105 
106  inline void refDown()
107  {
108  --_refcnt;
109  if ( !_refcnt )
110  closeLog();
111  }
112  }
113 
115  //
116  // CLASS NAME : HistoryLog
117  //
119 
120  HistoryLog::HistoryLog( const Pathname & rootdir )
121  {
122  setRoot( rootdir );
123  refUp();
124  }
125 
127  {
128  refDown();
129  }
130 
131  void HistoryLog::setRoot( const Pathname & rootdir )
132  {
133  if ( ! rootdir.absolute() )
134  return;
135 
136  if ( _refcnt )
137  closeLog();
138 
139  _fname = rootdir / ZConfig::instance().historyLogFile();
140  filesystem::assert_dir( _fname.dirname() );
141  MIL << "installation log file " << _fname << endl;
142 
143  if ( _refcnt )
144  openLog();
145  }
146 
147  const Pathname & HistoryLog::fname()
148  {
149  if ( _fname.empty() )
150  _fname = ZConfig::instance().historyLogFile();
151  return _fname;
152  }
153 
155 
156  void HistoryLog::comment( const string & comment, bool timestamp )
157  {
158  if (comment.empty())
159  return;
160 
161  _log << "# ";
162  if ( timestamp )
163  _log << ::timestamp() << " ";
164 
165  const char * s = comment.c_str();
166  const char * c = s;
167  unsigned size = comment.size();
168 
169  // ignore the last newline
170  if (comment[size-1] == '\n')
171  --size;
172 
173  for ( unsigned i = 0; i < size; ++i, ++c )
174  if ( *c == '\n' )
175  {
176  _log << string( s, c + 1 - s ) << "# ";
177  s = c + 1;
178  }
179 
180  if ( s < c )
181  _log << std::string( s, c-s );
182 
183  _log << endl;
184  }
185 
187 
188  void HistoryLog::install( const PoolItem & pi )
189  {
190  const Package::constPtr p = asKind<Package>(pi.resolvable());
191  if (!p)
192  return;
193 
194  _log
195  << timestamp() // 1 timestamp
196  << _sep << HistoryActionID::INSTALL.asString(true) // 2 action
197  << _sep << p->name() // 3 name
198  << _sep << p->edition() // 4 evr
199  << _sep << p->arch(); // 5 arch
200 
201  // ApplLow is what the solver selected on behalf of the user.
202  if (pi.status().isByUser() || pi.status().isByApplLow() )
203  _log << _sep << userAtHostname(); // 6 reqested by
204  else if (pi.status().isByApplHigh())
205  _log << _sep << pidAndAppname();
206  else
207  _log << _sep;
208 
209  _log
210  << _sep << p->repoInfo().alias() // 7 repo alias
211  << _sep << p->checksum().checksum() // 8 checksum
212  << _sep << str::escape(ZConfig::instance().userData(), _sep) // 9 userdata
213  << endl;
214  }
215 
216 
217  void HistoryLog::remove( const PoolItem & pi )
218  {
219  const Package::constPtr p = asKind<Package>(pi.resolvable());
220  if (!p)
221  return;
222 
223  _log
224  << timestamp() // 1 timestamp
225  << _sep << HistoryActionID::REMOVE.asString(true) // 2 action
226  << _sep << p->name() // 3 name
227  << _sep << p->edition() // 4 evr
228  << _sep << p->arch(); // 5 arch
229 
230  // ApplLow is what the solver selected on behalf of the user.
231  if ( pi.status().isByUser() || pi.status().isByApplLow() )
232  _log << _sep << userAtHostname(); // 6 reqested by
233  else if (pi.status().isByApplHigh())
234  _log << _sep << pidAndAppname();
235  else
236  _log << _sep;
237 
238  _log
239  << _sep << str::escape(ZConfig::instance().userData(), _sep) // 7 userdata
240  << endl;
241  }
242 
244 
246  {
247  _log
248  << timestamp() // 1 timestamp
249  << _sep << HistoryActionID::REPO_ADD.asString(true) // 2 action
250  << _sep << str::escape(repo.alias(), _sep) // 3 alias
251  << _sep << *repo.baseUrlsBegin() // 4 primary URL
252  << _sep << str::escape(ZConfig::instance().userData(), _sep) // 5 userdata
253  << endl;
254  }
255 
256 
258  {
259  _log
260  << timestamp() // 1 timestamp
261  << _sep << HistoryActionID::REPO_REMOVE.asString(true) // 2 action
262  << _sep << str::escape(repo.alias(), _sep) // 3 alias
263  << _sep << str::escape(ZConfig::instance().userData(), _sep) // 4 userdata
264  << endl;
265  }
266 
267 
269  const RepoInfo & oldrepo, const RepoInfo & newrepo)
270  {
271  if (oldrepo.alias() != newrepo.alias())
272  {
273  _log
274  << timestamp() // 1 timestamp
275  << _sep << HistoryActionID::REPO_CHANGE_ALIAS.asString(true) // 2 action
276  << _sep << str::escape(oldrepo.alias(), _sep) // 3 old alias
277  << _sep << str::escape(newrepo.alias(), _sep) // 4 new alias
278  << _sep << str::escape(ZConfig::instance().userData(), _sep) // 5 userdata
279  << endl;
280  }
281  if (*oldrepo.baseUrlsBegin() != *newrepo.baseUrlsBegin())
282  {
283  _log
284  << timestamp() // 1 timestamp
285  << _sep << HistoryActionID::REPO_CHANGE_URL.asString(true) // 2 action
286  << _sep << str::escape(oldrepo.alias(), _sep) // 3 old url
287  << _sep << *newrepo.baseUrlsBegin() // 4 new url
288  << _sep << str::escape(ZConfig::instance().userData(), _sep) // 5 userdata
289  << endl;
290  }
291  }
292 
294 
295 } // namespace zypp
int assert_dir(const Pathname &path, unsigned mode)
Like &#39;mkdir -p&#39;.
Definition: PathInfo.cc:324
bool isByApplLow() const
Definition: ResStatus.h:281
#define MIL
Definition: Logger.h:47
std::string alias() const
unique identifier for this source.
static ZConfig & instance()
Singleton ctor.
Definition: ZConfig.cc:655
int readlink(const Pathname &symlink_r, Pathname &target_r)
Like &#39;readlink&#39;.
Definition: PathInfo.cc:853
urls_const_iterator baseUrlsBegin() const
iterator that points at begin of repository urls
Definition: RepoInfo.cc:252
std::string escape(const C_Str &str_r, const char sep_r)
Escape desired character c using a backslash.
Definition: String.cc:339
static const HistoryActionID REMOVE
What is known about a repository.
Definition: RepoInfo.h:66
static const HistoryActionID REPO_CHANGE_ALIAS
void install(const PoolItem &pi)
Log installation (or update) of a package.
Definition: HistoryLog.cc:188
static const HistoryActionID INSTALL
#define ERR
Definition: Logger.h:49
Pathname historyLogFile() const
Path where ZYpp install history is logged.
Definition: ZConfig.cc:931
ResObject::constPtr resolvable() const
Returns the ResObject::constPtr.
Definition: PoolItem.cc:280
void removeRepository(const RepoInfo &repo)
Log recently removed repository.
Definition: HistoryLog.cc:257
bool isByUser() const
Definition: ResStatus.h:287
static const Pathname & fname()
Get the current log file path.
Definition: HistoryLog.cc:147
const std::string & asString(bool pad=false) const
static const HistoryActionID REPO_REMOVE
ResStatus & status() const
Returns the current status.
Definition: PoolItem.cc:241
void addRepository(const RepoInfo &repo)
Log a newly added repository.
Definition: HistoryLog.cc:245
static const HistoryActionID REPO_CHANGE_URL
bool isByApplHigh() const
Definition: ResStatus.h:284
std::string numstring(char n, int w=0)
Definition: String.h:219
static void setRoot(const Pathname &root)
Set new root directory to the default history log file path.
Definition: HistoryLog.cc:131
std::string form(const std::string &format_r) const
Return string representation according to format as localtime.
Definition: Date.h:107
static const HistoryActionID REPO_ADD
static Date now()
Return the current time.
Definition: Date.h:76
void remove(const PoolItem &pi)
Log removal of a package.
Definition: HistoryLog.cc:217
std::string userData() const
User defined string value to be passed to log, history, plugins...
Definition: ZConfig.cc:743
void comment(const std::string &comment, bool timestamp=false)
Log a comment (even multiline).
Definition: HistoryLog.cc:156
Reference to a PoolItem connecting ResObject and ResStatus.
Definition: PoolItem.h:50
void modifyRepository(const RepoInfo &oldrepo, const RepoInfo &newrepo)
Log certain modifications to a repository.
Definition: HistoryLog.cc:268
#define HISTORY_LOG_DATE_FORMAT
HistoryLog(const HistoryLog &)
TraitsType::constPtrType constPtr
Definition: Package.h:38