fileio: make get_status_field() more generic

All users of get_status_field() expect the field pattern to occur in
the beginning of a line, and the delimiter is ':'.

Hardcode this into the function, and also skip any whitespace before ':'
to support fields in files like /proc/cpuinfo. Add support for returning
the full field value (currently stops on first whitespace).

Rename the function so it's easier to ensure all callers switch to new
semantics.
This commit is contained in:
Aaro Koskinen 2015-09-30 15:57:55 +03:00
parent 5e6ad75f25
commit c4cd1d4d93
6 changed files with 40 additions and 16 deletions

View File

@ -775,15 +775,19 @@ int executable_is_script(const char *path, char **interpreter) {
/**
* Retrieve one field from a file like /proc/self/status. pattern
* should start with '\n' and end with a ':'. Whitespace and zeros
* after the ':' will be skipped. field must be freed afterwards.
* should not include whitespace or the delimiter (':'). pattern matches only
* the beginning of a line. Whitespace before ':' is skipped. Whitespace and
* zeros after the ':' will be skipped. field must be freed afterwards.
* terminator specifies the terminating characters of the field value (not
* included in the value).
*/
int get_status_field(const char *filename, const char *pattern, char **field) {
int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) {
_cleanup_free_ char *status = NULL;
char *t, *f;
size_t len;
int r;
assert(terminator);
assert(filename);
assert(pattern);
assert(field);
@ -792,11 +796,31 @@ int get_status_field(const char *filename, const char *pattern, char **field) {
if (r < 0)
return r;
t = strstr(status, pattern);
if (!t)
return -ENOENT;
t = status;
do {
bool pattern_ok;
do {
t = strstr(t, pattern);
if (!t)
return -ENOENT;
/* Check that pattern occurs in beginning of line. */
pattern_ok = (t == status || t[-1] == '\n');
t += strlen(pattern);
} while (!pattern_ok);
t += strspn(t, " \t");
if (!*t)
return -ENOENT;
} while (*t != ':');
t++;
t += strlen(pattern);
if (*t) {
t += strspn(t, " \t");
@ -812,7 +836,7 @@ int get_status_field(const char *filename, const char *pattern, char **field) {
t --;
}
len = strcspn(t, WHITESPACE);
len = strcspn(t, terminator);
f = strndup(t, len);
if (!f)

View File

@ -48,4 +48,4 @@ int write_env_file(const char *fname, char **l);
int executable_is_script(const char *path, char **interpreter);
int get_status_field(const char *filename, const char *pattern, char **field);
int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field);

View File

@ -215,7 +215,7 @@ int get_process_capeff(pid_t pid, char **capeff) {
p = procfs_file_alloca(pid, "status");
r = get_status_field(p, "\nCapEff:", capeff);
r = get_proc_field(p, "CapEff", WHITESPACE, capeff);
if (r == -ENOENT)
return -ESRCH;

View File

@ -240,7 +240,7 @@ static int detect_vm_zvm(void) {
_cleanup_free_ char *t = NULL;
int r;
r = get_status_field("/proc/sysinfo", "VM00 Control Program:", &t);
r = get_proc_field("/proc/sysinfo", "VM00 Control Program", WHITESPACE, &t);
if (r == -ENOENT)
return VIRTUALIZATION_NONE;
if (r < 0)

View File

@ -226,7 +226,7 @@ static bool enough_memory_for_hibernation(void) {
if (r < 0)
return false;
r = get_status_field("/proc/meminfo", "\nActive(anon):", &active);
r = get_proc_field("/proc/meminfo", "Active(anon)", WHITESPACE, &active);
if (r < 0) {
log_error_errno(r, "Failed to retrieve Active(anon) from /proc/meminfo: %m");
return false;

View File

@ -241,18 +241,18 @@ static void test_status_field(void) {
unsigned long long total = 0, buffers = 0;
int r;
assert_se(get_status_field("/proc/self/status", "\nThreads:", &t) == 0);
assert_se(get_proc_field("/proc/self/status", "Threads", WHITESPACE, &t) == 0);
puts(t);
assert_se(streq(t, "1"));
r = get_status_field("/proc/meminfo", "MemTotal:", &p);
r = get_proc_field("/proc/meminfo", "MemTotal", WHITESPACE, &p);
if (r != -ENOENT) {
assert_se(r == 0);
puts(p);
assert_se(safe_atollu(p, &total) == 0);
}
r = get_status_field("/proc/meminfo", "\nBuffers:", &s);
r = get_proc_field("/proc/meminfo", "Buffers", WHITESPACE, &s);
if (r != -ENOENT) {
assert_se(r == 0);
puts(s);
@ -263,7 +263,7 @@ static void test_status_field(void) {
assert_se(buffers < total);
/* Seccomp should be a good test for field full of zeros. */
r = get_status_field("/proc/meminfo", "\nSeccomp:", &z);
r = get_proc_field("/proc/meminfo", "Seccomp", WHITESPACE, &z);
if (r != -ENOENT) {
assert_se(r == 0);
puts(z);