No version for distro humble showing jazzy. Known supported distros are highlighted in the buttons above.
Repo symbol

pfs repository

pfs

ROS Distro
jazzy

Repository Summary

Checkout URI https://github.com/dtrugman/pfs.git
VCS Type git
VCS Version main
Last Updated 2026-04-12
Dev Status MAINTAINED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Packages

Name Version
pfs 0.13.1

README

pfs

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

Build & Test

Run cmake . && make

Currently supported CMake configuration flags:

  • CMAKE_BUILD_TYPE=<Debug|Release>: Standard CMake flags to control build type (DEFAULT: Debug)
  • pfs_BUILD_SHARED_LIBS=<ON|OFF>: ON to compile a shared library. OFF to compile a static library (DEFAULT: Inherit BUILD_SHARE_LIBS, which is OFF by default))
  • pfs_BUILD_ASAN=<ON|OFF>: ON to enable address sanitizer (DEFAULT: OFF)
  • pfs_BUILD_COVERAGE=<ON|OFF>: ON to enable coverage instrumentation (DEFAULT: OFF)
  • pfs_BUILD_SAMPLES=<ON|OFF>: ON to build the sample programs (DEFAULT: ON)
  • pfs_BUILD_TESTS=<ON|OFF>: ON to build the tests (DEFAULT: ON)

You can pass any number of those to the cmake command: cmake -D<CONFIG_FLAG>=<VALUE> .

NOTE: After running cmake for the first time, some values are cached in CMakeCache.txt and will not change when running cmake for a second time with different flags.

Build using clang

If you prefer using clang, just configure the compiler while running cmake:

CXX=<clang++> CC=<clang> cmake .

After that, just use make as always.

Code Coverage

Generate a coverage report is via Docker:

./docker/docker-pfs coverage

This builds the project with coverage instrumentation, runs all tests, and produces:

  • A text summary printed to the terminal
  • An HTML report at ./coverage/index.html

Integrate

  • Compile as a shared or static library.
  • Add the contents of /lib into your link directories
  • Add the contents of /include into your include directories. That’s it, you are good to go.

Use CMake’s find_package()

Option #1: make install (Preferred way)

After building the project, you can install it locally using make install. In your project’s CMake file, you can then add the following snippet, and CMake will handle the rest:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> pfs)

NOTE: CMake generates an install_manifest.txt file to track all the created files, this will help you uninstall the library if you need to do so.

Option #2: Without make install

Build the pfs project. No need to call make install. In your project’s CMake file, you can then add the following snippet:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> -L${pfs_LIBRARY_DIR} ${pfs_LIBRARIES})
target_include_directories (<your-target> [PUBLIC|PRIVATE] ${pfs_INCLUDE_DIRS})

Features

  • 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

  • The library requires C++11 or newer
  • The library aims to support Linux kernel versions >= 2.6.32.

Notes

General notes

File truncated at 100 lines see the full file

CONTRIBUTING

Contributing to pfs

By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that:

  1. Your contribution is your original work and you have the right to submit it.
  2. Your contribution is submitted under the Apache License 2.0 that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project.
  3. The project author retains complete and sole copyright over the project.

This is consistent with the Developer Certificate of Origin (DCO) 1.1 used across many open-source projects.

Adding a new parser

Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file’s format, implement the parser, wire it in, and add a test.


Pattern 1: kv_file_parser<T> — key-value files

Use this when the file has the form Key: value (one key per line, order irrelevant). Examples: /proc/<pid>/status, /proc/stat.

How it works:

kv_file_parser<T> (in include/pfs/parsers/kv_file_parser.hpp) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name.

Steps:

  1. Add the output type to include/pfs/types.hpp if it doesn’t exist.

  2. Create the parser header in include/pfs/parsers/:

    // include/pfs/parsers/my_file.hpp
    #include "kv_file_parser.hpp"
    #include "pfs/types.hpp"

    namespace pfs { namespace impl { namespace parsers {

    class my_file_parser : public kv_file_parser<my_type>
    {
    public:
        my_file_parser() : kv_file_parser<my_type>(DELIM, PARSERS) {}
    private:
        static const char DELIM;
        static const value_parsers PARSERS;
    };

    }}}
    
  1. Create the parser implementation in src/parsers/:
    // src/parsers/my_file.cpp
    #include "pfs/parsers/my_file.hpp"
    #include "pfs/parsers/number.hpp"

    namespace pfs { namespace impl { namespace parsers {

    const char my_file_parser::DELIM = ':';

    const my_file_parser::value_parsers my_file_parser::PARSERS = {
        {"SomeNumber", [](const std::string& value, my_type& out) {
            to_number(value, out.some_number);
        }},
        {"SomeString", [](const std::string& value, my_type& out) {
            out.some_string = value;
        }},
    };

    }}}
    
  1. Wire it in by adding a getter to the appropriate class (task, net, or procfs) that constructs the parser and calls .parse(path).

  2. Add a unit test in test/. Create a temp file with representative content and assert the parsed fields. See test/test_task_status.cpp for a full example.


Pattern 2: parse_file_lines — tabular/repeated-row files

Use this when each line is an independent record (a row in a table, one entry per line). Examples: /proc/meminfo, /proc/net/tcp, /proc/<pid>/maps.

How it works:

File truncated at 100 lines see the full file

# Contributing to pfs ## License and Copyright By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that: 1. Your contribution is your original work and you have the right to submit it. 2. Your contribution is submitted under the [Apache License 2.0](LICENSE) that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project. 3. The project author retains complete and sole copyright over the project. This is consistent with the [Developer Certificate of Origin (DCO) 1.1](https://developercertificate.org/) used across many open-source projects. ## Adding a new parser Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file's format, implement the parser, wire it in, and add a test. --- ### Pattern 1: `kv_file_parser` — key-value files Use this when the file has the form `Key: value` (one key per line, order irrelevant). Examples: `/proc//status`, `/proc/stat`. **How it works:** `kv_file_parser` (in `include/pfs/parsers/kv_file_parser.hpp`) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name. **Steps:** 1. **Add the output type** to `include/pfs/types.hpp` if it doesn't exist. 2. **Create the parser header** in `include/pfs/parsers/`: ```cpp // include/pfs/parsers/my_file.hpp #include "kv_file_parser.hpp" #include "pfs/types.hpp" namespace pfs { namespace impl { namespace parsers { class my_file_parser : public kv_file_parser { public: my_file_parser() : kv_file_parser(DELIM, PARSERS) {} private: static const char DELIM; static const value_parsers PARSERS; }; }}} ``` 3. **Create the parser implementation** in `src/parsers/`: ```cpp // src/parsers/my_file.cpp #include "pfs/parsers/my_file.hpp" #include "pfs/parsers/number.hpp" namespace pfs { namespace impl { namespace parsers { const char my_file_parser::DELIM = ':'; const my_file_parser::value_parsers my_file_parser::PARSERS = { {"SomeNumber", [](const std::string& value, my_type& out) { to_number(value, out.some_number); }}, {"SomeString", [](const std::string& value, my_type& out) { out.some_string = value; }}, }; }}} ``` 4. **Wire it in** by adding a getter to the appropriate class (`task`, `net`, or `procfs`) that constructs the parser and calls `.parse(path)`. 5. **Add a unit test** in `test/`. Create a temp file with representative content and assert the parsed fields. See `test/test_task_status.cpp` for a full example. --- ### Pattern 2: `parse_file_lines` — tabular/repeated-row files Use this when each line is an independent record (a row in a table, one entry per line). Examples: `/proc/meminfo`, `/proc/net/tcp`, `/proc//maps`. **How it works:** File truncated at 100 lines [see the full file](https://github.com/dtrugman/pfs/tree/main/CONTRIBUTING.md)
Repo symbol

pfs repository

pfs

ROS Distro
jazzy

Repository Summary

Checkout URI https://github.com/dtrugman/pfs.git
VCS Type git
VCS Version main
Last Updated 2026-04-12
Dev Status MAINTAINED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Packages

Name Version
pfs 0.13.1

README

pfs

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

Build & Test

Run cmake . && make

Currently supported CMake configuration flags:

  • CMAKE_BUILD_TYPE=<Debug|Release>: Standard CMake flags to control build type (DEFAULT: Debug)
  • pfs_BUILD_SHARED_LIBS=<ON|OFF>: ON to compile a shared library. OFF to compile a static library (DEFAULT: Inherit BUILD_SHARE_LIBS, which is OFF by default))
  • pfs_BUILD_ASAN=<ON|OFF>: ON to enable address sanitizer (DEFAULT: OFF)
  • pfs_BUILD_COVERAGE=<ON|OFF>: ON to enable coverage instrumentation (DEFAULT: OFF)
  • pfs_BUILD_SAMPLES=<ON|OFF>: ON to build the sample programs (DEFAULT: ON)
  • pfs_BUILD_TESTS=<ON|OFF>: ON to build the tests (DEFAULT: ON)

You can pass any number of those to the cmake command: cmake -D<CONFIG_FLAG>=<VALUE> .

NOTE: After running cmake for the first time, some values are cached in CMakeCache.txt and will not change when running cmake for a second time with different flags.

Build using clang

If you prefer using clang, just configure the compiler while running cmake:

CXX=<clang++> CC=<clang> cmake .

After that, just use make as always.

Code Coverage

Generate a coverage report is via Docker:

./docker/docker-pfs coverage

This builds the project with coverage instrumentation, runs all tests, and produces:

  • A text summary printed to the terminal
  • An HTML report at ./coverage/index.html

Integrate

  • Compile as a shared or static library.
  • Add the contents of /lib into your link directories
  • Add the contents of /include into your include directories. That’s it, you are good to go.

Use CMake’s find_package()

Option #1: make install (Preferred way)

After building the project, you can install it locally using make install. In your project’s CMake file, you can then add the following snippet, and CMake will handle the rest:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> pfs)

NOTE: CMake generates an install_manifest.txt file to track all the created files, this will help you uninstall the library if you need to do so.

Option #2: Without make install

Build the pfs project. No need to call make install. In your project’s CMake file, you can then add the following snippet:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> -L${pfs_LIBRARY_DIR} ${pfs_LIBRARIES})
target_include_directories (<your-target> [PUBLIC|PRIVATE] ${pfs_INCLUDE_DIRS})

Features

  • 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

  • The library requires C++11 or newer
  • The library aims to support Linux kernel versions >= 2.6.32.

Notes

General notes

File truncated at 100 lines see the full file

CONTRIBUTING

Contributing to pfs

By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that:

  1. Your contribution is your original work and you have the right to submit it.
  2. Your contribution is submitted under the Apache License 2.0 that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project.
  3. The project author retains complete and sole copyright over the project.

This is consistent with the Developer Certificate of Origin (DCO) 1.1 used across many open-source projects.

Adding a new parser

Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file’s format, implement the parser, wire it in, and add a test.


Pattern 1: kv_file_parser<T> — key-value files

Use this when the file has the form Key: value (one key per line, order irrelevant). Examples: /proc/<pid>/status, /proc/stat.

How it works:

kv_file_parser<T> (in include/pfs/parsers/kv_file_parser.hpp) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name.

Steps:

  1. Add the output type to include/pfs/types.hpp if it doesn’t exist.

  2. Create the parser header in include/pfs/parsers/:

    // include/pfs/parsers/my_file.hpp
    #include "kv_file_parser.hpp"
    #include "pfs/types.hpp"

    namespace pfs { namespace impl { namespace parsers {

    class my_file_parser : public kv_file_parser<my_type>
    {
    public:
        my_file_parser() : kv_file_parser<my_type>(DELIM, PARSERS) {}
    private:
        static const char DELIM;
        static const value_parsers PARSERS;
    };

    }}}
    
  1. Create the parser implementation in src/parsers/:
    // src/parsers/my_file.cpp
    #include "pfs/parsers/my_file.hpp"
    #include "pfs/parsers/number.hpp"

    namespace pfs { namespace impl { namespace parsers {

    const char my_file_parser::DELIM = ':';

    const my_file_parser::value_parsers my_file_parser::PARSERS = {
        {"SomeNumber", [](const std::string& value, my_type& out) {
            to_number(value, out.some_number);
        }},
        {"SomeString", [](const std::string& value, my_type& out) {
            out.some_string = value;
        }},
    };

    }}}
    
  1. Wire it in by adding a getter to the appropriate class (task, net, or procfs) that constructs the parser and calls .parse(path).

  2. Add a unit test in test/. Create a temp file with representative content and assert the parsed fields. See test/test_task_status.cpp for a full example.


Pattern 2: parse_file_lines — tabular/repeated-row files

Use this when each line is an independent record (a row in a table, one entry per line). Examples: /proc/meminfo, /proc/net/tcp, /proc/<pid>/maps.

How it works:

File truncated at 100 lines see the full file

# Contributing to pfs ## License and Copyright By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that: 1. Your contribution is your original work and you have the right to submit it. 2. Your contribution is submitted under the [Apache License 2.0](LICENSE) that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project. 3. The project author retains complete and sole copyright over the project. This is consistent with the [Developer Certificate of Origin (DCO) 1.1](https://developercertificate.org/) used across many open-source projects. ## Adding a new parser Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file's format, implement the parser, wire it in, and add a test. --- ### Pattern 1: `kv_file_parser` — key-value files Use this when the file has the form `Key: value` (one key per line, order irrelevant). Examples: `/proc//status`, `/proc/stat`. **How it works:** `kv_file_parser` (in `include/pfs/parsers/kv_file_parser.hpp`) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name. **Steps:** 1. **Add the output type** to `include/pfs/types.hpp` if it doesn't exist. 2. **Create the parser header** in `include/pfs/parsers/`: ```cpp // include/pfs/parsers/my_file.hpp #include "kv_file_parser.hpp" #include "pfs/types.hpp" namespace pfs { namespace impl { namespace parsers { class my_file_parser : public kv_file_parser { public: my_file_parser() : kv_file_parser(DELIM, PARSERS) {} private: static const char DELIM; static const value_parsers PARSERS; }; }}} ``` 3. **Create the parser implementation** in `src/parsers/`: ```cpp // src/parsers/my_file.cpp #include "pfs/parsers/my_file.hpp" #include "pfs/parsers/number.hpp" namespace pfs { namespace impl { namespace parsers { const char my_file_parser::DELIM = ':'; const my_file_parser::value_parsers my_file_parser::PARSERS = { {"SomeNumber", [](const std::string& value, my_type& out) { to_number(value, out.some_number); }}, {"SomeString", [](const std::string& value, my_type& out) { out.some_string = value; }}, }; }}} ``` 4. **Wire it in** by adding a getter to the appropriate class (`task`, `net`, or `procfs`) that constructs the parser and calls `.parse(path)`. 5. **Add a unit test** in `test/`. Create a temp file with representative content and assert the parsed fields. See `test/test_task_status.cpp` for a full example. --- ### Pattern 2: `parse_file_lines` — tabular/repeated-row files Use this when each line is an independent record (a row in a table, one entry per line). Examples: `/proc/meminfo`, `/proc/net/tcp`, `/proc//maps`. **How it works:** File truncated at 100 lines [see the full file](https://github.com/dtrugman/pfs/tree/main/CONTRIBUTING.md)
Repo symbol

pfs repository

pfs

ROS Distro
kilted

Repository Summary

Checkout URI https://github.com/dtrugman/pfs.git
VCS Type git
VCS Version main
Last Updated 2026-04-12
Dev Status MAINTAINED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Packages

Name Version
pfs 0.13.1

README

pfs

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

Build & Test

Run cmake . && make

Currently supported CMake configuration flags:

  • CMAKE_BUILD_TYPE=<Debug|Release>: Standard CMake flags to control build type (DEFAULT: Debug)
  • pfs_BUILD_SHARED_LIBS=<ON|OFF>: ON to compile a shared library. OFF to compile a static library (DEFAULT: Inherit BUILD_SHARE_LIBS, which is OFF by default))
  • pfs_BUILD_ASAN=<ON|OFF>: ON to enable address sanitizer (DEFAULT: OFF)
  • pfs_BUILD_COVERAGE=<ON|OFF>: ON to enable coverage instrumentation (DEFAULT: OFF)
  • pfs_BUILD_SAMPLES=<ON|OFF>: ON to build the sample programs (DEFAULT: ON)
  • pfs_BUILD_TESTS=<ON|OFF>: ON to build the tests (DEFAULT: ON)

You can pass any number of those to the cmake command: cmake -D<CONFIG_FLAG>=<VALUE> .

NOTE: After running cmake for the first time, some values are cached in CMakeCache.txt and will not change when running cmake for a second time with different flags.

Build using clang

If you prefer using clang, just configure the compiler while running cmake:

CXX=<clang++> CC=<clang> cmake .

After that, just use make as always.

Code Coverage

Generate a coverage report is via Docker:

./docker/docker-pfs coverage

This builds the project with coverage instrumentation, runs all tests, and produces:

  • A text summary printed to the terminal
  • An HTML report at ./coverage/index.html

Integrate

  • Compile as a shared or static library.
  • Add the contents of /lib into your link directories
  • Add the contents of /include into your include directories. That’s it, you are good to go.

Use CMake’s find_package()

Option #1: make install (Preferred way)

After building the project, you can install it locally using make install. In your project’s CMake file, you can then add the following snippet, and CMake will handle the rest:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> pfs)

NOTE: CMake generates an install_manifest.txt file to track all the created files, this will help you uninstall the library if you need to do so.

Option #2: Without make install

Build the pfs project. No need to call make install. In your project’s CMake file, you can then add the following snippet:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> -L${pfs_LIBRARY_DIR} ${pfs_LIBRARIES})
target_include_directories (<your-target> [PUBLIC|PRIVATE] ${pfs_INCLUDE_DIRS})

Features

  • 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

  • The library requires C++11 or newer
  • The library aims to support Linux kernel versions >= 2.6.32.

Notes

General notes

File truncated at 100 lines see the full file

CONTRIBUTING

Contributing to pfs

By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that:

  1. Your contribution is your original work and you have the right to submit it.
  2. Your contribution is submitted under the Apache License 2.0 that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project.
  3. The project author retains complete and sole copyright over the project.

