fileio: modernize get_proc_field()
- Drop effectively unused "terminator" param, imply whitespace
- Make ret param optional
- Return ENODATA if the requested key is not found, rather than
ENOENT
- Turn ENOENT -> ENOSYS if /proc/ is not mounted
- Don't skip whitespaces before ':', nothing needs this handling
anyways
- Remove the special treatment for all "0"s. We don't actually
use this for capabilities given pidref_get_capability() exists
- Switch away from read_full_virtual_file() - files using "field"
scheme under /proc/ seem all to be "seq_file"s (refer to
da65941c3e for details on file types)
This commit is contained in:
+29
-57
@@ -889,74 +889,46 @@ int script_get_shebang_interpreter(const char *path, char **ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve one field from a file like /proc/self/status. pattern
|
||||
* 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_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) {
|
||||
_cleanup_free_ char *status = NULL;
|
||||
char *t, *f;
|
||||
int get_proc_field(const char *path, const char *key, char **ret) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
int r;
|
||||
|
||||
assert(terminator);
|
||||
assert(filename);
|
||||
assert(pattern);
|
||||
assert(field);
|
||||
/* Retrieve one field from a file like /proc/self/status. "key" matches the beginning of the line
|
||||
* and should not include whitespace or the delimiter (':').
|
||||
* Whitespaces after the ':' will be skipped. Only the first element is returned
|
||||
* (i.e. for /proc/meminfo line "MemTotal: 1024 kB" -> return "1024"). */
|
||||
|
||||
r = read_full_virtual_file(filename, &status, NULL);
|
||||
assert(path);
|
||||
assert(key);
|
||||
|
||||
r = fopen_unlocked(path, "re", &f);
|
||||
if (r == -ENOENT && proc_mounted() == 0)
|
||||
return -ENOSYS;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
t = status;
|
||||
for (;;) {
|
||||
_cleanup_free_ char *line = NULL;
|
||||
|
||||
do {
|
||||
bool pattern_ok;
|
||||
r = read_line(f, LONG_LINE_MAX, &line);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return -ENODATA;
|
||||
|
||||
do {
|
||||
t = strstr(t, pattern);
|
||||
if (!t)
|
||||
return -ENOENT;
|
||||
char *l = startswith(line, key);
|
||||
if (l && *l == ':') {
|
||||
if (ret) {
|
||||
char *s = strdupcspn(skip_leading_chars(l + 1, " \t"), WHITESPACE);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Check that pattern occurs in beginning of line. */
|
||||
pattern_ok = (t == status || t[-1] == '\n');
|
||||
*ret = s;
|
||||
}
|
||||
|
||||
t += strlen(pattern);
|
||||
|
||||
} while (!pattern_ok);
|
||||
|
||||
t += strspn(t, " \t");
|
||||
if (!*t)
|
||||
return -ENOENT;
|
||||
|
||||
} while (*t != ':');
|
||||
|
||||
t++;
|
||||
|
||||
if (*t) {
|
||||
t += strspn(t, " \t");
|
||||
|
||||
/* Also skip zeros, because when this is used for
|
||||
* capabilities, we don't want the zeros. This way the
|
||||
* same capability set always maps to the same string,
|
||||
* irrespective of the total capability set size. For
|
||||
* other numbers it shouldn't matter. */
|
||||
t += strspn(t, "0");
|
||||
/* Back off one char if there's nothing but whitespace
|
||||
and zeros */
|
||||
if (!*t || isspace(*t))
|
||||
t--;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
f = strdupcspn(t, terminator);
|
||||
if (!f)
|
||||
return -ENOMEM;
|
||||
|
||||
*field = f;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DIR* xopendirat(int dir_fd, const char *name, int flags) {
|
||||
|
||||
+1
-1
@@ -98,7 +98,7 @@ int verify_file_at(int dir_fd, const char *fn, const char *blob, bool accept_ext
|
||||
|
||||
int script_get_shebang_interpreter(const char *path, char **ret);
|
||||
|
||||
int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field);
|
||||
int get_proc_field(const char *path, const char *key, char **ret);
|
||||
|
||||
DIR* xopendirat(int dir_fd, const char *name, int flags);
|
||||
|
||||
|
||||
@@ -870,7 +870,7 @@ int get_process_umask(pid_t pid, mode_t *ret) {
|
||||
|
||||
p = procfs_file_alloca(pid, "status");
|
||||
|
||||
r = get_proc_field(p, "Umask", WHITESPACE, &m);
|
||||
r = get_proc_field(p, "Umask", &m);
|
||||
if (r == -ENOENT)
|
||||
return -ESRCH;
|
||||
if (r < 0)
|
||||
@@ -2079,9 +2079,9 @@ int get_process_threads(pid_t pid) {
|
||||
|
||||
p = procfs_file_alloca(pid, "status");
|
||||
|
||||
r = get_proc_field(p, "Threads", WHITESPACE, &t);
|
||||
r = get_proc_field(p, "Threads", &t);
|
||||
if (r == -ENOENT)
|
||||
return proc_mounted() == 0 ? -ENOSYS : -ESRCH;
|
||||
return -ESRCH;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
+3
-3
@@ -432,8 +432,8 @@ static Virtualization detect_vm_zvm(void) {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
int r;
|
||||
|
||||
r = get_proc_field("/proc/sysinfo", "VM00 Control Program", WHITESPACE, &t);
|
||||
if (r == -ENOENT)
|
||||
r = get_proc_field("/proc/sysinfo", "VM00 Control Program", &t);
|
||||
if (IN_SET(r, -ENOENT, -ENODATA))
|
||||
return VIRTUALIZATION_NONE;
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -655,7 +655,7 @@ Virtualization detect_container(void) {
|
||||
/* proot doesn't use PID namespacing, so we can just check if we have a matching tracer for this
|
||||
* invocation without worrying about it being elsewhere.
|
||||
*/
|
||||
r = get_proc_field("/proc/self/status", "TracerPid", WHITESPACE, &p);
|
||||
r = get_proc_field("/proc/self/status", "TracerPid", &p);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to read our own trace PID, ignoring: %m");
|
||||
else if (!streq(p, "0")) {
|
||||
|
||||
Reference in New Issue
Block a user