diff --git a/collector/lib/ProcfsScraper.cpp b/collector/lib/ProcfsScraper.cpp index f02f086d7c..2348f8d92c 100644 --- a/collector/lib/ProcfsScraper.cpp +++ b/collector/lib/ProcfsScraper.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -143,6 +144,26 @@ bool GetSocketINodes(int dirfd, uint64_t pid, UnorderedSet* sock_ino return true; } +// IsZombieProcess fetches the current state of the process pointed to by dirfd, and +// - returns true, if the process state is 'Z' +// - returns false otherwise +bool IsZombieProcess(int dirfd) { + FileHandle stat_file(FDHandle(openat(dirfd, "stat", O_RDONLY)), "r"); + if (!stat_file.valid()) { + return false; + } + + char linebuf[512]; + + if (fgets(linebuf, sizeof(linebuf), stat_file.get()) == nullptr) { + return false; + } + + auto state = ExtractProcessState(linebuf); + + return state && *state == 'Z'; +} + // GetContainerID retrieves the container ID of the process represented by dirfd. The container ID is extracted from // the cgroup. std::optional GetContainerID(int dirfd) { @@ -491,6 +512,10 @@ bool ReadContainerConnections(const char* proc_path, std::shared_ptr ExtractContainerID(std::string_view cgroup_line) return ExtractContainerIDFromCgroup(cgroup_path); } +std::optional ExtractProcessState(std::string_view line) { + size_t last_parenthese; + + if ((last_parenthese = line.rfind(") ")) == line.npos) { + return {}; + } + + line.remove_prefix(last_parenthese + 2); + + if (line.empty()) { + return {}; + } + + return line[0]; +} + bool ConnScraper::Scrape(std::vector* connections, std::vector* listen_endpoints) { return ReadContainerConnections(proc_path_.c_str(), process_store_, connections, listen_endpoints); } diff --git a/collector/lib/ProcfsScraper_internal.h b/collector/lib/ProcfsScraper_internal.h index ca5e6b91ef..f2542f8f6c 100644 --- a/collector/lib/ProcfsScraper_internal.h +++ b/collector/lib/ProcfsScraper_internal.h @@ -9,6 +9,11 @@ namespace collector { // ExtractContainerID tries to extract a container ID from a cgroup line. std::optional ExtractContainerID(std::string_view cgroup_line); +// ExtractProcessState retrieves the state of the process (3rd element). +// as found in /proc//stat. +// Returns: the state character or nullopt in case of error. +std::optional ExtractProcessState(std::string_view proc_pid_stat_line); + } // namespace collector #endif diff --git a/collector/test/ConnScraperTest.cpp b/collector/test/ConnScraperTest.cpp index e902ec0a04..eeb48a9487 100644 --- a/collector/test/ConnScraperTest.cpp +++ b/collector/test/ConnScraperTest.cpp @@ -46,6 +46,27 @@ TEST(ConnScraperTest, TestExtractContainerID) { } } +TEST(ConnScraperTest, TestProcStateExtract) { + std::optional state; + + // valid line + state = ExtractProcessState("13934 (prog) Z 2312 13934 2312 34819 13934 4194304 94 0 0 0 0 0 0 0 20 0 1 0 608787 5758976 409 18446744073709551615 94201870180352 94201870200233 140728860702192 0 0 0 0 0 0 0 0 0 17 4 0 0 0 0 0 94201870216240 94201870217856 94202687545344 140728860710184 140728860710204 140728860710204 140728860712939 0\n"); + + EXPECT_TRUE(state); + EXPECT_EQ(*state, 'Z'); + + // invalid + state = ExtractProcessState("13934 (prog) "); + + EXPECT_FALSE(state); + + // program name containing ')' + state = ExtractProcessState("13934 (prog ) Z) R 2312 13934 2312 34819 13934 4194304 94 0 0 0 0 0 0 0 20 0 1 0 608787 5758976 409 18446744073709551615 94201870180352 94201870200233 140728860702192 0 0 0 0 0 0 0 0 0 17 4 0 0 0 0 0 94201870216240 94201870217856 94202687545344 140728860710184 140728860710204 140728860710204 140728860712939 0\n"); + + EXPECT_TRUE(state); + EXPECT_EQ(*state, 'R'); +} + } // namespace } // namespace collector