This is consistent with the Developer Certificate of Origin (DCO) 1.1 used across many open-source projects.

Adding a new parser

Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file’s format, implement the parser, wire it in, and add a test.


Pattern 1: kv_file_parser<T> — key-value files

Use this when the file has the form Key: value (one key per line, order irrelevant). Examples: /proc/<pid>/status, /proc/stat.

How it works:

kv_file_parser<T> (in include/pfs/parsers/kv_file_parser.hpp) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name.

Steps:

  1. Add the output type to include/pfs/types.hpp if it doesn’t exist.

  2. Create the parser header in include/pfs/parsers/:

    // include/pfs/parsers/my_file.hpp
    #include "kv_file_parser.hpp"
    #include "pfs/types.hpp"

    namespace pfs { namespace impl { namespace parsers {

    class my_file_parser : public kv_file_parser<my_type>
    {
    public:
        my_file_parser() : kv_file_parser<my_type>(DELIM, PARSERS) {}
    private:
        static const char DELIM;
        static const value_parsers PARSERS;
    };

    }}}
    
  1. Create the parser implementation in src/parsers/:
    // src/parsers/my_file.cpp
    #include "pfs/parsers/my_file.hpp"
    #include "pfs/parsers/number.hpp"

    namespace pfs { namespace impl { namespace parsers {

    const char my_file_parser::DELIM = ':';

    const my_file_parser::value_parsers my_file_parser::PARSERS = {
        {"SomeNumber", [](const std::string& value, my_type& out) {
            to_number(value, out.some_number);
        }},
        {"SomeString", [](const std::string& value, my_type& out) {
            out.some_string = value;
        }},
    };

    }}}
    
  1. Wire it in by adding a getter to the appropriate class (task, net, or procfs) that constructs the parser and calls .parse(path).

  2. Add a unit test in test/. Create a temp file with representative content and assert the parsed fields. See test/test_task_status.cpp for a full example.


Pattern 2: parse_file_lines — tabular/repeated-row files

Use this when each line is an independent record (a row in a table, one entry per line). Examples: /proc/meminfo, /proc/net/tcp, /proc/<pid>/maps.

How it works:

File truncated at 100 lines see the full file

# Contributing to pfs ## License and Copyright By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that: 1. Your contribution is your original work and you have the right to submit it. 2. Your contribution is submitted under the [Apache License 2.0](LICENSE) that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project. 3. The project author retains complete and sole copyright over the project. This is consistent with the [Developer Certificate of Origin (DCO) 1.1](https://developercertificate.org/) used across many open-source projects. ## Adding a new parser Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file's format, implement the parser, wire it in, and add a test. --- ### Pattern 1: `kv_file_parser` — key-value files Use this when the file has the form `Key: value` (one key per line, order irrelevant). Examples: `/proc//status`, `/proc/stat`. **How it works:** `kv_file_parser` (in `include/pfs/parsers/kv_file_parser.hpp`) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name. **Steps:** 1. **Add the output type** to `include/pfs/types.hpp` if it doesn't exist. 2. **Create the parser header** in `include/pfs/parsers/`: ```cpp // include/pfs/parsers/my_file.hpp #include "kv_file_parser.hpp" #include "pfs/types.hpp" namespace pfs { namespace impl { namespace parsers { class my_file_parser : public kv_file_parser { public: my_file_parser() : kv_file_parser(DELIM, PARSERS) {} private: static const char DELIM; static const value_parsers PARSERS; }; }}} ``` 3. **Create the parser implementation** in `src/parsers/`: ```cpp // src/parsers/my_file.cpp #include "pfs/parsers/my_file.hpp" #include "pfs/parsers/number.hpp" namespace pfs { namespace impl { namespace parsers { const char my_file_parser::DELIM = ':'; const my_file_parser::value_parsers my_file_parser::PARSERS = { {"SomeNumber", [](const std::string& value, my_type& out) { to_number(value, out.some_number); }}, {"SomeString", [](const std::string& value, my_type& out) { out.some_string = value; }}, }; }}} ``` 4. **Wire it in** by adding a getter to the appropriate class (`task`, `net`, or `procfs`) that constructs the parser and calls `.parse(path)`. 5. **Add a unit test** in `test/`. Create a temp file with representative content and assert the parsed fields. See `test/test_task_status.cpp` for a full example. --- ### Pattern 2: `parse_file_lines` — tabular/repeated-row files Use this when each line is an independent record (a row in a table, one entry per line). Examples: `/proc/meminfo`, `/proc/net/tcp`, `/proc//maps`. **How it works:** File truncated at 100 lines [see the full file](https://github.com/dtrugman/pfs/tree/main/CONTRIBUTING.md)
No version for distro rolling showing jazzy. Known supported distros are highlighted in the buttons above.
Repo symbol

pfs repository

pfs

ROS Distro
jazzy

Repository Summary

Checkout URI https://github.com/dtrugman/pfs.git
VCS Type git
VCS Version main
Last Updated 2026-04-12
Dev Status MAINTAINED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Packages

Name Version
pfs 0.13.1

README

pfs

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

Build & Test

Run cmake . && make

Currently supported CMake configuration flags:

  • CMAKE_BUILD_TYPE=<Debug|Release>: Standard CMake flags to control build type (DEFAULT: Debug)
  • pfs_BUILD_SHARED_LIBS=<ON|OFF>: ON to compile a shared library. OFF to compile a static library (DEFAULT: Inherit BUILD_SHARE_LIBS, which is OFF by default))
  • pfs_BUILD_ASAN=<ON|OFF>: ON to enable address sanitizer (DEFAULT: OFF)
  • pfs_BUILD_COVERAGE=<ON|OFF>: ON to enable coverage instrumentation (DEFAULT: OFF)
  • pfs_BUILD_SAMPLES=<ON|OFF>: ON to build the sample programs (DEFAULT: ON)
  • pfs_BUILD_TESTS=<ON|OFF>: ON to build the tests (DEFAULT: ON)

You can pass any number of those to the cmake command: cmake -D<CONFIG_FLAG>=<VALUE> .

NOTE: After running cmake for the first time, some values are cached in CMakeCache.txt and will not change when running cmake for a second time with different flags.

Build using clang

If you prefer using clang, just configure the compiler while running cmake:

CXX=<clang++> CC=<clang> cmake .

After that, just use make as always.

Code Coverage

Generate a coverage report is via Docker:

./docker/docker-pfs coverage

This builds the project with coverage instrumentation, runs all tests, and produces:

  • A text summary printed to the terminal
  • An HTML report at ./coverage/index.html

Integrate

  • Compile as a shared or static library.
  • Add the contents of /lib into your link directories
  • Add the contents of /include into your include directories. That’s it, you are good to go.

Use CMake’s find_package()

Option #1: make install (Preferred way)

After building the project, you can install it locally using make install. In your project’s CMake file, you can then add the following snippet, and CMake will handle the rest:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> pfs)

NOTE: CMake generates an install_manifest.txt file to track all the created files, this will help you uninstall the library if you need to do so.

Option #2: Without make install

Build the pfs project. No need to call make install. In your project’s CMake file, you can then add the following snippet:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> -L${pfs_LIBRARY_DIR} ${pfs_LIBRARIES})
target_include_directories (<your-target> [PUBLIC|PRIVATE] ${pfs_INCLUDE_DIRS})

Features

  • 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

  • The library requires C++11 or newer
  • The library aims to support Linux kernel versions >= 2.6.32.

Notes

General notes

File truncated at 100 lines see the full file

CONTRIBUTING

Contributing to pfs

By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that:

  1. Your contribution is your original work and you have the right to submit it.
  2. Your contribution is submitted under the Apache License 2.0 that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project.
  3. The project author retains complete and sole copyright over the project.

This is consistent with the Developer Certificate of Origin (DCO) 1.1 used across many open-source projects.

Adding a new parser

Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file’s format, implement the parser, wire it in, and add a test.


Pattern 1: kv_file_parser<T> — key-value files

Use this when the file has the form Key: value (one key per line, order irrelevant). Examples: /proc/<pid>/status, /proc/stat.

How it works:

kv_file_parser<T> (in include/pfs/parsers/kv_file_parser.hpp) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name.

Steps:

  1. Add the output type to include/pfs/types.hpp if it doesn’t exist.

  2. Create the parser header in include/pfs/parsers/:

    // include/pfs/parsers/my_file.hpp
    #include "kv_file_parser.hpp"
    #include "pfs/types.hpp"

    namespace pfs { namespace impl { namespace parsers {

    class my_file_parser : public kv_file_parser<my_type>
    {
    public:
        my_file_parser() : kv_file_parser<my_type>(DELIM, PARSERS) {}
    private:
        static const char DELIM;
        static const value_parsers PARSERS;
    };

    }}}
    
  1. Create the parser implementation in src/parsers/:
    // src/parsers/my_file.cpp
    #include "pfs/parsers/my_file.hpp"
    #include "pfs/parsers/number.hpp"

    namespace pfs { namespace impl { namespace parsers {

    const char my_file_parser::DELIM = ':';

    const my_file_parser::value_parsers my_file_parser::PARSERS = {
        {"SomeNumber", [](const std::string& value, my_type& out) {
            to_number(value, out.some_number);
        }},
        {"SomeString", [](const std::string& value, my_type& out) {
            out.some_string = value;
        }},
    };

    }}}
    
  1. Wire it in by adding a getter to the appropriate class (task, net, or procfs) that constructs the parser and calls .parse(path).

  2. Add a unit test in test/. Create a temp file with representative content and assert the parsed fields. See test/test_task_status.cpp for a full example.


Pattern 2: parse_file_lines — tabular/repeated-row files

Use this when each line is an independent record (a row in a table, one entry per line). Examples: /proc/meminfo, /proc/net/tcp, /proc/<pid>/maps.

How it works:

File truncated at 100 lines see the full file

# Contributing to pfs ## License and Copyright By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that: 1. Your contribution is your original work and you have the right to submit it. 2. Your contribution is submitted under the [Apache License 2.0](LICENSE) that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project. 3. The project author retains complete and sole copyright over the project. This is consistent with the [Developer Certificate of Origin (DCO) 1.1](https://developercertificate.org/) used across many open-source projects. ## Adding a new parser Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file's format, implement the parser, wire it in, and add a test. --- ### Pattern 1: `kv_file_parser` — key-value files Use this when the file has the form `Key: value` (one key per line, order irrelevant). Examples: `/proc//status`, `/proc/stat`. **How it works:** `kv_file_parser` (in `include/pfs/parsers/kv_file_parser.hpp`) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name. **Steps:** 1. **Add the output type** to `include/pfs/types.hpp` if it doesn't exist. 2. **Create the parser header** in `include/pfs/parsers/`: ```cpp // include/pfs/parsers/my_file.hpp #include "kv_file_parser.hpp" #include "pfs/types.hpp" namespace pfs { namespace impl { namespace parsers { class my_file_parser : public kv_file_parser { public: my_file_parser() : kv_file_parser(DELIM, PARSERS) {} private: static const char DELIM; static const value_parsers PARSERS; }; }}} ``` 3. **Create the parser implementation** in `src/parsers/`: ```cpp // src/parsers/my_file.cpp #include "pfs/parsers/my_file.hpp" #include "pfs/parsers/number.hpp" namespace pfs { namespace impl { namespace parsers { const char my_file_parser::DELIM = ':'; const my_file_parser::value_parsers my_file_parser::PARSERS = { {"SomeNumber", [](const std::string& value, my_type& out) { to_number(value, out.some_number); }}, {"SomeString", [](const std::string& value, my_type& out) { out.some_string = value; }}, }; }}} ``` 4. **Wire it in** by adding a getter to the appropriate class (`task`, `net`, or `procfs`) that constructs the parser and calls `.parse(path)`. 5. **Add a unit test** in `test/`. Create a temp file with representative content and assert the parsed fields. See `test/test_task_status.cpp` for a full example. --- ### Pattern 2: `parse_file_lines` — tabular/repeated-row files Use this when each line is an independent record (a row in a table, one entry per line). Examples: `/proc/meminfo`, `/proc/net/tcp`, `/proc//maps`. **How it works:** File truncated at 100 lines [see the full file](https://github.com/dtrugman/pfs/tree/main/CONTRIBUTING.md)
No version for distro ardent showing jazzy. Known supported distros are highlighted in the buttons above.
Repo symbol

pfs repository

pfs

ROS Distro
jazzy

Repository Summary

Checkout URI https://github.com/dtrugman/pfs.git
VCS Type git
VCS Version main
Last Updated 2026-04-12
Dev Status MAINTAINED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Packages

Name Version
pfs 0.13.1

README

pfs

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

Build & Test

Run cmake . && make

Currently supported CMake configuration flags:

  • CMAKE_BUILD_TYPE=<Debug|Release>: Standard CMake flags to control build type (DEFAULT: Debug)
  • pfs_BUILD_SHARED_LIBS=<ON|OFF>: ON to compile a shared library. OFF to compile a static library (DEFAULT: Inherit BUILD_SHARE_LIBS, which is OFF by default))
  • pfs_BUILD_ASAN=<ON|OFF>: ON to enable address sanitizer (DEFAULT: OFF)
  • pfs_BUILD_COVERAGE=<ON|OFF>: ON to enable coverage instrumentation (DEFAULT: OFF)
  • pfs_BUILD_SAMPLES=<ON|OFF>: ON to build the sample programs (DEFAULT: ON)
  • pfs_BUILD_TESTS=<ON|OFF>: ON to build the tests (DEFAULT: ON)

You can pass any number of those to the cmake command: cmake -D<CONFIG_FLAG>=<VALUE> .

NOTE: After running cmake for the first time, some values are cached in CMakeCache.txt and will not change when running cmake for a second time with different flags.

Build using clang

If you prefer using clang, just configure the compiler while running cmake:

CXX=<clang++> CC=<clang> cmake .

After that, just use make as always.

Code Coverage

Generate a coverage report is via Docker:

./docker/docker-pfs coverage

This builds the project with coverage instrumentation, runs all tests, and produces:

  • A text summary printed to the terminal
  • An HTML report at ./coverage/index.html

Integrate

  • Compile as a shared or static library.
  • Add the contents of /lib into your link directories
  • Add the contents of /include into your include directories. That’s it, you are good to go.

Use CMake’s find_package()

Option #1: make install (Preferred way)

After building the project, you can install it locally using make install. In your project’s CMake file, you can then add the following snippet, and CMake will handle the rest:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> pfs)

NOTE: CMake generates an install_manifest.txt file to track all the created files, this will help you uninstall the library if you need to do so.

Option #2: Without make install

Build the pfs project. No need to call make install. In your project’s CMake file, you can then add the following snippet:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> -L${pfs_LIBRARY_DIR} ${pfs_LIBRARIES})
target_include_directories (<your-target> [PUBLIC|PRIVATE] ${pfs_INCLUDE_DIRS})

Features

  • 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

  • The library requires C++11 or newer
  • The library aims to support Linux kernel versions >= 2.6.32.

Notes

General notes

File truncated at 100 lines see the full file

CONTRIBUTING

Contributing to pfs

By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that:

  1. Your contribution is your original work and you have the right to submit it.
  2. Your contribution is submitted under the Apache License 2.0 that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project.
  3. The project author retains complete and sole copyright over the project.

This is consistent with the Developer Certificate of Origin (DCO) 1.1 used across many open-source projects.

Adding a new parser

Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file’s format, implement the parser, wire it in, and add a test.


Pattern 1: kv_file_parser<T> — key-value files

Use this when the file has the form Key: value (one key per line, order irrelevant). Examples: /proc/<pid>/status, /proc/stat.

How it works:

kv_file_parser<T> (in include/pfs/parsers/kv_file_parser.hpp) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name.

Steps:

  1. Add the output type to include/pfs/types.hpp if it doesn’t exist.

  2. Create the parser header in include/pfs/parsers/:

    // include/pfs/parsers/my_file.hpp
    #include "kv_file_parser.hpp"
    #include "pfs/types.hpp"

    namespace pfs { namespace impl { namespace parsers {

    class my_file_parser : public kv_file_parser<my_type>
    {
    public:
        my_file_parser() : kv_file_parser<my_type>(DELIM, PARSERS) {}
    private:
        static const char DELIM;
        static const value_parsers PARSERS;
    };

    }}}
    
  1. Create the parser implementation in src/parsers/:
    // src/parsers/my_file.cpp
    #include "pfs/parsers/my_file.hpp"
    #include "pfs/parsers/number.hpp"

    namespace pfs { namespace impl { namespace parsers {

    const char my_file_parser::DELIM = ':';

    const my_file_parser::value_parsers my_file_parser::PARSERS = {
        {"SomeNumber", [](const std::string& value, my_type& out) {
            to_number(value, out.some_number);
        }},
        {"SomeString", [](const std::string& value, my_type& out) {
            out.some_string = value;
        }},
    };

    }}}
    
  1. Wire it in by adding a getter to the appropriate class (task, net, or procfs) that constructs the parser and calls .parse(path).

  2. Add a unit test in test/. Create a temp file with representative content and assert the parsed fields. See test/test_task_status.cpp for a full example.


Pattern 2: parse_file_lines — tabular/repeated-row files

Use this when each line is an independent record (a row in a table, one entry per line). Examples: /proc/meminfo, /proc/net/tcp, /proc/<pid>/maps.

How it works:

File truncated at 100 lines see the full file

