25 | 25 |
// http://man7.org/linux/man-pages/man2/getrlimit.2.html.
|
26 | 26 |
type ProcLimits struct {
|
27 | 27 |
// CPU time limit in seconds.
|
28 | |
CPUTime int64
|
|
28 |
CPUTime uint64
|
29 | 29 |
// Maximum size of files that the process may create.
|
30 | |
FileSize int64
|
|
30 |
FileSize uint64
|
31 | 31 |
// Maximum size of the process's data segment (initialized data,
|
32 | 32 |
// uninitialized data, and heap).
|
33 | |
DataSize int64
|
|
33 |
DataSize uint64
|
34 | 34 |
// Maximum size of the process stack in bytes.
|
35 | |
StackSize int64
|
|
35 |
StackSize uint64
|
36 | 36 |
// Maximum size of a core file.
|
37 | |
CoreFileSize int64
|
|
37 |
CoreFileSize uint64
|
38 | 38 |
// Limit of the process's resident set in pages.
|
39 | |
ResidentSet int64
|
|
39 |
ResidentSet uint64
|
40 | 40 |
// Maximum number of processes that can be created for the real user ID of
|
41 | 41 |
// the calling process.
|
42 | |
Processes int64
|
|
42 |
Processes uint64
|
43 | 43 |
// Value one greater than the maximum file descriptor number that can be
|
44 | 44 |
// opened by this process.
|
45 | |
OpenFiles int64
|
|
45 |
OpenFiles uint64
|
46 | 46 |
// Maximum number of bytes of memory that may be locked into RAM.
|
47 | |
LockedMemory int64
|
|
47 |
LockedMemory uint64
|
48 | 48 |
// Maximum size of the process's virtual memory address space in bytes.
|
49 | |
AddressSpace int64
|
|
49 |
AddressSpace uint64
|
50 | 50 |
// Limit on the combined number of flock(2) locks and fcntl(2) leases that
|
51 | 51 |
// this process may establish.
|
52 | |
FileLocks int64
|
|
52 |
FileLocks uint64
|
53 | 53 |
// Limit of signals that may be queued for the real user ID of the calling
|
54 | 54 |
// process.
|
55 | |
PendingSignals int64
|
|
55 |
PendingSignals uint64
|
56 | 56 |
// Limit on the number of bytes that can be allocated for POSIX message
|
57 | 57 |
// queues for the real user ID of the calling process.
|
58 | |
MsqqueueSize int64
|
|
58 |
MsqqueueSize uint64
|
59 | 59 |
// Limit of the nice priority set using setpriority(2) or nice(2).
|
60 | |
NicePriority int64
|
|
60 |
NicePriority uint64
|
61 | 61 |
// Limit of the real-time priority set using sched_setscheduler(2) or
|
62 | 62 |
// sched_setparam(2).
|
63 | |
RealtimePriority int64
|
|
63 |
RealtimePriority uint64
|
64 | 64 |
// Limit (in microseconds) on the amount of CPU time that a process
|
65 | 65 |
// scheduled under a real-time scheduling policy may consume without making
|
66 | 66 |
// a blocking system call.
|
67 | |
RealtimeTimeout int64
|
|
67 |
RealtimeTimeout uint64
|
68 | 68 |
}
|
69 | 69 |
|
70 | 70 |
const (
|
71 | |
limitsFields = 3
|
|
71 |
limitsFields = 4
|
72 | 72 |
limitsUnlimited = "unlimited"
|
73 | 73 |
)
|
74 | 74 |
|
75 | 75 |
var (
|
76 | |
limitsDelimiter = regexp.MustCompile(" +")
|
|
76 |
limitsMatch = regexp.MustCompile(`(Max \w+\s{0,1}?\w*\s{0,1}\w*)\s{2,}(\w+)\s+(\w+)`)
|
77 | 77 |
)
|
78 | 78 |
|
79 | 79 |
// NewLimits returns the current soft limits of the process.
|
|
95 | 95 |
l = ProcLimits{}
|
96 | 96 |
s = bufio.NewScanner(f)
|
97 | 97 |
)
|
|
98 |
|
|
99 |
s.Scan() // Skip limits header
|
|
100 |
|
98 | 101 |
for s.Scan() {
|
99 | |
fields := limitsDelimiter.Split(s.Text(), limitsFields)
|
|
102 |
//fields := limitsMatch.Split(s.Text(), limitsFields)
|
|
103 |
fields := limitsMatch.FindStringSubmatch(s.Text())
|
100 | 104 |
if len(fields) != limitsFields {
|
101 | 105 |
return ProcLimits{}, fmt.Errorf(
|
102 | 106 |
"couldn't parse %s line %s", f.Name(), s.Text())
|
103 | 107 |
}
|
104 | 108 |
|
105 | |
switch fields[0] {
|
|
109 |
switch fields[1] {
|
106 | 110 |
case "Max cpu time":
|
107 | |
l.CPUTime, err = parseInt(fields[1])
|
|
111 |
l.CPUTime, err = parseUint(fields[2])
|
108 | 112 |
case "Max file size":
|
109 | |
l.FileSize, err = parseInt(fields[1])
|
|
113 |
l.FileSize, err = parseUint(fields[2])
|
110 | 114 |
case "Max data size":
|
111 | |
l.DataSize, err = parseInt(fields[1])
|
|
115 |
l.DataSize, err = parseUint(fields[2])
|
112 | 116 |
case "Max stack size":
|
113 | |
l.StackSize, err = parseInt(fields[1])
|
|
117 |
l.StackSize, err = parseUint(fields[2])
|
114 | 118 |
case "Max core file size":
|
115 | |
l.CoreFileSize, err = parseInt(fields[1])
|
|
119 |
l.CoreFileSize, err = parseUint(fields[2])
|
116 | 120 |
case "Max resident set":
|
117 | |
l.ResidentSet, err = parseInt(fields[1])
|
|
121 |
l.ResidentSet, err = parseUint(fields[2])
|
118 | 122 |
case "Max processes":
|
119 | |
l.Processes, err = parseInt(fields[1])
|
|
123 |
l.Processes, err = parseUint(fields[2])
|
120 | 124 |
case "Max open files":
|
121 | |
l.OpenFiles, err = parseInt(fields[1])
|
|
125 |
l.OpenFiles, err = parseUint(fields[2])
|
122 | 126 |
case "Max locked memory":
|
123 | |
l.LockedMemory, err = parseInt(fields[1])
|
|
127 |
l.LockedMemory, err = parseUint(fields[2])
|
124 | 128 |
case "Max address space":
|
125 | |
l.AddressSpace, err = parseInt(fields[1])
|
|
129 |
l.AddressSpace, err = parseUint(fields[2])
|
126 | 130 |
case "Max file locks":
|
127 | |
l.FileLocks, err = parseInt(fields[1])
|
|
131 |
l.FileLocks, err = parseUint(fields[2])
|
128 | 132 |
case "Max pending signals":
|
129 | |
l.PendingSignals, err = parseInt(fields[1])
|
|
133 |
l.PendingSignals, err = parseUint(fields[2])
|
130 | 134 |
case "Max msgqueue size":
|
131 | |
l.MsqqueueSize, err = parseInt(fields[1])
|
|
135 |
l.MsqqueueSize, err = parseUint(fields[2])
|
132 | 136 |
case "Max nice priority":
|
133 | |
l.NicePriority, err = parseInt(fields[1])
|
|
137 |
l.NicePriority, err = parseUint(fields[2])
|
134 | 138 |
case "Max realtime priority":
|
135 | |
l.RealtimePriority, err = parseInt(fields[1])
|
|
139 |
l.RealtimePriority, err = parseUint(fields[2])
|
136 | 140 |
case "Max realtime timeout":
|
137 | |
l.RealtimeTimeout, err = parseInt(fields[1])
|
|
141 |
l.RealtimeTimeout, err = parseUint(fields[2])
|
138 | 142 |
}
|
139 | 143 |
if err != nil {
|
140 | 144 |
return ProcLimits{}, err
|
|
144 | 148 |
return l, s.Err()
|
145 | 149 |
}
|
146 | 150 |
|
147 | |
func parseInt(s string) (int64, error) {
|
|
151 |
func parseUint(s string) (uint64, error) {
|
148 | 152 |
if s == limitsUnlimited {
|
149 | |
return -1, nil
|
|
153 |
return 18446744073709551615, nil
|
150 | 154 |
}
|
151 | |
i, err := strconv.ParseInt(s, 10, 64)
|
|
155 |
i, err := strconv.ParseUint(s, 10, 64)
|
152 | 156 |
if err != nil {
|
153 | 157 |
return 0, fmt.Errorf("couldn't parse value %s: %s", s, err)
|
154 | 158 |
}
|