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

systemd / systemd / 15263807472

26 May 2025 08:53PM UTC coverage: 72.046% (-0.002%) from 72.048%
15263807472

push

github

yuwata
src/core/manager.c: log preset activity on first boot

This gives us a little more information about what units were enabled
or disabled on that first boot and will be useful for OS developers
tracking down the source of unit state.

An example with this enabled looks like:

```
NET: Registered PF_VSOCK protocol family
systemd[1]: Applying preset policy.
systemd[1]: Unit /etc/systemd/system/dnsmasq.service is masked, ignoring.
systemd[1]: Unit /etc/systemd/system/systemd-repart.service is masked, ignoring.
systemd[1]: Removed '/etc/systemd/system/sockets.target.wants/systemd-resolved-monitor.socket'.
systemd[1]: Removed '/etc/systemd/system/sockets.target.wants/systemd-resolved-varlink.socket'.
systemd[1]: Created symlink '/etc/systemd/system/multi-user.target.wants/var-mnt-workdir.mount' → '/etc/systemd/system/var-mnt-workdir.mount'.
systemd[1]: Created symlink '/etc/systemd/system/multi-user.target.wants/var-mnt-workdir\x2dtmp.mount' → '/etc/systemd/system/var-mnt-workdir\x2dtmp.mount'.
systemd[1]: Created symlink '/etc/systemd/system/afterburn-sshkeys.target.requires/afterburn-sshkeys@core.service' → '/usr/lib/systemd/system/afterburn-sshkeys@.service'.
systemd[1]: Created symlink '/etc/systemd/system/sockets.target.wants/systemd-resolved-varlink.socket' → '/usr/lib/systemd/system/systemd-resolved-varlink.socket'.
systemd[1]: Created symlink '/etc/systemd/system/sockets.target.wants/systemd-resolved-monitor.socket' → '/usr/lib/systemd/system/systemd-resolved-monitor.socket'.
systemd[1]: Populated /etc with preset unit settings.
```

Considering it only happens on first boot and not on every boot I think
the extra information is worth the extra verbosity in the logs just for
that boot.

5 of 6 new or added lines in 1 file covered. (83.33%)

5463 existing lines in 165 files now uncovered.

299151 of 415222 relevant lines covered (72.05%)

702386.45 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 <unistd.h>
4

5
#include "alloc-util.h"
6
#include "extract-word.h"
7
#include "fd-util.h"
8
#include "fileio.h"
9
#include "parse-util.h"
10
#include "process-util.h"
11
#include "procfs-util.h"
12
#include "stdio-util.h"
13
#include "string-util.h"
14
#include "time-util.h"
15

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

20
        assert(ret);
6,914✔
21

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

26
        return safe_atou64(value, ret);
6,914✔
27
}
28

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

33
        assert(ret);
6,913✔
34

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

39
        return safe_atou64(value, ret);
6,913✔
40
}
41

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

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

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

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

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

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

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

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

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

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

88
        return 0;
89
}
90

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

97
        assert(ret);
1✔
98

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

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

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

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

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

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

121
                t = a % b;
1✔
122

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

127
        return a;
1✔
128
}
129

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

139
        assert(ret);
1✔
140

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

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

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

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

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

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

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

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

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

183
        assert(s);
223✔
184
        assert(ret);
223✔
185

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

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

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

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

205
        *ret = v;
222✔
206
        return 0;
222✔
207
}
208

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

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

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

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

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

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

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

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

251
        if (ret_total)
29✔
252
                *ret_total = mem_total;
26✔
253
        if (ret_used)
29✔
254
                *ret_used = mem_total - mem_available;
3✔
255
        return 0;
256
}
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