diff --git a/.gitignore b/.gitignore
index 068cac8486c64698e534ae390b34fd82411a5b30..5e50b521b78ae49458c1aff3d46a163e12543e5b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -178,6 +178,7 @@
/tests/virauthconfigtest
/tests/virbitmaptest
/tests/virbuftest
+/tests/vircgrouptest
/tests/virdrivermoduletest
/tests/virendiantest
/tests/virhashtest
diff --git a/cfg.mk b/cfg.mk
index 394521e476aa074b35850d65771910562e2a1118..e60c4e31c1f87159b7d247bea360ff4267db7895 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -788,15 +788,16 @@ $(srcdir)/src/remote/remote_client_bodies.h: $(srcdir)/src/remote/remote_protoco
exclude_file_name_regexp--sc_avoid_strcase = ^tools/virsh\.h$$
_src1=libvirt|fdstream|qemu/qemu_monitor|util/(vircommand|virutil)|xen/xend_internal|rpc/virnetsocket|lxc/lxc_controller|locking/lock_daemon
+_test1=shunloadtest|virnettlscontexttest|vircgroupmock
exclude_file_name_regexp--sc_avoid_write = \
- ^(src/($(_src1))|daemon/libvirtd|tools/console|tests/(shunload|virnettlscontext)test)\.c$$
+ ^(src/($(_src1))|daemon/libvirtd|tools/console|tests/($(_test1)))\.c$$
exclude_file_name_regexp--sc_bindtextdomain = ^(tests|examples)/
exclude_file_name_regexp--sc_copyright_address = \
^COPYING\.LIB$$
-exclude_file_name_regexp--sc_flags_usage = ^(docs/|src/util/virnetdevtap\.c$$)
+exclude_file_name_regexp--sc_flags_usage = ^(docs/|src/util/virnetdevtap\.c$$|tests/vircgroupmock\.c$$)
exclude_file_name_regexp--sc_libvirt_unmarked_diagnostics = \
^(src/rpc/gendispatch\.pl$$|tests/)
@@ -812,10 +813,10 @@ exclude_file_name_regexp--sc_prohibit_always_true_header_tests = \
^python/(libvirt-(lxc-|qemu-)?override|typewrappers)\.c$$
exclude_file_name_regexp--sc_prohibit_asprintf = \
- ^(bootstrap.conf$$|src/util/virutil\.c$$|examples/domain-events/events-c/event-test\.c$$)
+ ^(bootstrap.conf$$|src/util/virutil\.c$$|examples/domain-events/events-c/event-test\.c$$|tests/vircgroupmock\.c$$)
exclude_file_name_regexp--sc_prohibit_close = \
- (\.p[yl]$$|^docs/|^(src/util/virfile\.c|src/libvirt\.c)$$)
+ (\.p[yl]$$|^docs/|^(src/util/virfile\.c|src/libvirt\.c|tests/vircgroupmock\.c)$$)
exclude_file_name_regexp--sc_prohibit_empty_lines_at_EOF = \
(^tests/(qemuhelp|nodeinfo)data/|\.(gif|ico|png|diff)$$)
@@ -836,7 +837,7 @@ exclude_file_name_regexp--sc_prohibit_nonreentrant = \
^((po|tests)/|docs/.*(py|html\.in)|run.in$$)
exclude_file_name_regexp--sc_prohibit_raw_allocation = \
- ^(docs/hacking\.html\.in)|(src/util/viralloc\.[ch]|examples/.*|tests/securityselinuxhelper.c)$$
+ ^(docs/hacking\.html\.in)|(src/util/viralloc\.[ch]|examples/.*|tests/securityselinuxhelper\.c|tests/vircgroupmock\.c)$$
exclude_file_name_regexp--sc_prohibit_readlink = \
^src/(util/virutil|lxc/lxc_container)\.c$$
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 7689453dde4ae17ca171e8348ffd8eafada5ed9a..68dbb273d7ca58b5a888c7176008a497056ee685 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -97,7 +97,9 @@ test_programs = virshtest sockettest \
utiltest shunloadtest \
virtimetest viruritest virkeyfiletest \
virauthconfigtest \
- virbitmaptest virendiantest \
+ virbitmaptest \
+ vircgrouptest \
+ virendiantest \
viridentitytest \
virkeycodetest \
virlockspacetest \
@@ -249,6 +251,7 @@ EXTRA_DIST += $(test_scripts)
test_libraries = libshunload.la \
libvirportallocatormock.la \
+ vircgroupmock.la \
$(NULL)
if WITH_QEMU
test_libraries += libqemumonitortestutils.la
@@ -598,6 +601,16 @@ libvirportallocatormock_la_CFLAGS = $(AM_CFLAGS) -DMOCK_HELPER=1
libvirportallocatormock_la_LDFLAGS = -module -avoid-version \
-rpath /evil/libtool/hack/to/force/shared/lib/creation
+vircgrouptest_SOURCES = \
+ vircgrouptest.c testutils.h testutils.c
+vircgrouptest_LDADD = $(LDADDS)
+
+vircgroupmock_la_SOURCES = \
+ vircgroupmock.c
+vircgroupmock_la_CFLAGS = $(AM_CFLAGS)
+vircgroupmock_la_LDFLAGS = -module -avoid-version \
+ -rpath /evil/libtool/hack/to/force/shared/lib/creation
+
viruritest_SOURCES = \
viruritest.c testutils.h testutils.c
diff --git a/tests/vircgroupmock.c b/tests/vircgroupmock.c
new file mode 100644
index 0000000000000000000000000000000000000000..1d5d46b603f4541d416733da83cb470fa1ba2bc1
--- /dev/null
+++ b/tests/vircgroupmock.c
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2013 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * .
+ *
+ * Author: Daniel P. Berrange
+ */
+
+#include
+
+#ifdef __linux__
+# include "internal.h"
+
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+
+static int (*realopen)(const char *path, int flags, ...);
+static FILE *(*realfopen)(const char *path, const char *mode);
+static int (*realaccess)(const char *path, int mode);
+static int (*realmkdir)(const char *path, mode_t mode);
+static char *fakesysfsdir;
+
+
+# define SYSFS_PREFIX "/not/really/sys/fs/cgroup/"
+
+/*
+ * The plan:
+ *
+ * We fake out /proc/mounts, so make it look as is cgroups
+ * are mounted on /not/really/sys/fs/cgroup. We don't
+ * use /sys/fs/cgroup, because we want to make it easy to
+ * detect places where we've not mocked enough syscalls.
+ *
+ * In any open/acces/mkdir calls we look at path and if
+ * it starts with /not/really/sys/fs/cgroup, we rewrite
+ * the path to point at a temporary directory referred
+ * to by LIBVIRT_FAKE_SYSFS_DIR env variable that is
+ * set by the main test suite
+ *
+ * In mkdir() calls, we simulate the cgroups behaviour
+ * whereby creating the directory auto-creates a bunch
+ * of files beneath it
+ */
+
+/*
+ * Intentionally missing the 'devices' mount.
+ * Co-mounting cpu & cpuacct controllers
+ * An anonymous controller for systemd
+ */
+const char *mounts =
+ "rootfs / rootfs rw 0 0\n"
+ "tmpfs /run tmpfs rw,seclabel,nosuid,nodev,mode=755 0 0\n"
+ "tmpfs /not/really/sys/fs/cgroup tmpfs rw,seclabel,nosuid,nodev,noexec,mode=755 0 0\n"
+ "cgroup /not/really/sys/fs/cgroup/systemd cgroup rw,nosuid,nodev,noexec,relatime,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd 0 0\n"
+ "cgroup /not/really/sys/fs/cgroup/cpuset cgroup rw,nosuid,nodev,noexec,relatime,cpuset 0 0\n"
+ "cgroup /not/really/sys/fs/cgroup/cpu,cpuacct cgroup rw,nosuid,nodev,noexec,relatime,cpuacct,cpu 0 0\n"
+ "cgroup /not/really/sys/fs/cgroup/freezer cgroup rw,nosuid,nodev,noexec,relatime,freezer 0 0\n"
+ "cgroup /not/really/sys/fs/cgroup/blkio cgroup rw,nosuid,nodev,noexec,relatime,blkio 0 0\n"
+ "cgroup /not/really/sys/fs/cgroup/memory cgroup rw,nosuid,nodev,noexec,relatime,memory 0 0\n"
+ "/dev/sda1 /boot ext4 rw,seclabel,relatime,data=ordered 0 0\n"
+ "tmpfs /tmp tmpfs rw,seclabel,relatime,size=1024000k 0 0\n";
+
+const char *cgroups =
+ "115:memory:/\n"
+ "8:blkio:/\n"
+ "6:freezer:/\n"
+ "3:cpuacct,cpu:/system\n"
+ "2:cpuset:/\n"
+ "1:name=systemd:/user/berrange/123\n";
+
+static int make_file(const char *path,
+ const char *name,
+ const char *value)
+{
+ int fd = -1;
+ int ret = -1;
+ char *filepath = NULL;
+
+ if (asprintf(&filepath, "%s/%s", path, name) < 0)
+ return -1;
+
+ if ((fd = realopen(filepath, O_CREAT|O_WRONLY, 0600)) < 0)
+ goto cleanup;
+
+ if (write(fd, value, strlen(value)) != strlen(value))
+ goto cleanup;
+
+ ret = 0;
+cleanup:
+ if (fd != -1 && close(fd) < 0)
+ ret = -1;
+ free(filepath);
+
+ return ret;
+}
+
+static int make_controller(const char *path, mode_t mode)
+{
+ int ret = -1;
+ const char *controller;
+
+ if (!STRPREFIX(path, fakesysfsdir)) {
+ errno = EINVAL;
+ return -1;
+ }
+ controller = path + strlen(fakesysfsdir) + 1;
+
+ if (STREQ(controller, "cpu"))
+ return symlink("cpu,cpuacct", path);
+ if (STREQ(controller, "cpuacct"))
+ return symlink("cpu,cpuacct", path);
+
+ if (realmkdir(path, mode) < 0)
+ goto cleanup;
+
+# define MAKE_FILE(name, value) \
+ do { \
+ if (make_file(path, name, value) < 0) \
+ goto cleanup; \
+ } while (0)
+
+ if (STRPREFIX(controller, "cpu,cpuacct")) {
+ MAKE_FILE("cpu.cfs_period_us", "100000\n");
+ MAKE_FILE("cpu.cfs_quota_us", "-1\n");
+ MAKE_FILE("cpu.rt_period_us", "1000000\n");
+ MAKE_FILE("cpu.rt_runtime_us", "950000\n");
+ MAKE_FILE("cpu.shares", "1024\n");
+ MAKE_FILE("cpu.stat",
+ "nr_periods 0\n"
+ "nr_throttled 0\n"
+ "throttled_time 0\n");
+ MAKE_FILE("cpuacct.stat",
+ "user 216687025\n"
+ "system 43421396\n");
+ MAKE_FILE("cpuacct.usage", "2787788855799582\n");
+ MAKE_FILE("cpuacct.usage_per_cpu", "1413142688153030 1374646168910542\n");
+ } else if (STRPREFIX(controller, "cpuset")) {
+ MAKE_FILE("cpuset.cpu_exclusive", "1\n");
+ if (STREQ(controller, "cpuset"))
+ MAKE_FILE("cpuset.cpus", "0-1");
+ else
+ MAKE_FILE("cpuset.cpus", ""); /* Values don't inherit */
+ MAKE_FILE("cpuset.mem_exclusive", "1\n");
+ MAKE_FILE("cpuset.mem_hardwall", "0\n");
+ MAKE_FILE("cpuset.memory_migrate", "0\n");
+ MAKE_FILE("cpuset.memory_pressure", "0\n");
+ MAKE_FILE("cpuset.memory_pressure_enabled", "0\n");
+ MAKE_FILE("cpuset.memory_spread_page", "0\n");
+ MAKE_FILE("cpuset.memory_spread_slab", "0\n");
+ if (STREQ(controller, "cpuset"))
+ MAKE_FILE("cpuset.mems", "0");
+ else
+ MAKE_FILE("cpuset.mems", ""); /* Values don't inherit */
+ MAKE_FILE("cpuset.sched_load_balance", "1\n");
+ MAKE_FILE("cpuset.sched_relax_domain_level", "-1\n");
+ } else if (STRPREFIX(controller, "memory")) {
+ MAKE_FILE("memory.failcnt", "0\n");
+ MAKE_FILE("memory.force_empty", ""); /* Write only */
+ MAKE_FILE("memory.kmem.tcp.failcnt", "0\n");
+ MAKE_FILE("memory.kmem.tcp.limit_in_bytes", "9223372036854775807\n");
+ MAKE_FILE("memory.kmem.tcp.max_usage_in_bytes", "0\n");
+ MAKE_FILE("memory.kmem.tcp.usage_in_bytes", "16384\n");
+ MAKE_FILE("memory.limit_in_bytes", "9223372036854775807\n");
+ MAKE_FILE("memory.max_usage_in_bytes", "0\n");
+ MAKE_FILE("memory.memsw.failcnt", ""); /* Not supported */
+ MAKE_FILE("memory.memsw.limit_in_bytes", ""); /* Not supported */
+ MAKE_FILE("memory.memsw.max_usage_in_bytes", ""); /* Not supported */
+ MAKE_FILE("memory.memsw.usage_in_bytes", ""); /* Not supported */
+ MAKE_FILE("memory.move_charge_at_immigrate", "0\n");
+ MAKE_FILE("memory.numa_stat",
+ "total=367664 N0=367664\n"
+ "file=314764 N0=314764\n"
+ "anon=51999 N0=51999\n"
+ "unevictable=901 N0=901\n");
+ MAKE_FILE("memory.oom_control",
+ "oom_kill_disable 0\n"
+ "under_oom 0\n");
+ MAKE_FILE("memory.soft_limit_in_bytes", "9223372036854775807\n");
+ MAKE_FILE("memory.stat",
+ "cache 1336619008\n"
+ "rss 97792000\n"
+ "mapped_file 42090496\n"
+ "pgpgin 13022605027\n"
+ "pgpgout 13023820533\n"
+ "pgfault 54429417056\n"
+ "pgmajfault 315715\n"
+ "inactive_anon 145887232\n"
+ "active_anon 67100672\n"
+ "inactive_file 627400704\n"
+ "active_file 661872640\n"
+ "unevictable 3690496\n"
+ "hierarchical_memory_limit 9223372036854775807\n"
+ "total_cache 1336635392\n"
+ "total_rss 118689792\n"
+ "total_mapped_file 42106880\n"
+ "total_pgpgin 13022606816\n"
+ "total_pgpgout 13023820793\n"
+ "total_pgfault 54429422313\n"
+ "total_pgmajfault 315715\n"
+ "total_inactive_anon 145891328\n"
+ "total_active_anon 88010752\n"
+ "total_inactive_file 627400704\n"
+ "total_active_file 661872640\n"
+ "total_unevictable 3690496\n"
+ "recent_rotated_anon 112807028\n"
+ "recent_rotated_file 2547948\n"
+ "recent_scanned_anon 113796164\n"
+ "recent_scanned_file 8199863\n");
+ MAKE_FILE("memory.swappiness", "60\n");
+ MAKE_FILE("memory.usage_in_bytes", "1455321088\n");
+ MAKE_FILE("memory.use_hierarchy", "0\n");
+ } else if (STRPREFIX(controller, "freezer")) {
+ MAKE_FILE("freezer.state", "THAWED");
+ } else if (STRPREFIX(controller, "blkio")) {
+ MAKE_FILE("blkio.io_merged",
+ "8:0 Read 1100949\n"
+ "8:0 Write 2248076\n"
+ "8:0 Sync 63063\n"
+ "8:0 Async 3285962\n"
+ "8:0 Total 3349025\n");
+ MAKE_FILE("blkio.io_queued",
+ "8:0 Read 0\n"
+ "8:0 Write 0\n"
+ "8:0 Sync 0\n"
+ "8:0 Async 0\n"
+ "8:0 Total 0\n");
+ MAKE_FILE("blkio.io_service_bytes",
+ "8:0 Read 59542078464\n"
+ "8:0 Write 397369182208\n"
+ "8:0 Sync 234080922624\n"
+ "8:0 Async 222830338048\n"
+ "8:0 Total 456911260672\n");
+ MAKE_FILE("blkio.io_serviced",
+ "8:0 Read 3402504\n"
+ "8:0 Write 14966516\n"
+ "8:0 Sync 12064031\n"
+ "8:0 Async 6304989\n"
+ "8:0 Total 18369020\n");
+ MAKE_FILE("blkio.io_service_time",
+ "8:0 Read 10747537542349\n"
+ "8:0 Write 9200028590575\n"
+ "8:0 Sync 6449319855381\n"
+ "8:0 Async 13498246277543\n"
+ "8:0 Total 19947566132924\n");
+ MAKE_FILE("blkio.io_wait_time",
+ "8:0 Read 14687514824889\n"
+ "8:0 Write 357748452187691\n"
+ "8:0 Sync 55296974349413\n"
+ "8:0 Async 317138992663167\n"
+ "8:0 Total 372435967012580\n");
+ MAKE_FILE("blkio.reset_stats", ""); /* Write only */
+ MAKE_FILE("blkio.sectors", "8:0 892404806\n");
+ MAKE_FILE("blkio.throttle.io_service_bytes",
+ "8:0 Read 59542107136\n"
+ "8:0 Write 411440480256\n"
+ "8:0 Sync 248486822912\n"
+ "8:0 Async 222495764480\n"
+ "8:0 Total 470982587392\n");
+ MAKE_FILE("blkio.throttle.io_serviced",
+ "8:0 Read 4832583\n"
+ "8:0 Write 36641903\n"
+ "8:0 Sync 30723171\n"
+ "8:0 Async 10751315\n"
+ "8:0 Total 41474486\n");
+ MAKE_FILE("blkio.throttle.read_bps_device", "");
+ MAKE_FILE("blkio.throttle.read_iops_device", "");
+ MAKE_FILE("blkio.throttle.write_bps_device", "");
+ MAKE_FILE("blkio.throttle.write_iops_device", "");
+ MAKE_FILE("blkio.time", "8:0 61019089\n");
+ MAKE_FILE("blkio.weight", "1000\n");
+ MAKE_FILE("blkio.weight_device", "");
+
+ } else {
+ errno = EINVAL;
+ goto cleanup;
+ }
+
+ ret = 0;
+cleanup:
+ return ret;
+}
+
+static void init_syms(void)
+{
+ if (realfopen)
+ return;
+
+# define LOAD_SYM(name) \
+ do { \
+ if (!(real ## name = dlsym(RTLD_NEXT, #name))) { \
+ fprintf(stderr, "Cannot find real '%s' symbol\n", #name); \
+ abort(); \
+ } \
+ } while (0)
+
+ LOAD_SYM(fopen);
+ LOAD_SYM(access);
+ LOAD_SYM(mkdir);
+ LOAD_SYM(open);
+}
+
+static void init_sysfs(void)
+{
+ if (fakesysfsdir)
+ return;
+
+ if (!(fakesysfsdir = getenv("LIBVIRT_FAKE_SYSFS_DIR"))) {
+ fprintf(stderr, "Missing LIBVIRT_FAKE_SYSFS_DIR env variable\n");
+ abort();
+ }
+
+# define MAKE_CONTROLLER(subpath) \
+ do { \
+ char *path; \
+ if (asprintf(&path,"%s/%s", fakesysfsdir, subpath) < 0) \
+ abort(); \
+ if (make_controller(path, 0755) < 0) { \
+ fprintf(stderr, "Cannot initialize %s\n", path); \
+ abort(); \
+ } \
+ } while (0)
+
+ MAKE_CONTROLLER("cpu");
+ MAKE_CONTROLLER("cpuacct");
+ MAKE_CONTROLLER("cpu,cpuacct");
+ MAKE_CONTROLLER("cpu,cpuacct/system");
+ MAKE_CONTROLLER("cpuset");
+ MAKE_CONTROLLER("blkio");
+ MAKE_CONTROLLER("memory");
+ MAKE_CONTROLLER("freezer");
+}
+
+
+FILE *fopen(const char *path, const char *mode)
+{
+ init_syms();
+
+ if (STREQ(path, "/proc/mounts")) {
+ if (STREQ(mode, "r")) {
+ return fmemopen((void *)mounts, strlen(mounts), mode);
+ } else {
+ errno = EACCES;
+ return NULL;
+ }
+ }
+ if (STREQ(path, "/proc/self/cgroup")) {
+ if (STREQ(mode, "r")) {
+ return fmemopen((void *)cgroups, strlen(cgroups), mode);
+ } else {
+ errno = EACCES;
+ return NULL;
+ }
+ }
+
+ return realfopen(path, mode);
+}
+
+int access(const char *path, int mode)
+{
+ int ret;
+
+ init_syms();
+
+ if (STRPREFIX(path, SYSFS_PREFIX)) {
+ init_sysfs();
+ char *newpath;
+ if (asprintf(&newpath, "%s/%s",
+ fakesysfsdir,
+ path + strlen(SYSFS_PREFIX)) < 0) {
+ errno = ENOMEM;
+ return -1;
+ }
+ ret = realaccess(newpath, mode);
+ free(newpath);
+ } else {
+ ret = realaccess(path, mode);
+ }
+ return ret;
+}
+
+int mkdir(const char *path, mode_t mode)
+{
+ int ret;
+
+ init_syms();
+
+ if (STRPREFIX(path, SYSFS_PREFIX)) {
+ init_sysfs();
+ char *newpath;
+ if (asprintf(&newpath, "%s/%s",
+ fakesysfsdir,
+ path + strlen(SYSFS_PREFIX)) < 0) {
+ errno = ENOMEM;
+ return -1;
+ }
+ ret = make_controller(newpath, mode);
+ free(newpath);
+ } else {
+ ret = realmkdir(path, mode);
+ }
+ return ret;
+}
+
+int open(const char *path, int flags, ...)
+{
+ int ret;
+ char *newpath = NULL;
+
+ init_syms();
+
+ if (STRPREFIX(path, SYSFS_PREFIX)) {
+ init_sysfs();
+ if (asprintf(&newpath, "%s/%s",
+ fakesysfsdir,
+ path + strlen(SYSFS_PREFIX)) < 0) {
+ errno = ENOMEM;
+ return -1;
+ }
+ }
+ if (flags & O_CREAT) {
+ va_list ap;
+ mode_t mode;
+ va_start(ap, flags);
+ mode = va_arg(ap, mode_t);
+ va_end(ap);
+ ret = realopen(newpath ? newpath : path, flags, mode);
+ } else {
+ ret = realopen(newpath ? newpath : path, flags);
+ }
+ free(newpath);
+ return ret;
+}
+#else
+/* Nothing to override on non-__linux__ platforms */
+#endif
diff --git a/tests/vircgrouptest.c b/tests/vircgrouptest.c
new file mode 100644
index 0000000000000000000000000000000000000000..d03962421501373d48182ddefd775324e34781b3
--- /dev/null
+++ b/tests/vircgrouptest.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2013 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * .
+ *
+ * Author: Daniel P. Berrange
+ */
+
+#include
+
+#include "testutils.h"
+
+#ifdef __linux__
+
+# include
+
+# define __VIR_CGROUP_ALLOW_INCLUDE_PRIV_H__
+# include "vircgrouppriv.h"
+# include "virutil.h"
+# include "virerror.h"
+# include "virlog.h"
+# include "virfile.h"
+
+# define VIR_FROM_THIS VIR_FROM_NONE
+
+static int validateCgroup(virCgroupPtr cgroup,
+ const char *expectPath,
+ const char **expectMountPoint,
+ const char **expectPlacement)
+{
+ int i;
+
+ if (STRNEQ(cgroup->path, expectPath)) {
+ fprintf(stderr, "Wrong path '%s', expected '%s'\n",
+ cgroup->path, expectPath);
+ return -1;
+ }
+
+ for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
+ if (STRNEQ_NULLABLE(expectMountPoint[i],
+ cgroup->controllers[i].mountPoint)) {
+ fprintf(stderr, "Wrong mount '%s', expected '%s' for '%s'\n",
+ cgroup->controllers[i].mountPoint,
+ expectMountPoint[i],
+ virCgroupControllerTypeToString(i));
+ return -1;
+ }
+ if (STRNEQ_NULLABLE(expectPlacement[i],
+ cgroup->controllers[i].placement)) {
+ fprintf(stderr, "Wrong placement '%s', expected '%s' for '%s'\n",
+ cgroup->controllers[i].placement,
+ expectPlacement[i],
+ virCgroupControllerTypeToString(i));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+const char *mountsSmall[VIR_CGROUP_CONTROLLER_LAST] = {
+ [VIR_CGROUP_CONTROLLER_CPU] = "/not/really/sys/fs/cgroup/cpu,cpuacct",
+ [VIR_CGROUP_CONTROLLER_CPUACCT] = "/not/really/sys/fs/cgroup/cpu,cpuacct",
+ [VIR_CGROUP_CONTROLLER_CPUSET] = NULL,
+ [VIR_CGROUP_CONTROLLER_MEMORY] = "/not/really/sys/fs/cgroup/memory",
+ [VIR_CGROUP_CONTROLLER_DEVICES] = NULL,
+ [VIR_CGROUP_CONTROLLER_FREEZER] = NULL,
+ [VIR_CGROUP_CONTROLLER_BLKIO] = NULL,
+};
+const char *mountsFull[VIR_CGROUP_CONTROLLER_LAST] = {
+ [VIR_CGROUP_CONTROLLER_CPU] = "/not/really/sys/fs/cgroup/cpu,cpuacct",
+ [VIR_CGROUP_CONTROLLER_CPUACCT] = "/not/really/sys/fs/cgroup/cpu,cpuacct",
+ [VIR_CGROUP_CONTROLLER_CPUSET] = "/not/really/sys/fs/cgroup/cpuset",
+ [VIR_CGROUP_CONTROLLER_MEMORY] = "/not/really/sys/fs/cgroup/memory",
+ [VIR_CGROUP_CONTROLLER_DEVICES] = NULL,
+ [VIR_CGROUP_CONTROLLER_FREEZER] = "/not/really/sys/fs/cgroup/freezer",
+ [VIR_CGROUP_CONTROLLER_BLKIO] = "/not/really/sys/fs/cgroup/blkio",
+};
+
+static int testCgroupNewForSelf(const void *args ATTRIBUTE_UNUSED)
+{
+ virCgroupPtr cgroup = NULL;
+ int ret = -1;
+ const char *placement[VIR_CGROUP_CONTROLLER_LAST] = {
+ [VIR_CGROUP_CONTROLLER_CPU] = "/system",
+ [VIR_CGROUP_CONTROLLER_CPUACCT] = "/system",
+ [VIR_CGROUP_CONTROLLER_CPUSET] = "",
+ [VIR_CGROUP_CONTROLLER_MEMORY] = "",
+ [VIR_CGROUP_CONTROLLER_DEVICES] = NULL,
+ [VIR_CGROUP_CONTROLLER_FREEZER] = "",
+ [VIR_CGROUP_CONTROLLER_BLKIO] = "",
+ };
+
+ if (virCgroupNewSelf(&cgroup) < 0) {
+ fprintf(stderr, "Cannot create cgroup for self\n");
+ goto cleanup;
+ }
+
+ ret = validateCgroup(cgroup, "/", mountsFull, placement);
+
+cleanup:
+ virCgroupFree(&cgroup);
+ return ret;
+}
+
+
+static int testCgroupNewForDriver(const void *args ATTRIBUTE_UNUSED)
+{
+ virCgroupPtr cgroup = NULL;
+ int ret = -1;
+ int rv;
+ const char *placement[VIR_CGROUP_CONTROLLER_LAST] = {
+ [VIR_CGROUP_CONTROLLER_CPU] = "/system",
+ [VIR_CGROUP_CONTROLLER_CPUACCT] = "/system",
+ [VIR_CGROUP_CONTROLLER_CPUSET] = "",
+ [VIR_CGROUP_CONTROLLER_MEMORY] = "",
+ [VIR_CGROUP_CONTROLLER_DEVICES] = NULL,
+ [VIR_CGROUP_CONTROLLER_FREEZER] = "",
+ [VIR_CGROUP_CONTROLLER_BLKIO] = "",
+ };
+
+ if ((rv = virCgroupNewDriver("lxc", true, false, -1, &cgroup)) != -ENOENT) {
+ fprintf(stderr, "Unexpected found LXC cgroup: %d\n", -rv);
+ goto cleanup;
+ }
+
+ /* Asking for impossible combination since CPU is co-mounted */
+ if ((rv = virCgroupNewDriver("lxc", true, true,
+ (1 << VIR_CGROUP_CONTROLLER_CPU),
+ &cgroup)) != -EINVAL) {
+ fprintf(stderr, "Should not have created LXC cgroup: %d\n", -rv);
+ goto cleanup;
+ }
+
+ /* Asking for impossible combination since devices is not mounted */
+ if ((rv = virCgroupNewDriver("lxc", true, true,
+ (1 << VIR_CGROUP_CONTROLLER_DEVICES),
+ &cgroup)) != -ENOENT) {
+ fprintf(stderr, "Should not have created LXC cgroup: %d\n", -rv);
+ goto cleanup;
+ }
+
+ /* Asking for small combination since devices is not mounted */
+ if ((rv = virCgroupNewDriver("lxc", true, true,
+ (1 << VIR_CGROUP_CONTROLLER_CPU) |
+ (1 << VIR_CGROUP_CONTROLLER_CPUACCT) |
+ (1 << VIR_CGROUP_CONTROLLER_MEMORY),
+ &cgroup)) != 0) {
+ fprintf(stderr, "Cannot create LXC cgroup: %d\n", -rv);
+ goto cleanup;
+ }
+ ret = validateCgroup(cgroup, "/libvirt/lxc", mountsSmall, placement);
+ virCgroupFree(&cgroup);
+
+ if ((rv = virCgroupNewDriver("lxc", true, true, -1, &cgroup)) != 0) {
+ fprintf(stderr, "Cannot create LXC cgroup: %d\n", -rv);
+ goto cleanup;
+ }
+ ret = validateCgroup(cgroup, "/libvirt/lxc", mountsFull, placement);
+
+cleanup:
+ virCgroupFree(&cgroup);
+ return ret;
+}
+
+
+static int testCgroupNewForDomain(const void *args ATTRIBUTE_UNUSED)
+{
+ virCgroupPtr drivercgroup = NULL;
+ virCgroupPtr domaincgroup = NULL;
+ int ret = -1;
+ int rv;
+ const char *placement[VIR_CGROUP_CONTROLLER_LAST] = {
+ [VIR_CGROUP_CONTROLLER_CPU] = "/system",
+ [VIR_CGROUP_CONTROLLER_CPUACCT] = "/system",
+ [VIR_CGROUP_CONTROLLER_CPUSET] = "",
+ [VIR_CGROUP_CONTROLLER_MEMORY] = "",
+ [VIR_CGROUP_CONTROLLER_DEVICES] = NULL,
+ [VIR_CGROUP_CONTROLLER_FREEZER] = "",
+ [VIR_CGROUP_CONTROLLER_BLKIO] = "",
+ };
+
+ if ((rv = virCgroupNewDriver("lxc", true, false, -1, &drivercgroup)) != 0) {
+ fprintf(stderr, "Cannot find LXC cgroup: %d\n", -rv);
+ goto cleanup;
+ }
+
+ if ((rv = virCgroupNewDomain(drivercgroup, "wibble", true, &domaincgroup)) != 0) {
+ fprintf(stderr, "Cannot create LXC cgroup: %d\n", -rv);
+ goto cleanup;
+ }
+
+ ret = validateCgroup(domaincgroup, "/libvirt/lxc/wibble", mountsFull, placement);
+
+cleanup:
+ virCgroupFree(&drivercgroup);
+ virCgroupFree(&domaincgroup);
+ return ret;
+}
+
+
+# define FAKESYSFSDIRTEMPLATE abs_builddir "/fakesysfsdir-XXXXXX"
+
+
+
+static int
+mymain(void)
+{
+ int ret = 0;
+ char *fakesysfsdir;
+
+ if (!(fakesysfsdir = strdup(FAKESYSFSDIRTEMPLATE))) {
+ fprintf(stderr, "Out of memory\n");
+ abort();
+ }
+
+ if (!mkdtemp(fakesysfsdir)) {
+ fprintf(stderr, "Cannot create fakesysfsdir");
+ abort();
+ }
+
+ setenv("LIBVIRT_FAKE_SYSFS_DIR", fakesysfsdir, 1);
+
+ if (virtTestRun("New cgroup for self", 1, testCgroupNewForSelf, NULL) < 0)
+ ret = -1;
+
+ if (virtTestRun("New cgroup for driver", 1, testCgroupNewForDriver, NULL) < 0)
+ ret = -1;
+
+ if (virtTestRun("New cgroup for domain", 1, testCgroupNewForDomain, NULL) < 0)
+ ret = -1;
+
+ if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL)
+ virFileDeleteTree(fakesysfsdir);
+
+ VIR_FREE(fakesysfsdir);
+
+ return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+VIRT_TEST_MAIN_PRELOAD(mymain, abs_builddir "/.libs/vircgroupmock.so")
+
+#else
+int
+main(void)
+{
+ return EXIT_AM_SKIP;
+}
+#endif