# Contributing to pfs ## License and Copyright By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that: 1. Your contribution is your original work and you have the right to submit it. 2. Your contribution is submitted under the [Apache License 2.0](LICENSE) that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project. 3. The project author retains complete and sole copyright over the project. This is consistent with the [Developer Certificate of Origin (DCO) 1.1](https://developercertificate.org/) used across many open-source projects. ## Adding a new parser Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file's format, implement the parser, wire it in, and add a test. --- ### Pattern 1: `kv_file_parser` — key-value files Use this when the file has the form `Key: value` (one key per line, order irrelevant). Examples: `/proc//status`, `/proc/stat`. **How it works:** `kv_file_parser` (in `include/pfs/parsers/kv_file_parser.hpp`) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name. **Steps:** 1. **Add the output type** to `include/pfs/types.hpp` if it doesn't exist. 2. **Create the parser header** in `include/pfs/parsers/`: ```cpp // include/pfs/parsers/my_file.hpp #include "kv_file_parser.hpp" #include "pfs/types.hpp" namespace pfs { namespace impl { namespace parsers { class my_file_parser : public kv_file_parser { public: my_file_parser() : kv_file_parser(DELIM, PARSERS) {} private: static const char DELIM; static const value_parsers PARSERS; }; }}} ``` 3. **Create the parser implementation** in `src/parsers/`: ```cpp // src/parsers/my_file.cpp #include "pfs/parsers/my_file.hpp" #include "pfs/parsers/number.hpp" namespace pfs { namespace impl { namespace parsers { const char my_file_parser::DELIM = ':'; const my_file_parser::value_parsers my_file_parser::PARSERS = { {"SomeNumber", [](const std::string& value, my_type& out) { to_number(value, out.some_number); }}, {"SomeString", [](const std::string& value, my_type& out) { out.some_string = value; }}, }; }}} ``` 4. **Wire it in** by adding a getter to the appropriate class (`task`, `net`, or `procfs`) that constructs the parser and calls `.parse(path)`. 5. **Add a unit test** in `test/`. Create a temp file with representative content and assert the parsed fields. See `test/test_task_status.cpp` for a full example. --- ### Pattern 2: `parse_file_lines` — tabular/repeated-row files Use this when each line is an independent record (a row in a table, one entry per line). Examples: `/proc/meminfo`, `/proc/net/tcp`, `/proc//maps`. **How it works:** File truncated at 100 lines [see the full file](https://github.com/dtrugman/pfs/tree/main/CONTRIBUTING.md)
No version for distro bouncy showing jazzy. Known supported distros are highlighted in the buttons above.
Repo symbol

pfs repository

pfs

ROS Distro
jazzy

Repository Summary

Checkout URI https://github.com/dtrugman/pfs.git
VCS Type git
VCS Version main
Last Updated 2026-04-12
Dev Status MAINTAINED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Packages

Name Version
pfs 0.13.1

README

pfs

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

Build & Test

Run cmake . && make

Currently supported CMake configuration flags:

  • CMAKE_BUILD_TYPE=<Debug|Release>: Standard CMake flags to control build type (DEFAULT: Debug)
  • pfs_BUILD_SHARED_LIBS=<ON|OFF>: ON to compile a shared library. OFF to compile a static library (DEFAULT: Inherit BUILD_SHARE_LIBS, which is OFF by default))
  • pfs_BUILD_ASAN=<ON|OFF>: ON to enable address sanitizer (DEFAULT: OFF)
  • pfs_BUILD_COVERAGE=<ON|OFF>: ON to enable coverage instrumentation (DEFAULT: OFF)
  • pfs_BUILD_SAMPLES=<ON|OFF>: ON to build the sample programs (DEFAULT: ON)
  • pfs_BUILD_TESTS=<ON|OFF>: ON to build the tests (DEFAULT: ON)

You can pass any number of those to the cmake command: cmake -D<CONFIG_FLAG>=<VALUE> .

NOTE: After running cmake for the first time, some values are cached in CMakeCache.txt and will not change when running cmake for a second time with different flags.

Build using clang

If you prefer using clang, just configure the compiler while running cmake:

CXX=<clang++> CC=<clang> cmake .

After that, just use make as always.

Code Coverage

Generate a coverage report is via Docker:

./docker/docker-pfs coverage

This builds the project with coverage instrumentation, runs all tests, and produces:

  • A text summary printed to the terminal
  • An HTML report at ./coverage/index.html

Integrate

  • Compile as a shared or static library.
  • Add the contents of /lib into your link directories
  • Add the contents of /include into your include directories. That’s it, you are good to go.

Use CMake’s find_package()

Option #1: make install (Preferred way)

After building the project, you can install it locally using make install. In your project’s CMake file, you can then add the following snippet, and CMake will handle the rest:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> pfs)

NOTE: CMake generates an install_manifest.txt file to track all the created files, this will help you uninstall the library if you need to do so.

Option #2: Without make install

Build the pfs project. No need to call make install. In your project’s CMake file, you can then add the following snippet:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> -L${pfs_LIBRARY_DIR} ${pfs_LIBRARIES})
target_include_directories (<your-target> [PUBLIC|PRIVATE] ${pfs_INCLUDE_DIRS})

Features

  • 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

  • The library requires C++11 or newer
  • The library aims to support Linux kernel versions >= 2.6.32.

Notes

General notes

File truncated at 100 lines see the full file

CONTRIBUTING

Contributing to pfs

By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that:

  1. Your contribution is your original work and you have the right to submit it.
  2. Your contribution is submitted under the Apache License 2.0 that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project.
  3. The project author retains complete and sole copyright over the project.

This is consistent with the Developer Certificate of Origin (DCO) 1.1 used across many open-source projects.

Adding a new parser

Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file’s format, implement the parser, wire it in, and add a test.


Pattern 1: kv_file_parser<T> — key-value files

Use this when the file has the form Key: value (one key per line, order irrelevant). Examples: /proc/<pid>/status, /proc/stat.

How it works:

kv_file_parser<T> (in include/pfs/parsers/kv_file_parser.hpp) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name.

Steps:

  1. Add the output type to include/pfs/types.hpp if it doesn’t exist.

  2. Create the parser header in include/pfs/parsers/:

    // include/pfs/parsers/my_file.hpp
    #include "kv_file_parser.hpp"
    #include "pfs/types.hpp"

    namespace pfs { namespace impl { namespace parsers {

    class my_file_parser : public kv_file_parser<my_type>
    {
    public:
        my_file_parser() : kv_file_parser<my_type>(DELIM, PARSERS) {}
    private:
        static const char DELIM;
        static const value_parsers PARSERS;
    };

    }}}
    
  1. Create the parser implementation in src/parsers/:
    // src/parsers/my_file.cpp
    #include "pfs/parsers/my_file.hpp"
    #include "pfs/parsers/number.hpp"

    namespace pfs { namespace impl { namespace parsers {

    const char my_file_parser::DELIM = ':';

    const my_file_parser::value_parsers my_file_parser::PARSERS = {
        {"SomeNumber", [](const std::string& value, my_type& out) {
            to_number(value, out.some_number);
        }},
        {"SomeString", [](const std::string& value, my_type& out) {
            out.some_string = value;
        }},
    };

    }}}
    
  1. Wire it in by adding a getter to the appropriate class (task, net, or procfs) that constructs the parser and calls .parse(path).

  2. Add a unit test in test/. Create a temp file with representative content and assert the parsed fields. See test/test_task_status.cpp for a full example.


Pattern 2: parse_file_lines — tabular/repeated-row files

Use this when each line is an independent record (a row in a table, one entry per line). Examples: /proc/meminfo, /proc/net/tcp, /proc/<pid>/maps.

How it works:

File truncated at 100 lines see the full file

# Contributing to pfs ## License and Copyright By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that: 1. Your contribution is your original work and you have the right to submit it. 2. Your contribution is submitted under the [Apache License 2.0](LICENSE) that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project. 3. The project author retains complete and sole copyright over the project. This is consistent with the [Developer Certificate of Origin (DCO) 1.1](https://developercertificate.org/) used across many open-source projects. ## Adding a new parser Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file's format, implement the parser, wire it in, and add a test. --- ### Pattern 1: `kv_file_parser` — key-value files Use this when the file has the form `Key: value` (one key per line, order irrelevant). Examples: `/proc//status`, `/proc/stat`. **How it works:** `kv_file_parser` (in `include/pfs/parsers/kv_file_parser.hpp`) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name. **Steps:** 1. **Add the output type** to `include/pfs/types.hpp` if it doesn't exist. 2. **Create the parser header** in `include/pfs/parsers/`: ```cpp // include/pfs/parsers/my_file.hpp #include "kv_file_parser.hpp" #include "pfs/types.hpp" namespace pfs { namespace impl { namespace parsers { class my_file_parser : public kv_file_parser { public: my_file_parser() : kv_file_parser(DELIM, PARSERS) {} private: static const char DELIM; static const value_parsers PARSERS; }; }}} ``` 3. **Create the parser implementation** in `src/parsers/`: ```cpp // src/parsers/my_file.cpp #include "pfs/parsers/my_file.hpp" #include "pfs/parsers/number.hpp" namespace pfs { namespace impl { namespace parsers { const char my_file_parser::DELIM = ':'; const my_file_parser::value_parsers my_file_parser::PARSERS = { {"SomeNumber", [](const std::string& value, my_type& out) { to_number(value, out.some_number); }}, {"SomeString", [](const std::string& value, my_type& out) { out.some_string = value; }}, }; }}} ``` 4. **Wire it in** by adding a getter to the appropriate class (`task`, `net`, or `procfs`) that constructs the parser and calls `.parse(path)`. 5. **Add a unit test** in `test/`. Create a temp file with representative content and assert the parsed fields. See `test/test_task_status.cpp` for a full example. --- ### Pattern 2: `parse_file_lines` — tabular/repeated-row files Use this when each line is an independent record (a row in a table, one entry per line). Examples: `/proc/meminfo`, `/proc/net/tcp`, `/proc//maps`. **How it works:** File truncated at 100 lines [see the full file](https://github.com/dtrugman/pfs/tree/main/CONTRIBUTING.md)
No version for distro crystal showing jazzy. Known supported distros are highlighted in the buttons above.
Repo symbol

pfs repository

pfs

ROS Distro
jazzy

Repository Summary

Checkout URI https://github.com/dtrugman/pfs.git
VCS Type git
VCS Version main
Last Updated 2026-04-12
Dev Status MAINTAINED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Packages

Name Version
pfs 0.13.1

README

pfs

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

Build & Test

Run cmake . && make

Currently supported CMake configuration flags:

  • CMAKE_BUILD_TYPE=<Debug|Release>: Standard CMake flags to control build type (DEFAULT: Debug)
  • pfs_BUILD_SHARED_LIBS=<ON|OFF>: ON to compile a shared library. OFF to compile a static library (DEFAULT: Inherit BUILD_SHARE_LIBS, which is OFF by default))
  • pfs_BUILD_ASAN=<ON|OFF>: ON to enable address sanitizer (DEFAULT: OFF)
  • pfs_BUILD_COVERAGE=<ON|OFF>: ON to enable coverage instrumentation (DEFAULT: OFF)
  • pfs_BUILD_SAMPLES=<ON|OFF>: ON to build the sample programs (DEFAULT: ON)
  • pfs_BUILD_TESTS=<ON|OFF>: ON to build the tests (DEFAULT: ON)

You can pass any number of those to the cmake command: cmake -D<CONFIG_FLAG>=<VALUE> .

NOTE: After running cmake for the first time, some values are cached in CMakeCache.txt and will not change when running cmake for a second time with different flags.

Build using clang

If you prefer using clang, just configure the compiler while running cmake:

CXX=<clang++> CC=<clang> cmake .

After that, just use make as always.

Code Coverage

Generate a coverage report is via Docker:

./docker/docker-pfs coverage

This builds the project with coverage instrumentation, runs all tests, and produces:

  • A text summary printed to the terminal
  • An HTML report at ./coverage/index.html

Integrate

  • Compile as a shared or static library.
  • Add the contents of /lib into your link directories
  • Add the contents of /include into your include directories. That’s it, you are good to go.

Use CMake’s find_package()

Option #1: make install (Preferred way)

After building the project, you can install it locally using make install. In your project’s CMake file, you can then add the following snippet, and CMake will handle the rest:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> pfs)

NOTE: CMake generates an install_manifest.txt file to track all the created files, this will help you uninstall the library if you need to do so.

Option #2: Without make install

Build the pfs project. No need to call make install. In your project’s CMake file, you can then add the following snippet:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> -L${pfs_LIBRARY_DIR} ${pfs_LIBRARIES})
target_include_directories (<your-target> [PUBLIC|PRIVATE] ${pfs_INCLUDE_DIRS})

Features

  • 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

  • The library requires C++11 or newer
  • The library aims to support Linux kernel versions >= 2.6.32.

Notes

General notes

File truncated at 100 lines see the full file

CONTRIBUTING

Contributing to pfs

By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that:

  1. Your contribution is your original work and you have the right to submit it.
  2. Your contribution is submitted under the Apache License 2.0 that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project.
  3. The project author retains complete and sole copyright over the project.

This is consistent with the Developer Certificate of Origin (DCO) 1.1 used across many open-source projects.

Adding a new parser

Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file’s format, implement the parser, wire it in, and add a test.


Pattern 1: kv_file_parser<T> — key-value files

Use this when the file has the form Key: value (one key per line, order irrelevant). Examples: /proc/<pid>/status, /proc/stat.

How it works:

kv_file_parser<T> (in include/pfs/parsers/kv_file_parser.hpp) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name.

Steps:

  1. Add the output type to include/pfs/types.hpp if it doesn’t exist.

  2. Create the parser header in include/pfs/parsers/:

    // include/pfs/parsers/my_file.hpp
    #include "kv_file_parser.hpp"
    #include "pfs/types.hpp"

    namespace pfs { namespace impl { namespace parsers {

    class my_file_parser : public kv_file_parser<my_type>
    {
    public:
        my_file_parser() : kv_file_parser<my_type>(DELIM, PARSERS) {}
    private:
        static const char DELIM;
        static const value_parsers PARSERS;
    };

    }}}
    
  1. Create the parser implementation in src/parsers/:
    // src/parsers/my_file.cpp
    #include "pfs/parsers/my_file.hpp"
    #include "pfs/parsers/number.hpp"

    namespace pfs { namespace impl { namespace parsers {

    const char my_file_parser::DELIM = ':';

    const my_file_parser::value_parsers my_file_parser::PARSERS = {
        {"SomeNumber", [](const std::string& value, my_type& out) {
            to_number(value, out.some_number);
        }},
        {"SomeString", [](const std::string& value, my_type& out) {
            out.some_string = value;
        }},
    };

    }}}
    
  1. Wire it in by adding a getter to the appropriate class (task, net, or procfs) that constructs the parser and calls .parse(path).

  2. Add a unit test in test/. Create a temp file with representative content and assert the parsed fields. See test/test_task_status.cpp for a full example.


Pattern 2: parse_file_lines — tabular/repeated-row files

Use this when each line is an independent record (a row in a table, one entry per line). Examples: /proc/meminfo, /proc/net/tcp, /proc/<pid>/maps.

How it works:

File truncated at 100 lines see the full file

# Contributing to pfs ## License and Copyright By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that: 1. Your contribution is your original work and you have the right to submit it. 2. Your contribution is submitted under the [Apache License 2.0](LICENSE) that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project. 3. The project author retains complete and sole copyright over the project. This is consistent with the [Developer Certificate of Origin (DCO) 1.1](https://developercertificate.org/) used across many open-source projects. ## Adding a new parser Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file's format, implement the parser, wire it in, and add a test. --- ### Pattern 1: `kv_file_parser` — key-value files Use this when the file has the form `Key: value` (one key per line, order irrelevant). Examples: `/proc//status`, `/proc/stat`. **How it works:** `kv_file_parser` (in `include/pfs/parsers/kv_file_parser.hpp`) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name. **Steps:** 1. **Add the output type** to `include/pfs/types.hpp` if it doesn't exist. 2. **Create the parser header** in `include/pfs/parsers/`: ```cpp // include/pfs/parsers/my_file.hpp #include "kv_file_parser.hpp" #include "pfs/types.hpp" namespace pfs { namespace impl { namespace parsers { class my_file_parser : public kv_file_parser { public: my_file_parser() : kv_file_parser(DELIM, PARSERS) {} private: static const char DELIM; static const value_parsers PARSERS; }; }}} ``` 3. **Create the parser implementation** in `src/parsers/`: ```cpp // src/parsers/my_file.cpp #include "pfs/parsers/my_file.hpp" #include "pfs/parsers/number.hpp" namespace pfs { namespace impl { namespace parsers { const char my_file_parser::DELIM = ':'; const my_file_parser::value_parsers my_file_parser::PARSERS = { {"SomeNumber", [](const std::string& value, my_type& out) { to_number(value, out.some_number); }}, {"SomeString", [](const std::string& value, my_type& out) { out.some_string = value; }}, }; }}} ``` 4. **Wire it in** by adding a getter to the appropriate class (`task`, `net`, or `procfs`) that constructs the parser and calls `.parse(path)`. 5. **Add a unit test** in `test/`. Create a temp file with representative content and assert the parsed fields. See `test/test_task_status.cpp` for a full example. --- ### Pattern 2: `parse_file_lines` — tabular/repeated-row files Use this when each line is an independent record (a row in a table, one entry per line). Examples: `/proc/meminfo`, `/proc/net/tcp`, `/proc//maps`. **How it works:** File truncated at 100 lines [see the full file](https://github.com/dtrugman/pfs/tree/main/CONTRIBUTING.md)
No version for distro eloquent showing jazzy. Known supported distros are highlighted in the buttons above.
Repo symbol

pfs repository

pfs

ROS Distro
jazzy

Repository Summary

Checkout URI https://github.com/dtrugman/pfs.git
VCS Type git
VCS Version main
Last Updated 2026-04-12
Dev Status MAINTAINED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Packages

Name Version
pfs 0.13.1

README

pfs

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

Build & Test

Run cmake . && make

Currently supported CMake configuration flags:

  • CMAKE_BUILD_TYPE=<Debug|Release>: Standard CMake flags to control build type (DEFAULT: Debug)
  • pfs_BUILD_SHARED_LIBS=<ON|OFF>: ON to compile a shared library. OFF to compile a static library (DEFAULT: Inherit BUILD_SHARE_LIBS, which is OFF by default))
  • pfs_BUILD_ASAN=<ON|OFF>: ON to enable address sanitizer (DEFAULT: OFF)
  • pfs_BUILD_COVERAGE=<ON|OFF>: ON to enable coverage instrumentation (DEFAULT: OFF)
  • pfs_BUILD_SAMPLES=<ON|OFF>: ON to build the sample programs (DEFAULT: ON)
  • pfs_BUILD_TESTS=<ON|OFF>: ON to build the tests (DEFAULT: ON)

