14#include <unordered_set>
27#include <zypp-core/base/InputStream>
34#undef ZYPP_BASE_LOGGER_LOGGROUP
35#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::misc"
54 using CacheEntry = std::pair<std::string, std::unordered_set<std::string>>;
62 struct FilterRunsInContainer
77 Type in_our_root(
const Pathname &path )
const {
79 const PathInfo procInfoStat( path );
82 if ( procInfoStat.error() )
return IGNORE;
85 if ( procInfoStat.nlink() == 0 )
90 if ( linkTarget.empty() )
return IGNORE;
94 if ( linkTarget.relative() )
return IGNORE;
102 const PathInfo linkStat( linkTarget );
105 if ( !linkStat.isExist() )
109 if ( linkStat.ino() != procInfoStat.ino())
113 if ( linkStat.dev() != procInfoStat.dev() )
128 const Pathname pidDir = Pathname(
"/proc") /
asString(pid);
129 const Pathname exeFile = pidDir /
"exe";
131 auto res = in_our_root( exeFile );
133 return res == CONTAINER;
139 std::unordered_set<std::string> tested;
142 filesystem::dirForEach( pidDir /
"map_files", [
this, &tested, &res ](
const Pathname & dir_r,
const char *
const & name_r ){
145 constexpr bool contloop =
true;
146 constexpr bool stoploop =
false;
148 const Pathname entryName = dir_r / name_r;
152 if ( linkTarget.empty() || !tested.insert( linkTarget.asString() ).second )
return contloop;
155 const auto mappedFileType = in_our_root( entryName );
158 if ( mappedFileType > IGNORE ) {
159 res = mappedFileType;
169 return res == CONTAINER;
172 FilterRunsInContainer() {}
183 using target::rpm::librpmDb;
184 librpmDb::db_const_iterator it(
"/" );
185 return( it.findPackage(
"lsof" ) && it->tag_edition() < Edition(
"4.90") && !it->tag_provides().count( Capability(
"backported-option-Ki") ) );
196 bool addDataIf(
const CacheEntry & cache_r, std::vector<std::string> *debMap =
nullptr );
197 void addCacheIf( CacheEntry & cache_r,
const std::string & line_r, std::vector<std::string> *debMap =
nullptr );
202 std::vector<CheckAccessDeleted::ProcInfo>
_data;
222 const auto & filelist( cache_r.second );
224 if ( filelist.empty() )
230 pinfo.
files.insert( pinfo.
files.begin(), filelist.begin(), filelist.end() );
232 const std::string & pline( cache_r.first );
233 std::string commandname;
234 std::ostringstream pLineStr;
235 for_( ch, pline.begin(), pline.end() )
240 pinfo.
pid = &*(ch+1);
242 pLineStr <<&*(ch)<<
'\0';
245 pinfo.
ppid = &*(ch+1);
247 pLineStr <<&*(ch)<<
'\0';
250 pinfo.
puid = &*(ch+1);
252 pLineStr <<&*(ch)<<
'\0';
255 pinfo.
login = &*(ch+1);
257 pLineStr <<&*(ch)<<
'\0';
261 commandname = &*(ch+1);
266 pinfo.
command = std::move(commandname);
268 pLineStr <<
'c'<<pinfo.
command<<
'\0';
272 if ( *ch ==
'\n' )
break;
273 do { ++ch; }
while ( *ch !=
'\0' );
279 debMap->front() = pLineStr.str();
299 static const str::regex statErr(R
"(.*\(stat: [^)]+\)$)");
301 for_( ch, line_r.c_str(), ch+line_r.size() )
306 if ( *(ch+1) !=
'0' )
319 if ( *ch ==
'\n' )
break;
320 do { ++ch; }
while ( *ch !=
'\0' );
323 if ( !t || !f || !n )
326 if ( !( ( *t ==
'R' && *(t+1) ==
'E' && *(t+2) ==
'G' && *(t+3) ==
'\0' )
327 || ( *t ==
'D' && *(t+1) ==
'E' && *(t+2) ==
'L' && *(t+3) ==
'\0' ) ) )
330 if ( !( ( *f ==
'm' && *(f+1) ==
'e' && *(f+2) ==
'm' && *(f+3) ==
'\0' )
331 || ( *f ==
't' && *(f+1) ==
'x' && *(f+2) ==
't' && *(f+3) ==
'\0' )
332 || ( *f ==
'D' && *(f+1) ==
'E' && *(f+2) ==
'L' && *(f+3) ==
'\0' )
333 || ( *f ==
'l' && *(f+1) ==
't' && *(f+2) ==
'x' && *(f+3) ==
'\0' ) ) )
347 if ( *f ==
'm' || *f ==
'D' )
349 static const char * black[] = {
365 if ( debMap && cache_r.second.find(n) == cache_r.second.end() ) {
366 debMap->push_back(line_r);
368 cache_r.second.insert( n );
374 if ( doCheck_r )
check();
379 _pimpl->_verbose = verbose_r;
380 _pimpl->_fromLsofFileMode =
true;
382 FILE *inFile = fopen( lsofOutput_r.
c_str(),
"r" );
389 auto cache =
_pimpl->filterInput( inSource );
390 return _pimpl->createProcInfo( cache );
397 std::map<pid_t,CacheEntry> cachemap;
402 FilterRunsInContainer runsInLXC;
403 MIL <<
"Silently scanning lsof output..." << endl;
405 for( std::string line = source.
receiveLine( 30 * 1000 ); ! line.empty(); line = source.
receiveLine( 30 * 1000 ) )
408 if ( line[0] ==
'p' )
412 if ( debugEnabled ) {
414 if ( pidMad.empty() )
415 debugMap[cachepid].push_back( line );
419 cachemap[cachepid].first.swap( line );
427 addCacheIf( cachemap[cachepid], line, debugEnabled ? &dbgMap :
nullptr);
435 static const char* argv[] = {
"lsof",
"-n",
"-FpcuLRftkn0",
"-K",
"i", NULL };
439 _pimpl->_verbose = verbose_r;
440 _pimpl->_fromLsofFileMode =
false;
443 std::map<pid_t,CacheEntry> cachemap;
446 cachemap =
_pimpl->filterInput( prog );
453 int ret = prog.
close();
465 return _pimpl->createProcInfo( cachemap );
470 std::ofstream debugFileOut;
471 bool debugEnabled =
false;
474 debugEnabled = debugFileOut.is_open();
476 if ( !debugEnabled ) {
482 for (
const auto &cached : in )
487 std::vector<std::string> *mapPtr =
nullptr;
489 auto dbgInfo =
debugMap.find(cached.first);
491 mapPtr = &(dbgInfo->second);
493 if( !
addDataIf( cached.second, mapPtr ) )
496 for (
const std::string &dbgLine: dbgInfo->second ) {
497 debugFileOut.write( dbgLine.c_str(), dbgLine.length() );
506 return _pimpl->_data.empty();
511 return _pimpl->_data.size();
516 return _pimpl->_data.begin();
521 return _pimpl->_data.end();
526 _pimpl->_debugFile = filename_r;
542 static const str::regex rx(
"(0::|[0-9]+:name=systemd:)/system.slice/(.*/)?(.*).service(/.*)?$" );
546 [&](
int num_r,
const std::string& line_r )->
bool
577 if ( obj.
pid.empty() )
578 return str <<
"<NoProc>";
bool operator()(const zypp::Arch &lhs, const zypp::Arch &rhs) const
Default order for std::container based Arch::compare.
CheckAccessDeleted::Impl * clone() const
CheckAccessDeleted::size_type createProcInfo(const std::map< pid_t, CacheEntry > &in)
std::map< pid_t, std::vector< std::string > > debugMap
void addCacheIf(CacheEntry &cache_r, const std::string &line_r, std::vector< std::string > *debMap=nullptr)
Add file to cache if it refers to a deleted executable or library file:
std::map< pid_t, CacheEntry > filterInput(externalprogram::ExternalDataSource &source)
bool addDataIf(const CacheEntry &cache_r, std::vector< std::string > *debMap=nullptr)
Add cache to data if the process is accessing deleted files.
std::vector< CheckAccessDeleted::ProcInfo > _data
size_type check(bool verbose_r=false)
Check for running processes which access deleted executables or libraries.
CheckAccessDeleted(bool doCheck_r=true)
Default ctor performs check immediately.
const_iterator end() const
std::ostream & operator<<(std::ostream &str, const CheckAccessDeleted &obj)
Stream output.
const_iterator begin() const
static std::string findService(pid_t pid_r)
Guess if pid was started by a systemd service script.
std::vector< ProcInfo >::const_iterator const_iterator
void setDebugOutputFile(const Pathname &filename_r)
Writes all filtered process entries that make it into the final set into a file specified by filename...
RWCOW_pointer< Impl > _pimpl
Base class for Exception.
void remember(const Exception &old_r)
Store an other Exception as history.
Execute a program and give access to its io An object of this class encapsulates the execution of an ...
int close() override
Wait for the progamm to complete.
bool kill()
Kill the program.
const std::string & execError() const
Some detail telling why the execution failed, if it failed.
Bidirectional stream to external data.
std::string receiveLine()
Read one line from the input stream.
const char * c_str() const
String representation.
Regular expression match result.
String related utilities and Regular expression matching.
int dirForEach(const Pathname &dir_r, const StrMatcher &matcher_r, function< bool(const Pathname &, const char *const)> fnc_r)
int readlink(const Pathname &symlink_r, Pathname &target_r)
Like 'readlink'.
int simpleParseFile(std::istream &str_r, ParseFlags flags_r, function< bool(int, std::string)> consume_r)
Simple lineparser optionally trimming and skipping comments.
std::string numstring(char n, int w=0)
bool hasPrefix(const C_Str &str_r, const C_Str &prefix_r)
Return whether str_r has prefix prefix_r.
bool startsWith(const C_Str &str_r, const C_Str &prefix_r)
alias for hasPrefix
bool regex_match(const std::string &s, smatch &matches, const regex ®ex)
\relates regex \ingroup ZYPP_STR_REGEX \relates regex \ingroup ZYPP_STR_REGEX
TInt strtonum(const C_Str &str)
Parsing numbers from string.
bool contains(const C_Str &str_r, const C_Str &val_r)
Locate substring case sensitive.
Easy-to use interface to the ZYPP dependency resolver.
std::ostream & dumpRangeLine(std::ostream &str, TIterator begin, TIterator end)
Print range defined by iterators (single line style).
std::ostream & dumpRange(std::ostream &str, TIterator begin, TIterator end, const std::string &intro="{", const std::string &pfx="\n ", const std::string &sep="\n ", const std::string &sfx="\n", const std::string &extro="}")
Print range defined by iterators (multiline style).
std::string asString(const Patch::Category &obj)
Data about one running process accessing deleted files.
std::string service() const
Guess if command was started by a systemd service script.
std::string pid
process ID
std::string login
process login name
std::string puid
process user ID
std::string command
process command name
std::vector< std::string > files
list of deleted executables or libraries accessed
std::string ppid
parent process ID
Exchange LineWriter for the lifetime of this object.
#define arrayBegin(A)
Simple C-array iterator.
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.