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.
As a bonus, after the rewrite 'line' is no longer leaked.
---
tools/virt-host-validate-common.c | 49 +++++++++++++++++++++++++++++++++------
1 file changed, 42 insertions(+), 7 deletions(-)
diff --git a/tools/virt-host-validate-common.c b/tools/virt-host-validate-common.c
index 8ebf73e..18b9f20 100644
--- a/tools/virt-host-validate-common.c
+++ b/tools/virt-host-validate-common.c
@@ -265,18 +265,53 @@ 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
+ */
+
+ /* Look for the first colon.
+ * The part we're interested in starts right after it */
+ if (!(start = strstr(line, ":"))) {
+ VIR_FREE(line);
continue;
+ }
+ start++;
- tmp += strlen(cg_name);
- if (*tmp != ',' &&
- *tmp != ':')
+ /* Look for the second colon.
+ * The part we're interested in ends exactly there */
+ if (!(end = strstr(start, ":"))) {
+ VIR_FREE(line);
continue;
+ }
+ *end = '\0';
- matched = true;
+ if (!(cgroups = virStringSplitCount(start, ",", 0, &ncgroups))) {
+ VIR_FREE(line);
+ continue;
+ }
+
+ /* 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_FREE(line);
+
VIR_FORCE_FCLOSE(fp);
if (!matched)
goto error;
--
2.5.5