You can pass any number of those to the cmake command: cmake -D<CONFIG_FLAG>=<VALUE> .

NOTE: After running cmake for the first time, some values are cached in CMakeCache.txt and will not change when running cmake for a second time with different flags.

Build using clang

If you prefer using clang, just configure the compiler while running cmake:

CXX=<clang++> CC=<clang> cmake .

After that, just use make as always.

Code Coverage

Generate a coverage report is via Docker:

./docker/docker-pfs coverage

This builds the project with coverage instrumentation, runs all tests, and produces:

  • A text summary printed to the terminal
  • An HTML report at ./coverage/index.html

Integrate

  • Compile as a shared or static library.
  • Add the contents of /lib into your link directories
  • Add the contents of /include into your include directories. That’s it, you are good to go.

Use CMake’s find_package()

Option #1: make install (Preferred way)

After building the project, you can install it locally using make install. In your project’s CMake file, you can then add the following snippet, and CMake will handle the rest:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> pfs)

NOTE: CMake generates an install_manifest.txt file to track all the created files, this will help you uninstall the library if you need to do so.

Option #2: Without make install

Build the pfs project. No need to call make install. In your project’s CMake file, you can then add the following snippet:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> -L${pfs_LIBRARY_DIR} ${pfs_LIBRARIES})
target_include_directories (<your-target> [PUBLIC|PRIVATE] ${pfs_INCLUDE_DIRS})

Features

  • 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

  • The library requires C++11 or newer
  • The library aims to support Linux kernel versions >= 2.6.32.

Notes

General notes

File truncated at 100 lines see the full file

CONTRIBUTING

Contributing to pfs

By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that:

  1. Your contribution is your original work and you have the right to submit it.
  2. Your contribution is submitted under the Apache License 2.0 that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project.
  3. The project author retains complete and sole copyright over the project.

This is consistent with the Developer Certificate of Origin (DCO) 1.1 used across many open-source projects.

Adding a new parser

Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file’s format, implement the parser, wire it in, and add a test.


Pattern 1: kv_file_parser<T> — key-value files

Use this when the file has the form Key: value (one key per line, order irrelevant). Examples: /proc/<pid>/status, /proc/stat.

How it works:

kv_file_parser<T> (in include/pfs/parsers/kv_file_parser.hpp) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name.

Steps:

  1. Add the output type to include/pfs/types.hpp if it doesn’t exist.

  2. Create the parser header in include/pfs/parsers/:

    // include/pfs/parsers/my_file.hpp
    #include "kv_file_parser.hpp"
    #include "pfs/types.hpp"

    namespace pfs { namespace impl { namespace parsers {

    class my_file_parser : public kv_file_parser<my_type>
    {
    public:
        my_file_parser() : kv_file_parser<my_type>(DELIM, PARSERS) {}
    private:
        static const char DELIM;
        static const value_parsers PARSERS;
    };

    }}}
    
  1. Create the parser implementation in src/parsers/:
    // src/parsers/my_file.cpp
    #include "pfs/parsers/my_file.hpp"
    #include "pfs/parsers/number.hpp"

    namespace pfs { namespace impl { namespace parsers {

    const char my_file_parser::DELIM = ':';

    const my_file_parser::value_parsers my_file_parser::PARSERS = {
        {"SomeNumber", [](const std::string& value, my_type& out) {
            to_number(value, out.some_number);
        }},
        {"SomeString", [](const std::string& value, my_type& out) {
            out.some_string = value;
        }},
    };

    }}}
    
  1. Wire it in by adding a getter to the appropriate class (task, net, or procfs) that constructs the parser and calls .parse(path).

  2. Add a unit test in test/. Create a temp file with representative content and assert the parsed fields. See test/test_task_status.cpp for a full example.


Pattern 2: parse_file_lines — tabular/repeated-row files

Use this when each line is an independent record (a row in a table, one entry per line). Examples: /proc/meminfo, /proc/net/tcp, /proc/<pid>/maps.

How it works:

File truncated at 100 lines see the full file

# Contributing to pfs ## License and Copyright By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that: 1. Your contribution is your original work and you have the right to submit it. 2. Your contribution is submitted under the [Apache License 2.0](LICENSE) that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project. 3. The project author retains complete and sole copyright over the project. This is consistent with the [Developer Certificate of Origin (DCO) 1.1](https://developercertificate.org/) used across many open-source projects. ## Adding a new parser Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file's format, implement the parser, wire it in, and add a test. --- ### Pattern 1: `kv_file_parser` — key-value files Use this when the file has the form `Key: value` (one key per line, order irrelevant). Examples: `/proc//status`, `/proc/stat`. **How it works:** `kv_file_parser` (in `include/pfs/parsers/kv_file_parser.hpp`) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name. **Steps:** 1. **Add the output type** to `include/pfs/types.hpp` if it doesn't exist. 2. **Create the parser header** in `include/pfs/parsers/`: ```cpp // include/pfs/parsers/my_file.hpp #include "kv_file_parser.hpp" #include "pfs/types.hpp" namespace pfs { namespace impl { namespace parsers { class my_file_parser : public kv_file_parser { public: my_file_parser() : kv_file_parser(DELIM, PARSERS) {} private: static const char DELIM; static const value_parsers PARSERS; }; }}} ``` 3. **Create the parser implementation** in `src/parsers/`: ```cpp // src/parsers/my_file.cpp #include "pfs/parsers/my_file.hpp" #include "pfs/parsers/number.hpp" namespace pfs { namespace impl { namespace parsers { const char my_file_parser::DELIM = ':'; const my_file_parser::value_parsers my_file_parser::PARSERS = { {"SomeNumber", [](const std::string& value, my_type& out) { to_number(value, out.some_number); }}, {"SomeString", [](const std::string& value, my_type& out) { out.some_string = value; }}, }; }}} ``` 4. **Wire it in** by adding a getter to the appropriate class (`task`, `net`, or `procfs`) that constructs the parser and calls `.parse(path)`. 5. **Add a unit test** in `test/`. Create a temp file with representative content and assert the parsed fields. See `test/test_task_status.cpp` for a full example. --- ### Pattern 2: `parse_file_lines` — tabular/repeated-row files Use this when each line is an independent record (a row in a table, one entry per line). Examples: `/proc/meminfo`, `/proc/net/tcp`, `/proc//maps`. **How it works:** File truncated at 100 lines [see the full file](https://github.com/dtrugman/pfs/tree/main/CONTRIBUTING.md)
No version for distro dashing showing jazzy. Known supported distros are highlighted in the buttons above.
Repo symbol

pfs repository

pfs

ROS Distro
jazzy

Repository Summary

Checkout URI https://github.com/dtrugman/pfs.git
VCS Type git
VCS Version main
Last Updated 2026-04-12
Dev Status MAINTAINED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Packages

Name Version
pfs 0.13.1

README

pfs

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

Build & Test

Run cmake . && make

Currently supported CMake configuration flags:

  • CMAKE_BUILD_TYPE=<Debug|Release>: Standard CMake flags to control build type (DEFAULT: Debug)
  • pfs_BUILD_SHARED_LIBS=<ON|OFF>: ON to compile a shared library. OFF to compile a static library (DEFAULT: Inherit BUILD_SHARE_LIBS, which is OFF by default))
  • pfs_BUILD_ASAN=<ON|OFF>: ON to enable address sanitizer (DEFAULT: OFF)
  • pfs_BUILD_COVERAGE=<ON|OFF>: ON to enable coverage instrumentation (DEFAULT: OFF)
  • pfs_BUILD_SAMPLES=<ON|OFF>: ON to build the sample programs (DEFAULT: ON)
  • pfs_BUILD_TESTS=<ON|OFF>: ON to build the tests (DEFAULT: ON)

You can pass any number of those to the cmake command: cmake -D<CONFIG_FLAG>=<VALUE> .

NOTE: After running cmake for the first time, some values are cached in CMakeCache.txt and will not change when running cmake for a second time with different flags.

Build using clang

If you prefer using clang, just configure the compiler while running cmake:

CXX=<clang++> CC=<clang> cmake .

After that, just use make as always.

Code Coverage

Generate a coverage report is via Docker:

./docker/docker-pfs coverage

This builds the project with coverage instrumentation, runs all tests, and produces:

  • A text summary printed to the terminal
  • An HTML report at ./coverage/index.html

Integrate

  • Compile as a shared or static library.
  • Add the contents of /lib into your link directories
  • Add the contents of /include into your include directories. That’s it, you are good to go.

Use CMake’s find_package()

Option #1: make install (Preferred way)

After building the project, you can install it locally using make install. In your project’s CMake file, you can then add the following snippet, and CMake will handle the rest:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> pfs)

NOTE: CMake generates an install_manifest.txt file to track all the created files, this will help you uninstall the library if you need to do so.

Option #2: Without make install

Build the pfs project. No need to call make install. In your project’s CMake file, you can then add the following snippet:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> -L${pfs_LIBRARY_DIR} ${pfs_LIBRARIES})
target_include_directories (<your-target> [PUBLIC|PRIVATE] ${pfs_INCLUDE_DIRS})

Features

  • 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

  • The library requires C++11 or newer
  • The library aims to support Linux kernel versions >= 2.6.32.

Notes

General notes

File truncated at 100 lines see the full file

CONTRIBUTING

Contributing to pfs

By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that:

  1. Your contribution is your original work and you have the right to submit it.
  2. Your contribution is submitted under the Apache License 2.0 that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project.
  3. The project author retains complete and sole copyright over the project.

This is consistent with the Developer Certificate of Origin (DCO) 1.1 used across many open-source projects.

Adding a new parser

Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file’s format, implement the parser, wire it in, and add a test.


Pattern 1: kv_file_parser<T> — key-value files

Use this when the file has the form Key: value (one key per line, order irrelevant). Examples: /proc/<pid>/status, /proc/stat.

How it works:

kv_file_parser<T> (in include/pfs/parsers/kv_file_parser.hpp) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name.

Steps:

  1. Add the output type to include/pfs/types.hpp if it doesn’t exist.

  2. Create the parser header in include/pfs/parsers/:

    // include/pfs/parsers/my_file.hpp
    #include "kv_file_parser.hpp"
    #include "pfs/types.hpp"

    namespace pfs { namespace impl { namespace parsers {

    class my_file_parser : public kv_file_parser<my_type>
    {
    public:
        my_file_parser() : kv_file_parser<my_type>(DELIM, PARSERS) {}
    private:
        static const char DELIM;
        static const value_parsers PARSERS;
    };

    }}}
    
  1. Create the parser implementation in src/parsers/:
    // src/parsers/my_file.cpp
    #include "pfs/parsers/my_file.hpp"
    #include "pfs/parsers/number.hpp"

    namespace pfs { namespace impl { namespace parsers {

    const char my_file_parser::DELIM = ':';

    const my_file_parser::value_parsers my_file_parser::PARSERS = {
        {"SomeNumber", [](const std::string& value, my_type& out) {
            to_number(value, out.some_number);
        }},
        {"SomeString", [](const std::string& value, my_type& out) {
            out.some_string = value;
        }},
    };

    }}}
    
  1. Wire it in by adding a getter to the appropriate class (task, net, or procfs) that constructs the parser and calls .parse(path).

  2. Add a unit test in test/. Create a temp file with representative content and assert the parsed fields. See test/test_task_status.cpp for a full example.


Pattern 2: parse_file_lines — tabular/repeated-row files

Use this when each line is an independent record (a row in a table, one entry per line). Examples: /proc/meminfo, /proc/net/tcp, /proc/<pid>/maps.

How it works:

File truncated at 100 lines see the full file

# Contributing to pfs ## License and Copyright By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that: 1. Your contribution is your original work and you have the right to submit it. 2. Your contribution is submitted under the [Apache License 2.0](LICENSE) that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project. 3. The project author retains complete and sole copyright over the project. This is consistent with the [Developer Certificate of Origin (DCO) 1.1](https://developercertificate.org/) used across many open-source projects. ## Adding a new parser Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file's format, implement the parser, wire it in, and add a test. --- ### Pattern 1: `kv_file_parser` — key-value files Use this when the file has the form `Key: value` (one key per line, order irrelevant). Examples: `/proc//status`, `/proc/stat`. **How it works:** `kv_file_parser` (in `include/pfs/parsers/kv_file_parser.hpp`) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name. **Steps:** 1. **Add the output type** to `include/pfs/types.hpp` if it doesn't exist. 2. **Create the parser header** in `include/pfs/parsers/`: ```cpp // include/pfs/parsers/my_file.hpp #include "kv_file_parser.hpp" #include "pfs/types.hpp" namespace pfs { namespace impl { namespace parsers { class my_file_parser : public kv_file_parser { public: my_file_parser() : kv_file_parser(DELIM, PARSERS) {} private: static const char DELIM; static const value_parsers PARSERS; }; }}} ``` 3. **Create the parser implementation** in `src/parsers/`: ```cpp // src/parsers/my_file.cpp #include "pfs/parsers/my_file.hpp" #include "pfs/parsers/number.hpp" namespace pfs { namespace impl { namespace parsers { const char my_file_parser::DELIM = ':'; const my_file_parser::value_parsers my_file_parser::PARSERS = { {"SomeNumber", [](const std::string& value, my_type& out) { to_number(value, out.some_number); }}, {"SomeString", [](const std::string& value, my_type& out) { out.some_string = value; }}, }; }}} ``` 4. **Wire it in** by adding a getter to the appropriate class (`task`, `net`, or `procfs`) that constructs the parser and calls `.parse(path)`. 5. **Add a unit test** in `test/`. Create a temp file with representative content and assert the parsed fields. See `test/test_task_status.cpp` for a full example. --- ### Pattern 2: `parse_file_lines` — tabular/repeated-row files Use this when each line is an independent record (a row in a table, one entry per line). Examples: `/proc/meminfo`, `/proc/net/tcp`, `/proc//maps`. **How it works:** File truncated at 100 lines [see the full file](https://github.com/dtrugman/pfs/tree/main/CONTRIBUTING.md)
No version for distro galactic showing jazzy. Known supported distros are highlighted in the buttons above.
Repo symbol

pfs repository

pfs

ROS Distro
jazzy

Repository Summary

Checkout URI https://github.com/dtrugman/pfs.git
VCS Type git
VCS Version main
Last Updated 2026-04-12
Dev Status MAINTAINED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Packages

Name Version
pfs 0.13.1

README

pfs

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

Build & Test

Run cmake . && make

Currently supported CMake configuration flags:

  • CMAKE_BUILD_TYPE=<Debug|Release>: Standard CMake flags to control build type (DEFAULT: Debug)
  • pfs_BUILD_SHARED_LIBS=<ON|OFF>: ON to compile a shared library. OFF to compile a static library (DEFAULT: Inherit BUILD_SHARE_LIBS, which is OFF by default))
  • pfs_BUILD_ASAN=<ON|OFF>: ON to enable address sanitizer (DEFAULT: OFF)
  • pfs_BUILD_COVERAGE=<ON|OFF>: ON to enable coverage instrumentation (DEFAULT: OFF)
  • pfs_BUILD_SAMPLES=<ON|OFF>: ON to build the sample programs (DEFAULT: ON)
  • pfs_BUILD_TESTS=<ON|OFF>: ON to build the tests (DEFAULT: ON)

You can pass any number of those to the cmake command: cmake -D<CONFIG_FLAG>=<VALUE> .

NOTE: After running cmake for the first time, some values are cached in CMakeCache.txt and will not change when running cmake for a second time with different flags.

Build using clang

If you prefer using clang, just configure the compiler while running cmake:

CXX=<clang++> CC=<clang> cmake .

After that, just use make as always.

Code Coverage

Generate a coverage report is via Docker:

./docker/docker-pfs coverage

This builds the project with coverage instrumentation, runs all tests, and produces:

  • A text summary printed to the terminal
  • An HTML report at ./coverage/index.html

Integrate

  • Compile as a shared or static library.
  • Add the contents of /lib into your link directories
  • Add the contents of /include into your include directories. That’s it, you are good to go.

Use CMake’s find_package()

Option #1: make install (Preferred way)

After building the project, you can install it locally using make install. In your project’s CMake file, you can then add the following snippet, and CMake will handle the rest:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> pfs)

NOTE: CMake generates an install_manifest.txt file to track all the created files, this will help you uninstall the library if you need to do so.

Option #2: Without make install

Build the pfs project. No need to call make install. In your project’s CMake file, you can then add the following snippet:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> -L${pfs_LIBRARY_DIR} ${pfs_LIBRARIES})
target_include_directories (<your-target> [PUBLIC|PRIVATE] ${pfs_INCLUDE_DIRS})

Features

  • 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

  • The library requires C++11 or newer
  • The library aims to support Linux kernel versions >= 2.6.32.

Notes

General notes

File truncated at 100 lines see the full file

CONTRIBUTING

Contributing to pfs

By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that:

  1. Your contribution is your original work and you have the right to submit it.
  2. Your contribution is submitted under the Apache License 2.0 that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project.
  3. The project author retains complete and sole copyright over the project.

This is consistent with the Developer Certificate of Origin (DCO) 1.1 used across many open-source projects.

Adding a new parser

Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file’s format, implement the parser, wire it in, and add a test.


Pattern 1: kv_file_parser<T> — key-value files

Use this when the file has the form Key: value (one key per line, order irrelevant). Examples: /proc/<pid>/status, /proc/stat.

How it works:

kv_file_parser<T> (in include/pfs/parsers/kv_file_parser.hpp) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name.

