/**
* 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);
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");
t --;
}
- len = strcspn(t, WHITESPACE);
+ len = strcspn(t, terminator);
f = strndup(t, len);
if (!f)
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);
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;
_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)
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;
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);
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);