diff --git a/mx_util.c b/mx_util.c index 7c42334..efde13f 100644 --- a/mx_util.c +++ b/mx_util.c @@ -842,6 +842,104 @@ int mx_strscan_ll(char **str, long long int *to) return res; } +int mx_strscan_proc_pid_stat(char *str, struct proc_pid_stat *pps) +{ + size_t res = 0; + char *p; + char *s; + + pps->comm = NULL; + + s = str; + + res += mx_strscan_ll(&s, &(pps->pid)); + + p = strrchr(s, ')'); + if (!p) + return -(errno=EINVAL); + + *p = 0; + s++; + + pps->comm = mx_strdup_forever(s); + s = p + 2; + + pps->state = *s; + res += !(*(s+1) == ' '); + s += 2; + + res += mx_strscan_ll(&s, &(pps->ppid)); + res += mx_strscan_ll(&s, &(pps->pgrp)); + res += mx_strscan_ll(&s, &(pps->session)); + res += mx_strscan_ll(&s, &(pps->tty_nr)); + res += mx_strscan_ll(&s, &(pps->tpgid)); + res += mx_strscan_ull(&s, &(pps->flags)); + res += mx_strscan_ull(&s, &(pps->minflt)); + res += mx_strscan_ull(&s, &(pps->cminflt)); + res += mx_strscan_ull(&s, &(pps->majflt)); + res += mx_strscan_ull(&s, &(pps->cmajflt)); + res += mx_strscan_ull(&s, &(pps->utime)); + res += mx_strscan_ull(&s, &(pps->stime)); + res += mx_strscan_ll(&s, &(pps->cutime)); + res += mx_strscan_ll(&s, &(pps->cstime)); + res += mx_strscan_ll(&s, &(pps->priority)); + res += mx_strscan_ll(&s, &(pps->nice)); + res += mx_strscan_ll(&s, &(pps->num_threads)); + res += mx_strscan_ll(&s, &(pps->itrealvalue)); + res += mx_strscan_ull(&s, &(pps->starttime)); + res += mx_strscan_ull(&s, &(pps->vsize)); + res += mx_strscan_ll(&s, &(pps->rss)); + res += mx_strscan_ull(&s, &(pps->rsslim)); + res += mx_strscan_ull(&s, &(pps->startcode)); + res += mx_strscan_ull(&s, &(pps->endcode)); + res += mx_strscan_ull(&s, &(pps->startstack)); + res += mx_strscan_ull(&s, &(pps->kstkesp)); + res += mx_strscan_ull(&s, &(pps->kstkeip)); + res += mx_strscan_ull(&s, &(pps->signal)); + res += mx_strscan_ull(&s, &(pps->blocked)); + res += mx_strscan_ull(&s, &(pps->sigignore)); + res += mx_strscan_ull(&s, &(pps->sigcatch)); + res += mx_strscan_ull(&s, &(pps->wchan)); + res += mx_strscan_ull(&s, &(pps->nswap)); + res += mx_strscan_ull(&s, &(pps->cnswap)); + res += mx_strscan_ll(&s, &(pps->exit_signal)); + res += mx_strscan_ll(&s, &(pps->processor)); + res += mx_strscan_ull(&s, &(pps->rt_priority)); + res += mx_strscan_ull(&s, &(pps->policy)); + res += mx_strscan_ull(&s, &(pps->delayacct_blkio_ticks)); + res += mx_strscan_ull(&s, &(pps->guest_time)); + res += mx_strscan_ll(&s, &(pps->cguest_time)); + + if (res != 0) + return -(errno=EINVAL); + + return 0; +} + +int mx_proc_pid_stat(struct proc_pid_stat *pps, pid_t pid) +{ + _mx_cleanup_free_ char *fname = NULL; + _mx_cleanup_free_ char *line = NULL; + int res; + + mx_asprintf_forever(&fname, "/proc/%d/stat", pid); + + res = mx_read_first_line_from_file(fname, &line); + if (res < 0) + return res; + + res = mx_strscan_proc_pid_stat(line, pps); + if (res < 0) + return res; + + return 0; +} + +void mx_proc_pid_stat_free(struct proc_pid_stat *pps) +{ + mx_free_null(pps->comm); +} + int mx_sleep(unsigned int seconds) { if (seconds) diff --git a/mx_util.h b/mx_util.h index e6787db..f79d77f 100644 --- a/mx_util.h +++ b/mx_util.h @@ -9,6 +9,53 @@ #include "mx_log.h" +struct proc_pid_stat { + long long int pid; /* 1 */ + char *comm; /* 2 (comm) */ + char state; /* 3 "RSDZTW" */ + long long int ppid; /* 4 */ + long long int pgrp; /* 5 */ + long long int session; /* 6 */ + long long int tty_nr; /* 7 */ + long long int tpgid; /* 8 */ + unsigned long long int flags; /* 9 */ + unsigned long long int minflt; /* 10 */ + unsigned long long int cminflt; /* 11 */ + unsigned long long int majflt; /* 12 */ + unsigned long long int cmajflt; /* 13 */ + unsigned long long int utime; /* 14 */ + unsigned long long int stime; /* 15 */ + long long int cutime; /* 16 */ + long long int cstime; /* 17 */ + long long int priority; /* 18 */ + long long int nice; /* 19 */ + long long int num_threads; /* 20 */ + long long int itrealvalue; /* 21 */ + unsigned long long int starttime; /* 22 */ + unsigned long long int vsize; /* 23 */ + long long int rss; /* 24 */ + unsigned long long int rsslim; /* 25 */ + unsigned long long int startcode; /* 26 */ + unsigned long long int endcode; /* 27 */ + unsigned long long int startstack; /* 28 */ + unsigned long long int kstkesp; /* 29 */ + unsigned long long int kstkeip; /* 30 */ + unsigned long long int signal; /* 31 */ + unsigned long long int blocked; /* 32 */ + unsigned long long int sigignore; /* 33 */ + unsigned long long int sigcatch; /* 34 */ + unsigned long long int wchan; /* 35 */ + unsigned long long int nswap; /* 36 */ + unsigned long long int cnswap; /* 37 */ + long long int exit_signal; /* 38 */ + long long int processor; /* 39 */ + unsigned long long int rt_priority; /* 40 */ + unsigned long long int policy; /* 41 */ + unsigned long long int delayacct_blkio_ticks; /* 42 */ + unsigned long long int guest_time; /* 43 */ + long long int cguest_time; /* 44 */ +}; + #ifdef MX_NDEBUG # include # define mx_assert_return_minus_errno(test, eno) \ @@ -119,6 +166,10 @@ int mx_read_first_line_from_file(char *fname, char **line); int mx_strscan_ull(char **str, unsigned long long int *to); int mx_strscan_ll(char **str, long long int *to); +int mx_strscan_proc_pid_stat(char *str, struct proc_pid_stat *pps); + +int mx_proc_pid_stat(struct proc_pid_stat *pps, pid_t pid); +void mx_proc_pid_stat_free(struct proc_pid_stat *pps); int mx_sleep(unsigned int seconds); int mx_sleep_nofail(unsigned int seconds); diff --git a/test_mx_util.c b/test_mx_util.c index 6263acf..5700e80 100644 --- a/test_mx_util.c +++ b/test_mx_util.c @@ -1,7 +1,11 @@ +#define _GNU_SOURCE + #include #include #include +#include +#include #include "mx_util.h" @@ -275,6 +279,7 @@ static void test_mx_strtobytes(void) static void test_mx_read_first_line_from_file(void) { char *str; + long long int l; assert(mx_read_first_line_from_file("/proc/sys/kernel/random/boot_id", &str) == 36); assert(str); @@ -289,6 +294,7 @@ static void test_mx_read_first_line_from_file(void) assert(mx_read_first_line_from_file("/proc/self/stat", &str) > 0); assert(str); + mx_strtoll(str, &l); mx_free_null(str); } @@ -298,6 +304,9 @@ static void test_mx_strscan(void) char *str; unsigned long long int ull; long long int ll; + _mx_cleanup_free_ char *line = NULL; + struct proc_pid_stat pps = {0}; + struct proc_pid_stat pps2 = {0}; assert(s = strdup("123 456 -789 246 abc")); str = s; @@ -331,8 +340,23 @@ static void test_mx_strscan(void) assert(mx_streq(str, "")); assert(mx_streq(s, "123")); + assert(mx_read_first_line_from_file("/proc/self/stat", &line) > 0); + assert(mx_strscan_proc_pid_stat(line, &pps) == 0); + assert(pps.pid == getpid()); + assert(pps.ppid == getppid()); + assert(pps.state == 'R'); + assert(mx_streq(pps.comm, program_invocation_short_name) || mx_streq(pps.comm, "memcheck-amd64-")); + mx_proc_pid_stat_free(&pps); + + assert(mx_proc_pid_stat(&pps2, getpid()) == 0); + assert(pps2.pid == getpid()); + assert(pps2.ppid == getppid()); + assert(pps2.state == 'R'); + assert(mx_streq(pps2.comm, program_invocation_short_name) || mx_streq(pps2.comm, "memcheck-amd64-")); + mx_proc_pid_stat_free(&pps2); } + int main(int argc, char *argv[]) { test_mx_strskipwhitespaces();