1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <stdio.h>
4 #include <unistd.h>
5
6 #include "alloc-util.h"
7 #include "errno-util.h"
8 #include "extract-word.h"
9 #include "fd-util.h"
10 #include "fileio.h"
11 #include "parse-util.h"
12 #include "psi-util.h"
13 #include "string-util.h"
14 #include "stat-util.h"
15 #include "strv.h"
16
read_resource_pressure(const char * path,PressureType type,ResourcePressure * ret)17 int read_resource_pressure(const char *path, PressureType type, ResourcePressure *ret) {
18 _cleanup_free_ char *line = NULL;
19 _cleanup_fclose_ FILE *f = NULL;
20 unsigned field_filled = 0;
21 ResourcePressure rp = {};
22 const char *t, *cline;
23 char *word;
24 int r;
25
26 assert(path);
27 assert(IN_SET(type, PRESSURE_TYPE_SOME, PRESSURE_TYPE_FULL));
28 assert(ret);
29
30 if (type == PRESSURE_TYPE_SOME)
31 t = "some";
32 else if (type == PRESSURE_TYPE_FULL)
33 t = "full";
34 else
35 return -EINVAL;
36
37 r = fopen_unlocked(path, "re", &f);
38 if (r < 0)
39 return r;
40
41 for (;;) {
42 _cleanup_free_ char *l = NULL;
43 char *w;
44
45 r = read_line(f, LONG_LINE_MAX, &l);
46 if (r < 0)
47 return r;
48 if (r == 0)
49 break;
50
51 w = first_word(l, t);
52 if (w) {
53 line = TAKE_PTR(l);
54 cline = w;
55 break;
56 }
57 }
58
59 if (!line)
60 return -ENODATA;
61
62 /* extracts either avgX=Y.Z or total=X */
63 while ((r = extract_first_word(&cline, &word, NULL, 0)) > 0) {
64 _cleanup_free_ char *w = word;
65 const char *v;
66
67 if ((v = startswith(w, "avg10="))) {
68 if (field_filled & (1U << 0))
69 return -EINVAL;
70
71 field_filled |= 1U << 0;
72 r = parse_loadavg_fixed_point(v, &rp.avg10);
73 } else if ((v = startswith(w, "avg60="))) {
74 if (field_filled & (1U << 1))
75 return -EINVAL;
76
77 field_filled |= 1U << 1;
78 r = parse_loadavg_fixed_point(v, &rp.avg60);
79 } else if ((v = startswith(w, "avg300="))) {
80 if (field_filled & (1U << 2))
81 return -EINVAL;
82
83 field_filled |= 1U << 2;
84 r = parse_loadavg_fixed_point(v, &rp.avg300);
85 } else if ((v = startswith(w, "total="))) {
86 if (field_filled & (1U << 3))
87 return -EINVAL;
88
89 field_filled |= 1U << 3;
90 r = safe_atou64(v, &rp.total);
91 } else
92 continue;
93
94 if (r < 0)
95 return r;
96 }
97
98 if (r < 0)
99 return r;
100
101 if (field_filled != 15U)
102 return -EINVAL;
103
104 *ret = rp;
105 return 0;
106 }
107
is_pressure_supported(void)108 int is_pressure_supported(void) {
109 /* The pressure files, both under /proc and in cgroups, will exist
110 * even if the kernel has PSI support disabled; we have to read
111 * the file to make sure it doesn't return -EOPNOTSUPP */
112 FOREACH_STRING(p, "/proc/pressure/cpu", "/proc/pressure/io", "/proc/pressure/memory") {
113 int r;
114
115 r = read_virtual_file(p, 0, NULL, NULL);
116 if (r == -ENOENT || ERRNO_IS_NOT_SUPPORTED(r))
117 return 0;
118 if (r < 0)
119 return r;
120 }
121
122 return 1;
123 }
124