Steps:

  1. Add the output type to include/pfs/types.hpp if it doesn’t exist.

  2. Create the parser header in include/pfs/parsers/:

    // include/pfs/parsers/my_file.hpp
    #include "kv_file_parser.hpp"
    #include "pfs/types.hpp"

    namespace pfs { namespace impl { namespace parsers {

    class my_file_parser : public kv_file_parser<my_type>
    {
    public:
        my_file_parser() : kv_file_parser<my_type>(DELIM, PARSERS) {}
    private:
        static const char DELIM;
        static const value_parsers PARSERS;
    };

    }}}
    
  1. Create the parser implementation in src/parsers/:
    // src/parsers/my_file.cpp
    #include "pfs/parsers/my_file.hpp"
    #include "pfs/parsers/number.hpp"

    namespace pfs { namespace impl { namespace parsers {

    const char my_file_parser::DELIM = ':';

    const my_file_parser::value_parsers my_file_parser::PARSERS = {
        {"SomeNumber", [](const std::string& value, my_type& out) {
            to_number(value, out.some_number);
        }},
        {"SomeString", [](const std::string& value, my_type& out) {
            out.some_string = value;
        }},
    };

    }}}
    
  1. Wire it in by adding a getter to the appropriate class (task, net, or procfs) that constructs the parser and calls .parse(path).

  2. Add a unit test in test/. Create a temp file with representative content and assert the parsed fields. See test/test_task_status.cpp for a full example.


Pattern 2: parse_file_lines — tabular/repeated-row files

Use this when each line is an independent record (a row in a table, one entry per line). Examples: /proc/meminfo, /proc/net/tcp, /proc/<pid>/maps.

How it works:

File truncated at 100 lines see the full file

# Contributing to pfs ## License and Copyright By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that: 1. Your contribution is your original work and you have the right to submit it. 2. Your contribution is submitted under the [Apache License 2.0](LICENSE) that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project. 3. The project author retains complete and sole copyright over the project. This is consistent with the [Developer Certificate of Origin (DCO) 1.1](https://developercertificate.org/) used across many open-source projects. ## Adding a new parser Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file's format, implement the parser, wire it in, and add a test. --- ### Pattern 1: `kv_file_parser` — key-value files Use this when the file has the form `Key: value` (one key per line, order irrelevant). Examples: `/proc//status`, `/proc/stat`. **How it works:** `kv_file_parser` (in `include/pfs/parsers/kv_file_parser.hpp`) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name. **Steps:** 1. **Add the output type** to `include/pfs/types.hpp` if it doesn't exist. 2. **Create the parser header** in `include/pfs/parsers/`: ```cpp // include/pfs/parsers/my_file.hpp #include "kv_file_parser.hpp" #include "pfs/types.hpp" namespace pfs { namespace impl { namespace parsers { class my_file_parser : public kv_file_parser { public: my_file_parser() : kv_file_parser(DELIM, PARSERS) {} private: static const char DELIM; static const value_parsers PARSERS; }; }}} ``` 3. **Create the parser implementation** in `src/parsers/`: ```cpp // src/parsers/my_file.cpp #include "pfs/parsers/my_file.hpp" #include "pfs/parsers/number.hpp" namespace pfs { namespace impl { namespace parsers { const char my_file_parser::DELIM = ':'; const my_file_parser::value_parsers my_file_parser::PARSERS = { {"SomeNumber", [](const std::string& value, my_type& out) { to_number(value, out.some_number); }}, {"SomeString", [](const std::string& value, my_type& out) { out.some_string = value; }}, }; }}} ``` 4. **Wire it in** by adding a getter to the appropriate class (`task`, `net`, or `procfs`) that constructs the parser and calls `.parse(path)`. 5. **Add a unit test** in `test/`. Create a temp file with representative content and assert the parsed fields. See `test/test_task_status.cpp` for a full example. --- ### Pattern 2: `parse_file_lines` — tabular/repeated-row files Use this when each line is an independent record (a row in a table, one entry per line). Examples: `/proc/meminfo`, `/proc/net/tcp`, `/proc//maps`. **How it works:** File truncated at 100 lines [see the full file](https://github.com/dtrugman/pfs/tree/main/CONTRIBUTING.md)
No version for distro foxy showing jazzy. Known supported distros are highlighted in the buttons above.
Repo symbol

pfs repository

pfs

ROS Distro
jazzy

Repository Summary

Checkout URI https://github.com/dtrugman/pfs.git
VCS Type git
VCS Version main
Last Updated 2026-04-12
Dev Status MAINTAINED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Packages

Name Version
pfs 0.13.1

README

pfs

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

Build & Test

Run cmake . && make

Currently supported CMake configuration flags:

  • CMAKE_BUILD_TYPE=<Debug|Release>: Standard CMake flags to control build type (DEFAULT: Debug)
  • pfs_BUILD_SHARED_LIBS=<ON|OFF>: ON to compile a shared library. OFF to compile a static library (DEFAULT: Inherit BUILD_SHARE_LIBS, which is OFF by default))
  • pfs_BUILD_ASAN=<ON|OFF>: ON to enable address sanitizer (DEFAULT: OFF)
  • pfs_BUILD_COVERAGE=<ON|OFF>: ON to enable coverage instrumentation (DEFAULT: OFF)
  • pfs_BUILD_SAMPLES=<ON|OFF>: ON to build the sample programs (DEFAULT: ON)
  • pfs_BUILD_TESTS=<ON|OFF>: ON to build the tests (DEFAULT: ON)

You can pass any number of those to the cmake command: cmake -D<CONFIG_FLAG>=<VALUE> .

NOTE: After running cmake for the first time, some values are cached in CMakeCache.txt and will not change when running cmake for a second time with different flags.

Build using clang

If you prefer using clang, just configure the compiler while running cmake:

CXX=<clang++> CC=<clang> cmake .

After that, just use make as always.

Code Coverage

Generate a coverage report is via Docker:

./docker/docker-pfs coverage

This builds the project with coverage instrumentation, runs all tests, and produces:

  • A text summary printed to the terminal
  • An HTML report at ./coverage/index.html

Integrate

  • Compile as a shared or static library.
  • Add the contents of /lib into your link directories
  • Add the contents of /include into your include directories. That’s it, you are good to go.

Use CMake’s find_package()

Option #1: make install (Preferred way)

After building the project, you can install it locally using make install. In your project’s CMake file, you can then add the following snippet, and CMake will handle the rest:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> pfs)

NOTE: CMake generates an install_manifest.txt file to track all the created files, this will help you uninstall the library if you need to do so.

Option #2: Without make install

Build the pfs project. No need to call make install. In your project’s CMake file, you can then add the following snippet:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> -L${pfs_LIBRARY_DIR} ${pfs_LIBRARIES})
target_include_directories (<your-target> [PUBLIC|PRIVATE] ${pfs_INCLUDE_DIRS})

Features

  • 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

  • The library requires C++11 or newer
  • The library aims to support Linux kernel versions >= 2.6.32.

Notes

General notes

File truncated at 100 lines see the full file

CONTRIBUTING

Contributing to pfs

By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that:

  1. Your contribution is your original work and you have the right to submit it.
  2. Your contribution is submitted under the Apache License 2.0 that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project.
  3. The project author retains complete and sole copyright over the project.

This is consistent with the Developer Certificate of Origin (DCO) 1.1 used across many open-source projects.

Adding a new parser

Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file’s format, implement the parser, wire it in, and add a test.


Pattern 1: kv_file_parser<T> — key-value files

Use this when the file has the form Key: value (one key per line, order irrelevant). Examples: /proc/<pid>/status, /proc/stat.

How it works:

kv_file_parser<T> (in include/pfs/parsers/kv_file_parser.hpp) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name.

Steps:

  1. Add the output type to include/pfs/types.hpp if it doesn’t exist.

  2. Create the parser header in include/pfs/parsers/:

    // include/pfs/parsers/my_file.hpp
    #include "kv_file_parser.hpp"
    #include "pfs/types.hpp"

    namespace pfs { namespace impl { namespace parsers {

    class my_file_parser : public kv_file_parser<my_type>
    {
    public:
        my_file_parser() : kv_file_parser<my_type>(DELIM, PARSERS) {}
    private:
        static const char DELIM;
        static const value_parsers PARSERS;
    };

    }}}
    
  1. Create the parser implementation in src/parsers/:
    // src/parsers/my_file.cpp
    #include "pfs/parsers/my_file.hpp"
    #include "pfs/parsers/number.hpp"

    namespace pfs { namespace impl { namespace parsers {

    const char my_file_parser::DELIM = ':';

    const my_file_parser::value_parsers my_file_parser::PARSERS = {
        {"SomeNumber", [](const std::string& value, my_type& out) {
            to_number(value, out.some_number);
        }},
        {"SomeString", [](const std::string& value, my_type& out) {
            out.some_string = value;
        }},
    };

    }}}
    
  1. Wire it in by adding a getter to the appropriate class (task, net, or procfs) that constructs the parser and calls .parse(path).

  2. Add a unit test in test/. Create a temp file with representative content and assert the parsed fields. See test/test_task_status.cpp for a full example.


Pattern 2: parse_file_lines — tabular/repeated-row files

Use this when each line is an independent record (a row in a table, one entry per line). Examples: /proc/meminfo, /proc/net/tcp, /proc/<pid>/maps.

How it works:

File truncated at 100 lines see the full file

# Contributing to pfs ## License and Copyright By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that: 1. Your contribution is your original work and you have the right to submit it. 2. Your contribution is submitted under the [Apache License 2.0](LICENSE) that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project. 3. The project author retains complete and sole copyright over the project. This is consistent with the [Developer Certificate of Origin (DCO) 1.1](https://developercertificate.org/) used across many open-source projects. ## Adding a new parser Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file's format, implement the parser, wire it in, and add a test. --- ### Pattern 1: `kv_file_parser` — key-value files Use this when the file has the form `Key: value` (one key per line, order irrelevant). Examples: `/proc//status`, `/proc/stat`. **How it works:** `kv_file_parser` (in `include/pfs/parsers/kv_file_parser.hpp`) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name. **Steps:** 1. **Add the output type** to `include/pfs/types.hpp` if it doesn't exist. 2. **Create the parser header** in `include/pfs/parsers/`: ```cpp // include/pfs/parsers/my_file.hpp #include "kv_file_parser.hpp" #include "pfs/types.hpp" namespace pfs { namespace impl { namespace parsers { class my_file_parser : public kv_file_parser { public: my_file_parser() : kv_file_parser(DELIM, PARSERS) {} private: static const char DELIM; static const value_parsers PARSERS; }; }}} ``` 3. **Create the parser implementation** in `src/parsers/`: ```cpp // src/parsers/my_file.cpp #include "pfs/parsers/my_file.hpp" #include "pfs/parsers/number.hpp" namespace pfs { namespace impl { namespace parsers { const char my_file_parser::DELIM = ':'; const my_file_parser::value_parsers my_file_parser::PARSERS = { {"SomeNumber", [](const std::string& value, my_type& out) { to_number(value, out.some_number); }}, {"SomeString", [](const std::string& value, my_type& out) { out.some_string = value; }}, }; }}} ``` 4. **Wire it in** by adding a getter to the appropriate class (`task`, `net`, or `procfs`) that constructs the parser and calls `.parse(path)`. 5. **Add a unit test** in `test/`. Create a temp file with representative content and assert the parsed fields. See `test/test_task_status.cpp` for a full example. --- ### Pattern 2: `parse_file_lines` — tabular/repeated-row files Use this when each line is an independent record (a row in a table, one entry per line). Examples: `/proc/meminfo`, `/proc/net/tcp`, `/proc//maps`. **How it works:** File truncated at 100 lines [see the full file](https://github.com/dtrugman/pfs/tree/main/CONTRIBUTING.md)
No version for distro iron showing jazzy. Known supported distros are highlighted in the buttons above.
Repo symbol

pfs repository

pfs

ROS Distro
jazzy

Repository Summary

Checkout URI https://github.com/dtrugman/pfs.git
VCS Type git
VCS Version main
Last Updated 2026-04-12
Dev Status MAINTAINED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Packages

Name Version
pfs 0.13.1

README

pfs

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

Build & Test

Run cmake . && make

Currently supported CMake configuration flags:

  • CMAKE_BUILD_TYPE=<Debug|Release>: Standard CMake flags to control build type (DEFAULT: Debug)
  • pfs_BUILD_SHARED_LIBS=<ON|OFF>: ON to compile a shared library. OFF to compile a static library (DEFAULT: Inherit BUILD_SHARE_LIBS, which is OFF by default))
  • pfs_BUILD_ASAN=<ON|OFF>: ON to enable address sanitizer (DEFAULT: OFF)
  • pfs_BUILD_COVERAGE=<ON|OFF>: ON to enable coverage instrumentation (DEFAULT: OFF)
  • pfs_BUILD_SAMPLES=<ON|OFF>: ON to build the sample programs (DEFAULT: ON)
  • pfs_BUILD_TESTS=<ON|OFF>: ON to build the tests (DEFAULT: ON)

You can pass any number of those to the cmake command: cmake -D<CONFIG_FLAG>=<VALUE> .

NOTE: After running cmake for the first time, some values are cached in CMakeCache.txt and will not change when running cmake for a second time with different flags.

Build using clang

If you prefer using clang, just configure the compiler while running cmake:

CXX=<clang++> CC=<clang> cmake .

After that, just use make as always.

Code Coverage

Generate a coverage report is via Docker:

./docker/docker-pfs coverage

This builds the project with coverage instrumentation, runs all tests, and produces:

  • A text summary printed to the terminal
  • An HTML report at ./coverage/index.html

Integrate

  • Compile as a shared or static library.
  • Add the contents of /lib into your link directories
  • Add the contents of /include into your include directories. That’s it, you are good to go.

Use CMake’s find_package()

Option #1: make install (Preferred way)

After building the project, you can install it locally using make install. In your project’s CMake file, you can then add the following snippet, and CMake will handle the rest:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> pfs)

NOTE: CMake generates an install_manifest.txt file to track all the created files, this will help you uninstall the library if you need to do so.

Option #2: Without make install

Build the pfs project. No need to call make install. In your project’s CMake file, you can then add the following snippet:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> -L${pfs_LIBRARY_DIR} ${pfs_LIBRARIES})
target_include_directories (<your-target> [PUBLIC|PRIVATE] ${pfs_INCLUDE_DIRS})

Features

  • 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

  • The library requires C++11 or newer
  • The library aims to support Linux kernel versions >= 2.6.32.

Notes

General notes

File truncated at 100 lines see the full file

CONTRIBUTING

Contributing to pfs

By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that:

  1. Your contribution is your original work and you have the right to submit it.
  2. Your contribution is submitted under the Apache License 2.0 that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project.
  3. The project author retains complete and sole copyright over the project.

This is consistent with the Developer Certificate of Origin (DCO) 1.1 used across many open-source projects.

Adding a new parser

Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file’s format, implement the parser, wire it in, and add a test.


Pattern 1: kv_file_parser<T> — key-value files

Use this when the file has the form Key: value (one key per line, order irrelevant). Examples: /proc/<pid>/status, /proc/stat.

How it works:

kv_file_parser<T> (in include/pfs/parsers/kv_file_parser.hpp) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name.

Steps:

  1. Add the output type to include/pfs/types.hpp if it doesn’t exist.

  2. Create the parser header in include/pfs/parsers/:

    // include/pfs/parsers/my_file.hpp
    #include "kv_file_parser.hpp"
    #include "pfs/types.hpp"

    namespace pfs { namespace impl { namespace parsers {

    class my_file_parser : public kv_file_parser<my_type>
    {
    public:
        my_file_parser() : kv_file_parser<my_type>(DELIM, PARSERS) {}
    private:
        static const char DELIM;
        static const value_parsers PARSERS;
    };

    }}}
    
  1. Create the parser implementation in src/parsers/:
    // src/parsers/my_file.cpp
    #include "pfs/parsers/my_file.hpp"
    #include "pfs/parsers/number.hpp"

    namespace pfs { namespace impl { namespace parsers {

    const char my_file_parser::DELIM = ':';

    const my_file_parser::value_parsers my_file_parser::PARSERS = {
        {"SomeNumber", [](const std::string& value, my_type& out) {
            to_number(value, out.some_number);
        }},
        {"SomeString", [](const std::string& value, my_type& out) {
            out.some_string = value;
        }},
    };

    }}}
    
  1. Wire it in by adding a getter to the appropriate class (task, net, or procfs) that constructs the parser and calls .parse(path).

  2. Add a unit test in test/. Create a temp file with representative content and assert the parsed fields. See test/test_task_status.cpp for a full example.


Pattern 2: parse_file_lines — tabular/repeated-row files

Use this when each line is an independent record (a row in a table, one entry per line). Examples: /proc/meminfo, /proc/net/tcp, /proc/<pid>/maps.

How it works:

File truncated at 100 lines see the full file

# Contributing to pfs ## License and Copyright By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that: 1. Your contribution is your original work and you have the right to submit it. 2. Your contribution is submitted under the [Apache License 2.0](LICENSE) that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project. 3. The project author retains complete and sole copyright over the project. This is consistent with the [Developer Certificate of Origin (DCO) 1.1](https://developercertificate.org/) used across many open-source projects. ## Adding a new parser Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file's format, implement the parser, wire it in, and add a test. --- ### Pattern 1: `kv_file_parser` — key-value files Use this when the file has the form `Key: value` (one key per line, order irrelevant). Examples: `/proc//status`, `/proc/stat`. **How it works:** `kv_file_parser` (in `include/pfs/parsers/kv_file_parser.hpp`) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name. **Steps:** 1. **Add the output type** to `include/pfs/types.hpp` if it doesn't exist. 2. **Create the parser header** in `include/pfs/parsers/`: ```cpp // include/pfs/parsers/my_file.hpp #include "kv_file_parser.hpp" #include "pfs/types.hpp" namespace pfs { namespace impl { namespace parsers { class my_file_parser : public kv_file_parser { public: my_file_parser() : kv_file_parser(DELIM, PARSERS) {} private: static const char DELIM; static const value_parsers PARSERS; }; }}} ``` 3. **Create the parser implementation** in `src/parsers/`: ```cpp // src/parsers/my_file.cpp #include "pfs/parsers/my_file.hpp" #include "pfs/parsers/number.hpp" namespace pfs { namespace impl { namespace parsers { const char my_file_parser::DELIM = ':'; const my_file_parser::value_parsers my_file_parser::PARSERS = { {"SomeNumber", [](const std::string& value, my_type& out) { to_number(value, out.some_number); }}, {"SomeString", [](const std::string& value, my_type& out) { out.some_string = value; }}, }; }}} ``` 4. **Wire it in** by adding a getter to the appropriate class (`task`, `net`, or `procfs`) that constructs the parser and calls `.parse(path)`. 5. **Add a unit test** in `test/`. Create a temp file with representative content and assert the parsed fields. See `test/test_task_status.cpp` for a full example. --- ### Pattern 2: `parse_file_lines` — tabular/repeated-row files Use this when each line is an independent record (a row in a table, one entry per line). Examples: `/proc/meminfo`, `/proc/net/tcp`, `/proc//maps`. **How it works:** File truncated at 100 lines [see the full file](https://github.com/dtrugman/pfs/tree/main/CONTRIBUTING.md)
No version for distro lunar showing jazzy. Known supported distros are highlighted in the buttons above.
Repo symbol

