]>
Commit | Line | Data |
---|---|---|
0ac2d74b MT |
1 | /*############################################################################# |
2 | # # | |
3 | # Pakfire - The IPFire package management system # | |
4 | # Copyright (C) 2023 Pakfire development team # | |
5 | # # | |
6 | # This program is free software: you can redistribute it and/or modify # | |
7 | # it under the terms of the GNU General Public License as published by # | |
8 | # the Free Software Foundation, either version 3 of the License, or # | |
9 | # (at your option) any later version. # | |
10 | # # | |
11 | # This program is distributed in the hope that it will be useful, # | |
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # | |
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # | |
14 | # GNU General Public License for more details. # | |
15 | # # | |
16 | # You should have received a copy of the GNU General Public License # | |
17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. # | |
18 | # # | |
19 | #############################################################################*/ | |
20 | ||
0ac2d74b | 21 | #include <errno.h> |
1d29d610 | 22 | #include <limits.h> |
0ac2d74b | 23 | #include <stdio.h> |
0ac2d74b | 24 | #include <string.h> |
8038a15d | 25 | #include <unistd.h> |
0ac2d74b MT |
26 | |
27 | #include <pakfire/os.h> | |
9abd1ca5 | 28 | #include <pakfire/parse.h> |
0ac2d74b MT |
29 | #include <pakfire/string.h> |
30 | ||
0ac2d74b MT |
31 | // CPU Info |
32 | ||
33 | static int pakfire_parse_cpuinfo(char* line, size_t length, void* data) { | |
34 | struct pakfire_cpuinfo* cpuinfo = data; | |
35 | int r; | |
36 | ||
37 | // Key & Value | |
9e5b19ac MT |
38 | char* k = NULL; |
39 | char* v = NULL; | |
0ac2d74b MT |
40 | |
41 | // Split the line | |
9abd1ca5 | 42 | r = pakfire_parse_split_line(line, length, &k, &v, ':'); |
0ac2d74b MT |
43 | if (r) |
44 | return r; | |
45 | ||
46 | // If we didn't get a result we skip this line | |
47 | if (!k || !v) | |
48 | return 0; | |
49 | ||
50 | // Vendor | |
51 | if (strcmp(k, "vendor_id") == 0) { | |
52 | r = pakfire_string_set(cpuinfo->vendor, v); | |
53 | if (r) | |
54 | return r; | |
55 | ||
56 | // Model Name | |
57 | } else if (strcmp(k, "model name") == 0) { | |
58 | r = pakfire_string_set(cpuinfo->model, v); | |
59 | if (r) | |
60 | return r; | |
61 | } | |
62 | ||
63 | return 0; | |
64 | } | |
65 | ||
66 | int pakfire_cpuinfo(struct pakfire_cpuinfo* cpuinfo) { | |
60610c0e MT |
67 | int r; |
68 | ||
69 | // Parse /proc/cpuinfo | |
70 | r = pakfire_parse_file("/proc/cpuinfo", pakfire_parse_cpuinfo, cpuinfo); | |
71 | if (r) | |
72 | return r; | |
73 | ||
74 | // Fetch the number of processors | |
75 | cpuinfo->count = sysconf(_SC_NPROCESSORS_CONF); | |
76 | ||
77 | return 0; | |
0ac2d74b | 78 | } |
1d29d610 | 79 | |
8038a15d MT |
80 | // CPU Stats |
81 | ||
82 | static int pakfire_parse_cpustat(char* line, size_t length, void* data) { | |
83 | struct pakfire_cpustat* cpustat = data; | |
84 | struct cpustat { | |
85 | unsigned long int user; | |
86 | unsigned long int nice; | |
87 | unsigned long int system; | |
88 | unsigned long int idle; | |
89 | unsigned long int iowait; | |
90 | unsigned long int irq; | |
91 | unsigned long int softirq; | |
92 | unsigned long int steal; | |
93 | unsigned long int guest; | |
94 | unsigned long int guest_nice; | |
95 | } stat; | |
96 | int r; | |
97 | ||
98 | // Only care about the line of interest | |
99 | if (pakfire_string_startswith(line, "cpu ")) { | |
100 | r = sscanf(line, "cpu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", | |
101 | &stat.user, &stat.nice, &stat.system, &stat.idle, &stat.iowait, | |
102 | &stat.irq, &stat.softirq, &stat.steal, &stat.guest, &stat.guest_nice); | |
103 | if (r < 10) | |
104 | return -EINVAL; | |
105 | ||
106 | // Fetch how many ticks a second | |
d955ac99 MT |
107 | unsigned long int ticks = stat.user + stat.nice + stat.system + stat.idle |
108 | + stat.iowait + stat.irq + stat.softirq + stat.steal + stat.guest + stat.guest_nice; | |
8038a15d MT |
109 | |
110 | // Convert to relative terms | |
d955ac99 MT |
111 | cpustat->user = (double)stat.user / ticks; |
112 | cpustat->nice = (double)stat.nice / ticks; | |
113 | cpustat->system = (double)stat.system / ticks; | |
114 | cpustat->idle = (double)stat.idle / ticks; | |
115 | cpustat->iowait = (double)stat.iowait / ticks; | |
116 | cpustat->irq = (double)stat.irq / ticks; | |
117 | cpustat->softirq = (double)stat.softirq / ticks; | |
118 | cpustat->steal = (double)stat.steal / ticks; | |
119 | cpustat->guest = (double)stat.guest / ticks; | |
120 | cpustat->guest_nice = (double)stat.guest_nice / ticks; | |
8038a15d MT |
121 | } |
122 | ||
123 | return 0; | |
124 | } | |
125 | ||
126 | int pakfire_cpustat(struct pakfire_cpustat* cpustat) { | |
127 | return pakfire_parse_file("/proc/stat", pakfire_parse_cpustat, cpustat); | |
128 | } | |
129 | ||
0a393fb7 MT |
130 | // Load Average |
131 | ||
132 | static int pakfire_parse_loadavg(char* line, size_t length, void* data) { | |
133 | struct pakfire_loadavg* loadavg = data; | |
134 | int r; | |
135 | ||
136 | // Parse the first three values | |
137 | r = sscanf(line, "%lf %lf %lf", &loadavg->load1, &loadavg->load5, &loadavg->load15); | |
138 | if (r < 3) | |
139 | return -EINVAL; | |
140 | ||
141 | return 0; | |
142 | } | |
143 | ||
144 | int pakfire_loadavg(struct pakfire_loadavg* loadavg) { | |
145 | return pakfire_parse_file("/proc/loadavg", pakfire_parse_loadavg, loadavg); | |
146 | } | |
147 | ||
1d29d610 MT |
148 | // Meminfo |
149 | ||
150 | static int pakfire_parse_meminfo_value(uint64_t* mem, const char* s) { | |
151 | char* remainder = NULL; | |
152 | uint64_t m = 0; | |
153 | ||
154 | // Parse the numeric value | |
155 | m = strtoul(s, &remainder, 10); | |
156 | if (m == ULONG_MAX) | |
157 | return -errno; | |
158 | ||
159 | // Convert into bytes | |
160 | if (strcmp(remainder, " kB") == 0) { | |
161 | // Check if the multiplication won't overflow | |
162 | if (m > UINT64_MAX / 1024) | |
163 | return -EOVERFLOW; | |
164 | ||
165 | m *= 1024; | |
166 | ||
167 | // Fail on anything else | |
168 | } else if (*remainder) | |
169 | return -EINVAL; | |
170 | ||
171 | // Store the value | |
172 | *mem = m; | |
173 | ||
174 | return 0; | |
175 | } | |
176 | ||
177 | static int pakfire_parse_meminfo(char* line, size_t length, void* data) { | |
178 | struct pakfire_meminfo* meminfo = data; | |
179 | int r; | |
180 | ||
181 | // Key & Value | |
9e5b19ac MT |
182 | char* k = NULL; |
183 | char* v = NULL; | |
1d29d610 MT |
184 | |
185 | // Split the line | |
9abd1ca5 | 186 | r = pakfire_parse_split_line(line, length, &k, &v, ':'); |
1d29d610 MT |
187 | if (r) |
188 | return r; | |
189 | ||
190 | // If we didn't get a result we skip this line | |
191 | if (!k || !v) | |
192 | return 0; | |
193 | ||
194 | // Total | |
195 | if (strcmp(k, "MemTotal") == 0) | |
196 | return pakfire_parse_meminfo_value(&meminfo->total, v); | |
197 | ||
198 | // Free | |
199 | else if (strcmp(k, "MemFree") == 0) | |
200 | return pakfire_parse_meminfo_value(&meminfo->free, v); | |
201 | ||
202 | // Available | |
203 | else if (strcmp(k, "MemAvailable") == 0) | |
204 | return pakfire_parse_meminfo_value(&meminfo->available, v); | |
205 | ||
206 | // Buffers | |
207 | else if (strcmp(k, "Buffers") == 0) | |
208 | return pakfire_parse_meminfo_value(&meminfo->buffers, v); | |
209 | ||
210 | // Cached | |
211 | else if (strcmp(k, "Cached") == 0) | |
212 | return pakfire_parse_meminfo_value(&meminfo->cached, v); | |
213 | ||
99cb9347 MT |
214 | // Shared |
215 | else if (strcmp(k, "Shmem") == 0) | |
216 | return pakfire_parse_meminfo_value(&meminfo->shared, v); | |
217 | ||
1d29d610 MT |
218 | // Active |
219 | else if (strcmp(k, "Active") == 0) | |
220 | return pakfire_parse_meminfo_value(&meminfo->active, v); | |
221 | ||
222 | // Inactive | |
223 | else if (strcmp(k, "Inactive") == 0) | |
224 | return pakfire_parse_meminfo_value(&meminfo->inactive, v); | |
225 | ||
226 | // Swap Total | |
227 | else if (strcmp(k, "SwapTotal") == 0) | |
228 | return pakfire_parse_meminfo_value(&meminfo->swap_total, v); | |
229 | ||
230 | // Swap Free | |
231 | else if (strcmp(k, "SwapFree") == 0) | |
232 | return pakfire_parse_meminfo_value(&meminfo->swap_free, v); | |
233 | ||
234 | return 0; | |
235 | } | |
236 | ||
237 | int pakfire_meminfo(struct pakfire_meminfo* meminfo) { | |
238 | int r; | |
239 | ||
240 | // Parse /proc/meminfo | |
241 | r = pakfire_parse_file("/proc/meminfo", pakfire_parse_meminfo, meminfo); | |
242 | if (r) | |
243 | return r; | |
244 | ||
245 | // Set used memory | |
246 | meminfo->used = meminfo->total - meminfo->free; | |
247 | ||
248 | // Set used swap | |
249 | meminfo->swap_used = meminfo->swap_total - meminfo->swap_free; | |
250 | ||
251 | return 0; | |
252 | } | |
9e5b19ac MT |
253 | |
254 | // Distro | |
255 | ||
256 | static int pakfire_parse_distro(char* line, size_t length, void* data) { | |
257 | struct pakfire_distro* distro = data; | |
258 | int r; | |
259 | ||
260 | // Key & Value | |
261 | char* k = NULL; | |
262 | char* v = NULL; | |
263 | ||
264 | // Split the line | |
9abd1ca5 | 265 | r = pakfire_parse_split_line(line, length, &k, &v, '='); |
9e5b19ac MT |
266 | if (r) |
267 | return r; | |
268 | ||
269 | // If we didn't get a result we skip this line | |
270 | if (!k || !v) | |
271 | return 0; | |
272 | ||
273 | // Unquote the strings | |
274 | pakfire_string_unquote(v); | |
275 | ||
276 | // PRETTY_NAME | |
277 | if (strcmp(k, "PRETTY_NAME") == 0) | |
278 | return pakfire_string_set(distro->pretty_name, v); | |
279 | ||
280 | // NAME | |
281 | else if (strcmp(k, "NAME") == 0) | |
282 | return pakfire_string_set(distro->name, v); | |
283 | ||
284 | // ID | |
285 | else if (strcmp(k, "ID") == 0) | |
286 | return pakfire_string_set(distro->id, v); | |
287 | ||
288 | // VERSION | |
289 | else if (strcmp(k, "VERSION") == 0) | |
290 | return pakfire_string_set(distro->version, v); | |
291 | ||
292 | // VERSION_CODENAME | |
293 | else if (strcmp(k, "VERSION_CODENAME") == 0) | |
294 | return pakfire_string_set(distro->version_codename, v); | |
295 | ||
296 | // VERSION_ID | |
297 | else if (strcmp(k, "VERSION_ID") == 0) | |
298 | return pakfire_string_set(distro->version_id, v); | |
299 | ||
300 | return 0; | |
301 | } | |
302 | ||
303 | int pakfire_distro(struct pakfire_distro* distro, const char* path) { | |
304 | if (!path) | |
305 | path = "/etc/os-release"; | |
306 | ||
307 | return pakfire_parse_file(path, pakfire_parse_distro, distro); | |
308 | } | |
9b171c6a MT |
309 | |
310 | // PIDFD | |
311 | ||
312 | static int pidfd_parse_pid(char* line, size_t length, void* data) { | |
313 | pid_t* pid = data; | |
314 | int r; | |
315 | ||
316 | // Key & Value | |
317 | char* k = NULL; | |
318 | char* v = NULL; | |
319 | ||
320 | // Split the line | |
9abd1ca5 | 321 | r = pakfire_parse_split_line(line, length, &k, &v, ':'); |
9b171c6a MT |
322 | if (r) |
323 | return r; | |
324 | ||
325 | // If we didn't get a result we skip this line | |
326 | if (!k || !v) | |
327 | return 0; | |
328 | ||
329 | if (strcmp(k, "Pid") == 0) | |
330 | *pid = strtoul(v, NULL, 10); | |
331 | ||
332 | return 0; | |
333 | } | |
334 | ||
335 | int pidfd_get_pid(int pidfd, pid_t* pid) { | |
336 | char path[PATH_MAX]; | |
337 | int r; | |
338 | ||
339 | if (!pid) | |
340 | return -EINVAL; | |
341 | ||
342 | // Compose path | |
343 | r = pakfire_string_format(path, "/proc/self/fdinfo/%d", pidfd); | |
344 | if (r) | |
345 | return r; | |
346 | ||
347 | return pakfire_parse_file(path, pidfd_parse_pid, pid); | |
348 | } |