在Linux中proc文件夹记录了系统当前运行的系统状态和进程状态。在每个进程文件中有一个status文件,该文件描述了当前进程的各种信息,如下图所示
Name: cat 进程名称。
Umask: 0022 文件创建掩码
State: R (running) 进程状态
Tgid: 1578975 线程组ID
Ngid: 0 Nice组ID
Pid: 1578975 进程ID
PPid: 1425046 父进程ID
TracerPid: 0 跟踪进程ID
Uid: 1001 1001 1001 1001 用户组ID
Gid: 1001 1001 1001 1001 组ID
FDSize: 128 文件描述符大小
Groups: 965 1001 进程所属组
NStgid: 1578975 新线程组ID
NSpid: 1578975 新进程组ID
NSpgid: 1578975 新线程组ID
NSsid: 1425046 新会话ID
Kthread: 0 内核线程
VmPeak: 8700 kB 进程使用的虚拟内存峰值
VmSize: 8700 kB 进程使用的虚拟内存大小
VmLck: 0 kB 锁定的虚拟内存大小
VmPin: 0 kB 钉住的虚拟内存大小
VmHWM: 1764 kB 进程使用的虚拟内存高水位标记
VmRSS: 1764 kB 进程使用的驻留集大小
RssAnon: 0 kB 匿名驻留集大小
RssFile: 1764 kB 文件驻留集大小
RssShmem: 0 kB 共享内存驻留集大小
VmData: 340 kB 数据段大小
VmStk: 136 kB 堆栈段大小
VmExe: 16 kB 可执行段大小
VmLib: 1544 kB 库段大小
VmPTE: 52 kB 页表条目大小
VmSwap: 0 kB 交换空间大小
HugetlbPages: 0 kB 大页面数量
CoreDumping: 0 核心转储状态
THP_enabled: 1 透明大页面启用状态
untag_mask: 0xffffffffffffffff 进程未标记的内存页面的范围
Threads: 1 线程数量
SigQ: 1/63004 信号队列
SigPnd: 0000000000000000 待处理信号数量
ShdPnd: 0000000000000000 待处理共享内存信号数量
SigBlk: 0000000000000000 被阻塞的信号数量
SigIgn: 0000000000000000 被忽略的信号数量
SigCgt: 0000000000000000 被捕获的信号数量
CapInh: 0000000000000000 被禁止的能力
CapPrm: 0000000000000000 被允许的能力
CapEff: 0000000000000000 有效的能力
CapBnd: 000001ffffffffff 绑定的能力
CapAmb: 0000000000000000 未决的能力
NoNewPrivs: 0 禁止新特权
Seccomp: 0 安全计算模式
Seccomp_filters: 0 安全计算过滤器
Speculation_Store_Bypass: thread vulnerable 推测存储绕过
SpeculationIndirectBranch: conditional enabled 推测间接分支
Cpus_allowed: ff 允许使用的 CPU
Cpus_allowed_list: 0-7
Mems_allowed: 00000001
Mems_allowed_list: 0
voluntary_ctxt_switches: 0
nonvoluntary_ctxt_switches: 0
1. 首先定义需要处理的结构体,这里直接定义所有类型为string
type Process struct {
Name string
Umask string
State string
Tgid string
Ngid string
Pid string
PPid string
TracerPid string
Uid string
Gid string
FDSize string
Groups string
NStgid string
NSpid string
NSpgid string
NSsid string
Kthread string
VmPeak string
VmSize string
VmLck string
VmPin string
VmHWM string
VmRSS string
RssAnon string
RssFile string
RssShmem string
VmData string
VmStk string
VmExe string
VmLib string
VmPTE string
VmSwap string
HugetlbPages string
CoreDumping string
THP_enabled string
untag_mask string
Threads string
SigQ string
SigPnd string
ShdPnd string
SigBlk string
SigIgn string
SigCgt string
CapInh string
CapPrm string
CapEff string
CapBnd string
CapAmb string
NoNewPrivs string
Seccomp string
Seccomp_filters string
Speculation_Store_Bypass string
SpeculationIndirectBranch string
Cpus_allowed string
Cpus_allowed_list string
Mems_allowed string
Mems_allowed_list string
voluntary_ctxt_switches string
nonvoluntary_ctxt_switches string
}
2. 获取原始文件
首先定义一个常量PROC_PATH用于保存proc文件系统路径
const PROC_PATH = "/proc"
3. 读取文件
使用os.ReadDir读取该文件夹下所有的目录
processList, err := os.ReadDir(PROC_PATH)
4. 正则匹配进程目录
在Linux中,进程存储在/proc/pid文件夹内,每个进程都是一个文件夹,而进程号则是以数字命名
validate := regexp.MustCompile("^[0-9]+$")
for _, info := range processList {
var process Process
if info.IsDir() && validate.MatchString(info.Name()) {
...
}
}
5. 将文件byte[]处理为string
首先将文件buffer转为string字符串
file := string(filebuffer)
6. 将字符处理为key[value]数据结构
每个进程状态描述文件的内容都是以key: value的形式组织,但是中间的间隔符有的是\t有的是\s需要统一并分割成key[value]形式,最终返回一个map数字
var regM = regexp.MustCompile(":{1}([\t| ])*")
var regV = regexp.MustCompile("(\t| )+")
func getStatusFileToObj(str string) map[string]string {
infoMap := make(map[string]string)
infoLineList := strings.Split(str, "\n")
for _, line := range infoLineList {
line1 := regM.ReplaceAllString(line, "___")
info := strings.Split(line1, "___")
if len(info) == 2 {
infoMap[info[0]] = regV.ReplaceAllString(info[1], ",")
}
}
return infoMap
}
7. 使用json.Marshal将字符转换为json,再利用json.Unmarshal将json转换为Process结构
j, _ := json.Marshal(getStatusFileToObj(file))
json.Unmarshal(j, &process)
processObjList = append(processObjList, process)
最终效果如下
{
"Name": "systemd",
"Umask": "0000",
"State": "S (sleeping)",
"Tgid": "1",
"Ngid": "0",
"Pid": "1",
"PPid": "0",
"TracerPid": "0",
"Uid": "0 0 0 0",
"Gid": "0 0 0 0",
"FDSize": "512",
"Groups": "",
"NStgid": "1",
"NSpid": "1",
"NSpgid": "1",
"NSsid": "1",
"Kthread": "0",
"VmPeak": "30704 kB",
"VmSize": "23104 kB",
"VmLck": "0 kB",
"VmPin": "0 kB",
"VmHWM": "20316 kB",
"VmRSS": "8928 kB",
"RssAnon": "2532 kB",
"RssFile": "6396 kB",
"RssShmem": "0 kB",
"VmData": "3016 kB",
"VmStk": "1036 kB",
"VmExe": "40 kB",
"VmLib": "11936 kB",
"VmPTE": "84 kB",
"VmSwap": "1920 kB",
"HugetlbPages": "0 kB",
"CoreDumping": "0",
"THP_enabled": "1",
"Threads": "1",
"SigQ": "1/63004",
"SigPnd": "0000000000000000",
"ShdPnd": "0000000000000000",
"SigBlk": "7fefc1fe28014a03",
"SigIgn": "0000000000001000",
"SigCgt": "00000000000004ec",
"CapInh": "0000000000000000",
"CapPrm": "000001ffffffffff",
"CapEff": "000001ffffffffff",
"CapBnd": "000001ffffffffff",
"CapAmb": "0000000000000000",
"NoNewPrivs": "0",
"Seccomp": "0",
"Seccomp_filters": "0",
"Speculation_Store_Bypass": "thread vulnerable",
"SpeculationIndirectBranch": "conditional enabled",
"Cpus_allowed": "ff",
"Cpus_allowed_list": "0-7",
"Mems_allowed": "00000001",
"Mems_allowed_list": "0"
}