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