cubefs
211 строк · 4.6 Кб
1// Copyright 2019 The Prometheus Authors
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14//go:build (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris) && !js
15// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
16// +build !js
17
18package procfs
19
20import (
21"bufio"
22"fmt"
23"os"
24"strconv"
25"strings"
26
27"golang.org/x/sys/unix"
28)
29
30// ProcMapPermissions contains permission settings read from `/proc/[pid]/maps`.
31type ProcMapPermissions struct {
32// mapping has the [R]ead flag set
33Read bool
34// mapping has the [W]rite flag set
35Write bool
36// mapping has the [X]ecutable flag set
37Execute bool
38// mapping has the [S]hared flag set
39Shared bool
40// mapping is marked as [P]rivate (copy on write)
41Private bool
42}
43
44// ProcMap contains the process memory-mappings of the process
45// read from `/proc/[pid]/maps`.
46type ProcMap struct {
47// The start address of current mapping.
48StartAddr uintptr
49// The end address of the current mapping
50EndAddr uintptr
51// The permissions for this mapping
52Perms *ProcMapPermissions
53// The current offset into the file/fd (e.g., shared libs)
54Offset int64
55// Device owner of this mapping (major:minor) in Mkdev format.
56Dev uint64
57// The inode of the device above
58Inode uint64
59// The file or psuedofile (or empty==anonymous)
60Pathname string
61}
62
63// parseDevice parses the device token of a line and converts it to a dev_t
64// (mkdev) like structure.
65func parseDevice(s string) (uint64, error) {
66toks := strings.Split(s, ":")
67if len(toks) < 2 {
68return 0, fmt.Errorf("unexpected number of fields")
69}
70
71major, err := strconv.ParseUint(toks[0], 16, 0)
72if err != nil {
73return 0, err
74}
75
76minor, err := strconv.ParseUint(toks[1], 16, 0)
77if err != nil {
78return 0, err
79}
80
81return unix.Mkdev(uint32(major), uint32(minor)), nil
82}
83
84// parseAddress converts a hex-string to a uintptr.
85func parseAddress(s string) (uintptr, error) {
86a, err := strconv.ParseUint(s, 16, 0)
87if err != nil {
88return 0, err
89}
90
91return uintptr(a), nil
92}
93
94// parseAddresses parses the start-end address.
95func parseAddresses(s string) (uintptr, uintptr, error) {
96toks := strings.Split(s, "-")
97if len(toks) < 2 {
98return 0, 0, fmt.Errorf("invalid address")
99}
100
101saddr, err := parseAddress(toks[0])
102if err != nil {
103return 0, 0, err
104}
105
106eaddr, err := parseAddress(toks[1])
107if err != nil {
108return 0, 0, err
109}
110
111return saddr, eaddr, nil
112}
113
114// parsePermissions parses a token and returns any that are set.
115func parsePermissions(s string) (*ProcMapPermissions, error) {
116if len(s) < 4 {
117return nil, fmt.Errorf("invalid permissions token")
118}
119
120perms := ProcMapPermissions{}
121for _, ch := range s {
122switch ch {
123case 'r':
124perms.Read = true
125case 'w':
126perms.Write = true
127case 'x':
128perms.Execute = true
129case 'p':
130perms.Private = true
131case 's':
132perms.Shared = true
133}
134}
135
136return &perms, nil
137}
138
139// parseProcMap will attempt to parse a single line within a proc/[pid]/maps
140// buffer.
141func parseProcMap(text string) (*ProcMap, error) {
142fields := strings.Fields(text)
143if len(fields) < 5 {
144return nil, fmt.Errorf("truncated procmap entry")
145}
146
147saddr, eaddr, err := parseAddresses(fields[0])
148if err != nil {
149return nil, err
150}
151
152perms, err := parsePermissions(fields[1])
153if err != nil {
154return nil, err
155}
156
157offset, err := strconv.ParseInt(fields[2], 16, 0)
158if err != nil {
159return nil, err
160}
161
162device, err := parseDevice(fields[3])
163if err != nil {
164return nil, err
165}
166
167inode, err := strconv.ParseUint(fields[4], 10, 0)
168if err != nil {
169return nil, err
170}
171
172pathname := ""
173
174if len(fields) >= 5 {
175pathname = strings.Join(fields[5:], " ")
176}
177
178return &ProcMap{
179StartAddr: saddr,
180EndAddr: eaddr,
181Perms: perms,
182Offset: offset,
183Dev: device,
184Inode: inode,
185Pathname: pathname,
186}, nil
187}
188
189// ProcMaps reads from /proc/[pid]/maps to get the memory-mappings of the
190// process.
191func (p Proc) ProcMaps() ([]*ProcMap, error) {
192file, err := os.Open(p.path("maps"))
193if err != nil {
194return nil, err
195}
196defer file.Close()
197
198maps := []*ProcMap{}
199scan := bufio.NewScanner(file)
200
201for scan.Scan() {
202m, err := parseProcMap(scan.Text())
203if err != nil {
204return nil, err
205}
206
207maps = append(maps, m)
208}
209
210return maps, nil
211}
212