Simply checking whether the cgroup name appears somewhere inside
/proc/self/cgroup is enough most of the time, but there are some
corner cases that require a more mindful parsing.
---
tools/virt-host-validate-common.c | 43 +++++++++++++++++++++++++++++++++------
1 file changed, 37 insertions(+), 6 deletions(-)
diff --git a/tools/virt-host-validate-common.c b/tools/virt-host-validate-common.c
index 95ae64a..e182d0c 100644
--- a/tools/virt-host-validate-common.c
+++ b/tools/virt-host-validate-common.c
@@ -303,17 +303,48 @@ static int virHostValidateCGroupSupport(const char *hvname,
goto error;
while ((ret = getline(&line, &len, fp)) >= 0 && !matched) {
- char *tmp = strstr(line, cg_name);
- if (!tmp)
+ char **cgroups;
+ char *start;
+ char *end;
+ size_t ncgroups;
+ size_t i;
+
+ /* Each line in this file looks like
+ *
+ * 4:cpu,cpuacct:/machine.slice/machine-qemu\x2dtest.scope/emulator
+ *
+ * Since multiple cgroups can be part of the same line and some cgroup
+ * names can appear as part of other cgroup names (eg. 'cpu' is a
+ * prefix for both 'cpuacct' and 'cpuset'), it's not enough
to simply
+ * check whether the cgroup name is present somewhere inside the file.
+ *
+ * Moreover, there's nothing stopping the cgroup name from appearing
+ * in an unrelated mount point name as well */
+
+ /* Look for the first colon.
+ * The part we're interested in starts right after it */
+ if (!(start = strchr(line, ':')))
+ continue;
+ start++;
+
+ /* Look for the second colon.
+ * The part we're interested in ends exactly there */
+ if (!(end = strchr(start, ':')))
continue;
+ *end = '\0';
- tmp += strlen(cg_name);
- if (*tmp != ',' &&
- *tmp != ':')
+ if (!(cgroups = virStringSplitCount(start, ",", 0, &ncgroups)))
continue;
- matched = true;
+ /* Look for the matching cgroup */
+ for (i = 0; i < ncgroups; i++) {
+ if (STREQ(cgroups[i], cg_name))
+ matched = true;
+ }
+
+ virStringFreeListCount(cgroups, ncgroups);
}
+
VIR_FREE(line);
VIR_FORCE_FCLOSE(fp);
if (!matched)
--
2.5.5