]> git.ipfire.org Git - people/ms/pakfire.git/blame - src/libpakfire/os.c
parse: Move parse function into an extra file
[people/ms/pakfire.git] / src / libpakfire / os.c
CommitLineData
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
33static 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
66int 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
82static 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
126int 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
132static 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
144int pakfire_loadavg(struct pakfire_loadavg* loadavg) {
145 return pakfire_parse_file("/proc/loadavg", pakfire_parse_loadavg, loadavg);
146}
147
1d29d610
MT
148// Meminfo
149
150static 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
177static 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
237int 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
256static 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
303int 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
312static 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
335int 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}