2
0
mirror of https://github.com/boostorg/process.git synced 2026-01-19 16:32:15 +00:00
Files
process/src/pid.cpp
2024-12-20 19:05:07 +08:00

841 lines
19 KiB
C++

// Copyright (c) 2022 Klemens D. Morgenstern
// Copyright (c) 2022 Samuel Venable
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/last_error.hpp>
#include <boost/process/v2/detail/throw_error.hpp>
#include <boost/process/v2/pid.hpp>
#if defined(BOOST_PROCESS_V2_WINDOWS)
#include <windows.h>
#include <tlhelp32.h>
#else
#include <unistd.h>
#endif
#if (defined(__APPLE__) && defined(__MACH__))
#include <TargetConditionals.h>
#if !TARGET_OS_IOS
#include <sys/proc_info.h>
#include <libproc.h>
#endif
#endif
#if (defined(__linux__) || defined(__ANDROID__))
#include <dirent.h>
#endif
#if defined(__FreeBSD__)
#include <fcntl.h>
#include <kvm.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#endif
#if (defined(__DragonFly__) || defined(__OpenBSD__))
#include <sys/types.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <kvm.h>
#endif
#if defined(__NetBSD__)
#include <sys/types.h>
#include <kvm.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#endif
#if defined(__sun)
#include <fcntl.h>
#include <sys/types.h>
#include <kvm.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/proc.h>
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
#if defined(BOOST_PROCESS_V2_WINDOWS)
pid_type current_pid() {return ::GetCurrentProcessId();}
#else
pid_type current_pid() {return ::getpid();}
#endif
#if defined(BOOST_PROCESS_V2_WINDOWS)
std::vector<pid_type> all_pids(error_code & ec)
{
std::vector<pid_type> vec;
HANDLE hp = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (!hp)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return vec;
}
PROCESSENTRY32 pe;
pe.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hp, &pe))
{
do
{
vec.push_back(pe.th32ProcessID);
} while (Process32Next(hp, &pe));
}
CloseHandle(hp);
return vec;
}
pid_type parent_pid(pid_type pid, error_code & ec)
{
pid_type ppid = static_cast<pid_type>(-1);
HANDLE hp = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (!hp)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return ppid;
}
PROCESSENTRY32 pe;
pe.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hp, &pe))
{
do
{
if (pe.th32ProcessID == pid)
{
ppid = pe.th32ParentProcessID;
break;
}
}
while (Process32Next(hp, &pe));
}
CloseHandle(hp);
return ppid;
}
std::vector<pid_type> child_pids(pid_type pid, error_code & ec)
{
std::vector<pid_type> vec;
HANDLE hp = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (!hp)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return vec;
}
PROCESSENTRY32 pe;
pe.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hp, &pe))
{
do
{
if (pe.th32ParentProcessID == pid)
{
vec.push_back(pe.th32ProcessID);
}
}
while (Process32Next(hp, &pe));
}
CloseHandle(hp);
return vec;
}
#elif (defined(__APPLE__) && defined(__MACH__)) && !TARGET_OS_IOS
std::vector<pid_type> all_pids(error_code & ec)
{
std::vector<pid_type> vec;
vec.resize(proc_listpids(PROC_ALL_PIDS, 0, nullptr, 0) / sizeof(pid_type));
const auto sz = proc_listpids(PROC_ALL_PIDS, 0, &vec[0], sizeof(pid_type) * vec.size());
if (sz < 0)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return {};
}
vec.resize(sz);
return vec;
}
pid_type parent_pid(pid_type pid, error_code & ec)
{
pid_type ppid = static_cast<pid_type>(-1);
proc_bsdinfo proc_info;
if (proc_pidinfo(pid, PROC_PIDTBSDINFO, 0, &proc_info, sizeof(proc_info)) <= 0)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return ppid;
}
else
ppid = proc_info.pbi_ppid;
return ppid;
}
std::vector<pid_type> child_pids(pid_type pid, error_code & ec)
{
std::vector<pid_type> vec;
vec.resize(proc_listpids(PROC_PPID_ONLY, (uint32_t)pid, nullptr, 0) / sizeof(pid_type));
const auto sz = proc_listpids(PROC_PPID_ONLY, (uint32_t)pid, &vec[0], sizeof(pid_type) * vec.size());
if (sz < 0)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return {};
}
vec.resize(sz);
return vec;
}
#elif (defined(__linux__) || defined(__ANDROID__))
std::vector<pid_type> all_pids(error_code & ec)
{
std::vector<pid_type> vec;
DIR *proc = opendir("/proc");
if (!proc)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return vec;
}
struct dirent *ent = nullptr;
while ((ent = readdir(proc)))
{
if (!isdigit(*ent->d_name))
continue;
vec.push_back(atoi(ent->d_name));
}
closedir(proc);
return vec;
}
pid_type parent_pid(pid_type pid, error_code & ec)
{
pid_type ppid = static_cast<pid_type>(-1);
char buffer[BUFSIZ];
sprintf(buffer, "/proc/%d/stat", pid);
FILE *stat = fopen(buffer, "r");
if (!stat)
{
if (errno == ENOENT)
BOOST_PROCESS_V2_ASSIGN_EC(ec, ESRCH, system_category());
else
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return ppid;
}
else
{
std::size_t size = fread(buffer, sizeof(char), sizeof(buffer), stat);
if (size > 0)
{
char *token = nullptr;
if ((token = strtok(buffer, " ")))
{
if ((token = strtok(nullptr, " ")))
{
if ((token = strtok(nullptr, " ")))
{
if ((token = strtok(nullptr, " ")))
{
ppid = (pid_type)strtoul(token, nullptr, 10);
}
}
}
}
if (!token)
{
fclose(stat);
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return ppid;
}
}
fclose(stat);
}
return ppid;
}
std::vector<pid_type> child_pids(pid_type pid, error_code & ec)
{
std::vector<pid_type> vec;
std::vector<pid_type> pids = all_pids(ec);
if (!pids.empty())
vec.reserve(pids.size());
for (std::size_t i = 0; i < pids.size(); i++)
{
pid_type ppid = parent_pid(pids[i], ec);
if (ppid != -1 && ppid == pid)
vec.push_back(pids[i]);
else if (ec.value() == ESRCH)
ec.clear();
}
return vec;
}
#elif defined(__FreeBSD__)
std::vector<pid_type> all_pids(error_code & ec)
{
std::vector<pid_type> vec;
int cntp = 0;
kinfo_proc *proc_info = nullptr;
const char *nlistf, *memf;
nlistf = memf = "/dev/null";
struct closer
{
void operator()(kvm_t * kd)
{
kvm_close(kd);
}
};
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nlistf, memf, nullptr, O_RDONLY, nullptr)};
if (!kd)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return vec;
}
if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_ALL, 0, &cntp)))
{
vec.reserve(cntp);
for (int i = 0; i < cntp; i++)
vec.push_back(proc_info[i].ki_pid);
}
else
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return vec;
}
pid_type parent_pid(pid_type pid, error_code & ec)
{
pid_type ppid = static_cast<pid_type>(-1);
int cntp = 0;
kinfo_proc *proc_info = nullptr;
const char *nlistf, *memf;
nlistf = memf = "/dev/null";
struct closer
{
void operator()(kvm_t * kd)
{
kvm_close(kd);
}
};
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nlistf, memf, nullptr, O_RDONLY, nullptr)};
if (!kd)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return ppid;
}
if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_PID, pid, &cntp)))
{
ppid = proc_info->ki_ppid;
}
else
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return ppid;
}
std::vector<pid_type> child_pids(pid_type pid, error_code & ec)
{
std::vector<pid_type> vec;
int cntp = 0;
kinfo_proc *proc_info = nullptr;
const char *nlistf, *memf;
nlistf = memf = "/dev/null";
struct closer
{
void operator()(kvm_t * kd)
{
kvm_close(kd);
}
};
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nlistf, memf, nullptr, O_RDONLY, nullptr)};
if (!kd)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return vec;
}
if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_ALL, 0, &cntp)))
{
vec.reserve(cntp);
for (int i = 0; i < cntp; i++)
{
if (proc_info[i].ki_ppid == pid)
{
vec.push_back(proc_info[i].ki_pid);
}
}
}
else
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return vec;
}
#elif defined(__DragonFly__)
std::vector<pid_type> all_pids(error_code & ec)
{
std::vector<pid_type> vec;
int cntp = 0;
kinfo_proc *proc_info = nullptr;
const char *nlistf, *memf;
nlistf = memf = "/dev/null";
struct closer
{
void operator()(kvm_t * kd)
{
kvm_close(kd);
}
};
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nlistf, memf, nullptr, O_RDONLY, nullptr)};
if (!kd)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return vec;
}
if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_ALL, 0, &cntp)))
{
vec.reserve(cntp);
for (int i = 0; i < cntp; i++)
if (proc_info[i].kp_pid >= 0)
vec.push_back(proc_info[i].kp_pid);
}
else
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return vec;
}
pid_type parent_pid(pid_type pid, error_code & ec)
{
pid_type ppid = static_cast<pid_type>(-1);
int cntp = 0;
kinfo_proc *proc_info = nullptr;
const char *nlistf, *memf;
nlistf = memf = "/dev/null";
struct closer
{
void operator()(kvm_t * kd)
{
kvm_close(kd);
}
};
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nlistf, memf, nullptr, O_RDONLY, nullptr)};
if (!kd)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return ppid;
}
if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_PID, pid, &cntp)))
{
if (proc_info->kp_ppid >= 0)
{
ppid = proc_info->kp_ppid;
}
}
else
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return ppid;
}
std::vector<pid_type> child_pids(pid_type pid, error_code & ec)
{
std::vector<pid_type> vec;
int cntp = 0;
kinfo_proc *proc_info = nullptr;
const char *nlistf, *memf;
nlistf = memf = "/dev/null";
struct closer
{
void operator()(kvm_t * kd)
{
kvm_close(kd);
}
};
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nlistf, memf, nullptr, O_RDONLY, nullptr)};
if (!kd)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return vec;
}
if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_ALL, 0, &cntp)))
{
vec.reserve(cntp);
for (int i = 0; i < cntp; i++)
{
if (proc_info[i].kp_pid >= 0 && proc_info[i].kp_ppid >= 0 && proc_info[i].kp_ppid == pid)
{
vec.push_back(proc_info[i].kp_pid);
}
}
}
else
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return vec;
}
#elif defined(__NetBSD__)
std::vector<pid_type> all_pids(error_code & ec)
{
std::vector<pid_type> vec;
int cntp = 0;
kinfo_proc2 *proc_info = nullptr;
struct closer
{
void operator()(kvm_t * kd)
{
kvm_close(kd);
}
};
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr)};
if (!kd)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return vec;
}
if ((proc_info = kvm_getproc2(kd.get(), KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2), &cntp)))
{
vec.reserve(cntp);
for (int i = cntp - 1; i >= 0; i--)
{
vec.push_back(proc_info[i].p_pid);
}
}
else
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return vec;
}
pid_type parent_pid(pid_type pid, error_code & ec)
{
pid_type ppid = static_cast<pid_type>(-1);
int cntp = 0;
kinfo_proc2 *proc_info = nullptr;
struct closer
{
void operator()(kvm_t * kd)
{
kvm_close(kd);
}
};
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr)};
if (!kd)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return ppid;
}
if ((proc_info = kvm_getproc2(kd.get(), KERN_PROC_PID, pid, sizeof(struct kinfo_proc2), &cntp)))
{
ppid = proc_info->p_ppid;
}
else
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return ppid;
}
std::vector<pid_type> child_pids(pid_type pid, error_code & ec)
{
std::vector<pid_type> vec;
int cntp = 0;
kinfo_proc2 *proc_info = nullptr;
struct closer
{
void operator()(kvm_t * kd)
{
kvm_close(kd);
}
};
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr)};
if (!kd)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return vec;
}
if ((proc_info = kvm_getproc2(kd.get(), KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2), &cntp)))
{
vec.reserve(cntp);
for (int i = cntp - 1; i >= 0; i--)
{
if (proc_info[i].p_ppid == pid)
{
vec.push_back(proc_info[i].p_pid);
}
}
}
else
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return vec;
}
#elif defined(__OpenBSD__)
std::vector<pid_type> all_pids(error_code & ec)
{
std::vector<pid_type> vec;
int cntp = 0;
kinfo_proc *proc_info = nullptr;
struct closer
{
void operator()(kvm_t * kd)
{
kvm_close(kd);
}
};
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr)};
if (!kd)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return vec;
}
if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), &cntp)))
{
vec.reserve(cntp);
for (int i = cntp - 1; i >= 0; i--)
{
if (proc_info[i].p_pid >= 0)
{
vec.push_back(proc_info[i].p_pid);
}
}
}
else
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return vec;
}
pid_type parent_pid(pid_type pid, error_code & ec)
{
pid_type ppid = static_cast<pid_type>(-1);
int cntp = 0;
kinfo_proc *proc_info = nullptr;
struct closer
{
void operator()(kvm_t * kd)
{
kvm_close(kd);
}
};
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr)};
if (!kd)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return ppid;
}
if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_PID, pid, sizeof(struct kinfo_proc), &cntp)))
{
ppid = proc_info->p_ppid;
}
else
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return ppid;
}
std::vector<pid_type> child_pids(pid_type pid, error_code & ec)
{
std::vector<pid_type> vec;
int cntp = 0;
kinfo_proc *proc_info = nullptr;
struct closer
{
void operator()(kvm_t * kd)
{
kvm_close(kd);
}
};
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr)};
if (!kd)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return vec;
}
if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), &cntp)))
{
vec.reserve(cntp);
for (int i = cntp - 1; i >= 0; i--)
{
if (proc_info[i].p_ppid == pid)
{
vec.push_back(proc_info[i].p_pid);
}
}
}
else
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return vec;
}
#elif defined(__sun)
std::vector<pid_type> all_pids(error_code & ec)
{
std::vector<pid_type> vec;
struct pid cur_pid;
proc *proc_info = nullptr;
struct closer
{
void operator()(kvm_t * kd)
{
kvm_close(kd);
}
};
std::unique_ptr<kvm_t, closer> kd{kvm_open(nullptr, nullptr, nullptr, O_RDONLY, nullptr)};
if (!kd)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return vec;
}
while ((proc_info = kvm_nextproc(kd.get())))
{
if (kvm_kread(kd.get(), (std::uintptr_t)proc_info->p_pidp, &cur_pid, sizeof(cur_pid)) != -1)
{
vec.insert(vec.begin(), cur_pid.pid_id);
}
else
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
break;
}
}
return vec;
}
pid_type parent_pid(pid_type pid, error_code & ec)
{
pid_type ppid = static_cast<pid_type>(-1);
proc *proc_info = nullptr;
struct closer
{
void operator()(kvm_t * kd)
{
kvm_close(kd);
}
};
std::unique_ptr<kvm_t, closer> kd{kvm_open(nullptr, nullptr, nullptr, O_RDONLY, nullptr)};
if (!kd)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return ppid;
}
if ((proc_info = kvm_getproc(kd.get(), pid)))
{
ppid = proc_info->p_ppid;
}
else
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return ppid;
}
std::vector<pid_type> child_pids(pid_type pid, error_code & ec)
{
std::vector<pid_type> vec;
struct pid cur_pid;
proc *proc_info = nullptr;
struct closer
{
void operator()(kvm_t * kd)
{
kvm_close(kd);
}
};
std::unique_ptr<kvm_t, closer> kd{kvm_open(nullptr, nullptr, nullptr, O_RDONLY, nullptr)};
if (!kd)
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
return vec;
}
while ((proc_info = kvm_nextproc(kd.get())))
{
if (proc_info->p_ppid == pid)
{
if (kvm_kread(kd.get(), (std::uintptr_t)proc_info->p_pidp, &cur_pid, sizeof(cur_pid)) != -1)
{
vec.insert(vec.begin(), cur_pid.pid_id);
}
else
{
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
break;
}
}
}
return vec;
}
#else
std::vector<pid_type> all_pids(error_code & ec)
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, ENOTSUP, system_category());
return {};
}
pid_type parent_pid(pid_type pid, error_code & ec)
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, ENOTSUP, system_category());
return pid;
}
std::vector<pid_type> child_pids(pid_type, error_code & ec)
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, ENOTSUP, system_category());
return {};
}
#endif
std::vector<pid_type> all_pids()
{
error_code ec;
auto res = all_pids(ec);
if (ec)
detail::throw_error(ec, "all_pids");
return res;
}
pid_type parent_pid(pid_type pid)
{
error_code ec;
auto res = parent_pid(pid, ec);
if (ec)
detail::throw_error(ec, "parent_pid");
return res;
}
std::vector<pid_type> child_pids(pid_type pid)
{
error_code ec;
auto res = child_pids(pid, ec);
if (ec)
detail::throw_error(ec, "child_pids");
return res;
}
BOOST_PROCESS_V2_END_NAMESPACE