core/common/ProcParser.h (177 lines of code) (raw):

// Copyright 2025 iLogtail Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #include <cstdint> #include <filesystem> #include <string> #include <vector> #include "common/StringView.h" using std::chrono::milliseconds; using std::chrono::steady_clock; using std::chrono::system_clock; namespace logtail { // TODO use definations in bpf_process_event_type.h #define DOCKER_ID_LENGTH 128 struct Proc { public: uint32_t ppid = 0U; // parent pid uint64_t pktime = 0U; uid_t realUid = 0; uid_t effectiveUid = 0; uid_t savedUid = 0; uid_t fsUid = 0; gid_t realGid = 0; gid_t effectiveGid = 0; gid_t savedGid = 0; gid_t fsGid = 0; uint32_t pid = 0; uint32_t tid = 0; uint32_t nspid = 0; uint32_t auid = 0; // Audit UID, loginuid uint32_t flags = 0; uint64_t ktime = 0; std::string cmdline; // \0 separated binary and args std::string comm; std::string cwd; #ifdef APSARA_UNIT_TEST_MAIN std::string environ; #endif std::string exe; std::string container_id; uint64_t effective = 0; uint64_t inheritable = 0; uint64_t permitted = 0; uint32_t uts_ns = 0; uint32_t ipc_ns = 0; uint32_t mnt_ns = 0; uint32_t pid_ns = 0; uint32_t pid_for_children_ns = 0; uint32_t net_ns = 0; uint32_t time_ns = 0; uint32_t time_for_children_ns = 0; uint32_t cgroup_ns = 0; uint32_t user_ns = 0; }; struct ProcessStat { pid_t pid = 0; uint64_t vSize = 0; uint64_t rss = 0; uint64_t minorFaults = 0; uint64_t majorFaults = 0; pid_t parentPid = 0; int tty = 0; int priority = 0; int nice = 0; int numThreads = 0; int64_t startTicks = 0; uint64_t utimeTicks{0}; uint64_t stimeTicks{0}; uint64_t cutimeTicks{0}; uint64_t cstimeTicks{0}; std::string name; char state = '\0'; int processor = 0; }; // See https://man7.org/linux/man-pages/man5/proc.5.html enum class EnumProcessStat : int { pid, // 0 comm, // 1 state, // 2 ppid, // 3 pgrp, // 4 session, // 5 tty_nr, // 6 tpgid, // 7 flags, // 8 minflt, // 9 cminflt, // 10 majflt, // 11 cmajflt, // 12 utime, // 13 stime, // 14 cutime, // 15 cstime, // 16 priority, // 17 nice, // 18 num_threads, // 19 itrealvalue, // 20 starttime, // 21 vsize, // 22 rss, // 23 rsslim, // 24 startcode, // 25 endcode, // 26 startstack, // 27 kstkesp, // 28 kstkeip, // 29 signal, // 30 blocked, // 31 sigignore, // 32 sigcatch, // 33 wchan, // 34 nswap, // 35 cnswap, // 36 exit_signal, // 37 processor, // 38 <--- 至少需要有该字段 rt_priority, // 39 policy, // 40 delayacct_blkio_ticks, // 41 guest_time, // 42 cguest_time, // 43 start_data, // 44 end_data, // 45 start_brk, // 46 arg_start, // 47 arg_end, // 48 env_start, // 49 env_end, // 50 exit_code, // 51 _count, // 只是用于计数,非实际字段 }; static_assert((int)EnumProcessStat::comm == 1, "EnumProcessStat invalid"); static_assert((int)EnumProcessStat::processor == 38, "EnumProcessStat invalid"); constexpr int operator-(EnumProcessStat a, EnumProcessStat b) { return (int)a - (int)b; } // 定义 ProcessStatus结构体,用于存储/proc/<pid>/status 文件解析结果 struct ProcessStatus { pid_t pid = 0; // UID信息 (real, effective, saved, filesystem) uid_t realUid = 0; uid_t effectiveUid = 0; uid_t savedUid = 0; uid_t fsUid = 0; // GID 信息(real, effective, saved, filesystem) gid_t realGid = 0; gid_t effectiveGid = 0; gid_t savedGid = 0; gid_t fsGid = 0; // 命名空间线程组ID std::vector<pid_t> nstgid; // 进程权限能力 (capabilities) uint64_t capPrm = 0; // 允许的权限能力 uint64_t capEff = 0; // 有效的权限能力 uint64_t capInh = 0; // 可继承的权限能力 }; class ProcParser { public: explicit ProcParser(const std::string& prefix) : mProcPath(prefix + "/proc") {} bool ParseProc(uint32_t pid, Proc& proc) const; std::string GetPIDCmdline(uint32_t pid) const; std::string GetPIDComm(uint32_t pid) const; std::string GetPIDEnviron(uint32_t pid) const; uint32_t GetPIDCWD(uint32_t pid, std::string& cwd) const; bool ReadProcessStat(pid_t pid, ProcessStat& ps) const; bool ParseProcessStat(pid_t pid, const std::string& line, ProcessStat& ps) const; bool ReadProcessStatus(pid_t pid, ProcessStatus& ps) const; bool ParseProcessStatus(pid_t pid, const std::string& content, ProcessStatus& ps) const; int64_t GetStatsKtime(ProcessStat& procStat) const; uid_t GetLoginUid(uint32_t pid) const; /** * Retrieves the container ID associated with the specified pid. * * @param pid The PID. * @param containerID The output parameter to store the container ID. * @return offset of containerId in the last segment path */ int GetPIDDockerId(uint32_t pid, std::string& containerId) const; /** * Retrieves the container ID associated with the specified cgroup path. * * @param cgroupPath The path to the cgroup. * @param containerID The output parameter to store the container ID. * @return offset of containerId in the last segment path */ static int GetContainerId(const std::string& cgroupPath, std::string& containerId); uint32_t GetPIDNsInode(uint32_t pid, const std::string& nsStr) const; std::string GetPIDExePath(uint32_t pid) const; std::tuple<std::string, std::string> ProcsFilename(const std::string& args); std::string GetUserNameByUid(uid_t uid); private: std::filesystem::path procPidPath(uint32_t pid, const std::string& subpath) const; std::string readPidFile(uint32_t pid, const std::string& filename) const; std::string readPidLink(uint32_t pid, const std::string& filename) const; static int lookupContainerId(const StringView& cgroupline, StringView& containerId); static bool isValidContainerId(const StringView& id); std::filesystem::path mProcPath; static constexpr size_t kContainerIdLength = 64; static constexpr size_t kCgroupNameLength = 128; }; } // namespace logtail