--- src/data_provider/src/sysInfoFreeBSD.cpp 2025-09-23 06:59:40.000000000 -0700 +++ src/data_provider/src/sysInfoFreeBSD.cpp 2025-10-16 15:42:56.638994000 -0700 @@ -11,20 +11,23 @@ #include "sysInfo.hpp" #include "cmdHelper.h" #include "stringHelper.h" +#include "timeHelper.h" #include "osinfo/sysOsParsers.h" #include #include #include #include "sharedDefs.h" +#include static void getMemory(nlohmann::json& info) { + constexpr auto vmFree{"vm.stats.vm.v_free_count"}; + constexpr auto vmInactive{"vm.stats.vm.v_inactive_count"}; constexpr auto vmPageSize{"vm.stats.vm.v_page_size"}; - constexpr auto vmTotal{"vm.vmtotal"}; + constexpr auto vmTotal{"hw.physmem"}; uint64_t ram{0}; - const std::vector mib{CTL_HW, HW_PHYSMEM}; size_t len{sizeof(ram)}; - auto ret{sysctl(const_cast(mib.data()), mib.size(), &ram, &len, nullptr, 0)}; + auto ret{sysctlbyname(vmTotal, &ram, &len, nullptr, 0)}; if (ret) { @@ -52,11 +55,23 @@ }; } - struct vmtotal vmt {}; + uint64_t freeMem{0}; + len = sizeof(freeMem); + ret = sysctlbyname(vmFree, &freeMem, &len, nullptr, 0); - len = sizeof(vmt); + if (ret) + { + throw std::system_error + { + ret, + std::system_category(), + "Error reading free memory size." + }; + } - ret = sysctlbyname(vmTotal, &vmt, &len, nullptr, 0); + uint64_t inactiveMem{0}; + len = sizeof(inactiveMem); + ret = sysctlbyname(vmInactive, &inactiveMem, &len, nullptr, 0); if (ret) { @@ -64,11 +79,11 @@ { ret, std::system_category(), - "Error reading total memory." + "Error reading inactive memory size." }; } - const auto ramFree{(vmt.t_free * pageSize) / KByte}; + const auto ramFree{(freeMem + inactiveMem) * pageSize / KByte}; info["ram_free"] = ramFree; info["ram_usage"] = 100 - (100 * ramFree / ramTotal); } @@ -184,8 +199,12 @@ nlohmann::json SysInfo::getProcessesInfo() const { - // Currently not supported for this OS - return nlohmann::json {}; + nlohmann::json ret; + getProcessesInfo([&ret](nlohmann::json & data) + { + ret.push_back(data); + }); + return ret; } nlohmann::json SysInfo::getOsInfo() const @@ -196,11 +215,12 @@ if (!spParser->parseUname(Utils::exec("uname -r"), ret)) { - ret["os_name"] = "BSD"; ret["os_platform"] = "bsd"; ret["os_version"] = UNKNOWN_VALUE; } + ret["os_name"] = "FreeBSD"; + if (uname(&uts) >= 0) { ret["sysname"] = uts.sysname; @@ -215,18 +235,200 @@ nlohmann::json SysInfo::getPorts() const { - // Currently not supported for this OS. - return nlohmann::json {}; + nlohmann::json ports {}; + + /* USER COMMAND PID FD PROTO LOCAL_ADDRESS FOREIGN_ADDRESS PATH_STATE CONN_STATE */ + +#if __FreeBSD_version > 1500045 + const auto query{exec(R"(sockstat -46qs --libxo json)")}; + + if (!query.empty()) + { + nlohmann::json portsjson; + portsjson = nlohmann::json::parse(query); + auto &portsResult = portsjson["sockstat"]["socket"]; + + for(auto &port : portsResult) { + std::string localip = ""; + std::string localport = ""; + std::string remoteip = ""; + std::string remoteport = ""; + std::string statedata = ""; + + if (port["pid"] != nullptr) { + + localip = port["local"]["address"]; + remoteip = port["foreign"]["address"]; + statedata = port["conn-state"] != nullptr ? (port["conn-state"] == "LISTEN" ? "listening" : Utils::toLowerCase(port["conn-state"])) : statedata; + + if (port["local"]["address"] == "*") { + if ((port["proto"] == "udp4") || (port["proto"] == "tcp4")) { + localip = "0.0.0.0"; + } else { + localip = "::"; + } + } + + localport = port["local"]["port"]; + + if (port["foreign"]["address"] == "*") { + if ((port["proto"] == "udp4") || (port["proto"] == "tcp4")) { + remoteip = 0.0.0.0; + } else { + remoteip = "::"; + } + } + + remoteport = port["foreign"]["port"]; + + nlohmann::json portRecord {}; + + portRecord["protocol"] = port["proto"]; + portRecord["local_ip"] = localip; + portRecord["local_port"] = localport == "*" ? "0" : localport; + portRecord["remote_ip"] = remoteip; + portRecord["remote_port"] = remoteport == "*" ? "0" : remoteport; + portRecord["tx_queue"] = 0; + portRecord["rx_queue"] = 0; + portRecord["inode"] = port["fd"]; + portRecord["state"] = statedata == "??" ? "" : statedata; + portRecord["pid"] = port["pid"]; + portRecord["process"] = port["command"]; + + ports.push_back(portRecord); + } + } + } +#else + const auto query{Utils::exec(R"(sockstat -46qs)")}; + + if (!query.empty()) + { + const auto lines{Utils::split(Utils::trimToOneSpace(query), '\n')}; + + std::regex expression(R"(^(\S+)\s+(\S+)\s+(\d+)\s+(\d+)\s*(\S+)\s+(\S+)\s+(\S+)(?:\s+(\S+))?\s*$)"); + + for (const auto& line : lines) + { + std::smatch data; + + if (std::regex_search(line, data, expression)) + { + std::string localip = ""; + std::string localport = ""; + std::string remoteip = ""; + std::string remoteport = ""; + std::string statedata = ""; + + auto localdata{Utils::split(data[6], ':')}; + auto remotedata{Utils::split(data[7], ':')}; + + if (data[8].matched ) { + statedata = data[8] == "LISTEN" ? "listening" : Utils::toLowerCase(data[8]); + } + + localport = localdata[localdata.size() - 1]; + localdata.pop_back(); + localip = Utils::join(localdata, ":"); + remoteport = remotedata[remotedata.size() - 1]; + remotedata.pop_back(); + remoteip = Utils::join(remotedata, ":"); + + if(localip == "*") { + if((data[5] == "tcp4") || (data[5] == "udp4")) { + localip = "0.0.0.0"; + } else { + localip = "::"; + } + } + + if(remoteip == "*") { + if((data[5] == "tcp4") || (data[5] == "udp4")) { + remoteip = "0.0.0.0"; + } else { + remoteip = "::"; + } + } + + if(data[0] != "?") { + nlohmann::json port {}; + + port["protocol"] = data[5]; + port["local_ip"] = localip; + port["local_port"] = localport == "*" ? "0" : localport; + port["remote_ip"] = remoteip; + port["remote_port"] = remoteport == "*" ? "0" : remoteport; + port["tx_queue"] = 0; + port["rx_queue"] = 0; + port["inode"] = data[4]; + port["state"] = statedata == "??" ? "" : statedata; + port["pid"] = data[3]; + port["process"] = data[2]; + + ports.push_back(port); + } + } + } + } +#endif + return ports; } -void SysInfo::getProcessesInfo(std::function /*callback*/) const +void SysInfo::getProcessesInfo(std::function callback) const { - // Currently not supported for this OS. + const auto query{Utils::exec(R"(ps -ax -w -o pid,comm,state,ppid,usertime,systime,user,ruser,svuid,group,rgroup,svgid,pri,nice,ssiz,vsz,rss,pmem,etimes,sid,pgid,tpgid,tty,cpu,nlwp,args --libxo json)")}; + + if (!query.empty()) + { + nlohmann::json psjson; + psjson = nlohmann::json::parse(query); + auto &processes = psjson["process-information"]["process"]; + + for(auto &process : processes) { + std::string user_time{""}; + std::string system_time{""}; + + user_time = process["user-time"].get(); + system_time = process["system-time"].get(); + + nlohmann::json jsProcessInfo{}; + jsProcessInfo["pid"] = process["pid"].get(); + jsProcessInfo["name"] = process["command"].get(); + jsProcessInfo["state"] = process["state"].get(); + jsProcessInfo["ppid"] = process["ppid"].get(); + jsProcessInfo["utime"] = Utils::timeToSeconds(user_time); + jsProcessInfo["stime"] = Utils::timeToSeconds(system_time); + jsProcessInfo["cmd"] = process["command"].get(); + jsProcessInfo["argvs"] = process["arguments"].get(); + jsProcessInfo["euser"] = process["user"].get(); + jsProcessInfo["ruser"] = process["real-user"].get(); + jsProcessInfo["suser"] = process["saved-uid"].get(); + jsProcessInfo["egroup"] = process["group"].get(); + jsProcessInfo["rgroup"] = process["real-group"].get(); + jsProcessInfo["sgroup"] = process["saved-gid"].get(); + jsProcessInfo["fgroup"] = process["group"].get(); + jsProcessInfo["priority"] = process["priority"].get(); + jsProcessInfo["nice"] = process["nice"].get(); + jsProcessInfo["size"] = process["stack-size"].get(); + jsProcessInfo["vm_size"] = process["virtual-size"].get(); + jsProcessInfo["resident"] = process["rss"].get(); + //jsProcessInfo["share"] = process["percent-memory"].get(); + jsProcessInfo["start_time"] = process["elapsed-times"].get() == "-" ? "0" : process["elapsed-times"].get(); + jsProcessInfo["pgrp"] = process["process-group"].get(); + jsProcessInfo["session"] = process["sid"].get(); + jsProcessInfo["tgid"] = process["terminal-process-gid"].get(); + //jsProcessInfo["tty"] = process["tty"].get(); // this field should be TEXT into local.db + jsProcessInfo["processor"] = process["on-cpu"].get(); + jsProcessInfo["nlwp"] = process["threads"].get(); + + callback(jsProcessInfo); + } + } } void SysInfo::getPackages(std::function callback) const { - const auto query{Utils::exec(R"(pkg query -a "%n|%m|%v|%q|%c")")}; + const auto query{Utils::exec(R"(pkg query -a "%n|%m|%v|%q|%c|%sb|%t|%R|%o")")}; if (!query.empty()) { @@ -235,6 +437,9 @@ for (const auto& line : lines) { const auto data{Utils::split(line, '|')}; + const auto archdata{Utils::split(data[3], ':')}; + const auto sectiondata{Utils::split(data[8], '/')}; + nlohmann::json package; std::string vendor { UNKNOWN_VALUE }; std::string email { UNKNOWN_VALUE }; @@ -244,14 +449,15 @@ package["name"] = data[0]; package["vendor"] = vendor; package["version"] = data[2]; - package["install_time"] = UNKNOWN_VALUE; + package["install_time"] = data[6]; package["location"] = UNKNOWN_VALUE; - package["architecture"] = data[3]; + package["architecture"] = archdata[2]; package["groups"] = UNKNOWN_VALUE; package["description"] = data[4]; - package["size"] = 0; + package["size"] = data[5]; package["priority"] = UNKNOWN_VALUE; - package["source"] = UNKNOWN_VALUE; + package["source"] = data[7]; + package["section"] = sectiondata[0]; package["format"] = "pkg"; // The multiarch field won't have a default value