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;
94 if ( linkTarget.relative() )
return IGNORE;
97 const PathInfo linkStat( linkTarget );
100 if ( !linkStat.isExist() )
104 if ( linkStat.ino() != procInfoStat.ino())
108 if ( linkStat.dev() != procInfoStat.dev() )
120 bool operator()(
const pid_t pid )
const {
123 const Pathname pidDir = Pathname(
"/proc") /
asString(pid);
124 const Pathname exeFile = pidDir /
"exe";
126 auto res = in_our_root( exeFile );
128 return res == CONTAINER;
134 std::unordered_set<std::string> tested;
137 filesystem::dirForEach( pidDir /
"map_files", [
this, &tested, &res ](
const Pathname & dir_r,
const char *
const & name_r ){
140 constexpr
bool contloop =
true;
141 constexpr
bool stoploop =
false;
143 const Pathname entryName = dir_r / name_r;
147 if ( linkTarget.empty() || !tested.insert( linkTarget.asString() ).second )
return contloop;
150 const auto mappedFileType = in_our_root( entryName );
153 if ( mappedFileType > IGNORE ) {
154 res = mappedFileType;
164 return res == CONTAINER;
167 FilterRunsInContainer() {}
178 using target::rpm::librpmDb;
183 : _wasBlocked( librpmDb::isBlocked() )
184 {
if ( _wasBlocked ) librpmDb::unblockAccess(); }
186 {
if ( _wasBlocked ) librpmDb::blockAccess(); }
191 librpmDb::db_const_iterator it;
192 return( it.findPackage(
"lsof" ) && it->tag_edition() < Edition(
"4.90") && !it->tag_provides().count( Capability(
"backported-option-Ki") ) );
203 bool addDataIf(
const CacheEntry & cache_r, std::vector<std::string> *debMap =
nullptr );
204 void addCacheIf( CacheEntry & cache_r,
const std::string & line_r, std::vector<std::string> *debMap =
nullptr );
209 std::vector<CheckAccessDeleted::ProcInfo>
_data;
229 const auto & filelist( cache_r.second );
231 if ( filelist.empty() )
237 pinfo.
files.insert( pinfo.files.begin(), filelist.begin(), filelist.end() );
239 const std::string & pline( cache_r.first );
240 std::string commandname;
241 std::ostringstream pLineStr;
242 for_( ch, pline.begin(), pline.end() )
247 pinfo.pid = &*(ch+1);
249 pLineStr <<&*(ch)<<
'\0';
252 pinfo.ppid = &*(ch+1);
254 pLineStr <<&*(ch)<<
'\0';
257 pinfo.puid = &*(ch+1);
259 pLineStr <<&*(ch)<<
'\0';
262 pinfo.login = &*(ch+1);
264 pLineStr <<&*(ch)<<
'\0';
267 if ( pinfo.command.empty() ) {
268 commandname = &*(ch+1);
270 if (!_fromLsofFileMode)
272 if ( pinfo.command.empty() )
273 pinfo.command = std::move(commandname);
275 pLineStr <<
'c'<<pinfo.command<<
'\0';
279 if ( *ch ==
'\n' )
break;
280 do { ++ch; }
while ( *ch !=
'\0' );
286 debMap->front() = pLineStr.str();
305 for_( ch, line_r.c_str(), ch+line_r.size() )
310 if ( *(ch+1) !=
'0' )
323 if ( *ch ==
'\n' )
break;
324 do { ++ch; }
while ( *ch !=
'\0' );
327 if ( !t || !f || !n )
330 if ( !( ( *t ==
'R' && *(t+1) ==
'E' && *(t+2) ==
'G' && *(t+3) ==
'\0' )
331 || ( *t ==
'D' && *(t+1) ==
'E' && *(t+2) ==
'L' && *(t+3) ==
'\0' ) ) )
334 if ( !( ( *f ==
'm' && *(f+1) ==
'e' && *(f+2) ==
'm' && *(f+3) ==
'\0' )
335 || ( *f ==
't' && *(f+1) ==
'x' && *(f+2) ==
't' && *(f+3) ==
'\0' )
336 || ( *f ==
'D' && *(f+1) ==
'E' && *(f+2) ==
'L' && *(f+3) ==
'\0' )
337 || ( *f ==
'l' && *(f+1) ==
't' && *(f+2) ==
'x' && *(f+3) ==
'\0' ) ) )
349 if ( *f ==
'm' || *f ==
'D' )
351 static const char * black[] = {
366 if ( debMap && cache_r.second.find(n) == cache_r.second.end() ) {
367 debMap->push_back(line_r);
369 cache_r.second.insert( n );
375 if ( doCheck_r )
check();
383 FILE *inFile = fopen( lsofOutput_r.
c_str(),
"r" );
398 std::map<pid_t,CacheEntry> cachemap;
403 FilterRunsInContainer runsInLXC;
404 MIL <<
"Silently scanning lsof output..." << endl;
406 for( std::string line = source.
receiveLine( 30 * 1000 ); ! line.empty(); line = source.
receiveLine( 30 * 1000 ) )
409 if ( line[0] ==
'p' )
413 if ( debugEnabled ) {
415 if ( pidMad.empty() )
416 debugMap[cachepid].push_back( line );
420 cachemap[cachepid].first.swap( line );
428 addCacheIf( cachemap[cachepid], line, debugEnabled ? &dbgMap :
nullptr);
436 static const char* argv[] = {
"lsof",
"-n",
"-FpcuLRftkn0",
"-K",
"i", NULL };
444 std::map<pid_t,CacheEntry> cachemap;
454 int ret = prog.
close();
471 std::ofstream debugFileOut;
472 bool debugEnabled =
false;
473 if ( !_debugFile.empty() ) {
474 debugFileOut.open( _debugFile.c_str() );
475 debugEnabled = debugFileOut.is_open();
477 if ( !debugEnabled ) {
478 ERR<<
"Unable to open debug file: "<<_debugFile<<endl;
483 for (
const auto &cached : in )
486 addDataIf( cached.second);
488 std::vector<std::string> *mapPtr =
nullptr;
490 auto dbgInfo = debugMap.find(cached.first);
491 if ( dbgInfo != debugMap.end() )
492 mapPtr = &(dbgInfo->second);
494 if( !addDataIf( cached.second, mapPtr ) )
497 for (
const std::string &dbgLine: dbgInfo->second ) {
498 debugFileOut.write( dbgLine.c_str(), dbgLine.length() );
543 static const str::regex rx(
"(0::|[0-9]+:name=systemd:)/system.slice/(.*/)?(.*).service(/.*)?$" );
547 [&](
int num_r, std::string line_r )->
bool 578 if ( obj.
pid.empty() )
579 return str <<
"<NoProc>";
std::string asString(const Patch::Category &obj)
bool addDataIf(const CacheEntry &cache_r, std::vector< std::string > *debMap=nullptr)
Add cache to data if the process is accessing deleted files.
Data about one running process accessing deleted files.
Bidirectional stream to external data.
bool contains(const C_Str &str_r, const C_Str &val_r)
Locate substring case sensitive.
std::map< pid_t, CacheEntry > filterInput(externalprogram::ExternalDataSource &source)
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
bool kill()
Kill the program.
std::map< pid_t, std::vector< std::string > > debugMap
int readlink(const Pathname &symlink_r, Pathname &target_r)
Like 'readlink'.
void setDebugOutputFile(const Pathname &filename_r)
Writes all filtered process entries that make it into the final set into a file specified by filename...
const std::string & execError() const
Some detail telling why the execution failed, if it failed.
std::ostream & dumpRange(std::ostream &str, TIterator begin, TIterator end, const std::string &intro="{", const std::string &pfx="\ ", const std::string &sep="\ ", const std::string &sfx="\, const std::string &extro="}")
Print range defined by iterators (multiline style).
int dirForEach(const Pathname &dir_r, const StrMatcher &matcher_r, function< bool(const Pathname &, const char *const)> fnc_r)
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
const char * c_str() const
String representation.
std::string command
process command name
String related utilities and Regular expression matching.
std::string receiveLine()
Read one line from the input stream.
Exchange LineWriter for the lifetime of this object.
std::ostream & operator<<(std::ostream &str, const CheckAccessDeleted &obj)
void remember(const Exception &old_r)
Store an other Exception as history.
CheckAccessDeleted::Impl * clone() const
bool empty() const
Test for an empty path.
size_type check(bool verbose_r=false)
Check for running processes which access deleted executables or libraries.
RWCOW_pointer< Impl > _pimpl
const_iterator begin() const
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 pid
process ID
Execute a program and give access to its io An object of this class encapsulates the execution of an ...
std::list< PublicKeyData > _data
std::vector< CheckAccessDeleted::ProcInfo > _data
TInt strtonum(const C_Str &str)
Parsing numbers from string.
std::string puid
process user ID
const_iterator end() const
std::string numstring(char n, int w=0)
CheckAccessDeleted::size_type createProcInfo(const std::map< pid_t, CacheEntry > &in)
int close()
Wait for the progamm to complete.
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Regular expression match result.
Base class for Exception.
Check for running processes which access deleted executables or libraries.
CheckAccessDeleted(bool doCheck_r=true)
Default ctor performs check immediately.
std::ostream & dumpRangeLine(std::ostream &str, TIterator begin, TIterator end)
Print range defined by iterators (single line style).
bool regex_match(const std::string &s, smatch &matches, const regex ®ex)
regex ZYPP_STR_REGEX regex ZYPP_STR_REGEX
Easy-to use interface to the ZYPP dependency resolver.
bool hasPrefix(const C_Str &str_r, const C_Str &prefix_r)
Return whether str_r has prefix prefix_r.
std::vector< ProcInfo >::const_iterator const_iterator
std::string login
process login name
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::vector< std::string > files
list of deleted executables or libraries accessed
#define arrayBegin(A)
Simple C-array iterator.
std::string ppid
parent process ID
std::string service() const
Guess if command was started by a systemd service script.
static std::string findService(pid_t pid_r)
Guess if pid was started by a systemd service script.