pfs repository

pfs

ROS Distro
jazzy

Repository Summary

Checkout URI https://github.com/dtrugman/pfs.git
VCS Type git
VCS Version main
Last Updated 2026-04-12
Dev Status MAINTAINED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Packages

Name Version
pfs 0.13.1

README

pfs

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

Build & Test

Run cmake . && make

Currently supported CMake configuration flags:

  • CMAKE_BUILD_TYPE=<Debug|Release>: Standard CMake flags to control build type (DEFAULT: Debug)
  • pfs_BUILD_SHARED_LIBS=<ON|OFF>: ON to compile a shared library. OFF to compile a static library (DEFAULT: Inherit BUILD_SHARE_LIBS, which is OFF by default))
  • pfs_BUILD_ASAN=<ON|OFF>: ON to enable address sanitizer (DEFAULT: OFF)
  • pfs_BUILD_COVERAGE=<ON|OFF>: ON to enable coverage instrumentation (DEFAULT: OFF)
  • pfs_BUILD_SAMPLES=<ON|OFF>: ON to build the sample programs (DEFAULT: ON)
  • pfs_BUILD_TESTS=<ON|OFF>: ON to build the tests (DEFAULT: ON)

You can pass any number of those to the cmake command: cmake -D<CONFIG_FLAG>=<VALUE> .

NOTE: After running cmake for the first time, some values are cached in CMakeCache.txt and will not change when running cmake for a second time with different flags.

Build using clang

If you prefer using clang, just configure the compiler while running cmake:

CXX=<clang++> CC=<clang> cmake .

After that, just use make as always.

Code Coverage

Generate a coverage report is via Docker:

./docker/docker-pfs coverage

This builds the project with coverage instrumentation, runs all tests, and produces:

  • A text summary printed to the terminal
  • An HTML report at ./coverage/index.html

Integrate

  • Compile as a shared or static library.
  • Add the contents of /lib into your link directories
  • Add the contents of /include into your include directories. That’s it, you are good to go.

Use CMake’s find_package()

Option #1: make install (Preferred way)

After building the project, you can install it locally using make install. In your project’s CMake file, you can then add the following snippet, and CMake will handle the rest:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> pfs)

NOTE: CMake generates an install_manifest.txt file to track all the created files, this will help you uninstall the library if you need to do so.

Option #2: Without make install

Build the pfs project. No need to call make install. In your project’s CMake file, you can then add the following snippet:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> -L${pfs_LIBRARY_DIR} ${pfs_LIBRARIES})
target_include_directories (<your-target> [PUBLIC|PRIVATE] ${pfs_INCLUDE_DIRS})

Features

  • 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

  • The library requires C++11 or newer
  • The library aims to support Linux kernel versions >= 2.6.32.

Notes

General notes

File truncated at 100 lines see the full file

CONTRIBUTING

Contributing to pfs

By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that:

  1. Your contribution is your original work and you have the right to submit it.
  2. Your contribution is submitted under the Apache License 2.0 that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project.
  3. The project author retains complete and sole copyright over the project.

This is consistent with the Developer Certificate of Origin (DCO) 1.1 used across many open-source projects.

Adding a new parser

Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file’s format, implement the parser, wire it in, and add a test.


Pattern 1: kv_file_parser<T> — key-value files

Use this when the file has the form Key: value (one key per line, order irrelevant). Examples: /proc/<pid>/status, /proc/stat.

How it works:

kv_file_parser<T> (in include/pfs/parsers/kv_file_parser.hpp) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name.

Steps:

  1. Add the output type to include/pfs/types.hpp if it doesn’t exist.

  2. Create the parser header in include/pfs/parsers/:

    // include/pfs/parsers/my_file.hpp
    #include "kv_file_parser.hpp"
    #include "pfs/types.hpp"

    namespace pfs { namespace impl { namespace parsers {

    class my_file_parser : public kv_file_parser<my_type>
    {
    public:
        my_file_parser() : kv_file_parser<my_type>(DELIM, PARSERS) {}
    private:
        static const char DELIM;
        static const value_parsers PARSERS;
    };

    }}}
    
  1. Create the parser implementation in src/parsers/:
    // src/parsers/my_file.cpp
    #include "pfs/parsers/my_file.hpp"
    #include "pfs/parsers/number.hpp"

    namespace pfs { namespace impl { namespace parsers {

    const char my_file_parser::DELIM = ':';

    const my_file_parser::value_parsers my_file_parser::PARSERS = {
        {"SomeNumber", [](const std::string& value, my_type& out) {
            to_number(value, out.some_number);
        }},
        {"SomeString", [](const std::string& value, my_type& out) {
            out.some_string = value;
        }},
    };

    }}}
    
  1. Wire it in by adding a getter to the appropriate class (task, net, or procfs) that constructs the parser and calls .parse(path).

  2. Add a unit test in test/. Create a temp file with representative content and assert the parsed fields. See test/test_task_status.cpp for a full example.


Pattern 2: parse_file_lines — tabular/repeated-row files

Use this when each line is an independent record (a row in a table, one entry per line). Examples: /proc/meminfo, /proc/net/tcp, /proc/<pid>/maps.

How it works:

File truncated at 100 lines see the full file

# Contributing to pfs ## License and Copyright By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that: 1. Your contribution is your original work and you have the right to submit it. 2. Your contribution is submitted under the [Apache License 2.0](LICENSE) that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project. 3. The project author retains complete and sole copyright over the project. This is consistent with the [Developer Certificate of Origin (DCO) 1.1](https://developercertificate.org/) used across many open-source projects. ## Adding a new parser Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file's format, implement the parser, wire it in, and add a test. --- ### Pattern 1: `kv_file_parser` — key-value files Use this when the file has the form `Key: value` (one key per line, order irrelevant). Examples: `/proc//status`, `/proc/stat`. **How it works:** `kv_file_parser` (in `include/pfs/parsers/kv_file_parser.hpp`) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name. **Steps:** 1. **Add the output type** to `include/pfs/types.hpp` if it doesn't exist. 2. **Create the parser header** in `include/pfs/parsers/`: ```cpp // include/pfs/parsers/my_file.hpp #include "kv_file_parser.hpp" #include "pfs/types.hpp" namespace pfs { namespace impl { namespace parsers { class my_file_parser : public kv_file_parser { public: my_file_parser() : kv_file_parser(DELIM, PARSERS) {} private: static const char DELIM; static const value_parsers PARSERS; }; }}} ``` 3. **Create the parser implementation** in `src/parsers/`: ```cpp // src/parsers/my_file.cpp #include "pfs/parsers/my_file.hpp" #include "pfs/parsers/number.hpp" namespace pfs { namespace impl { namespace parsers { const char my_file_parser::DELIM = ':'; const my_file_parser::value_parsers my_file_parser::PARSERS = { {"SomeNumber", [](const std::string& value, my_type& out) { to_number(value, out.some_number); }}, {"SomeString", [](const std::string& value, my_type& out) { out.some_string = value; }}, }; }}} ``` 4. **Wire it in** by adding a getter to the appropriate class (`task`, `net`, or `procfs`) that constructs the parser and calls `.parse(path)`. 5. **Add a unit test** in `test/`. Create a temp file with representative content and assert the parsed fields. See `test/test_task_status.cpp` for a full example. --- ### Pattern 2: `parse_file_lines` — tabular/repeated-row files Use this when each line is an independent record (a row in a table, one entry per line). Examples: `/proc/meminfo`, `/proc/net/tcp`, `/proc//maps`. **How it works:** File truncated at 100 lines [see the full file](https://github.com/dtrugman/pfs/tree/main/CONTRIBUTING.md)
No version for distro jade showing jazzy. Known supported distros are highlighted in the buttons above.
Repo symbol

pfs repository

pfs

ROS Distro
jazzy

Repository Summary

Checkout URI https://github.com/dtrugman/pfs.git
VCS Type git
VCS Version main
Last Updated 2026-04-12
Dev Status MAINTAINED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Packages

Name Version
pfs 0.13.1

README

pfs

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

Build & Test

Run cmake . && make

Currently supported CMake configuration flags:

  • CMAKE_BUILD_TYPE=<Debug|Release>: Standard CMake flags to control build type (DEFAULT: Debug)
  • pfs_BUILD_SHARED_LIBS=<ON|OFF>: ON to compile a shared library. OFF to compile a static library (DEFAULT: Inherit BUILD_SHARE_LIBS, which is OFF by default))
  • pfs_BUILD_ASAN=<ON|OFF>: ON to enable address sanitizer (DEFAULT: OFF)
  • pfs_BUILD_COVERAGE=<ON|OFF>: ON to enable coverage instrumentation (DEFAULT: OFF)
  • pfs_BUILD_SAMPLES=<ON|OFF>: ON to build the sample programs (DEFAULT: ON)
  • pfs_BUILD_TESTS=<ON|OFF>: ON to build the tests (DEFAULT: ON)

You can pass any number of those to the cmake command: cmake -D<CONFIG_FLAG>=<VALUE> .

NOTE: After running cmake for the first time, some values are cached in CMakeCache.txt and will not change when running cmake for a second time with different flags.

Build using clang

If you prefer using clang, just configure the compiler while running cmake:

CXX=<clang++> CC=<clang> cmake .

After that, just use make as always.

Code Coverage

Generate a coverage report is via Docker:

./docker/docker-pfs coverage

This builds the project with coverage instrumentation, runs all tests, and produces:

  • A text summary printed to the terminal
  • An HTML report at ./coverage/index.html

Integrate

  • Compile as a shared or static library.
  • Add the contents of /lib into your link directories
  • Add the contents of /include into your include directories. That’s it, you are good to go.

Use CMake’s find_package()

Option #1: make install (Preferred way)

After building the project, you can install it locally using make install. In your project’s CMake file, you can then add the following snippet, and CMake will handle the rest:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> pfs)

NOTE: CMake generates an install_manifest.txt file to track all the created files, this will help you uninstall the library if you need to do so.

Option #2: Without make install

Build the pfs project. No need to call make install. In your project’s CMake file, you can then add the following snippet:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> -L${pfs_LIBRARY_DIR} ${pfs_LIBRARIES})
target_include_directories (<your-target> [PUBLIC|PRIVATE] ${pfs_INCLUDE_DIRS})

Features

  • 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

  • The library requires C++11 or newer
  • The library aims to support Linux kernel versions >= 2.6.32.

Notes

General notes

File truncated at 100 lines see the full file

CONTRIBUTING

Contributing to pfs

By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that:

  1. Your contribution is your original work and you have the right to submit it.
  2. Your contribution is submitted under the Apache License 2.0 that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project.
  3. The project author retains complete and sole copyright over the project.

This is consistent with the Developer Certificate of Origin (DCO) 1.1 used across many open-source projects.

Adding a new parser

Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file’s format, implement the parser, wire it in, and add a test.


Pattern 1: kv_file_parser<T> — key-value files

Use this when the file has the form Key: value (one key per line, order irrelevant). Examples: /proc/<pid>/status, /proc/stat.

How it works:

kv_file_parser<T> (in include/pfs/parsers/kv_file_parser.hpp) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name.

Steps:

  1. Add the output type to include/pfs/types.hpp if it doesn’t exist.

  2. Create the parser header in include/pfs/parsers/:

    // include/pfs/parsers/my_file.hpp
    #include "kv_file_parser.hpp"
    #include "pfs/types.hpp"

    namespace pfs { namespace impl { namespace parsers {

    class my_file_parser : public kv_file_parser<my_type>
    {
    public:
        my_file_parser() : kv_file_parser<my_type>(DELIM, PARSERS) {}
    private:
        static const char DELIM;
        static const value_parsers PARSERS;
    };

    }}}
    
  1. Create the parser implementation in src/parsers/:
    // src/parsers/my_file.cpp
    #include "pfs/parsers/my_file.hpp"
    #include "pfs/parsers/number.hpp"

    namespace pfs { namespace impl { namespace parsers {

    const char my_file_parser::DELIM = ':';

    const my_file_parser::value_parsers my_file_parser::PARSERS = {
        {"SomeNumber", [](const std::string& value, my_type& out) {
            to_number(value, out.some_number);
        }},
        {"SomeString", [](const std::string& value, my_type& out) {
            out.some_string = value;
        }},
    };

    }}}
    
  1. Wire it in by adding a getter to the appropriate class (task, net, or procfs) that constructs the parser and calls .parse(path).

  2. Add a unit test in test/. Create a temp file with representative content and assert the parsed fields. See test/test_task_status.cpp for a full example.


Pattern 2: parse_file_lines — tabular/repeated-row files

Use this when each line is an independent record (a row in a table, one entry per line). Examples: /proc/meminfo, /proc/net/tcp, /proc/<pid>/maps.

How it works:

File truncated at 100 lines see the full file

# Contributing to pfs ## License and Copyright By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that: 1. Your contribution is your original work and you have the right to submit it. 2. Your contribution is submitted under the [Apache License 2.0](LICENSE) that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project. 3. The project author retains complete and sole copyright over the project. This is consistent with the [Developer Certificate of Origin (DCO) 1.1](https://developercertificate.org/) used across many open-source projects. ## Adding a new parser Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file's format, implement the parser, wire it in, and add a test. --- ### Pattern 1: `kv_file_parser` — key-value files Use this when the file has the form `Key: value` (one key per line, order irrelevant). Examples: `/proc//status`, `/proc/stat`. **How it works:** `kv_file_parser` (in `include/pfs/parsers/kv_file_parser.hpp`) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name. **Steps:** 1. **Add the output type** to `include/pfs/types.hpp` if it doesn't exist. 2. **Create the parser header** in `include/pfs/parsers/`: ```cpp // include/pfs/parsers/my_file.hpp #include "kv_file_parser.hpp" #include "pfs/types.hpp" namespace pfs { namespace impl { namespace parsers { class my_file_parser : public kv_file_parser { public: my_file_parser() : kv_file_parser(DELIM, PARSERS) {} private: static const char DELIM; static const value_parsers PARSERS; }; }}} ``` 3. **Create the parser implementation** in `src/parsers/`: ```cpp // src/parsers/my_file.cpp #include "pfs/parsers/my_file.hpp" #include "pfs/parsers/number.hpp" namespace pfs { namespace impl { namespace parsers { const char my_file_parser::DELIM = ':'; const my_file_parser::value_parsers my_file_parser::PARSERS = { {"SomeNumber", [](const std::string& value, my_type& out) { to_number(value, out.some_number); }}, {"SomeString", [](const std::string& value, my_type& out) { out.some_string = value; }}, }; }}} ``` 4. **Wire it in** by adding a getter to the appropriate class (`task`, `net`, or `procfs`) that constructs the parser and calls `.parse(path)`. 5. **Add a unit test** in `test/`. Create a temp file with representative content and assert the parsed fields. See `test/test_task_status.cpp` for a full example. --- ### Pattern 2: `parse_file_lines` — tabular/repeated-row files Use this when each line is an independent record (a row in a table, one entry per line). Examples: `/proc/meminfo`, `/proc/net/tcp`, `/proc//maps`. **How it works:** File truncated at 100 lines [see the full file](https://github.com/dtrugman/pfs/tree/main/CONTRIBUTING.md)
No version for distro indigo showing jazzy. Known supported distros are highlighted in the buttons above.
Repo symbol

pfs repository

pfs

ROS Distro
jazzy

Repository Summary

Checkout URI https://github.com/dtrugman/pfs.git
VCS Type git
VCS Version main
Last Updated 2026-04-12
Dev Status MAINTAINED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Packages

Name Version
pfs 0.13.1

README

pfs

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

Build & Test

Run cmake . && make

Currently supported CMake configuration flags:

  • CMAKE_BUILD_TYPE=<Debug|Release>: Standard CMake flags to control build type (DEFAULT: Debug)
  • pfs_BUILD_SHARED_LIBS=<ON|OFF>: ON to compile a shared library. OFF to compile a static library (DEFAULT: Inherit BUILD_SHARE_LIBS, which is OFF by default))
  • pfs_BUILD_ASAN=<ON|OFF>: ON to enable address sanitizer (DEFAULT: OFF)
  • pfs_BUILD_COVERAGE=<ON|OFF>: ON to enable coverage instrumentation (DEFAULT: OFF)
  • pfs_BUILD_SAMPLES=<ON|OFF>: ON to build the sample programs (DEFAULT: ON)
  • pfs_BUILD_TESTS=<ON|OFF>: ON to build the tests (DEFAULT: ON)

You can pass any number of those to the cmake command: cmake -D<CONFIG_FLAG>=<VALUE> .

NOTE: After running cmake for the first time, some values are cached in CMakeCache.txt and will not change when running cmake for a second time with different flags.

Build using clang

If you prefer using clang, just configure the compiler while running cmake:

CXX=<clang++> CC=<clang> cmake .

After that, just use make as always.

Code Coverage

Generate a coverage report is via Docker:

./docker/docker-pfs coverage

This builds the project with coverage instrumentation, runs all tests, and produces:

  • A text summary printed to the terminal
  • An HTML report at ./coverage/index.html

Integrate

  • Compile as a shared or static library.
  • Add the contents of /lib into your link directories
  • Add the contents of /include into your include directories. That’s it, you are good to go.

Use CMake’s find_package()

Option #1: make install (Preferred way)

After building the project, you can install it locally using make install. In your project’s CMake file, you can then add the following snippet, and CMake will handle the rest:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> pfs)

NOTE: CMake generates an install_manifest.txt file to track all the created files, this will help you uninstall the library if you need to do so.

Option #2: Without make install

Build the pfs project. No need to call make install. In your project’s CMake file, you can then add the following snippet:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> -L${pfs_LIBRARY_DIR} ${pfs_LIBRARIES})
target_include_directories (<your-target> [PUBLIC|PRIVATE] ${pfs_INCLUDE_DIRS})

Features

  • 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

  • The library requires C++11 or newer
  • The library aims to support Linux kernel versions >= 2.6.32.

Notes

General notes

File truncated at 100 lines see the full file

CONTRIBUTING

Contributing to pfs

By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that:

  1. Your contribution is your original work and you have the right to submit it.
  2. Your contribution is submitted under the Apache License 2.0 that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project.
  3. The project author retains complete and sole copyright over the project.

This is consistent with the Developer Certificate of Origin (DCO) 1.1 used across many open-source projects.

Adding a new parser

Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file’s format, implement the parser, wire it in, and add a test.


Pattern 1: kv_file_parser<T> — key-value files

Use this when the file has the form Key: value (one key per line, order irrelevant). Examples: /proc/<pid>/status, /proc/stat.

How it works:

kv_file_parser<T> (in include/pfs/parsers/kv_file_parser.hpp) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name.

Steps:

  1. Add the output type to include/pfs/types.hpp if it doesn’t exist.

  2. Create the parser header in include/pfs/parsers/:

    // include/pfs/parsers/my_file.hpp
    #include "kv_file_parser.hpp"
    #include "pfs/types.hpp"

    namespace pfs { namespace impl { namespace parsers {

    class my_file_parser : public kv_file_parser<my_type>
    {
    public:
        my_file_parser() : kv_file_parser<my_type>(DELIM, PARSERS) {}
    private:
        static const char DELIM;
        static const value_parsers PARSERS;
    };

    }}}
    
  1. Create the parser implementation in src/parsers/:
    // src/parsers/my_file.cpp
    #include "pfs/parsers/my_file.hpp"
    #include "pfs/parsers/number.hpp"

    namespace pfs { namespace impl { namespace parsers {

    const char my_file_parser::DELIM = ':';

    const my_file_parser::value_parsers my_file_parser::PARSERS = {
        {"SomeNumber", [](const std::string& value, my_type& out) {
            to_number(value, out.some_number);
        }},
        {"SomeString", [](const std::string& value, my_type& out) {
            out.some_string = value;
        }},
    };

    }}}
    
  1. Wire it in by adding a getter to the appropriate class (task, net, or procfs) that constructs the parser and calls .parse(path).

  2. Add a unit test in test/. Create a temp file with representative content and assert the parsed fields. See test/test_task_status.cpp for a full example.


Pattern 2: parse_file_lines — tabular/repeated-row files

Use this when each line is an independent record (a row in a table, one entry per line). Examples: /proc/meminfo, /proc/net/tcp, /proc/<pid>/maps.

How it works:

File truncated at 100 lines see the full file

# Contributing to pfs ## License and Copyright By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that: 1. Your contribution is your original work and you have the right to submit it. 2. Your contribution is submitted under the [Apache License 2.0](LICENSE) that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project. 3. The project author retains complete and sole copyright over the project. This is consistent with the [Developer Certificate of Origin (DCO) 1.1](https://developercertificate.org/) used across many open-source projects. ## Adding a new parser Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file's format, implement the parser, wire it in, and add a test. --- ### Pattern 1: `kv_file_parser` — key-value files Use this when the file has the form `Key: value` (one key per line, order irrelevant). Examples: `/proc//status`, `/proc/stat`. **How it works:** `kv_file_parser` (in `include/pfs/parsers/kv_file_parser.hpp`) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name. **Steps:** 1. **Add the output type** to `include/pfs/types.hpp` if it doesn't exist. 2. **Create the parser header** in `include/pfs/parsers/`: ```cpp // include/pfs/parsers/my_file.hpp #include "kv_file_parser.hpp" #include "pfs/types.hpp" namespace pfs { namespace impl { namespace parsers { class my_file_parser : public kv_file_parser { public: my_file_parser() : kv_file_parser(DELIM, PARSERS) {} private: static const char DELIM; static const value_parsers PARSERS; }; }}} ``` 3. **Create the parser implementation** in `src/parsers/`: ```cpp // src/parsers/my_file.cpp #include "pfs/parsers/my_file.hpp" #include "pfs/parsers/number.hpp" namespace pfs { namespace impl { namespace parsers { const char my_file_parser::DELIM = ':'; const my_file_parser::value_parsers my_file_parser::PARSERS = { {"SomeNumber", [](const std::string& value, my_type& out) { to_number(value, out.some_number); }}, {"SomeString", [](const std::string& value, my_type& out) { out.some_string = value; }}, }; }}} ``` 4. **Wire it in** by adding a getter to the appropriate class (`task`, `net`, or `procfs`) that constructs the parser and calls `.parse(path)`. 5. **Add a unit test** in `test/`. Create a temp file with representative content and assert the parsed fields. See `test/test_task_status.cpp` for a full example. --- ### Pattern 2: `parse_file_lines` — tabular/repeated-row files Use this when each line is an independent record (a row in a table, one entry per line). Examples: `/proc/meminfo`, `/proc/net/tcp`, `/proc//maps`. **How it works:** File truncated at 100 lines [see the full file](https://github.com/dtrugman/pfs/tree/main/CONTRIBUTING.md)
No version for distro hydro showing jazzy. Known supported distros are highlighted in the buttons above.
Repo symbol

pfs repository

pfs

ROS Distro
jazzy

Repository Summary

Checkout URI https://github.com/dtrugman/pfs.git
VCS Type git
VCS Version main
Last Updated 2026-04-12
Dev Status MAINTAINED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Packages

Name Version
pfs 0.13.1

README

pfs

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

Build & Test

Run cmake . && make

Currently supported CMake configuration flags:

  • CMAKE_BUILD_TYPE=<Debug|Release>: Standard CMake flags to control build type (DEFAULT: Debug)
  • pfs_BUILD_SHARED_LIBS=<ON|OFF>: ON to compile a shared library. OFF to compile a static library (DEFAULT: Inherit BUILD_SHARE_LIBS, which is OFF by default))
  • pfs_BUILD_ASAN=<ON|OFF>: ON to enable address sanitizer (DEFAULT: OFF)
  • pfs_BUILD_COVERAGE=<ON|OFF>: ON to enable coverage instrumentation (DEFAULT: OFF)
  • pfs_BUILD_SAMPLES=<ON|OFF>: ON to build the sample programs (DEFAULT: ON)
  • pfs_BUILD_TESTS=<ON|OFF>: ON to build the tests (DEFAULT: ON)

You can pass any number of those to the cmake command: cmake -D<CONFIG_FLAG>=<VALUE> .

NOTE: After running cmake for the first time, some values are cached in CMakeCache.txt and will not change when running cmake for a second time with different flags.

Build using clang

If you prefer using clang, just configure the compiler while running cmake:

CXX=<clang++> CC=<clang> cmake .

After that, just use make as always.

Code Coverage

Generate a coverage report is via Docker:

./docker/docker-pfs coverage

This builds the project with coverage instrumentation, runs all tests, and produces:

  • A text summary printed to the terminal
  • An HTML report at ./coverage/index.html

Integrate

  • Compile as a shared or static library.
  • Add the contents of /lib into your link directories
  • Add the contents of /include into your include directories. That’s it, you are good to go.

Use CMake’s find_package()

Option #1: make install (Preferred way)

After building the project, you can install it locally using make install. In your project’s CMake file, you can then add the following snippet, and CMake will handle the rest:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> pfs)

NOTE: CMake generates an install_manifest.txt file to track all the created files, this will help you uninstall the library if you need to do so.

Option #2: Without make install

Build the pfs project. No need to call make install. In your project’s CMake file, you can then add the following snippet:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> -L${pfs_LIBRARY_DIR} ${pfs_LIBRARIES})
target_include_directories (<your-target> [PUBLIC|PRIVATE] ${pfs_INCLUDE_DIRS})

Features

  • 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

  • The library requires C++11 or newer
  • The library aims to support Linux kernel versions >= 2.6.32.

Notes

General notes

File truncated at 100 lines see the full file

CONTRIBUTING

Contributing to pfs

By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that:

  1. Your contribution is your original work and you have the right to submit it.
  2. Your contribution is submitted under the Apache License 2.0 that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project.
  3. The project author retains complete and sole copyright over the project.

This is consistent with the Developer Certificate of Origin (DCO) 1.1 used across many open-source projects.

Adding a new parser

Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file’s format, implement the parser, wire it in, and add a test.


Pattern 1: kv_file_parser<T> — key-value files

Use this when the file has the form Key: value (one key per line, order irrelevant). Examples: /proc/<pid>/status, /proc/stat.

How it works:

kv_file_parser<T> (in include/pfs/parsers/kv_file_parser.hpp) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name.

Steps:

  1. Add the output type to include/pfs/types.hpp if it doesn’t exist.

  2. Create the parser header in include/pfs/parsers/:

    // include/pfs/parsers/my_file.hpp
    #include "kv_file_parser.hpp"
    #include "pfs/types.hpp"

    namespace pfs { namespace impl { namespace parsers {

    class my_file_parser : public kv_file_parser<my_type>
    {
    public:
        my_file_parser() : kv_file_parser<my_type>(DELIM, PARSERS) {}
    private:
        static const char DELIM;
        static const value_parsers PARSERS;
    };

    }}}
    
  1. Create the parser implementation in src/parsers/:
    // src/parsers/my_file.cpp
    #include "pfs/parsers/my_file.hpp"
    #include "pfs/parsers/number.hpp"

    namespace pfs { namespace impl { namespace parsers {

    const char my_file_parser::DELIM = ':';

    const my_file_parser::value_parsers my_file_parser::PARSERS = {
        {"SomeNumber", [](const std::string& value, my_type& out) {
            to_number(value, out.some_number);
        }},
        {"SomeString", [](const std::string& value, my_type& out) {
            out.some_string = value;
        }},
    };

    }}}
    
  1. Wire it in by adding a getter to the appropriate class (task, net, or procfs) that constructs the parser and calls .parse(path).

  2. Add a unit test in test/. Create a temp file with representative content and assert the parsed fields. See test/test_task_status.cpp for a full example.


Pattern 2: parse_file_lines — tabular/repeated-row files

Use this when each line is an independent record (a row in a table, one entry per line). Examples: /proc/meminfo, /proc/net/tcp, /proc/<pid>/maps.

How it works:

File truncated at 100 lines see the full file

# Contributing to pfs ## License and Copyright By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that: 1. Your contribution is your original work and you have the right to submit it. 2. Your contribution is submitted under the [Apache License 2.0](LICENSE) that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project. 3. The project author retains complete and sole copyright over the project. This is consistent with the [Developer Certificate of Origin (DCO) 1.1](https://developercertificate.org/) used across many open-source projects. ## Adding a new parser Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file's format, implement the parser, wire it in, and add a test. --- ### Pattern 1: `kv_file_parser` — key-value files Use this when the file has the form `Key: value` (one key per line, order irrelevant). Examples: `/proc//status`, `/proc/stat`. **How it works:** `kv_file_parser` (in `include/pfs/parsers/kv_file_parser.hpp`) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name. **Steps:** 1. **Add the output type** to `include/pfs/types.hpp` if it doesn't exist. 2. **Create the parser header** in `include/pfs/parsers/`: ```cpp // include/pfs/parsers/my_file.hpp #include "kv_file_parser.hpp" #include "pfs/types.hpp" namespace pfs { namespace impl { namespace parsers { class my_file_parser : public kv_file_parser { public: my_file_parser() : kv_file_parser(DELIM, PARSERS) {} private: static const char DELIM; static const value_parsers PARSERS; }; }}} ``` 3. **Create the parser implementation** in `src/parsers/`: ```cpp // src/parsers/my_file.cpp #include "pfs/parsers/my_file.hpp" #include "pfs/parsers/number.hpp" namespace pfs { namespace impl { namespace parsers { const char my_file_parser::DELIM = ':'; const my_file_parser::value_parsers my_file_parser::PARSERS = { {"SomeNumber", [](const std::string& value, my_type& out) { to_number(value, out.some_number); }}, {"SomeString", [](const std::string& value, my_type& out) { out.some_string = value; }}, }; }}} ``` 4. **Wire it in** by adding a getter to the appropriate class (`task`, `net`, or `procfs`) that constructs the parser and calls `.parse(path)`. 5. **Add a unit test** in `test/`. Create a temp file with representative content and assert the parsed fields. See `test/test_task_status.cpp` for a full example. --- ### Pattern 2: `parse_file_lines` — tabular/repeated-row files Use this when each line is an independent record (a row in a table, one entry per line). Examples: `/proc/meminfo`, `/proc/net/tcp`, `/proc//maps`. **How it works:** File truncated at 100 lines [see the full file](https://github.com/dtrugman/pfs/tree/main/CONTRIBUTING.md)
No version for distro kinetic showing jazzy. Known supported distros are highlighted in the buttons above.
Repo symbol

pfs repository

pfs

ROS Distro
jazzy

Repository Summary

Checkout URI https://github.com/dtrugman/pfs.git
VCS Type git
VCS Version main
Last Updated 2026-04-12
Dev Status MAINTAINED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Packages

Name Version
pfs 0.13.1

README

pfs

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

Build & Test

Run cmake . && make

Currently supported CMake configuration flags:

  • CMAKE_BUILD_TYPE=<Debug|Release>: Standard CMake flags to control build type (DEFAULT: Debug)
  • pfs_BUILD_SHARED_LIBS=<ON|OFF>: ON to compile a shared library. OFF to compile a static library (DEFAULT: Inherit BUILD_SHARE_LIBS, which is OFF by default))
  • pfs_BUILD_ASAN=<ON|OFF>: ON to enable address sanitizer (DEFAULT: OFF)
  • pfs_BUILD_COVERAGE=<ON|OFF>: ON to enable coverage instrumentation (DEFAULT: OFF)
  • pfs_BUILD_SAMPLES=<ON|OFF>: ON to build the sample programs (DEFAULT: ON)
  • pfs_BUILD_TESTS=<ON|OFF>: ON to build the tests (DEFAULT: ON)

You can pass any number of those to the cmake command: cmake -D<CONFIG_FLAG>=<VALUE> .

NOTE: After running cmake for the first time, some values are cached in CMakeCache.txt and will not change when running cmake for a second time with different flags.

Build using clang

If you prefer using clang, just configure the compiler while running cmake:

CXX=<clang++> CC=<clang> cmake .

After that, just use make as always.

Code Coverage

Generate a coverage report is via Docker:

./docker/docker-pfs coverage

This builds the project with coverage instrumentation, runs all tests, and produces:

  • A text summary printed to the terminal
  • An HTML report at ./coverage/index.html

Integrate

  • Compile as a shared or static library.
  • Add the contents of /lib into your link directories
  • Add the contents of /include into your include directories. That’s it, you are good to go.

Use CMake’s find_package()

Option #1: make install (Preferred way)

After building the project, you can install it locally using make install. In your project’s CMake file, you can then add the following snippet, and CMake will handle the rest:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> pfs)

NOTE: CMake generates an install_manifest.txt file to track all the created files, this will help you uninstall the library if you need to do so.

Option #2: Without make install

Build the pfs project. No need to call make install. In your project’s CMake file, you can then add the following snippet:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> -L${pfs_LIBRARY_DIR} ${pfs_LIBRARIES})
target_include_directories (<your-target> [PUBLIC|PRIVATE] ${pfs_INCLUDE_DIRS})

Features

  • 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

  • The library requires C++11 or newer
  • The library aims to support Linux kernel versions >= 2.6.32.

Notes

General notes

File truncated at 100 lines see the full file

CONTRIBUTING

Contributing to pfs

By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that:

  1. Your contribution is your original work and you have the right to submit it.
  2. Your contribution is submitted under the Apache License 2.0 that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project.
  3. The project author retains complete and sole copyright over the project.

This is consistent with the Developer Certificate of Origin (DCO) 1.1 used across many open-source projects.

Adding a new parser

Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file’s format, implement the parser, wire it in, and add a test.


Pattern 1: kv_file_parser<T> — key-value files

Use this when the file has the form Key: value (one key per line, order irrelevant). Examples: /proc/<pid>/status, /proc/stat.

How it works:

kv_file_parser<T> (in include/pfs/parsers/kv_file_parser.hpp) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name.

Steps:

  1. Add the output type to include/pfs/types.hpp if it doesn’t exist.

  2. Create the parser header in include/pfs/parsers/:

    // include/pfs/parsers/my_file.hpp
    #include "kv_file_parser.hpp"
    #include "pfs/types.hpp"

    namespace pfs { namespace impl { namespace parsers {

    class my_file_parser : public kv_file_parser<my_type>
    {
    public:
        my_file_parser() : kv_file_parser<my_type>(DELIM, PARSERS) {}
    private:
        static const char DELIM;
        static const value_parsers PARSERS;
    };

    }}}
    
  1. Create the parser implementation in src/parsers/:
    // src/parsers/my_file.cpp
    #include "pfs/parsers/my_file.hpp"
    #include "pfs/parsers/number.hpp"

    namespace pfs { namespace impl { namespace parsers {

    const char my_file_parser::DELIM = ':';

    const my_file_parser::value_parsers my_file_parser::PARSERS = {
        {"SomeNumber", [](const std::string& value, my_type& out) {
            to_number(value, out.some_number);
        }},
        {"SomeString", [](const std::string& value, my_type& out) {
            out.some_string = value;
        }},
    };

    }}}
    
  1. Wire it in by adding a getter to the appropriate class (task, net, or procfs) that constructs the parser and calls .parse(path).

  2. Add a unit test in test/. Create a temp file with representative content and assert the parsed fields. See test/test_task_status.cpp for a full example.


Pattern 2: parse_file_lines — tabular/repeated-row files

Use this when each line is an independent record (a row in a table, one entry per line). Examples: /proc/meminfo, /proc/net/tcp, /proc/<pid>/maps.

How it works:

File truncated at 100 lines see the full file

