forked from rfjakob/earlyoom
-
Notifications
You must be signed in to change notification settings - Fork 0
/
proc_pid.c
75 lines (70 loc) · 2.62 KB
/
proc_pid.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "globals.h"
#include "msg.h"
#include "proc_pid.h"
// Parse a buffer that contains the text from /proc/$pid/stat. Example:
// $ cat /proc/self/stat
// 551716 (cat) R 551087 551716 551087 34816 551716 4194304 94 0 0 0 0 0 0 0 20 0 1 0 5017160 227065856 448 18446744073709551615 94898152189952 94898152206609 140721104501216 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 94898152221328 94898152222824 94898185641984 140721104505828 140721104505848 140721104505848 140721104510955 0
bool parse_proc_pid_stat_buf(pid_stat_t* out, char* buf)
{
char* closing_bracket = strrchr(buf, ')');
if (!closing_bracket) {
return false;
}
// If the string ends (i.e. has a null byte) after the closing bracket: bail out.
if (!closing_bracket[1]) {
return false;
}
// Because of the check above, there must be at least one more byte at
// closing_bracket[2] (possibly a null byte, but sscanf will handle that).
char* state_field = &closing_bracket[2];
int ret = sscanf(state_field,
"%c " // state
"%d %*d %*d %*d %*d " // ppid, pgrp, sid, tty_nr, tty_pgrp
"%*u %*u %*u %*u %*u " // flags, min_flt, cmin_flt, maj_flt, cmaj_flt
"%*u %*u %*u %*u " // utime, stime, cutime, cstime
"%*d %*d " // priority, nice
"%ld " // num_threads
"%*d %*d %*d" // itrealvalue, starttime, vsize
"%ld ", // rss
&out->state,
&out->ppid,
&out->num_threads,
&out->rss);
if (ret != 4) {
return false;
};
return true;
};
// Read and parse /proc/$pid/stat. Returns true on success, false on error.
bool parse_proc_pid_stat(pid_stat_t* out, int pid)
{
// Largest /proc/*/stat file here is 363 bytes acc. to:
// wc -c /proc/*/stat | sort
// 512 seems safe given that we only need the first 20 fields.
char buf[512] = { 0 };
// Read /proc/$pid/stat
snprintf(buf, sizeof(buf), "%s/%d/stat", procdir_path, pid);
FILE* f = fopen(buf, "r");
if (f == NULL) {
// Process is gone - good.
return false;
}
memset(buf, 0, sizeof(buf));
// File content looks like this:
// 10751 (cat) R 2663 10751 2663[...]
// File may be bigger than 256 bytes, but we only need the first 20 or so.
int len = (int)fread(buf, 1, sizeof(buf) - 1, f);
bool read_error = ferror(f) || len == 0;
fclose(f);
if (read_error) {
warn("%s: fread failed: %s\n", __func__, strerror(errno));
return false;
}
// Terminate string at end of data
buf[len] = 0;
return parse_proc_pid_stat_buf(out, buf);
}