14#include <unordered_set>
17#include <zypp/base/LogControl.h>
18#include <zypp/base/LogTools.h>
19#include <zypp/base/String.h>
20#include <zypp/base/Gettext.h>
21#include <zypp/base/Exception.h>
23#include <zypp/PathInfo.h>
24#include <zypp/ExternalProgram.h>
25#include <zypp/base/Regex.h>
26#include <zypp/base/IOStream.h>
27#include <zypp-core/base/InputStream>
34#undef ZYPP_BASE_LOGGER_LOGGROUP
35#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::misc"
54 typedef std::pair<std::string,std::unordered_set<std::string>> CacheEntry;
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;
93 const PathInfo linkStat( linkTarget );
96 if ( !linkStat.isExist() )
100 if ( linkStat.ino() != procInfoStat.ino())
104 if ( linkStat.dev() != procInfoStat.dev() )
116 bool operator()(
const pid_t pid )
const {
119 const Pathname pidDir = Pathname(
"/proc") / asString(pid);
120 const Pathname exeFile = pidDir /
"exe";
122 auto res = in_our_root( exeFile );
124 return res == CONTAINER;
130 std::unordered_set<std::string> tested;
133 filesystem::dirForEach( pidDir /
"map_files", [
this, &tested, &res ](
const Pathname & dir_r,
const char *
const & name_r ){
136 constexpr bool contloop =
true;
137 constexpr bool stoploop =
false;
139 const Pathname entryName = dir_r / name_r;
143 if ( linkTarget.empty() || !tested.insert( linkTarget.asString() ).second )
return contloop;
146 const auto mappedFileType = in_our_root( entryName );
149 if ( mappedFileType > IGNORE ) {
150 res = mappedFileType;
160 return res == CONTAINER;
163 FilterRunsInContainer() {}
174 using target::rpm::librpmDb;
179 : _wasBlocked( librpmDb::isBlocked() )
180 {
if ( _wasBlocked ) librpmDb::unblockAccess(); }
182 {
if ( _wasBlocked ) librpmDb::blockAccess(); }
187 librpmDb::db_const_iterator it;
188 return( it.findPackage(
"lsof" ) && it->tag_edition() < Edition(
"4.90") && !it->tag_provides().count( Capability(
"backported-option-Ki") ) );
199 bool addDataIf(
const CacheEntry & cache_r, std::vector<std::string> *debMap =
nullptr );
200 void addCacheIf( CacheEntry & cache_r,
const std::string & line_r, std::vector<std::string> *debMap =
nullptr );
205 std::vector<CheckAccessDeleted::ProcInfo>
_data;
225 const auto & filelist( cache_r.second );
227 if ( filelist.empty() )
233 pinfo.
files.insert( pinfo.
files.begin(), filelist.begin(), filelist.end() );
235 const std::string & pline( cache_r.first );
236 std::string commandname;
237 std::ostringstream pLineStr;
238 for_( ch, pline.begin(), pline.end() )
243 pinfo.
pid = &*(ch+1);
245 pLineStr <<&*(ch)<<
'\0';
248 pinfo.
ppid = &*(ch+1);
250 pLineStr <<&*(ch)<<
'\0';
253 pinfo.
puid = &*(ch+1);
255 pLineStr <<&*(ch)<<
'\0';
258 pinfo.
login = &*(ch+1);
260 pLineStr <<&*(ch)<<
'\0';
264 commandname = &*(ch+1);
266 if (!_fromLsofFileMode)
269 pinfo.
command = std::move(commandname);
271 pLineStr <<
'c'<<pinfo.
command<<
'\0';
275 if ( *ch ==
'\n' )
break;
276 do { ++ch; }
while ( *ch !=
'\0' );
282 debMap->front() = pLineStr.str();
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' ) ) )
345 if ( *f ==
'm' || *f ==
'D' )
347 static const char * black[] = {
362 if ( debMap && cache_r.second.find(n) == cache_r.second.end() ) {
363 debMap->push_back(line_r);
365 cache_r.second.insert( n );
371 if ( doCheck_r )
check();
376 _pimpl->_verbose = verbose_r;
377 _pimpl->_fromLsofFileMode =
true;
379 FILE *inFile = fopen( lsofOutput_r.
c_str(),
"r" );
386 auto cache =
_pimpl->filterInput( inSource );
387 return _pimpl->createProcInfo( cache );
394 std::map<pid_t,CacheEntry> cachemap;
399 FilterRunsInContainer runsInLXC;
400 MIL <<
"Silently scanning lsof output..." << endl;
402 for( std::string line = source.
receiveLine( 30 * 1000 ); ! line.empty(); line = source.
receiveLine( 30 * 1000 ) )
405 if ( line[0] ==
'p' )
409 if ( debugEnabled ) {
411 if ( pidMad.empty() )
412 debugMap[cachepid].push_back( line );
416 cachemap[cachepid].first.swap( line );
424 addCacheIf( cachemap[cachepid], line, debugEnabled ? &dbgMap :
nullptr);
432 static const char* argv[] = {
"lsof",
"-n",
"-FpcuLRftkn0",
"-K",
"i", NULL };
436 _pimpl->_verbose = verbose_r;
437 _pimpl->_fromLsofFileMode =
false;
440 std::map<pid_t,CacheEntry> cachemap;
443 cachemap =
_pimpl->filterInput( prog );
450 int ret = prog.
close();
462 return _pimpl->createProcInfo( cachemap );
467 std::ofstream debugFileOut;
468 bool debugEnabled =
false;
469 if ( !_debugFile.empty() ) {
470 debugFileOut.open( _debugFile.c_str() );
471 debugEnabled = debugFileOut.is_open();
473 if ( !debugEnabled ) {
474 ERR<<
"Unable to open debug file: "<<_debugFile<<endl;
479 for (
const auto &cached : in )
482 addDataIf( cached.second);
484 std::vector<std::string> *mapPtr =
nullptr;
486 auto dbgInfo = debugMap.find(cached.first);
487 if ( dbgInfo != debugMap.end() )
488 mapPtr = &(dbgInfo->second);
490 if( !addDataIf( cached.second, mapPtr ) )
493 for (
const std::string &dbgLine: dbgInfo->second ) {
494 debugFileOut.write( dbgLine.c_str(), dbgLine.length() );
503 return _pimpl->_data.empty();
508 return _pimpl->_data.size();
513 return _pimpl->_data.begin();
518 return _pimpl->_data.end();
523 _pimpl->_debugFile = filename_r;
539 static const str::regex rx(
"(0::|[0-9]+:name=systemd:)/system.slice/(.*/)?(.*).service(/.*)?$" );
543 [&](
int num_r, std::string line_r )->
bool
574 if ( obj.
pid.empty() )
575 return str <<
"<NoProc>";
std::list< PublicKeyData > _data
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
Check for running processes which access deleted executables or libraries.
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.
std::vector< ProcInfo >::const_iterator const_iterator
const_iterator begin() const
static std::string findService(pid_t pid_r)
Guess if pid was started by a systemd service script.
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 ...
bool kill()
Kill the program.
const std::string & execError() const
Some detail telling why the execution failed, if it failed.
int close()
Wait for the progamm to complete.
Bidirectional stream to external data.
std::string receiveLine()
Read one line from the input stream.
const char * c_str() const
String representation.
bool empty() const
Test for an empty path.
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 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).
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.