# Contributing to pfs ## License and Copyright By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that: 1. Your contribution is your original work and you have the right to submit it. 2. Your contribution is submitted under the [Apache License 2.0](LICENSE) that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project. 3. The project author retains complete and sole copyright over the project. This is consistent with the [Developer Certificate of Origin (DCO) 1.1](https://developercertificate.org/) used across many open-source projects. ## Adding a new parser Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file's format, implement the parser, wire it in, and add a test. --- ### Pattern 1: `kv_file_parser` — key-value files Use this when the file has the form `Key: value` (one key per line, order irrelevant). Examples: `/proc//status`, `/proc/stat`. **How it works:** `kv_file_parser` (in `include/pfs/parsers/kv_file_parser.hpp`) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name. **Steps:** 1. **Add the output type** to `include/pfs/types.hpp` if it doesn't exist. 2. **Create the parser header** in `include/pfs/parsers/`: ```cpp // include/pfs/parsers/my_file.hpp #include "kv_file_parser.hpp" #include "pfs/types.hpp" namespace pfs { namespace impl { namespace parsers { class my_file_parser : public kv_file_parser { public: my_file_parser() : kv_file_parser(DELIM, PARSERS) {} private: static const char DELIM; static const value_parsers PARSERS; }; }}} ``` 3. **Create the parser implementation** in `src/parsers/`: ```cpp // src/parsers/my_file.cpp #include "pfs/parsers/my_file.hpp" #include "pfs/parsers/number.hpp" namespace pfs { namespace impl { namespace parsers { const char my_file_parser::DELIM = ':'; const my_file_parser::value_parsers my_file_parser::PARSERS = { {"SomeNumber", [](const std::string& value, my_type& out) { to_number(value, out.some_number); }}, {"SomeString", [](const std::string& value, my_type& out) { out.some_string = value; }}, }; }}} ``` 4. **Wire it in** by adding a getter to the appropriate class (`task`, `net`, or `procfs`) that constructs the parser and calls `.parse(path)`. 5. **Add a unit test** in `test/`. Create a temp file with representative content and assert the parsed fields. See `test/test_task_status.cpp` for a full example. --- ### Pattern 2: `parse_file_lines` — tabular/repeated-row files Use this when each line is an independent record (a row in a table, one entry per line). Examples: `/proc/meminfo`, `/proc/net/tcp`, `/proc//maps`. **How it works:** File truncated at 100 lines [see the full file](https://github.com/dtrugman/pfs/tree/main/CONTRIBUTING.md)
No version for distro melodic showing jazzy. Known supported distros are highlighted in the buttons above.
Repo symbol

pfs repository

pfs

ROS Distro
jazzy

Repository Summary

Checkout URI https://github.com/dtrugman/pfs.git
VCS Type git
VCS Version main
Last Updated 2026-04-12
Dev Status MAINTAINED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Packages

Name Version
pfs 0.13.1

README

pfs

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

Build & Test

Run cmake . && make

Currently supported CMake configuration flags:

  • CMAKE_BUILD_TYPE=<Debug|Release>: Standard CMake flags to control build type (DEFAULT: Debug)
  • pfs_BUILD_SHARED_LIBS=<ON|OFF>: ON to compile a shared library. OFF to compile a static library (DEFAULT: Inherit BUILD_SHARE_LIBS, which is OFF by default))
  • pfs_BUILD_ASAN=<ON|OFF>: ON to enable address sanitizer (DEFAULT: OFF)
  • pfs_BUILD_COVERAGE=<ON|OFF>: ON to enable coverage instrumentation (DEFAULT: OFF)
  • pfs_BUILD_SAMPLES=<ON|OFF>: ON to build the sample programs (DEFAULT: ON)
  • pfs_BUILD_TESTS=<ON|OFF>: ON to build the tests (DEFAULT: ON)

You can pass any number of those to the cmake command: cmake -D<CONFIG_FLAG>=<VALUE> .

NOTE: After running cmake for the first time, some values are cached in CMakeCache.txt and will not change when running cmake for a second time with different flags.

Build using clang

If you prefer using clang, just configure the compiler while running cmake:

CXX=<clang++> CC=<clang> cmake .

After that, just use make as always.

Code Coverage

Generate a coverage report is via Docker:

./docker/docker-pfs coverage

This builds the project with coverage instrumentation, runs all tests, and produces:

  • A text summary printed to the terminal
  • An HTML report at ./coverage/index.html

Integrate

  • Compile as a shared or static library.
  • Add the contents of /lib into your link directories
  • Add the contents of /include into your include directories. That’s it, you are good to go.

Use CMake’s find_package()

Option #1: make install (Preferred way)

After building the project, you can install it locally using make install. In your project’s CMake file, you can then add the following snippet, and CMake will handle the rest:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> pfs)

NOTE: CMake generates an install_manifest.txt file to track all the created files, this will help you uninstall the library if you need to do so.

Option #2: Without make install

Build the pfs project. No need to call make install. In your project’s CMake file, you can then add the following snippet:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> -L${pfs_LIBRARY_DIR} ${pfs_LIBRARIES})
target_include_directories (<your-target> [PUBLIC|PRIVATE] ${pfs_INCLUDE_DIRS})

Features

  • 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

  • The library requires C++11 or newer
  • The library aims to support Linux kernel versions >= 2.6.32.

Notes

General notes

File truncated at 100 lines see the full file

CONTRIBUTING

Contributing to pfs

By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that:

  1. Your contribution is your original work and you have the right to submit it.
  2. Your contribution is submitted under the Apache License 2.0 that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project.
  3. The project author retains complete and sole copyright over the project.

This is consistent with the Developer Certificate of Origin (DCO) 1.1 used across many open-source projects.

Adding a new parser

Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file’s format, implement the parser, wire it in, and add a test.


Pattern 1: kv_file_parser<T> — key-value files

Use this when the file has the form Key: value (one key per line, order irrelevant). Examples: /proc/<pid>/status, /proc/stat.

How it works:

kv_file_parser<T> (in include/pfs/parsers/kv_file_parser.hpp) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name.

Steps:

  1. Add the output type to include/pfs/types.hpp if it doesn’t exist.

  2. Create the parser header in include/pfs/parsers/:

    // include/pfs/parsers/my_file.hpp
    #include "kv_file_parser.hpp"
    #include "pfs/types.hpp"

    namespace pfs { namespace impl { namespace parsers {

    class my_file_parser : public kv_file_parser<my_type>
    {
    public:
        my_file_parser() : kv_file_parser<my_type>(DELIM, PARSERS) {}
    private:
        static const char DELIM;
        static const value_parsers PARSERS;
    };

    }}}
    
  1. Create the parser implementation in src/parsers/:
    // src/parsers/my_file.cpp
    #include "pfs/parsers/my_file.hpp"
    #include "pfs/parsers/number.hpp"

    namespace pfs { namespace impl { namespace parsers {

    const char my_file_parser::DELIM = ':';

    const my_file_parser::value_parsers my_file_parser::PARSERS = {
        {"SomeNumber", [](const std::string& value, my_type& out) {
            to_number(value, out.some_number);
        }},
        {"SomeString", [](const std::string& value, my_type& out) {
            out.some_string = value;
        }},
    };

    }}}
    
  1. Wire it in by adding a getter to the appropriate class (task, net, or procfs) that constructs the parser and calls .parse(path).

  2. Add a unit test in test/. Create a temp file with representative content and assert the parsed fields. See test/test_task_status.cpp for a full example.


Pattern 2: parse_file_lines — tabular/repeated-row files

Use this when each line is an independent record (a row in a table, one entry per line). Examples: /proc/meminfo, /proc/net/tcp, /proc/<pid>/maps.

How it works:

File truncated at 100 lines see the full file

# Contributing to pfs ## License and Copyright By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that: 1. Your contribution is your original work and you have the right to submit it. 2. Your contribution is submitted under the [Apache License 2.0](LICENSE) that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project. 3. The project author retains complete and sole copyright over the project. This is consistent with the [Developer Certificate of Origin (DCO) 1.1](https://developercertificate.org/) used across many open-source projects. ## Adding a new parser Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file's format, implement the parser, wire it in, and add a test. --- ### Pattern 1: `kv_file_parser` — key-value files Use this when the file has the form `Key: value` (one key per line, order irrelevant). Examples: `/proc//status`, `/proc/stat`. **How it works:** `kv_file_parser` (in `include/pfs/parsers/kv_file_parser.hpp`) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name. **Steps:** 1. **Add the output type** to `include/pfs/types.hpp` if it doesn't exist. 2. **Create the parser header** in `include/pfs/parsers/`: ```cpp // include/pfs/parsers/my_file.hpp #include "kv_file_parser.hpp" #include "pfs/types.hpp" namespace pfs { namespace impl { namespace parsers { class my_file_parser : public kv_file_parser { public: my_file_parser() : kv_file_parser(DELIM, PARSERS) {} private: static const char DELIM; static const value_parsers PARSERS; }; }}} ``` 3. **Create the parser implementation** in `src/parsers/`: ```cpp // src/parsers/my_file.cpp #include "pfs/parsers/my_file.hpp" #include "pfs/parsers/number.hpp" namespace pfs { namespace impl { namespace parsers { const char my_file_parser::DELIM = ':'; const my_file_parser::value_parsers my_file_parser::PARSERS = { {"SomeNumber", [](const std::string& value, my_type& out) { to_number(value, out.some_number); }}, {"SomeString", [](const std::string& value, my_type& out) { out.some_string = value; }}, }; }}} ``` 4. **Wire it in** by adding a getter to the appropriate class (`task`, `net`, or `procfs`) that constructs the parser and calls `.parse(path)`. 5. **Add a unit test** in `test/`. Create a temp file with representative content and assert the parsed fields. See `test/test_task_status.cpp` for a full example. --- ### Pattern 2: `parse_file_lines` — tabular/repeated-row files Use this when each line is an independent record (a row in a table, one entry per line). Examples: `/proc/meminfo`, `/proc/net/tcp`, `/proc//maps`. **How it works:** File truncated at 100 lines [see the full file](https://github.com/dtrugman/pfs/tree/main/CONTRIBUTING.md)
No version for distro noetic showing jazzy. Known supported distros are highlighted in the buttons above.
Repo symbol

pfs repository

pfs

ROS Distro
jazzy

Repository Summary

Checkout URI https://github.com/dtrugman/pfs.git
VCS Type git
VCS Version main
Last Updated 2026-04-12
Dev Status MAINTAINED
Released RELEASED
Contributing Help Wanted (-)
Good First Issues (-)
Pull Requests to Review (-)

Packages

Name Version
pfs 0.13.1

README

pfs

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

Build & Test

Run cmake . && make

Currently supported CMake configuration flags:

  • CMAKE_BUILD_TYPE=<Debug|Release>: Standard CMake flags to control build type (DEFAULT: Debug)
  • pfs_BUILD_SHARED_LIBS=<ON|OFF>: ON to compile a shared library. OFF to compile a static library (DEFAULT: Inherit BUILD_SHARE_LIBS, which is OFF by default))
  • pfs_BUILD_ASAN=<ON|OFF>: ON to enable address sanitizer (DEFAULT: OFF)
  • pfs_BUILD_COVERAGE=<ON|OFF>: ON to enable coverage instrumentation (DEFAULT: OFF)
  • pfs_BUILD_SAMPLES=<ON|OFF>: ON to build the sample programs (DEFAULT: ON)
  • pfs_BUILD_TESTS=<ON|OFF>: ON to build the tests (DEFAULT: ON)

You can pass any number of those to the cmake command: cmake -D<CONFIG_FLAG>=<VALUE> .

NOTE: After running cmake for the first time, some values are cached in CMakeCache.txt and will not change when running cmake for a second time with different flags.

Build using clang

If you prefer using clang, just configure the compiler while running cmake:

CXX=<clang++> CC=<clang> cmake .

After that, just use make as always.

Code Coverage

Generate a coverage report is via Docker:

./docker/docker-pfs coverage

This builds the project with coverage instrumentation, runs all tests, and produces:

  • A text summary printed to the terminal
  • An HTML report at ./coverage/index.html

Integrate

  • Compile as a shared or static library.
  • Add the contents of /lib into your link directories
  • Add the contents of /include into your include directories. That’s it, you are good to go.

Use CMake’s find_package()

Option #1: make install (Preferred way)

After building the project, you can install it locally using make install. In your project’s CMake file, you can then add the following snippet, and CMake will handle the rest:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> pfs)

NOTE: CMake generates an install_manifest.txt file to track all the created files, this will help you uninstall the library if you need to do so.

Option #2: Without make install

Build the pfs project. No need to call make install. In your project’s CMake file, you can then add the following snippet:

find_package (pfs REQUIRED)
...
# Somewhere along the file you define your target
add_<library|executable> (<your-target> ...)
...
target_link_libraries (<your-target> -L${pfs_LIBRARY_DIR} ${pfs_LIBRARIES})
target_include_directories (<your-target> [PUBLIC|PRIVATE] ${pfs_INCLUDE_DIRS})

Features

  • 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

  • The library requires C++11 or newer
  • The library aims to support Linux kernel versions >= 2.6.32.

Notes

General notes

File truncated at 100 lines see the full file

CONTRIBUTING

Contributing to pfs

By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that:

  1. Your contribution is your original work and you have the right to submit it.
  2. Your contribution is submitted under the Apache License 2.0 that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project.
  3. The project author retains complete and sole copyright over the project.

This is consistent with the Developer Certificate of Origin (DCO) 1.1 used across many open-source projects.

Adding a new parser

Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file’s format, implement the parser, wire it in, and add a test.


Pattern 1: kv_file_parser<T> — key-value files

Use this when the file has the form Key: value (one key per line, order irrelevant). Examples: /proc/<pid>/status, /proc/stat.

How it works:

kv_file_parser<T> (in include/pfs/parsers/kv_file_parser.hpp) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name.

Steps:

  1. Add the output type to include/pfs/types.hpp if it doesn’t exist.

  2. Create the parser header in include/pfs/parsers/:

    // include/pfs/parsers/my_file.hpp
    #include "kv_file_parser.hpp"
    #include "pfs/types.hpp"

    namespace pfs { namespace impl { namespace parsers {

    class my_file_parser : public kv_file_parser<my_type>
    {
    public:
        my_file_parser() : kv_file_parser<my_type>(DELIM, PARSERS) {}
    private:
        static const char DELIM;
        static const value_parsers PARSERS;
    };

    }}}
    
  1. Create the parser implementation in src/parsers/:
    // src/parsers/my_file.cpp
    #include "pfs/parsers/my_file.hpp"
    #include "pfs/parsers/number.hpp"

    namespace pfs { namespace impl { namespace parsers {

    const char my_file_parser::DELIM = ':';

    const my_file_parser::value_parsers my_file_parser::PARSERS = {
        {"SomeNumber", [](const std::string& value, my_type& out) {
            to_number(value, out.some_number);
        }},
        {"SomeString", [](const std::string& value, my_type& out) {
            out.some_string = value;
        }},
    };

    }}}
    
  1. Wire it in by adding a getter to the appropriate class (task, net, or procfs) that constructs the parser and calls .parse(path).

  2. Add a unit test in test/. Create a temp file with representative content and assert the parsed fields. See test/test_task_status.cpp for a full example.


Pattern 2: parse_file_lines — tabular/repeated-row files

Use this when each line is an independent record (a row in a table, one entry per line). Examples: /proc/meminfo, /proc/net/tcp, /proc/<pid>/maps.

How it works:

File truncated at 100 lines see the full file

# Contributing to pfs ## License and Copyright By submitting a contribution to this project (including pull requests, patches, and any other material), you agree that: 1. Your contribution is your original work and you have the right to submit it. 2. Your contribution is submitted under the [Apache License 2.0](LICENSE) that governs this project, and you grant the project author a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to use, reproduce, modify, distribute, and sublicense your contribution as part of this project. 3. The project author retains complete and sole copyright over the project. This is consistent with the [Developer Certificate of Origin (DCO) 1.1](https://developercertificate.org/) used across many open-source projects. ## Adding a new parser Every procfs/sysfs file maps to one of two parser patterns. Choose based on the file's format, implement the parser, wire it in, and add a test. --- ### Pattern 1: `kv_file_parser` — key-value files Use this when the file has the form `Key: value` (one key per line, order irrelevant). Examples: `/proc//status`, `/proc/stat`. **How it works:** `kv_file_parser` (in `include/pfs/parsers/kv_file_parser.hpp`) reads the file line by line, splits each line on a delimiter, and dispatches the value to a registered parser function keyed by the field name. **Steps:** 1. **Add the output type** to `include/pfs/types.hpp` if it doesn't exist. 2. **Create the parser header** in `include/pfs/parsers/`: ```cpp // include/pfs/parsers/my_file.hpp #include "kv_file_parser.hpp" #include "pfs/types.hpp" namespace pfs { namespace impl { namespace parsers { class my_file_parser : public kv_file_parser { public: my_file_parser() : kv_file_parser(DELIM, PARSERS) {} private: static const char DELIM; static const value_parsers PARSERS; }; }}} ``` 3. **Create the parser implementation** in `src/parsers/`: ```cpp // src/parsers/my_file.cpp #include "pfs/parsers/my_file.hpp" #include "pfs/parsers/number.hpp" namespace pfs { namespace impl { namespace parsers { const char my_file_parser::DELIM = ':'; const my_file_parser::value_parsers my_file_parser::PARSERS = { {"SomeNumber", [](const std::string& value, my_type& out) { to_number(value, out.some_number); }}, {"SomeString", [](const std::string& value, my_type& out) { out.some_string = value; }}, }; }}} ``` 4. **Wire it in** by adding a getter to the appropriate class (`task`, `net`, or `procfs`) that constructs the parser and calls `.parse(path)`. 5. **Add a unit test** in `test/`. Create a temp file with representative content and assert the parsed fields. See `test/test_task_status.cpp` for a full example. --- ### Pattern 2: `parse_file_lines` — tabular/repeated-row files Use this when each line is an independent record (a row in a table, one entry per line). Examples: `/proc/meminfo`, `/proc/net/tcp`, `/proc//maps`. **How it works:** File truncated at 100 lines [see the full file](https://github.com/dtrugman/pfs/tree/main/CONTRIBUTING.md)