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