📄 log.cc
字号:
//=======================================================================// Log.cc//-----------------------------------------------------------------------// This file is part of the package paco// Copyright (C) 2004-2007 David Rosal <david.3r@gmail.com>// For more information visit http://paco.sourceforge.net//=======================================================================#include "config.h"#include "global.h"#include "PkgSet.h"#include "Pkg.h"#include "Log.h"#include "LogInfo.h"#include <fstream>#include <sstream>#include <iostream>#include <iterator>#include <algorithm>#include <glob.h>using namespace Paco;using namespace std;// Forward declarationsstatic string searchLibpaco();static void setEnv(char const* var, string const& val);static string getTmpName();static string stripSuffix(string const&);static bool isNotValidPath(string const&);Log::Log(Options const& opt): mOpt(opt), mAppend(opt.append()), mPkgName(opt.logPkg()), mTmpFile(), mFiles(){ if (opt.args().size()) fromCmd(); else fromStdin(); if (mFiles.empty()) return; filterFiles(); if (mPkgName.size()) toPkg(); else toStream(cout);}Log::~Log(){ unlink(mTmpFile.c_str()); rmdir(Config::logdir().c_str());}// [static]void Log::run(Options const& opt){ static Log log(opt);}void Log::fromStdin(){ getFilesFromStream(cin);}void Log::toStream(ostream& s){ copy(mFiles.begin(), mFiles.end(), ostream_iterator<string>(s, "\n"));}void Log::getFilesFromStream(istream& f){ vector<string> x; remove_copy_if(istream_iterator<string>(f), istream_iterator<string>(), back_inserter(x), isNotValidPath); transform(x.begin(), x.end(), inserter(mFiles, mFiles.begin()), realDir);}void Log::fromCmd(){ mTmpFile = getTmpName(); pid_t pid = fork(); if (pid == 0) { // child string command; string libpaco = searchLibpaco(); for (uint i = 0; i < mOpt.args().size(); ++i) command += mOpt.args()[i] + " "; setEnv("PACO_TMPFILE", mTmpFile); setEnv("LD_PRELOAD", libpaco); setEnv("PACO_DEBUG", gOut.verbosity() > Out::VERBOSE ? "yes" : ""); gOut.dbgTitle("settings"); gOut.dbg("TMPFILE=" + mTmpFile + "\n"); gOut.dbg("INCLUDE=" + mOpt.include() + "\n"); gOut.dbg("EXCLUDE=" + mOpt.exclude() + "\n"); gOut.dbg("IGNORE_ERRORS=" + string(mOpt.logIgnoreErrors() ? "1" : "0") + "\n"); gOut.dbg("IGNORE_SHARED=" + string(mOpt.logIgnoreShared() ? "1" : "0") + "\n"); gOut.dbg("LD_PRELOAD=" + libpaco + "\n"); gOut.dbg("command: " + command + "\n"); gOut.dbgTitle("libpaco-log"); char* cmd[] = { "sh", "-c", const_cast<char*>(command.c_str()), NULL }; execv("/bin/sh", cmd); throw XErrno("execv()"); } else if (pid == -1) throw XErrno("fork()"); int status; waitpid(pid, &status, 0); if (!WIFEXITED(status)) gExitStatus = EXIT_FAILURE_EXTERNAL; else gExitStatus = WEXITSTATUS(status); if (!mOpt.logIgnoreErrors() && gExitStatus != EXIT_SUCCESS) exit(gExitStatus); FileStream<ifstream> f(mTmpFile); getFilesFromStream(f);}void Log::appendPkgFiles(){ Pkg old(mPkgName); old.getFiles(); for (Pkg::iterator p = old.begin(); p != old.end(); ++p) mFiles.insert(stripSuffix((*p)->name()));}void Log::filterFiles(){ Out::Silencer* s = mPkgName.empty() ? new Out::Silencer() : NULL; vector<string> x; remove_copy_if(mFiles.begin(), mFiles.end(), back_inserter(x), Excluder(*this)); gOut.dbgTitle("logged files"); mFiles.clear(); if (mPkgName.empty()) copy(x.begin(), x.end(), inserter(mFiles, mFiles.begin())); else { transform(x.begin(), x.end(), inserter(mFiles, mFiles.begin()), stripSuffix); } delete s;}void Log::writeFiles(string const& logFile){ vector<string> head; FileStream<ifstream> fi(logFile); string buf; while (getline(fi, buf) && buf[0] == '#') head.push_back(buf); fi.close(); assert(head.empty() == false); FileStream<ofstream> fo(logFile); copy(head.begin(), head.end(), ostream_iterator<string>(fo, "\n")); copy(mFiles.begin(), mFiles.end(), ostream_iterator<string>(fo, "\n"));}void Log::toPkg(){ assert(!mPkgName.empty()); if (mFiles.empty()) { if (!mAppend) { gOut.dbg("Package not logged (no files)\n"); gOut.dbgTitle(""); } return; } if (mAppend) { try { appendPkgFiles(); } catch (...) { mAppend = false; } } if (!mAppend) { mkdir(Config::logdir().c_str(), 0755); LogInfo info(*this); } string const logFile(Config::logdir() + "/" + mPkgName); writeFiles(logFile); if (!Pkg::updateLog(logFile)) gOut.dbg("Package not logged\n"); else if (gOut.verbosity() == Out::VERBOSE) toStream(cerr);}//---------------//// Log::Excluder ////---------------//Log::Excluder::Excluder(Log const& log): mInclude(log.mOpt.include()), mExclude(log.mOpt.exclude()), mLogMissing(log.mOpt.logMissing()), mIgnoreShared(log.mOpt.logIgnoreShared()), mPkgSet(), mCnt(0){ if (mIgnoreShared) { mPkgSet.getAllPkgs(); mPkgSet.getFiles(); }}bool Log::Excluder::isShared(string const& path){ for (PkgSet::iterator p = mPkgSet.begin(); p != mPkgSet.end(); ++p) { if ((*p)->hasFile(path)) return true; } return false;}void Log::Excluder::logDebug(string const& msg){ if (!mCnt++) gOut.dbgTitle("excluded files"); gOut.dbg(msg);}bool Log::Excluder::operator()(string const& path){ struct stat s; bool ret = true; if (inPaths(path, mExclude) || !inPaths(path, mInclude)) logDebug(path + "\n"); // non-existent files else if (lstat(path.c_str(), &s) < 0) { if (mLogMissing) ret = false; else logDebug(path + " (missing)\n"); } // skip directories else if (UNLIKELY(S_ISDIR(s.st_mode))) logDebug(path + " (directory)\n"); else if (mIgnoreShared && isShared(path)) logDebug(path + " (shared)\n"); else ret = false; return ret;}//-------------------//// Static free funcs ////-------------------//static bool isNotValidPath(string const& path){ return UNLIKELY(path[0] == '#');}static string stripSuffix(string const& mPath){ string path(mPath); string::size_type p; if ((p = path.rfind(".bz2")) == path.size() - 4 || (p = path.rfind(".gz")) == path.size() - 3) path.erase(p); gOut.dbg(path + "\n"); return path;}//// Search for libpaco-log.so in the filesystem.// Take into account libpaco-log.so.0.1.0, libpaco-log.so.0.0 and so.//static string searchLibpaco(){ string libpath(LIBDIR "/libpaco-log.so"); struct stat s; if (!stat(libpath.c_str(), &s)) return libpath; glob_t g; memset(&g, 0, sizeof(g)); if (!glob(LIBDIR "/libpaco-log.so.[0-9]*", GLOB_NOSORT,0, &g) && g.gl_pathc) libpath = g.gl_pathv[0]; globfree(&g); return libpath;}static void setEnv(char const* var, string const& val){#if HAVE_SETENV if (setenv(var, val.c_str(), 1) < 0) throw XErrno(string("setenv(") + var + ", " + val + ", 1)");#else string str(var + "=" + val); if (putenv(str.c_str()) < 0) throw XErrno("putenv(" + str + ")");#endif}static string getTmpName(){ char* tmpFile = getenv("PACO_TMPFILE"); if (tmpFile) return tmpFile; char* tmpDir = getenv("TMPDIR"); char name[4096]; snprintf(name, sizeof(name), "%s/pacoXXXXXX", tmpDir ? tmpDir : "/tmp"); int fd = mkstemp(name); if (fd > 0) { fchmod(fd, 0644); close(fd); } else snprintf(name, sizeof(name), "/tmp/paco%d", getpid()); return name;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -