]>
git.ipfire.org Git - people/ms/pakfire.git/blob - src/libpakfire/os.c
2fa63e3604081b55c5694a94e453b199c3a46cd5
1 /*#############################################################################
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2023 Pakfire development team #
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. #
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. #
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/>. #
19 #############################################################################*/
29 #include <pakfire/os.h>
30 #include <pakfire/string.h>
32 typedef int (*pakfire_parse_line
)(char* line
, size_t length
, void* data
);
34 static int pakfire_parse_file(const char* path
, pakfire_parse_line parse
, void* data
) {
40 ssize_t bytes_read
= 0;
47 // Walk through the file line by line
49 bytes_read
= getline(&line
, &length
, f
);
53 r
= parse(line
, length
, data
);
67 static int pakfire_split_line(char* line
, size_t length
, char** key
, char** value
, char delim
) {
72 // Strip any trailing whitespace
73 pakfire_string_strip(line
);
79 p
= strchr(line
, delim
);
83 // The value starts somewhere after the delimiter
86 // Replace the delimiter by NULL
90 pakfire_string_strip(k
);
97 pakfire_string_strip(v
);
99 // Return the pointers
108 static int pakfire_parse_cpuinfo(char* line
, size_t length
, void* data
) {
109 struct pakfire_cpuinfo
* cpuinfo
= data
;
117 r
= pakfire_split_line(line
, length
, &k
, &v
, ':');
121 // If we didn't get a result we skip this line
126 if (strcmp(k
, "vendor_id") == 0) {
127 r
= pakfire_string_set(cpuinfo
->vendor
, v
);
132 } else if (strcmp(k
, "model name") == 0) {
133 r
= pakfire_string_set(cpuinfo
->model
, v
);
141 int pakfire_cpuinfo(struct pakfire_cpuinfo
* cpuinfo
) {
144 // Parse /proc/cpuinfo
145 r
= pakfire_parse_file("/proc/cpuinfo", pakfire_parse_cpuinfo
, cpuinfo
);
149 // Fetch the number of processors
150 cpuinfo
->count
= sysconf(_SC_NPROCESSORS_CONF
);
157 static int pakfire_parse_cpustat(char* line
, size_t length
, void* data
) {
158 struct pakfire_cpustat
* cpustat
= data
;
160 unsigned long int user
;
161 unsigned long int nice
;
162 unsigned long int system
;
163 unsigned long int idle
;
164 unsigned long int iowait
;
165 unsigned long int irq
;
166 unsigned long int softirq
;
167 unsigned long int steal
;
168 unsigned long int guest
;
169 unsigned long int guest_nice
;
173 // Only care about the line of interest
174 if (pakfire_string_startswith(line
, "cpu ")) {
175 r
= sscanf(line
, "cpu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
176 &stat
.user
, &stat
.nice
, &stat
.system
, &stat
.idle
, &stat
.iowait
,
177 &stat
.irq
, &stat
.softirq
, &stat
.steal
, &stat
.guest
, &stat
.guest_nice
);
181 // Fetch how many ticks a second
182 unsigned long int ticks
= stat
.user
+ stat
.nice
+ stat
.system
+ stat
.idle
183 + stat
.iowait
+ stat
.irq
+ stat
.softirq
+ stat
.steal
+ stat
.guest
+ stat
.guest_nice
;
185 // Convert to relative terms
186 cpustat
->user
= (double)stat
.user
/ ticks
;
187 cpustat
->nice
= (double)stat
.nice
/ ticks
;
188 cpustat
->system
= (double)stat
.system
/ ticks
;
189 cpustat
->idle
= (double)stat
.idle
/ ticks
;
190 cpustat
->iowait
= (double)stat
.iowait
/ ticks
;
191 cpustat
->irq
= (double)stat
.irq
/ ticks
;
192 cpustat
->softirq
= (double)stat
.softirq
/ ticks
;
193 cpustat
->steal
= (double)stat
.steal
/ ticks
;
194 cpustat
->guest
= (double)stat
.guest
/ ticks
;
195 cpustat
->guest_nice
= (double)stat
.guest_nice
/ ticks
;
201 int pakfire_cpustat(struct pakfire_cpustat
* cpustat
) {
202 return pakfire_parse_file("/proc/stat", pakfire_parse_cpustat
, cpustat
);
207 static int pakfire_parse_loadavg(char* line
, size_t length
, void* data
) {
208 struct pakfire_loadavg
* loadavg
= data
;
211 // Parse the first three values
212 r
= sscanf(line
, "%lf %lf %lf", &loadavg
->load1
, &loadavg
->load5
, &loadavg
->load15
);
219 int pakfire_loadavg(struct pakfire_loadavg
* loadavg
) {
220 return pakfire_parse_file("/proc/loadavg", pakfire_parse_loadavg
, loadavg
);
225 static int pakfire_parse_meminfo_value(uint64_t* mem
, const char* s
) {
226 char* remainder
= NULL
;
229 // Parse the numeric value
230 m
= strtoul(s
, &remainder
, 10);
234 // Convert into bytes
235 if (strcmp(remainder
, " kB") == 0) {
236 // Check if the multiplication won't overflow
237 if (m
> UINT64_MAX
/ 1024)
242 // Fail on anything else
243 } else if (*remainder
)
252 static int pakfire_parse_meminfo(char* line
, size_t length
, void* data
) {
253 struct pakfire_meminfo
* meminfo
= data
;
261 r
= pakfire_split_line(line
, length
, &k
, &v
, ':');
265 // If we didn't get a result we skip this line
270 if (strcmp(k
, "MemTotal") == 0)
271 return pakfire_parse_meminfo_value(&meminfo
->total
, v
);
274 else if (strcmp(k
, "MemFree") == 0)
275 return pakfire_parse_meminfo_value(&meminfo
->free
, v
);
278 else if (strcmp(k
, "MemAvailable") == 0)
279 return pakfire_parse_meminfo_value(&meminfo
->available
, v
);
282 else if (strcmp(k
, "Buffers") == 0)
283 return pakfire_parse_meminfo_value(&meminfo
->buffers
, v
);
286 else if (strcmp(k
, "Cached") == 0)
287 return pakfire_parse_meminfo_value(&meminfo
->cached
, v
);
290 else if (strcmp(k
, "Shmem") == 0)
291 return pakfire_parse_meminfo_value(&meminfo
->shared
, v
);
294 else if (strcmp(k
, "Active") == 0)
295 return pakfire_parse_meminfo_value(&meminfo
->active
, v
);
298 else if (strcmp(k
, "Inactive") == 0)
299 return pakfire_parse_meminfo_value(&meminfo
->inactive
, v
);
302 else if (strcmp(k
, "SwapTotal") == 0)
303 return pakfire_parse_meminfo_value(&meminfo
->swap_total
, v
);
306 else if (strcmp(k
, "SwapFree") == 0)
307 return pakfire_parse_meminfo_value(&meminfo
->swap_free
, v
);
312 int pakfire_meminfo(struct pakfire_meminfo
* meminfo
) {
315 // Parse /proc/meminfo
316 r
= pakfire_parse_file("/proc/meminfo", pakfire_parse_meminfo
, meminfo
);
321 meminfo
->used
= meminfo
->total
- meminfo
->free
;
324 meminfo
->swap_used
= meminfo
->swap_total
- meminfo
->swap_free
;
331 static int pakfire_parse_distro(char* line
, size_t length
, void* data
) {
332 struct pakfire_distro
* distro
= data
;
340 r
= pakfire_split_line(line
, length
, &k
, &v
, '=');
344 // If we didn't get a result we skip this line
348 // Unquote the strings
349 pakfire_string_unquote(v
);
352 if (strcmp(k
, "PRETTY_NAME") == 0)
353 return pakfire_string_set(distro
->pretty_name
, v
);
356 else if (strcmp(k
, "NAME") == 0)
357 return pakfire_string_set(distro
->name
, v
);
360 else if (strcmp(k
, "ID") == 0)
361 return pakfire_string_set(distro
->id
, v
);
364 else if (strcmp(k
, "VERSION") == 0)
365 return pakfire_string_set(distro
->version
, v
);
368 else if (strcmp(k
, "VERSION_CODENAME") == 0)
369 return pakfire_string_set(distro
->version_codename
, v
);
372 else if (strcmp(k
, "VERSION_ID") == 0)
373 return pakfire_string_set(distro
->version_id
, v
);
378 int pakfire_distro(struct pakfire_distro
* distro
, const char* path
) {
380 path
= "/etc/os-release";
382 return pakfire_parse_file(path
, pakfire_parse_distro
, distro
);
387 static int pidfd_parse_pid(char* line
, size_t length
, void* data
) {
396 r
= pakfire_split_line(line
, length
, &k
, &v
, ':');
400 // If we didn't get a result we skip this line
404 if (strcmp(k
, "Pid") == 0)
405 *pid
= strtoul(v
, NULL
, 10);
410 int pidfd_get_pid(int pidfd
, pid_t
* pid
) {
418 r
= pakfire_string_format(path
, "/proc/self/fdinfo/%d", pidfd
);
422 return pakfire_parse_file(path
, pidfd_parse_pid
, pid
);