From c82b7489a0faf81184e2aafe1d283e48ef108829 Mon Sep 17 00:00:00 2001 From: Daniel Trugman Date: Tue, 26 Dec 2023 21:44:45 +0000 Subject: [PATCH 01/11] Minor formatting --- include/pfs/types.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/pfs/types.hpp b/include/pfs/types.hpp index b8d02cf..7fd20c7 100644 --- a/include/pfs/types.hpp +++ b/include/pfs/types.hpp @@ -480,10 +480,10 @@ struct net_socket { enum class timer { - none = 0, // No timer is pending - retransmit = 1, // Retransmit-timer is pending - another = 2, // Another timer (e.g. delayed ack or keepalive) is pending - time_wait = 3, // This is a socket in TIME_WAIT state. Not all fields + none = 0, // No timer is pending + retransmit = 1, // Retransmit-timer is pending + another = 2, // Another timer (e.g. delayed ack or keepalive) is pending + time_wait = 3, // This is a socket in TIME_WAIT state. Not all fields // will contain data (or even exist) zero_window = 4, // zero window probe timer is pending }; From bb31b9939e9ec8053b42aa5e6cb76474d1a646f3 Mon Sep 17 00:00:00 2001 From: Daniel Trugman Date: Tue, 26 Dec 2023 21:51:11 +0000 Subject: [PATCH 02/11] Fix net for tasks with a separate net namespace --- include/pfs/net.hpp | 10 ++++++---- src/net.cpp | 8 ++++---- src/task.cpp | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/include/pfs/net.hpp b/include/pfs/net.hpp index de69c97..2e5985a 100644 --- a/include/pfs/net.hpp +++ b/include/pfs/net.hpp @@ -42,7 +42,7 @@ class net final public: std::vector get_dev() const; - + std::vector get_icmp() const; std::vector get_icmp6() const; std::vector get_raw() const; @@ -62,15 +62,17 @@ class net final private: friend class task; - net(const std::string& procfs_root); + net(const std::string& parent_root); private: std::vector get_net_sockets(const std::string& file) const; - static std::string build_net_root(const std::string& procfs_root); + static std::string build_net_root(const std::string& parent_root); private: - const std::string _procfs_root; + // Net has a "parent root", and not a "procfs root", because we could + // be looking at a net namespace of a specific process. + const std::string _parent_root; const std::string _net_root; }; diff --git a/src/net.cpp b/src/net.cpp index 9bf8976..40f2d83 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -26,14 +26,14 @@ namespace pfs { using namespace impl; -net::net(const std::string& procfs_root) - : _procfs_root(procfs_root), _net_root(build_net_root(procfs_root)) +net::net(const std::string& parent_root) + : _parent_root(parent_root), _net_root(build_net_root(parent_root)) {} -std::string net::build_net_root(const std::string& procfs_root) +std::string net::build_net_root(const std::string& parent_root) { static const std::string NET_DIR("net/"); - return procfs_root + NET_DIR; + return parent_root + NET_DIR; } std::vector net::get_dev() const diff --git a/src/task.cpp b/src/task.cpp index 7740e12..98e974b 100644 --- a/src/task.cpp +++ b/src/task.cpp @@ -392,7 +392,7 @@ std::unordered_map task::get_fds() const net task::get_net() const { - return net(_procfs_root); + return net(_task_root); } ino_t task::get_ns(const std::string& ns) const From 02c4c26ed3c93f4ddbb03846add6c7b5e1512411 Mon Sep 17 00:00:00 2001 From: Daniel Trugman Date: Wed, 27 Dec 2023 23:30:00 +0000 Subject: [PATCH 03/11] Add get_fds_inodes() to task class --- include/pfs/task.hpp | 2 ++ src/task.cpp | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/include/pfs/task.hpp b/include/pfs/task.hpp index d8b064a..dbdef3b 100644 --- a/include/pfs/task.hpp +++ b/include/pfs/task.hpp @@ -65,6 +65,8 @@ class task final std::unordered_map get_fds() const; + std::set get_fds_inodes() const; + std::vector get_maps() const; mem get_mem() const; diff --git a/src/task.cpp b/src/task.cpp index 98e974b..9cc3d75 100644 --- a/src/task.cpp +++ b/src/task.cpp @@ -387,9 +387,22 @@ std::unordered_map task::get_fds() const { fds.emplace(num, fd(path, num)); } + return fds; } +std::set task::get_fds_inodes() const +{ + std::set inodes; + + for (auto& fd : get_fds()) + { + inodes.insert(fd.second.get_target_stat().st_ino); + } + + return inodes; +} + net task::get_net() const { return net(_task_root); From 6b8a2341fb394926afc6643f02a6c66da44429cf Mon Sep 17 00:00:00 2001 From: Daniel Trugman Date: Wed, 27 Dec 2023 23:32:01 +0000 Subject: [PATCH 04/11] Net interface supports filters --- include/pfs/net.hpp | 39 ++++++++++------- include/pfs/parsers/generic.hpp | 24 +++++++++-- src/net.cpp | 75 ++++++++++++++++++--------------- test/test_parsers.cpp | 10 ++++- 4 files changed, 94 insertions(+), 54 deletions(-) diff --git a/include/pfs/net.hpp b/include/pfs/net.hpp index 2e5985a..922b962 100644 --- a/include/pfs/net.hpp +++ b/include/pfs/net.hpp @@ -17,6 +17,7 @@ #ifndef PFS_NET_HPP #define PFS_NET_HPP +#include #include #include @@ -41,31 +42,39 @@ class net final net& operator=(net&&) = delete; public: - std::vector get_dev() const; + using net_device_filter = std::function; + using net_socket_filter = std::function; + using netlink_socket_filter = std::function; + using unix_socket_filter = std::function; + using net_route_filter = std::function; - std::vector get_icmp() const; - std::vector get_icmp6() const; - std::vector get_raw() const; - std::vector get_raw6() const; - std::vector get_tcp() const; - std::vector get_tcp6() const; - std::vector get_udp() const; - std::vector get_udp6() const; - std::vector get_udplite() const; - std::vector get_udplite6() const; +public: + std::vector get_dev(net_device_filter filter = nullptr) const; + + std::vector get_icmp(net_socket_filter filter = nullptr) const; + std::vector get_icmp6(net_socket_filter filter = nullptr) const; + std::vector get_raw(net_socket_filter filter = nullptr) const; + std::vector get_raw6(net_socket_filter filter = nullptr) const; + std::vector get_tcp(net_socket_filter filter = nullptr) const; + std::vector get_tcp6(net_socket_filter filter = nullptr) const; + std::vector get_udp(net_socket_filter filter = nullptr) const; + std::vector get_udp6(net_socket_filter filter = nullptr) const; + std::vector get_udplite(net_socket_filter filter = nullptr) const; + std::vector get_udplite6(net_socket_filter filter = nullptr) const; - std::vector get_netlink() const; + std::vector get_netlink(netlink_socket_filter filter = nullptr) const; - std::vector get_unix() const; + std::vector get_unix(unix_socket_filter filter = nullptr) const; - std::vector get_route() const; + std::vector get_route(net_route_filter filter = nullptr) const; private: friend class task; net(const std::string& parent_root); private: - std::vector get_net_sockets(const std::string& file) const; + std::vector get_net_sockets(const std::string& file, + net_socket_filter filter = nullptr) const; static std::string build_net_root(const std::string& parent_root); diff --git a/include/pfs/parsers/generic.hpp b/include/pfs/parsers/generic.hpp index e7b34a5..a34c5d8 100644 --- a/include/pfs/parsers/generic.hpp +++ b/include/pfs/parsers/generic.hpp @@ -31,9 +31,11 @@ template using inserted_type = typename Inserter::container_type::value_type; template -void parse_lines( - const std::string& path, Inserter inserter, +void parse_and_filter_lines( + const std::string& path, + Inserter inserter, std::function(const std::string&)> parser, + std::function&)> filter = nullptr, size_t lines_to_skip = 0) { std::ifstream in(path); @@ -55,10 +57,26 @@ void parse_lines( continue; } - inserter = parser(line); + auto inserted = parser(line); + if (filter && filter(inserted)) + { + continue; + } + + inserter = std::move(inserted); } } +template +void parse_lines( + const std::string& path, + Inserter inserter, + std::function(const std::string&)> parser, + size_t lines_to_skip = 0) +{ + parse_and_filter_lines(path, inserter, parser, nullptr, lines_to_skip); +} + template static void to_number(const std::string& value, T& out, utils::base base = utils::base::decimal) diff --git a/src/net.cpp b/src/net.cpp index 40f2d83..2b3f878 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -36,7 +36,7 @@ std::string net::build_net_root(const std::string& parent_root) return parent_root + NET_DIR; } -std::vector net::get_dev() const +std::vector net::get_dev(net_device_filter filter) const { static const std::string DEV_FILE("dev"); auto path = _net_root + DEV_FILE; @@ -44,72 +44,72 @@ std::vector net::get_dev() const static const size_t HEADER_LINES = 2; std::vector output; - parsers::parse_lines(path, std::back_inserter(output), - parsers::parse_net_device_line, HEADER_LINES); + parsers::parse_and_filter_lines(path, std::back_inserter(output), + parsers::parse_net_device_line, filter, HEADER_LINES); return output; } -std::vector net::get_icmp() const +std::vector net::get_icmp(net_socket_filter filter) const { static const std::string ICMP_FILE("icmp"); - return get_net_sockets(ICMP_FILE); + return get_net_sockets(ICMP_FILE, filter); } -std::vector net::get_icmp6() const +std::vector net::get_icmp6(net_socket_filter filter) const { static const std::string ICMP6_FILE("icmp6"); - return get_net_sockets(ICMP6_FILE); + return get_net_sockets(ICMP6_FILE, filter); } -std::vector net::get_raw() const +std::vector net::get_raw(net_socket_filter filter) const { static const std::string RAW_FILE("raw"); - return get_net_sockets(RAW_FILE); + return get_net_sockets(RAW_FILE, filter); } -std::vector net::get_raw6() const +std::vector net::get_raw6(net_socket_filter filter) const { static const std::string RAW6_FILE("raw6"); - return get_net_sockets(RAW6_FILE); + return get_net_sockets(RAW6_FILE, filter); } -std::vector net::get_tcp() const +std::vector net::get_tcp(net_socket_filter filter) const { static const std::string TCP_FILE("tcp"); - return get_net_sockets(TCP_FILE); + return get_net_sockets(TCP_FILE, filter); } -std::vector net::get_tcp6() const +std::vector net::get_tcp6(net_socket_filter filter) const { static const std::string TCP6_FILE("tcp6"); - return get_net_sockets(TCP6_FILE); + return get_net_sockets(TCP6_FILE, filter); } -std::vector net::get_udp() const +std::vector net::get_udp(net_socket_filter filter) const { static const std::string UDP_FILE("udp"); - return get_net_sockets(UDP_FILE); + return get_net_sockets(UDP_FILE, filter); } -std::vector net::get_udp6() const +std::vector net::get_udp6(net_socket_filter filter) const { static const std::string UDP6_FILE("udp6"); - return get_net_sockets(UDP6_FILE); + return get_net_sockets(UDP6_FILE, filter); } -std::vector net::get_udplite() const +std::vector net::get_udplite(net_socket_filter filter) const { static const std::string UDPLITE_FILE("udplite"); - return get_net_sockets(UDPLITE_FILE); + return get_net_sockets(UDPLITE_FILE, filter); } -std::vector net::get_udplite6() const +std::vector net::get_udplite6(net_socket_filter filter) const { static const std::string UDPLITE6_FILE("udplite6"); - return get_net_sockets(UDPLITE6_FILE); + return get_net_sockets(UDPLITE6_FILE, filter); } -std::vector net::get_netlink() const +std::vector net::get_netlink(netlink_socket_filter filter) const { static const std::string NETLINK_FILE("netlink"); auto path = _net_root + NETLINK_FILE; @@ -117,12 +117,13 @@ std::vector net::get_netlink() const static const size_t HEADER_LINES = 1; std::vector output; - parsers::parse_lines(path, std::back_inserter(output), - parsers::parse_netlink_socket_line, HEADER_LINES); + parsers::parse_and_filter_lines(path, std::back_inserter(output), + parsers::parse_netlink_socket_line, + filter, HEADER_LINES); return output; } -std::vector net::get_unix() const +std::vector net::get_unix(unix_socket_filter filter) const { static const std::string UNIX_FILE("unix"); auto path = _net_root + UNIX_FILE; @@ -130,24 +131,27 @@ std::vector net::get_unix() const static const size_t HEADER_LINES = 1; std::vector output; - parsers::parse_lines(path, std::back_inserter(output), - parsers::parse_unix_socket_line, HEADER_LINES); + parsers::parse_and_filter_lines(path, std::back_inserter(output), + parsers::parse_unix_socket_line, + filter, HEADER_LINES); return output; } -std::vector net::get_net_sockets(const std::string& file) const +std::vector net::get_net_sockets(const std::string& file, + net_socket_filter filter) const { auto path = _net_root + file; static const size_t HEADER_LINES = 1; std::vector output; - parsers::parse_lines(path, std::back_inserter(output), - parsers::parse_net_socket_line, HEADER_LINES); + parsers::parse_and_filter_lines(path, std::back_inserter(output), + parsers::parse_net_socket_line, + filter, HEADER_LINES); return output; } -std::vector net::get_route() const +std::vector net::get_route(net_route_filter filter) const { static const size_t HEADER_LINES = 1; @@ -155,8 +159,9 @@ std::vector net::get_route() const auto path = _net_root + ROUTES_FILE; std::vector output; - parsers::parse_lines(path, std::back_inserter(output), - parsers::parse_net_route_line, HEADER_LINES); + parsers::parse_and_filter_lines(path, std::back_inserter(output), + parsers::parse_net_route_line, + filter, HEADER_LINES); return output; } diff --git a/test/test_parsers.cpp b/test/test_parsers.cpp index c556295..d123a99 100644 --- a/test/test_parsers.cpp +++ b/test/test_parsers.cpp @@ -70,6 +70,7 @@ TEST_CASE("Parse lines functionality", "[parsers]") std::vector content; std::vector expected; std::vector output; + std::function filter = nullptr; size_t skipped = 0; std::string file; @@ -96,7 +97,14 @@ TEST_CASE("Parse lines functionality", "[parsers]") skipped = 5; } + SECTION("Filter lines") + { + content = {"a", "x", "x", "b", "x", "c"}; + expected = {"a", "b", "c"}; + filter = [](const std::string& entry) { return entry == "x"; }; + } + file = create_temp_file(content); - parse_lines(file, std::back_inserter(output), parser, skipped); + parse_and_filter_lines(file, std::back_inserter(output), parser, filter, skipped); REQUIRE(output == expected); } From 809807e984b8161a156735bf66496e81bfc666e3 Mon Sep 17 00:00:00 2001 From: Daniel Trugman Date: Wed, 27 Dec 2023 23:48:06 +0000 Subject: [PATCH 05/11] Split parsers/generic.hpp - Move parse lines into lines.hpp - Move to_number into number.hpp - Move to_sequence into proc_stat.cpp --- .../pfs/parsers/{generic.hpp => lines.hpp} | 62 ------------------- include/pfs/parsers/number.hpp | 51 +++++++++++++++ src/block.cpp | 2 +- src/block_queue.cpp | 2 +- src/net.cpp | 2 +- src/parsers/proc_stat.cpp | 46 +++++++++++++- src/parsers/task_io.cpp | 2 +- src/procfs.cpp | 2 +- src/task.cpp | 2 +- test/test_parsers.cpp | 2 +- 10 files changed, 103 insertions(+), 70 deletions(-) rename include/pfs/parsers/{generic.hpp => lines.hpp} (57%) create mode 100644 include/pfs/parsers/number.hpp diff --git a/include/pfs/parsers/generic.hpp b/include/pfs/parsers/lines.hpp similarity index 57% rename from include/pfs/parsers/generic.hpp rename to include/pfs/parsers/lines.hpp index a34c5d8..086d1cd 100644 --- a/include/pfs/parsers/generic.hpp +++ b/include/pfs/parsers/lines.hpp @@ -77,68 +77,6 @@ void parse_lines( parse_and_filter_lines(path, inserter, parser, nullptr, lines_to_skip); } -template -static void to_number(const std::string& value, T& out, - utils::base base = utils::base::decimal) -{ - try - { - utils::stot(value, out, base); - } - catch (const std::invalid_argument& ex) - { - throw parser_error("Corrupted number - Invalid argument", value); - } - catch (const std::out_of_range& ex) - { - throw parser_error("Corrupted number - Out of range", value); - } -} - -template -static void to_sequence(const std::string& value, proc_stat::sequence& out) -{ - // Some examples: - // clang-format off - // 975101428 40707218 345522235 433770 2054357 19668 0 1807723 381659448 33954 202863055 - // clang-format on - - enum token - { - TOTAL = 0, - MIN_COUNT = 1, - }; - - auto tokens = utils::split(value); - if (tokens.size() < MIN_COUNT) - { - throw parser_error("Corrupted sequence - Unexpected tokens count", - value); - } - - try - { - proc_stat::sequence sequence; - - utils::stot(tokens[TOTAL], out.total); - - for (size_t i = MIN_COUNT; i < tokens.size(); i++) - { - unsigned long long value; - utils::stot(tokens[i], value); - out.per_item.push_back(value); - } - } - catch (const std::invalid_argument& ex) - { - throw parser_error("Corrupted sequence - Invalid argument", value); - } - catch (const std::out_of_range& ex) - { - throw parser_error("Corrupted sequence - Out of range", value); - } -} - } // namespace parsers } // namespace impl } // namespace pfs diff --git a/include/pfs/parsers/number.hpp b/include/pfs/parsers/number.hpp new file mode 100644 index 0000000..8f7ff30 --- /dev/null +++ b/include/pfs/parsers/number.hpp @@ -0,0 +1,51 @@ +/* + * Copyright 2020-present Daniel Trugman + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PFS_PARSERS_NUMBER_HPP +#define PFS_PARSERS_NUMBER_HPP + +#include + +#include "pfs/parser_error.hpp" +#include "pfs/utils.hpp" + +namespace pfs { +namespace impl { +namespace parsers { + +template +static void to_number(const std::string& value, T& out, + utils::base base = utils::base::decimal) +{ + try + { + utils::stot(value, out, base); + } + catch (const std::invalid_argument& ex) + { + throw parser_error("Corrupted number - Invalid argument", value); + } + catch (const std::out_of_range& ex) + { + throw parser_error("Corrupted number - Out of range", value); + } +} + +} // namespace parsers +} // namespace impl +} // namespace pfs + +#endif // PFS_PARSERS_NUMBER_HPP diff --git a/src/block.cpp b/src/block.cpp index d1835ae..806b2a6 100644 --- a/src/block.cpp +++ b/src/block.cpp @@ -19,7 +19,7 @@ #include "pfs/defer.hpp" #include "pfs/parsers/block_stat.hpp" #include "pfs/parsers/common.hpp" -#include "pfs/parsers/generic.hpp" +#include "pfs/parsers/number.hpp" #include "pfs/block.hpp" #include "pfs/utils.hpp" diff --git a/src/block_queue.cpp b/src/block_queue.cpp index 3ea582a..9e2db54 100644 --- a/src/block_queue.cpp +++ b/src/block_queue.cpp @@ -18,7 +18,7 @@ #include "pfs/defer.hpp" #include "pfs/parsers/common.hpp" -#include "pfs/parsers/generic.hpp" +#include "pfs/parsers/number.hpp" #include "pfs/block_queue.hpp" namespace pfs { diff --git a/src/net.cpp b/src/net.cpp index 2b3f878..484837e 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -20,7 +20,7 @@ #include "pfs/parsers/net_socket.hpp" #include "pfs/parsers/unix_socket.hpp" #include "pfs/parsers/netlink_socket.hpp" -#include "pfs/parsers/generic.hpp" +#include "pfs/parsers/lines.hpp" namespace pfs { diff --git a/src/parsers/proc_stat.cpp b/src/parsers/proc_stat.cpp index 4dc795b..2a575c1 100644 --- a/src/parsers/proc_stat.cpp +++ b/src/parsers/proc_stat.cpp @@ -17,7 +17,7 @@ #include #include -#include "pfs/parsers/generic.hpp" +#include "pfs/parsers/number.hpp" #include "pfs/parsers/proc_stat.hpp" #include "pfs/utils.hpp" @@ -27,6 +27,50 @@ namespace parsers { namespace { +template +static void to_sequence(const std::string& value, proc_stat::sequence& out) +{ + // Some examples: + // clang-format off + // 975101428 40707218 345522235 433770 2054357 19668 0 1807723 381659448 33954 202863055 + // clang-format on + + enum token + { + TOTAL = 0, + MIN_COUNT = 1, + }; + + auto tokens = utils::split(value); + if (tokens.size() < MIN_COUNT) + { + throw parser_error("Corrupted sequence - Unexpected tokens count", + value); + } + + try + { + proc_stat::sequence sequence; + + utils::stot(tokens[TOTAL], out.total); + + for (size_t i = MIN_COUNT; i < tokens.size(); i++) + { + unsigned long long value; + utils::stot(tokens[i], value); + out.per_item.push_back(value); + } + } + catch (const std::invalid_argument& ex) + { + throw parser_error("Corrupted sequence - Invalid argument", value); + } + catch (const std::out_of_range& ex) + { + throw parser_error("Corrupted sequence - Out of range", value); + } +} + static void to_cpu(const std::string& value, proc_stat::cpu& out) { // Some examples: diff --git a/src/parsers/task_io.cpp b/src/parsers/task_io.cpp index 5e6cbec..cb210fc 100644 --- a/src/parsers/task_io.cpp +++ b/src/parsers/task_io.cpp @@ -15,7 +15,7 @@ */ -#include "pfs/parsers/generic.hpp" +#include "pfs/parsers/number.hpp" #include "pfs/parsers/task_io.hpp" #include "pfs/utils.hpp" diff --git a/src/procfs.cpp b/src/procfs.cpp index eaebe1e..0d808ac 100644 --- a/src/procfs.cpp +++ b/src/procfs.cpp @@ -27,7 +27,7 @@ #include "pfs/parsers/loadavg.hpp" #include "pfs/parsers/uptime.hpp" #include "pfs/parsers/modules.hpp" -#include "pfs/parsers/generic.hpp" +#include "pfs/parsers/lines.hpp" #include "pfs/parsers/proc_stat.hpp" #include "pfs/procfs.hpp" #include "pfs/utils.hpp" diff --git a/src/task.cpp b/src/task.cpp index 9cc3d75..a5a0dbc 100644 --- a/src/task.cpp +++ b/src/task.cpp @@ -31,7 +31,7 @@ #include "pfs/parsers/cgroup.hpp" #include "pfs/parsers/maps.hpp" #include "pfs/parsers/mountinfo.hpp" -#include "pfs/parsers/generic.hpp" +#include "pfs/parsers/lines.hpp" #include "pfs/parsers/common.hpp" #include "pfs/parsers/task_io.hpp" #include "pfs/parsers/task_status.hpp" diff --git a/test/test_parsers.cpp b/test/test_parsers.cpp index d123a99..d599ea4 100644 --- a/test/test_parsers.cpp +++ b/test/test_parsers.cpp @@ -2,7 +2,7 @@ #include "test_utils.hpp" #include "pfs/defer.hpp" -#include "pfs/parsers/generic.hpp" +#include "pfs/parsers/lines.hpp" using namespace pfs::impl::parsers; From ec87534eec2d05c52ebcf5b3a808b47645aff624 Mon Sep 17 00:00:00 2001 From: Daniel Trugman Date: Thu, 28 Dec 2023 00:11:47 +0000 Subject: [PATCH 06/11] Merge parse lines implementations --- include/pfs/parsers/lines.hpp | 13 ++----------- src/net.cpp | 33 +++++++++++++++++---------------- src/procfs.cpp | 25 +++++++++++++------------ src/task.cpp | 20 ++++++++++---------- test/test_parsers.cpp | 4 ++-- 5 files changed, 44 insertions(+), 51 deletions(-) diff --git a/include/pfs/parsers/lines.hpp b/include/pfs/parsers/lines.hpp index 086d1cd..bb203d2 100644 --- a/include/pfs/parsers/lines.hpp +++ b/include/pfs/parsers/lines.hpp @@ -31,7 +31,7 @@ template using inserted_type = typename Inserter::container_type::value_type; template -void parse_and_filter_lines( +void parse_file_lines( const std::string& path, Inserter inserter, std::function(const std::string&)> parser, @@ -58,6 +58,7 @@ void parse_and_filter_lines( } auto inserted = parser(line); + if (filter && filter(inserted)) { continue; @@ -67,16 +68,6 @@ void parse_and_filter_lines( } } -template -void parse_lines( - const std::string& path, - Inserter inserter, - std::function(const std::string&)> parser, - size_t lines_to_skip = 0) -{ - parse_and_filter_lines(path, inserter, parser, nullptr, lines_to_skip); -} - } // namespace parsers } // namespace impl } // namespace pfs diff --git a/src/net.cpp b/src/net.cpp index 484837e..00ebd9d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -44,8 +44,9 @@ std::vector net::get_dev(net_device_filter filter) const static const size_t HEADER_LINES = 2; std::vector output; - parsers::parse_and_filter_lines(path, std::back_inserter(output), - parsers::parse_net_device_line, filter, HEADER_LINES); + parsers::parse_file_lines(path, std::back_inserter(output), + parsers::parse_net_device_line, + filter, HEADER_LINES); return output; } @@ -117,9 +118,9 @@ std::vector net::get_netlink(netlink_socket_filter filter) const static const size_t HEADER_LINES = 1; std::vector output; - parsers::parse_and_filter_lines(path, std::back_inserter(output), - parsers::parse_netlink_socket_line, - filter, HEADER_LINES); + parsers::parse_file_lines(path, std::back_inserter(output), + parsers::parse_netlink_socket_line, + filter, HEADER_LINES); return output; } @@ -131,9 +132,9 @@ std::vector net::get_unix(unix_socket_filter filter) const static const size_t HEADER_LINES = 1; std::vector output; - parsers::parse_and_filter_lines(path, std::back_inserter(output), - parsers::parse_unix_socket_line, - filter, HEADER_LINES); + parsers::parse_file_lines(path, std::back_inserter(output), + parsers::parse_unix_socket_line, + filter, HEADER_LINES); return output; } @@ -145,23 +146,23 @@ std::vector net::get_net_sockets(const std::string& file, static const size_t HEADER_LINES = 1; std::vector output; - parsers::parse_and_filter_lines(path, std::back_inserter(output), - parsers::parse_net_socket_line, - filter, HEADER_LINES); + parsers::parse_file_lines(path, std::back_inserter(output), + parsers::parse_net_socket_line, + filter, HEADER_LINES); return output; } std::vector net::get_route(net_route_filter filter) const { - static const size_t HEADER_LINES = 1; - static const std::string ROUTES_FILE("route"); auto path = _net_root + ROUTES_FILE; + static const size_t HEADER_LINES = 1; + std::vector output; - parsers::parse_and_filter_lines(path, std::back_inserter(output), - parsers::parse_net_route_line, - filter, HEADER_LINES); + parsers::parse_file_lines(path, std::back_inserter(output), + parsers::parse_net_route_line, + filter, HEADER_LINES); return output; } diff --git a/src/procfs.cpp b/src/procfs.cpp index 0d808ac..43a156b 100644 --- a/src/procfs.cpp +++ b/src/procfs.cpp @@ -92,21 +92,22 @@ std::vector procfs::get_buddyinfo() const auto path = _root + BUDDYINFO_FILE; std::vector output; - parsers::parse_lines(path, std::back_inserter(output), - parsers::parse_buddyinfo_line); + parsers::parse_file_lines(path, std::back_inserter(output), + parsers::parse_buddyinfo_line); return output; } std::vector procfs::get_cgroups() const { - static const size_t HEADER_LINES = 1; - static const std::string CGROUPS_FILE("cgroups"); auto path = _root + CGROUPS_FILE; + static const size_t HEADER_LINES = 1; + std::vector output; - parsers::parse_lines(path, std::back_inserter(output), - parsers::parse_cgroup_controller_line, HEADER_LINES); + parsers::parse_file_lines(path, std::back_inserter(output), + parsers::parse_cgroup_controller_line, + /* filter = */ nullptr, HEADER_LINES); return output; } @@ -124,8 +125,8 @@ std::unordered_map procfs::get_filesystems() const auto path = _root + FILESYSTEMS_FILE; std::unordered_map output; - parsers::parse_lines(path, std::inserter(output, output.begin()), - parsers::parse_filesystems_line); + parsers::parse_file_lines(path, std::inserter(output, output.begin()), + parsers::parse_filesystems_line); return output; } @@ -135,8 +136,8 @@ std::unordered_map procfs::get_meminfo() const auto path = _root + MEMINFO_FILE; std::unordered_map output; - parsers::parse_lines(path, std::inserter(output, output.begin()), - parsers::parse_meminfo_line); + parsers::parse_file_lines(path, std::inserter(output, output.begin()), + parsers::parse_meminfo_line); return output; } @@ -172,8 +173,8 @@ std::vector procfs::get_modules() const auto path = _root + MODULES_FILE; std::vector output; - parsers::parse_lines(path, std::back_inserter(output), - parsers::parse_modules_line); + parsers::parse_file_lines(path, std::back_inserter(output), + parsers::parse_modules_line); return output; } diff --git a/src/task.cpp b/src/task.cpp index a5a0dbc..e7e47e1 100644 --- a/src/task.cpp +++ b/src/task.cpp @@ -80,8 +80,8 @@ std::vector task::get_cgroups() const auto path = _task_root + CGROUP_FILE; std::vector output; - parsers::parse_lines(path, std::back_inserter(output), - parsers::parse_cgroup_line); + parsers::parse_file_lines(path, std::back_inserter(output), + parsers::parse_cgroup_line); return output; } @@ -345,8 +345,8 @@ std::vector task::get_maps() const auto path = _task_root + MAPS_FILE; std::vector output; - parsers::parse_lines(path, std::back_inserter(output), - parsers::parse_maps_line); + parsers::parse_file_lines(path, std::back_inserter(output), + parsers::parse_maps_line); return output; } @@ -364,8 +364,8 @@ std::vector task::get_mountinfo() const auto path = _task_root + MOUNTINFO_FILE; std::vector output; - parsers::parse_lines(path, std::back_inserter(output), - parsers::parse_mountinfo_line); + parsers::parse_file_lines(path, std::back_inserter(output), + parsers::parse_mountinfo_line); return output; } @@ -473,8 +473,8 @@ std::vector task::get_uid_map() const auto path = _task_root + UID_MAP_FILE; std::vector output; - parsers::parse_lines(path, std::back_inserter(output), - parsers::parse_id_map_line); + parsers::parse_file_lines(path, std::back_inserter(output), + parsers::parse_id_map_line); return output; } @@ -484,8 +484,8 @@ std::vector task::get_gid_map() const auto path = _task_root + GID_MAP_FILE; std::vector output; - parsers::parse_lines(path, std::back_inserter(output), - parsers::parse_id_map_line); + parsers::parse_file_lines(path, std::back_inserter(output), + parsers::parse_id_map_line); return output; } diff --git a/test/test_parsers.cpp b/test/test_parsers.cpp index d599ea4..d909f33 100644 --- a/test/test_parsers.cpp +++ b/test/test_parsers.cpp @@ -50,7 +50,7 @@ TEST_CASE("Parse lines move()-s", "[parsers]") pfs::impl::defer unlink_temp_file([&file] { unlink(file.c_str()); }); std::vector output; - parse_lines(file, std::back_inserter(output), parser); + parse_file_lines(file, std::back_inserter(output), parser); REQUIRE(output.size() == content.size()); for (size_t i = 0; i < output.size(); ++i) @@ -105,6 +105,6 @@ TEST_CASE("Parse lines functionality", "[parsers]") } file = create_temp_file(content); - parse_and_filter_lines(file, std::back_inserter(output), parser, filter, skipped); + parse_file_lines(file, std::back_inserter(output), parser, filter, skipped); REQUIRE(output == expected); } From 1bef73ed197364ac5a0f2a057fa57a2cc233ad70 Mon Sep 17 00:00:00 2001 From: Daniel Trugman Date: Thu, 14 Dec 2023 21:26:46 +0000 Subject: [PATCH 07/11] Add netstat sample application --- README.md | 2 + sample/sample.cpp | 20 ++++++--- sample/tool.hpp | 1 + sample/tool_netstat.cpp | 92 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 sample/tool_netstat.cpp diff --git a/README.md b/README.md index cea3cc5..8478182 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,8 @@ How does that affect `pfs`? The directory `sample` contains a full blown application that calls all(!) the supported APIs and prints all the information gathered. When compiling the library, the sample applications is compiled as well. +You can find a basic implementation of `netstat` (see `sample/tool_netstat.cpp`) and `lsmod` (see `sample/tool_lsmod.cpp`) that you can easily reuse in your projects. + Anyway, here are some cool (and concise) examples: **Example 1:** Iterater over all the loaded unsigned or out-of-tree kernel modules diff --git a/sample/sample.cpp b/sample/sample.cpp index 751b200..6c35ca5 100644 --- a/sample/sample.cpp +++ b/sample/sample.cpp @@ -37,12 +37,20 @@ int main(int argc, char** argv) // clang-format off auto commands = std::vector{ - {command("system", "", "Enumerate system-wide information", enum_system)}, - {command("net", "", "Enumerate network information", enum_net)}, - {command("tasks", "[task-id]...", "Enumerate running tasks", enum_tasks)}, - {command("fds", "[task-id]...", "Enumerate fds for a specific task", enum_fds)}, - {command("lsmod", "[filter]", "Enumerate all loaded modules that match the filter", tool_lsmod)}, - {command("blocks", "[block-name]...", "Enumerate block devices", enum_blocks)}, + {command("system", "", + "Enumerate system-wide information", enum_system)}, + {command("net", "", + "Enumerate network information", enum_net)}, + {command("tasks", "[task-id]...", + "Enumerate running tasks", enum_tasks)}, + {command("fds", "[task-id]...", + "Enumerate fds for a specific task", enum_fds)}, + {command("blocks", "[block-name]...", + "Enumerate block devices", enum_blocks)}, + {command("lsmod", "[filter]", + "Enumerate all loaded modules that match the filter", tool_lsmod)}, + {command("netstat", "(tcp|udp) [task-id]...", + "Enumerate all sockets of said type for tasks", tool_netstat)}, }; // clang-format on diff --git a/sample/tool.hpp b/sample/tool.hpp index 67aa16e..94b0b6c 100644 --- a/sample/tool.hpp +++ b/sample/tool.hpp @@ -18,5 +18,6 @@ #define SAMPLE_TOOL_HPP int tool_lsmod(std::vector&& args); +int tool_netstat(std::vector&& args); #endif // SAMPLE_TOOL_HPP diff --git a/sample/tool_netstat.cpp b/sample/tool_netstat.cpp new file mode 100644 index 0000000..e73411e --- /dev/null +++ b/sample/tool_netstat.cpp @@ -0,0 +1,92 @@ +/* + * Copyright 2020-present Daniel Trugman + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "format.hpp" +#include "log.hpp" +#include "tool.hpp" + +static const std::string TCP("tcp"); +static const std::string UDP("udp"); + +void task_netstat(const pfs::task& task, const std::string& type) +{ + LOG("========================================================="); + LOG("Netstat for task ID[" << task.id() << "]"); + LOG("========================================================="); + + auto inodes = task.get_fds_inodes(); + pfs::net::net_socket_filter filter = [&inodes](const pfs::net_socket& sock){ + return inodes.find(sock.inode) == inodes.end(); + }; + + auto net = task.get_net(); + std::vector sockets; + if (type == TCP) + { + sockets = net.get_tcp(filter); + } + else if (type == UDP) + { + sockets = net.get_udp(filter); + } + + print(sockets); +} + +int tool_netstat(std::vector&& args) +{ + if (args.size() < 1) + { + return -EINVAL; + } + + std::string type(args[0]); + if (type != TCP && type != UDP) + { + return -EINVAL; + } + + try + { + pfs::procfs pfs; + + if (args.size() > 1) + { + for (unsigned arg = 1; arg < args.size(); ++arg) + { + auto id = std::stoi(args[arg]); + auto task = pfs.get_task(id); + task_netstat(task, type); + } + } + else + { + for (auto& task : pfs.get_processes()) + { + task_netstat(task, type); + } + } + } + catch (const std::runtime_error& ex) + { + LOG("Error when printing netstat:"); + LOG(TAB << ex.what()); + } + + return 0; +} From 13268ea4211e577ab95720d42d7793817b2f37f3 Mon Sep 17 00:00:00 2001 From: Daniel Trugman Date: Mon, 1 Jan 2024 22:24:46 +0000 Subject: [PATCH 08/11] Update README --- README.md | 74 +++++++++++++++++++++------------------------- sample/enum_fd.cpp | 4 +-- 2 files changed, 35 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 8478182..61a6fb7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ ![pfs](./img/pfs.png "Logo") -Very easy to use, procfs parsing library in C++. +Production grade, very easy to use, procfs parsing library in C++. +Used in production by S&P 500 tech companies and startups! + +**NEW** Basic parsing of sysfs (Additional `sysfs` feature requests are welcome!) ## Build @@ -53,6 +56,7 @@ CMake generates an `install_manifest.txt` file to track all the created files, t - Parsing system-wide information from files directly under `/procfs`. See `procfs.hpp` for all the supported files. - Parsing per-task (processes and threads) information from files under `/procfs/[task-id]/`. See `task.hpp` for all the supported files. - Parsing network information from files under `/procfs/net` (which is an alias to `/procfs/self/net` nowadays) +- **NEW** Parsing of basic disk information from `sysfs/block` (Additional `sysfs` feature requests are welcome!) ## Requirements @@ -72,7 +76,7 @@ CMake generates an `install_manifest.txt` file to track all the created files, t If you call `procfs().get_task()` and that task doesn't really exist, the constructor will succeed. -Since tasks can die any time, instead of adding some extra validation during construction, that might be confusing, the current design assumes the first call after the tasks died will fail. +Since tasks can die any time, instead of adding extra validation during construction, which might be confusing, the current design assumes the first call after the tasks died will fail. ### Collecting thread information @@ -91,24 +95,43 @@ How does that affect `pfs`? The directory `sample` contains a full blown application that calls all(!) the supported APIs and prints all the information gathered. When compiling the library, the sample applications is compiled as well. -You can find a basic implementation of `netstat` (see `sample/tool_netstat.cpp`) and `lsmod` (see `sample/tool_lsmod.cpp`) that you can easily reuse in your projects. +You can find a basic implementations of `netstat` (see `sample/tool_netstat.cpp`) and `lsmod` (see `sample/tool_lsmod.cpp`) that you can easily reuse in your projects. Anyway, here are some cool (and concise) examples: -**Example 1:** Iterater over all the loaded unsigned or out-of-tree kernel modules +**Example 1:** Find all the process that hold an open file descriptor to a specific file: ``` +auto file = "/path/to/file"; auto pfs = pfs::procfs(); -auto modules = pfs.get_modules(); -for (const auto& module : modules) +for (const auto& process : pfs.get_processes()) { - if (module.is_out_of_tree || module.is_unsigned) + for (const auto& thread : process.get_tasks()) { - ... do your work ... + for (const auto& fd : thread.get_fds()) + { + if (fd.get_target() == file) + { + ... do something ... + } + } } } ``` +_Note: This is pedantic implementation that takes into account the fact that a threads might not share the file descriptor with the process, see CLONE_FILES in [clone(2)](https://man7.org/linux/man-pages/man2/clone.2.html)_ + +**Example 2:** Iterate over all the IPv4 TCP sockets currently in listening state (in my current network namespace) and print their local port: +``` +auto filter_listening = [](const net_socket& socket){ + return socket.socket_net_state == pfs::net_socket::net_state::listen; +} + +for (auto& socket : pfs::procfs().get_net().get_tcp(filter_listening)) +{ + std::cout << socket.local_port << std::endl; +} +``` -**Example 2:** Find all the memory maps for task 1234 (This can be both a process or a thread) that start with an ELFs header +**Example 3:** Find all the memory maps for task 1234 (This can be both a process or a thread) that start with an ELFs header ``` auto task = pfs::procfs().get_task(1234); auto mem = task.get_mem(); @@ -122,38 +145,9 @@ for (auto& map : task.get_maps()) static const std::vector ELF_HEADER = { 0x7F, 0x45, 0x4C, 0x46 }; if (mem.read(map.start_address, ELF_HEADER.size()) == ELF_HEADER) { - ... do your work ... - } -} -``` -_(You can either create `pfs` every time or once and keep it, the overhead is really small)_ - -**Example 3:** Iterate over all the IPv4 TCP sockets currently in listening state (in my current network namespace): -``` -// Same as pfs::procfs().get_task().get_net().get_tcp() -for (auto& socket : pfs::procfs().get_net().get_tcp()) -{ - if (socket.socket_net_state == pfs::net_socket::net_state::listen) - { - ... do your work ... - } -} -``` -_(API behaves similar to the `procfs`, where `/proc/net` is a soft link to `/proc/self/net`)_ - -**Example 4:** Get all the IPv6 UDP sockets in the root network namespace belonging to a specific user ID: -``` -for (auto& socket : pfs::procfs().get_task(1).get_net().get_udp6()) -{ - if (socket.uid == ) - { - ... do your work ... + ... do something ... } } ``` +_(You can either create `pfs::procfs()` every time or once and keep it, the overhead is really small)_ -**Example 5:** Check if the process catches SIGSTOP signals -``` -auto status = pfs::procfs().get_task(1234).get_status(); -bool handles_sigstop = status.sig_cgt.is_set(pfs::signal::sigstop); -``` diff --git a/sample/enum_fd.cpp b/sample/enum_fd.cpp index 7cc4712..31d6898 100644 --- a/sample/enum_fd.cpp +++ b/sample/enum_fd.cpp @@ -64,12 +64,10 @@ void enum_task_fds(const pfs::task& task) auto num = iter.first; auto& fd = iter.second; - auto st = fd.get_target_stat(); - auto inode = st.st_ino; - std::ostringstream out; out << "target[" << fd.get_target() << "] "; + auto inode = fd.get_target_stat().st_ino; auto socket = sockets.find(inode); if (socket != sockets.end()) { From a8b92816993cb754164bd456c414a03404a36dfd Mon Sep 17 00:00:00 2001 From: Daniel Trugman Date: Tue, 2 Jan 2024 21:35:16 +0000 Subject: [PATCH 09/11] Add debian12 Dockerfile --- docker/Dockerfile-debian12 | 11 +++++++++++ docker/{Dockerfile-redhat => Dockerfile-redhat8} | 0 docker/{Dockerfile-ubuntu => Dockerfile-ubuntu22} | 0 3 files changed, 11 insertions(+) create mode 100644 docker/Dockerfile-debian12 rename docker/{Dockerfile-redhat => Dockerfile-redhat8} (100%) rename docker/{Dockerfile-ubuntu => Dockerfile-ubuntu22} (100%) diff --git a/docker/Dockerfile-debian12 b/docker/Dockerfile-debian12 new file mode 100644 index 0000000..86b5eb6 --- /dev/null +++ b/docker/Dockerfile-debian12 @@ -0,0 +1,11 @@ +FROM debian:bookworm + +WORKDIR /pfs + +RUN apt-get update && \ + apt-get install -y cmake g++ build-essential + +ENV CXX=g++ +ENV CC=gcc + +CMD /bin/bash diff --git a/docker/Dockerfile-redhat b/docker/Dockerfile-redhat8 similarity index 100% rename from docker/Dockerfile-redhat rename to docker/Dockerfile-redhat8 diff --git a/docker/Dockerfile-ubuntu b/docker/Dockerfile-ubuntu22 similarity index 100% rename from docker/Dockerfile-ubuntu rename to docker/Dockerfile-ubuntu22 From 75b1c12e565130644cf1f0702404e5c4e7a7120e Mon Sep 17 00:00:00 2001 From: Daniel Trugman Date: Tue, 2 Jan 2024 21:35:33 +0000 Subject: [PATCH 10/11] Fix compilation issue with newer compilers --- sample/enum_block.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sample/enum_block.cpp b/sample/enum_block.cpp index b2c3a81..8109c5b 100644 --- a/sample/enum_block.cpp +++ b/sample/enum_block.cpp @@ -15,8 +15,8 @@ */ #include "enum.hpp" -#include "log.hpp" #include "format.hpp" +#include "log.hpp" #include "pfs/sysfs.hpp" From 489bfeace37b6536a945b4c1113235e17260edff Mon Sep 17 00:00:00 2001 From: Daniel Trugman Date: Tue, 2 Jan 2024 21:50:51 +0000 Subject: [PATCH 11/11] Use an enum for the filter return type --- include/pfs/filter.hpp | 31 +++++++++++++++++++++++++++++++ include/pfs/net.hpp | 11 ++++++----- include/pfs/parsers/lines.hpp | 5 +++-- sample/tool_netstat.cpp | 4 +++- test/test_parsers.cpp | 6 ++++-- 5 files changed, 47 insertions(+), 10 deletions(-) create mode 100644 include/pfs/filter.hpp diff --git a/include/pfs/filter.hpp b/include/pfs/filter.hpp new file mode 100644 index 0000000..5338c85 --- /dev/null +++ b/include/pfs/filter.hpp @@ -0,0 +1,31 @@ +/* + * Copyright 2020-present Daniel Trugman + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PFS_FILTER_HPP +#define PFS_FILTER_HPP + +namespace pfs { +namespace filter { + +enum class action { + drop, + keep, +}; + +} // namespace filter +} // namespace pfs + +#endif // PFS_FILTER_HPP diff --git a/include/pfs/net.hpp b/include/pfs/net.hpp index 922b962..723dbd4 100644 --- a/include/pfs/net.hpp +++ b/include/pfs/net.hpp @@ -22,6 +22,7 @@ #include #include "types.hpp" +#include "filter.hpp" namespace pfs { @@ -42,11 +43,11 @@ class net final net& operator=(net&&) = delete; public: - using net_device_filter = std::function; - using net_socket_filter = std::function; - using netlink_socket_filter = std::function; - using unix_socket_filter = std::function; - using net_route_filter = std::function; + using net_device_filter = std::function; + using net_socket_filter = std::function; + using netlink_socket_filter = std::function; + using unix_socket_filter = std::function; + using net_route_filter = std::function; public: std::vector get_dev(net_device_filter filter = nullptr) const; diff --git a/include/pfs/parsers/lines.hpp b/include/pfs/parsers/lines.hpp index bb203d2..5d7327a 100644 --- a/include/pfs/parsers/lines.hpp +++ b/include/pfs/parsers/lines.hpp @@ -22,6 +22,7 @@ #include "pfs/parser_error.hpp" #include "pfs/utils.hpp" +#include "pfs/filter.hpp" namespace pfs { namespace impl { @@ -35,7 +36,7 @@ void parse_file_lines( const std::string& path, Inserter inserter, std::function(const std::string&)> parser, - std::function&)> filter = nullptr, + std::function&)> filter = nullptr, size_t lines_to_skip = 0) { std::ifstream in(path); @@ -59,7 +60,7 @@ void parse_file_lines( auto inserted = parser(line); - if (filter && filter(inserted)) + if (filter && filter(inserted) != filter::action::keep) { continue; } diff --git a/sample/tool_netstat.cpp b/sample/tool_netstat.cpp index e73411e..ca54f50 100644 --- a/sample/tool_netstat.cpp +++ b/sample/tool_netstat.cpp @@ -31,7 +31,9 @@ void task_netstat(const pfs::task& task, const std::string& type) auto inodes = task.get_fds_inodes(); pfs::net::net_socket_filter filter = [&inodes](const pfs::net_socket& sock){ - return inodes.find(sock.inode) == inodes.end(); + return inodes.find(sock.inode) != inodes.end() + ? pfs::filter::action::keep + : pfs::filter::action::drop; }; auto net = task.get_net(); diff --git a/test/test_parsers.cpp b/test/test_parsers.cpp index d909f33..b1cd931 100644 --- a/test/test_parsers.cpp +++ b/test/test_parsers.cpp @@ -70,7 +70,7 @@ TEST_CASE("Parse lines functionality", "[parsers]") std::vector content; std::vector expected; std::vector output; - std::function filter = nullptr; + std::function filter = nullptr; size_t skipped = 0; std::string file; @@ -101,7 +101,9 @@ TEST_CASE("Parse lines functionality", "[parsers]") { content = {"a", "x", "x", "b", "x", "c"}; expected = {"a", "b", "c"}; - filter = [](const std::string& entry) { return entry == "x"; }; + filter = [](const std::string& entry) { + return entry == "x" ? pfs::filter::action::drop : pfs::filter::action::keep; + }; } file = create_temp_file(content);