libzypp  11.13.5
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 
213  _log << endl;
214 
215  //_log << pi << endl;
216  }
217 
218 
219  void HistoryLog::remove( const PoolItem & pi )
220  {
221  const Package::constPtr p = asKind<Package>(pi.resolvable());
222  if (!p)
223  return;
224 
225  _log
226  << timestamp() // 1 timestamp
227  << _sep << HistoryActionID::REMOVE.asString(true) // 2 action
228  << _sep << p->name() // 3 name
229  << _sep << p->edition() // 4 evr
230  << _sep << p->arch(); // 5 arch
231 
232  // ApplLow is what the solver selected on behalf of the user.
233  if ( pi.status().isByUser() || pi.status().isByApplLow() )
234  _log << _sep << userAtHostname(); // 6 reqested by
235  else if (pi.status().isByApplHigh())
236  _log << _sep << pidAndAppname();
237  else
238  _log << _sep;
239 
240  // we don't have checksum in rpm db
241  // << _sep << p->checksum().checksum(); // x checksum
242 
243  _log << endl;
244 
245  //_log << pi << endl;
246  }
247 
249 
251  {
252  _log
253  << timestamp() // 1 timestamp
254  << _sep << HistoryActionID::REPO_ADD.asString(true) // 2 action
255  << _sep << str::escape(repo.alias(), _sep) // 3 alias
256  // what about the rest of the URLs??
257  << _sep << *repo.baseUrlsBegin() // 4 primary URL
258  << endl;
259  }
260 
261 
263  {
264  _log
265  << timestamp() // 1 timestamp
266  << _sep << HistoryActionID::REPO_REMOVE.asString(true) // 2 action
267  << _sep << str::escape(repo.alias(), _sep) // 3 alias
268  << endl;
269  }
270 
271 
273  const RepoInfo & oldrepo, const RepoInfo & newrepo)
274  {
275  if (oldrepo.alias() != newrepo.alias())
276  {
277  _log
278  << timestamp() // 1 timestamp
279  << _sep << HistoryActionID::REPO_CHANGE_ALIAS.asString(true) // 2 action
280  << _sep << str::escape(oldrepo.alias(), _sep) // 3 old alias
281  << _sep << str::escape(newrepo.alias(), _sep) // 4 new alias
282  << endl;
283  }
284 
285  if (*oldrepo.baseUrlsBegin() != *newrepo.baseUrlsBegin())
286  {
287  _log
288  << timestamp() //1 timestamp
289  << _sep << HistoryActionID::REPO_CHANGE_URL.asString(true) // 2 action
290  << _sep << str::escape(oldrepo.alias(), _sep) // 3 old url
291  << _sep << *newrepo.baseUrlsBegin() // 4 new url
292  << endl;
293  }
294  }
295 
297 
298 } // namespace zypp