• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 14554080340

19 Apr 2025 11:46AM UTC coverage: 72.101% (-0.03%) from 72.13%
14554080340

push

github

web-flow
Add two new paragraphs to coding style about header files (#37188)

296880 of 411754 relevant lines covered (72.1%)

687547.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.97
/src/basic/procfs-util.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <errno.h>
4
#include <unistd.h>
5

6
#include "alloc-util.h"
7
#include "constants.h"
8
#include "fd-util.h"
9
#include "fileio.h"
10
#include "log.h"
11
#include "parse-util.h"
12
#include "process-util.h"
13
#include "procfs-util.h"
14
#include "stdio-util.h"
15
#include "string-util.h"
16

17
int procfs_get_pid_max(uint64_t *ret) {
6,705✔
18
        _cleanup_free_ char *value = NULL;
6,705✔
19
        int r;
6,705✔
20

21
        assert(ret);
6,705✔
22

23
        r = read_one_line_file("/proc/sys/kernel/pid_max", &value);
6,705✔
24
        if (r < 0)
6,705✔
25
                return r;
26

27
        return safe_atou64(value, ret);
6,705✔
28
}
29

30
int procfs_get_threads_max(uint64_t *ret) {
6,704✔
31
        _cleanup_free_ char *value = NULL;
6,704✔
32
        int r;
6,704✔
33

34
        assert(ret);
6,704✔
35

36
        r = read_one_line_file("/proc/sys/kernel/threads-max", &value);
6,704✔
37
        if (r < 0)
6,704✔
38
                return r;
39

40
        return safe_atou64(value, ret);
6,704✔
41
}
42

43
int procfs_tasks_set_limit(uint64_t limit) {
2✔
44
        char buffer[DECIMAL_STR_MAX(uint64_t)+1];
2✔
45
        uint64_t pid_max;
2✔
46
        int r;
2✔
47

48
        if (limit == 0) /* This makes no sense, we are userspace and hence count as tasks too, and we want to live,
2✔
49
                         * hence the limit conceptually has to be above 0. Also, most likely if anyone asks for a zero
50
                         * limit they probably mean "no limit", hence let's better refuse this to avoid
51
                         * confusion. */
52
                return -EINVAL;
2✔
53

54
        /* The Linux kernel doesn't allow this value to go below 20, hence don't allow this either, higher values than
55
         * TASKS_MAX are not accepted by the pid_max sysctl. We'll treat anything this high as "unbounded" and hence
56
         * set it to the maximum. */
57
        limit = CLAMP(limit, 20U, TASKS_MAX);
2✔
58

59
        r = procfs_get_pid_max(&pid_max);
2✔
60
        if (r < 0)
2✔
61
                return r;
62

63
        /* As pid_max is about the numeric pid_t range we'll bump it if necessary, but only ever increase it, never
64
         * decrease it, as threads-max is the much more relevant sysctl. */
65
        if (limit > pid_max-1) {
2✔
66
                xsprintf(buffer, "%" PRIu64, limit+1); /* Add one, since PID 0 is not a valid PID */
×
67
                r = write_string_file("/proc/sys/kernel/pid_max", buffer, WRITE_STRING_FILE_DISABLE_BUFFER);
×
68
                if (r < 0)
×
69
                        return r;
70
        }
71

72
        xsprintf(buffer, "%" PRIu64, limit);
2✔
73
        r = write_string_file("/proc/sys/kernel/threads-max", buffer, WRITE_STRING_FILE_DISABLE_BUFFER);
2✔
74
        if (r < 0) {
2✔
75
                uint64_t threads_max;
2✔
76

77
                /* Hmm, we couldn't write this? If so, maybe it was already set properly? In that case let's not
78
                 * generate an error */
79

80
                if (procfs_get_threads_max(&threads_max) < 0)
2✔
81
                        return r; /* return original error */
1✔
82

83
                if (MIN(pid_max - 1, threads_max) != limit)
2✔
84
                        return r; /* return original error */
85

86
                /* Yay! Value set already matches what we were trying to set, hence consider this a success. */
87
        }
88

89
        return 0;
90
}
91

92
int procfs_tasks_get_current(uint64_t *ret) {
1✔
93
        _cleanup_free_ char *value = NULL;
1✔
94
        const char *p, *nr;
1✔
95
        size_t n;
1✔
96
        int r;
1✔
97

98
        assert(ret);
1✔
99

100
        r = read_one_line_file("/proc/loadavg", &value);
1✔
101
        if (r < 0)
1✔
102
                return r;
103

104
        /* Look for the second part of the fourth field, which is separated by a slash from the first part. None of the
105
         * earlier fields use a slash, hence let's use this to find the right spot. */
106
        p = strchr(value, '/');
1✔
107
        if (!p)
1✔
108
                return -EINVAL;
109

110
        p++;
1✔
111
        n = strspn(p, DIGITS);
1✔
112
        nr = strndupa_safe(p, n);
1✔
113

114
        return safe_atou64(nr, ret);
1✔
115
}
116

117
static uint64_t calc_gcd64(uint64_t a, uint64_t b) {
1✔
118

119
        while (b > 0) {
2✔
120
                uint64_t t;
1✔
121

122
                t = a % b;
1✔
123

124
                a = b;
1✔
125
                b = t;
1✔
126
        }
127

128
        return a;
1✔
129
}
130

131
int procfs_cpu_get_usage(nsec_t *ret) {
1✔
132
        _cleanup_free_ char *first_line = NULL;
1✔
133
        unsigned long user_ticks, nice_ticks, system_ticks, irq_ticks, softirq_ticks,
1✔
134
                guest_ticks = 0, guest_nice_ticks = 0;
1✔
135
        long ticks_per_second;
1✔
136
        uint64_t sum, gcd, a, b;
1✔
137
        const char *p;
1✔
138
        int r;
1✔
139

140
        assert(ret);
1✔
141

142
        r = read_one_line_file("/proc/stat", &first_line);
1✔
143
        if (r < 0)
1✔
144
                return r;
145

146
        p = first_word(first_line, "cpu");
1✔
147
        if (!p)
1✔
148
                return -EINVAL;
149

150
        if (sscanf(p, "%lu %lu %lu %*u %*u %lu %lu %*u %lu %lu",
1✔
151
                   &user_ticks,
152
                   &nice_ticks,
153
                   &system_ticks,
154
                   &irq_ticks,
155
                   &softirq_ticks,
156
                   &guest_ticks,
157
                   &guest_nice_ticks) < 5) /* we only insist on the first five fields */
158
                return -EINVAL;
159

160
        ticks_per_second = sysconf(_SC_CLK_TCK);
1✔
161
        if (ticks_per_second  < 0)
1✔
162
                return -errno;
×
163
        assert(ticks_per_second > 0);
1✔
164

165
        sum = (uint64_t) user_ticks + (uint64_t) nice_ticks + (uint64_t) system_ticks +
1✔
166
                (uint64_t) irq_ticks + (uint64_t) softirq_ticks +
1✔
167
                (uint64_t) guest_ticks + (uint64_t) guest_nice_ticks;
1✔
168

169
        /* Let's reduce this fraction before we apply it to avoid overflows when converting this to μsec */
170
        gcd = calc_gcd64(NSEC_PER_SEC, ticks_per_second);
1✔
171

172
        a = (uint64_t) NSEC_PER_SEC / gcd;
1✔
173
        b = (uint64_t) ticks_per_second / gcd;
1✔
174

175
        *ret = DIV_ROUND_UP((nsec_t) sum * (nsec_t) a, (nsec_t) b);
1✔
176
        return 0;
1✔
177
}
178

179
int convert_meminfo_value_to_uint64_bytes(const char *s, uint64_t *ret) {
215✔
180
        _cleanup_free_ char *w = NULL;
215✔
181
        uint64_t v;
215✔
182
        int r;
215✔
183

184
        assert(s);
215✔
185
        assert(ret);
215✔
186

187
        r = extract_first_word(&s, &w, /* separators = */ NULL, /* flags = */ 0);
215✔
188
        if (r < 0)
215✔
189
                return r;
190
        if (r == 0)
215✔
191
                return -EINVAL;
192

193
        /* Ensure the line ends in "kB" */
194
        if (!streq(s, "kB"))
215✔
195
                return -EINVAL;
196

197
        r = safe_atou64(w, &v);
214✔
198
        if (r < 0)
214✔
199
                return r;
200
        if (v == UINT64_MAX)
214✔
201
                return -EINVAL;
202

203
        if (!MUL_ASSIGN_SAFE(&v, U64_KB))
214✔
204
                return -EOVERFLOW;
205

206
        *ret = v;
214✔
207
        return 0;
214✔
208
}
209

210
int procfs_memory_get(uint64_t *ret_total, uint64_t *ret_used) {
29✔
211
        uint64_t mem_total = UINT64_MAX, mem_available = UINT64_MAX;
29✔
212
        _cleanup_fclose_ FILE *f = NULL;
29✔
213
        int r;
29✔
214

215
        f = fopen("/proc/meminfo", "re");
29✔
216
        if (!f)
29✔
217
                return -errno;
×
218

219
        for (;;) {
87✔
220
                _cleanup_free_ char *line = NULL;
58✔
221
                uint64_t *v;
87✔
222
                char *p;
87✔
223

224
                r = read_line(f, LONG_LINE_MAX, &line);
87✔
225
                if (r < 0)
87✔
226
                        return r;
227
                if (r == 0)
87✔
228
                        return -EINVAL; /* EOF: Couldn't find one or both fields? */
229

230
                p = first_word(line, "MemTotal:");
87✔
231
                if (p)
87✔
232
                        v = &mem_total;
233
                else {
234
                        p = first_word(line, "MemAvailable:");
58✔
235
                        if (p)
58✔
236
                                v = &mem_available;
237
                        else
238
                                continue;
29✔
239
                }
240

241
                r = convert_meminfo_value_to_uint64_bytes(p, v);
58✔
242
                if (r < 0)
58✔
243
                        return r;
244

245
                if (mem_total != UINT64_MAX && mem_available != UINT64_MAX)
58✔
246
                        break;
247
        }
248

249
        if (mem_available > mem_total)
29✔
250
                return -EINVAL;
251

252
        if (ret_total)
29✔
253
                *ret_total = mem_total;
26✔
254
        if (ret_used)
29✔
255
                *ret_used = mem_total - mem_available;
3✔
256
        return 0;
257
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc