backup: Wire up qemu full pull backup commands over QMP
[libvirt/ericb.git] / tests / vircgroupmock.c
blob7bbaa6dd0fc14c42070b083719ab3f7efc9493fa
1 /*
2 * Copyright (C) 2013 Red Hat, Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see
16 * <http://www.gnu.org/licenses/>.
19 #include <config.h>
21 #ifdef __linux__
22 # include "virmock.h"
23 # include <unistd.h>
24 # include <fcntl.h>
25 # include <sys/stat.h>
27 # ifdef MAJOR_IN_MKDEV
28 # include <sys/mkdev.h>
29 # elif MAJOR_IN_SYSMACROS
30 # include <sys/sysmacros.h>
31 # endif
33 # include <stdarg.h>
34 # include "testutilslxc.h"
35 # include "virstring.h"
36 # include "virfile.h"
37 # include "viralloc.h"
39 static int (*real_open)(const char *path, int flags, ...);
40 static FILE *(*real_fopen)(const char *path, const char *mode);
41 static int (*real_access)(const char *path, int mode);
42 static int (*real_mkdir)(const char *path, mode_t mode);
44 /* Don't make static, since it causes problems with clang
45 * when passed as an arg to asprintf()
46 * vircgroupmock.c:462:22: error: static variable 'fakesysfsdir' is used in an inline function with external linkage [-Werror,-Wstatic-in-inline]
48 char *fakerootdir;
49 char *fakesysfscgroupdir;
50 const char *fakedevicedir0 = FAKEDEVDIR0;
51 const char *fakedevicedir1 = FAKEDEVDIR1;
54 # define SYSFS_CGROUP_PREFIX "/not/really/sys/fs/cgroup"
55 # define SYSFS_CPU_PRESENT "/sys/devices/system/cpu/present"
56 # define SYSFS_CPU_PRESENT_MOCKED "devices_system_cpu_present"
59 * The plan:
61 * We fake out /proc/mounts, so make it look as is cgroups
62 * are mounted on /not/really/sys/fs/cgroup. We don't
63 * use /sys/fs/cgroup, because we want to make it easy to
64 * detect places where we've not mocked enough syscalls.
66 * In any open/acces/mkdir calls we look at path and if
67 * it starts with /not/really/sys/fs/cgroup, we rewrite
68 * the path to point at a subdirectory of the temporary
69 * directory referred to by LIBVIRT_FAKE_ROOT_DIR env
70 * variable that is set by the main test suite
72 * In mkdir() calls, we simulate the cgroups behaviour
73 * whereby creating the directory auto-creates a bunch
74 * of files beneath it
77 static int make_file(const char *path,
78 const char *name,
79 const char *value)
81 int fd = -1;
82 int ret = -1;
83 char *filepath = NULL;
85 if (asprintf(&filepath, "%s/%s", path, name) < 0)
86 return -1;
88 if ((fd = real_open(filepath, O_CREAT|O_WRONLY, 0600)) < 0)
89 goto cleanup;
91 if (write(fd, value, strlen(value)) != strlen(value))
92 goto cleanup;
94 ret = 0;
95 cleanup:
96 if (fd != -1 && close(fd) < 0)
97 ret = -1;
98 free(filepath);
100 return ret;
104 static int make_controller_v1(const char *path, mode_t mode)
106 int ret = -1;
107 const char *controller;
109 if (!STRPREFIX(path, fakesysfscgroupdir)) {
110 errno = EINVAL;
111 return -1;
113 controller = path + strlen(fakesysfscgroupdir) + 1;
115 if (STREQ(controller, "cpu"))
116 return symlink("cpu,cpuacct", path);
117 if (STREQ(controller, "cpuacct"))
118 return symlink("cpu,cpuacct", path);
120 if (real_mkdir(path, mode) < 0)
121 goto cleanup;
123 # define MAKE_FILE(name, value) \
124 do { \
125 if (make_file(path, name, value) < 0) \
126 goto cleanup; \
127 } while (0)
129 if (STRPREFIX(controller, "cpu,cpuacct")) {
130 MAKE_FILE("cpu.cfs_period_us", "100000\n");
131 MAKE_FILE("cpu.cfs_quota_us", "-1\n");
132 MAKE_FILE("cpu.shares", "1024\n");
133 MAKE_FILE("cpuacct.stat",
134 "user 216687025\n"
135 "system 43421396\n");
136 MAKE_FILE("cpuacct.usage", "2787788855799582\n");
137 MAKE_FILE("cpuacct.usage_percpu",
138 "7059492996 0 0 0 0 0 0 0 4180532496 0 0 0 0 0 0 0 "
139 "1957541268 0 0 0 0 0 0 0 2065932204 0 0 0 0 0 0 0 "
140 "18228689414 0 0 0 0 0 0 0 4245525148 0 0 0 0 0 0 0 "
141 "2911161568 0 0 0 0 0 0 0 1407758136 0 0 0 0 0 0 0 "
142 "1836807700 0 0 0 0 0 0 0 1065296618 0 0 0 0 0 0 0 "
143 "2046213266 0 0 0 0 0 0 0 747889778 0 0 0 0 0 0 0 "
144 "709566900 0 0 0 0 0 0 0 444777342 0 0 0 0 0 0 0 "
145 "5683512916 0 0 0 0 0 0 0 635751356 0 0 0 0 0 0 0\n");
146 } else if (STRPREFIX(controller, "cpuset")) {
147 if (STREQ(controller, "cpuset"))
148 MAKE_FILE("cpuset.cpus", "0-1");
149 else
150 MAKE_FILE("cpuset.cpus", ""); /* Values don't inherit */
151 MAKE_FILE("cpuset.memory_migrate", "0\n");
152 if (STREQ(controller, "cpuset"))
153 MAKE_FILE("cpuset.mems", "0");
154 else
155 MAKE_FILE("cpuset.mems", ""); /* Values don't inherit */
156 } else if (STRPREFIX(controller, "memory")) {
157 MAKE_FILE("memory.limit_in_bytes", "9223372036854775807\n");
158 MAKE_FILE("memory.memsw.limit_in_bytes", ""); /* Not supported */
159 MAKE_FILE("memory.memsw.usage_in_bytes", ""); /* Not supported */
160 MAKE_FILE("memory.soft_limit_in_bytes", "9223372036854775807\n");
161 MAKE_FILE("memory.stat",
162 "cache 1336619008\n"
163 "rss 97792000\n"
164 "mapped_file 42090496\n"
165 "pgpgin 13022605027\n"
166 "pgpgout 13023820533\n"
167 "pgfault 54429417056\n"
168 "pgmajfault 315715\n"
169 "inactive_anon 145887232\n"
170 "active_anon 67100672\n"
171 "inactive_file 627400704\n"
172 "active_file 661872640\n"
173 "unevictable 3690496\n"
174 "hierarchical_memory_limit 9223372036854775807\n"
175 "total_cache 1336635392\n"
176 "total_rss 118689792\n"
177 "total_mapped_file 42106880\n"
178 "total_pgpgin 13022606816\n"
179 "total_pgpgout 13023820793\n"
180 "total_pgfault 54429422313\n"
181 "total_pgmajfault 315715\n"
182 "total_inactive_anon 145891328\n"
183 "total_active_anon 88010752\n"
184 "total_inactive_file 627400704\n"
185 "total_active_file 661872640\n"
186 "total_unevictable 3690496\n"
187 "recent_rotated_anon 112807028\n"
188 "recent_rotated_file 2547948\n"
189 "recent_scanned_anon 113796164\n"
190 "recent_scanned_file 8199863\n");
191 MAKE_FILE("memory.usage_in_bytes", "1455321088\n");
192 MAKE_FILE("memory.use_hierarchy", "0\n");
193 } else if (STRPREFIX(controller, "freezer")) {
194 MAKE_FILE("freezer.state", "THAWED");
195 } else if (STRPREFIX(controller, "blkio")) {
196 MAKE_FILE("blkio.throttle.io_service_bytes",
197 "8:0 Read 59542107136\n"
198 "8:0 Write 411440480256\n"
199 "8:0 Sync 248486822912\n"
200 "8:0 Async 222495764480\n"
201 "8:0 Total 470982587392\n"
202 "9:0 Read 59542107137\n"
203 "9:0 Write 411440480257\n"
204 "9:0 Sync 248486822912\n"
205 "9:0 Async 222495764480\n"
206 "9:0 Total 470982587392\n");
207 MAKE_FILE("blkio.throttle.io_serviced",
208 "8:0 Read 4832583\n"
209 "8:0 Write 36641903\n"
210 "8:0 Sync 30723171\n"
211 "8:0 Async 10751315\n"
212 "8:0 Total 41474486\n"
213 "9:0 Read 4832584\n"
214 "9:0 Write 36641904\n"
215 "9:0 Sync 30723171\n"
216 "9:0 Async 10751315\n"
217 "9:0 Total 41474486\n");
218 MAKE_FILE("blkio.throttle.read_bps_device", "");
219 MAKE_FILE("blkio.throttle.read_iops_device", "");
220 MAKE_FILE("blkio.throttle.write_bps_device", "");
221 MAKE_FILE("blkio.throttle.write_iops_device", "");
222 MAKE_FILE("blkio.weight", "1000\n");
223 MAKE_FILE("blkio.weight_device", "");
225 } else {
226 errno = EINVAL;
227 goto cleanup;
230 # undef MAKE_FILE
232 ret = 0;
233 cleanup:
234 return ret;
238 static int make_controller_v2(const char *path, mode_t mode)
240 if (!STRPREFIX(path, fakesysfscgroupdir)) {
241 errno = EINVAL;
242 return -1;
245 if (real_mkdir(path, mode) < 0 && errno != EEXIST)
246 return -1;
248 # define MAKE_FILE(name, value) \
249 do { \
250 if (make_file(path, name, value) < 0) \
251 return -1; \
252 } while (0)
254 MAKE_FILE("cgroup.controllers", "cpu io memory\n");
255 MAKE_FILE("cgroup.subtree_control", "");
256 MAKE_FILE("cgroup.type", "domain\n");
257 MAKE_FILE("cpu.max", "max 100000\n");
258 MAKE_FILE("cpu.stat",
259 "usage_usec 0\n"
260 "user_usec 0\n"
261 "system_usec 0\n"
262 "nr_periods 0\n"
263 "nr_throttled 0\n"
264 "throttled_usec 0\n");
265 MAKE_FILE("cpu.weight", "100\n");
266 MAKE_FILE("memory.current", "1455321088\n");
267 MAKE_FILE("memory.high", "max\n");
268 MAKE_FILE("memory.max", "max\n");
269 MAKE_FILE("memory.stat",
270 "anon 0\n"
271 "file 0\n"
272 "kernel_stack 0\n"
273 "slab 0\n"
274 "sock 0\n"
275 "shmem 0\n"
276 "file_mapped 0\n"
277 "file_dirty 0\n"
278 "file_writeback 0\n"
279 "inactive_anon 0\n"
280 "active_anon 0\n"
281 "inactive_file 0\n"
282 "active_file 0\n"
283 "unevictable 0\n"
284 "slab_reclaimable 0\n"
285 "slab_unreclaimable 0\n"
286 "pgfault 0\n"
287 "pgmajfault 0\n"
288 "pgrefill 0\n"
289 "pgscan 0\n"
290 "pgsteal 0\n"
291 "pgactivate 0\n"
292 "pgdeactivate 0\n"
293 "pglazyfree 0\n"
294 "pglazyfreed 0\n"
295 "workingset_refault 0\n"
296 "workingset_activate 0\n"
297 "workingset_nodereclaim 0\n");
298 MAKE_FILE("memory.swap.current", "0\n");
299 MAKE_FILE("memory.swap.max", "max\n");
300 MAKE_FILE("io.stat", "8:0 rbytes=26828800 wbytes=77062144 rios=2256 wios=7849 dbytes=0 dios=0\n");
301 MAKE_FILE("io.max", "");
302 MAKE_FILE("io.weight", "default 100\n");
304 # undef MAKE_FILE
306 return 0;
310 static void init_syms(void)
312 if (real_fopen)
313 return;
315 VIR_MOCK_REAL_INIT(fopen);
316 VIR_MOCK_REAL_INIT(access);
317 VIR_MOCK_REAL_INIT(mkdir);
318 VIR_MOCK_REAL_INIT(open);
322 static int make_controller(const char *path, mode_t mode)
324 const char *mock;
325 bool unified = false;
326 bool hybrid = false;
328 mock = getenv("VIR_CGROUP_MOCK_MODE");
329 if (mock) {
330 if (STREQ(mock, "unified")) {
331 unified = true;
332 } else if (STREQ(mock, "hybrid")) {
333 hybrid = true;
334 } else {
335 fprintf(stderr, "invalid mode '%s'\n", mock);
336 abort();
340 if (unified || (hybrid && strstr(path, "unified"))) {
341 return make_controller_v2(path, mode);
342 } else {
343 return make_controller_v1(path, mode);
348 static void init_sysfs(void)
350 const char *mock;
351 char *newfakerootdir;
352 bool unified = false;
353 bool hybrid = false;
355 if (!(newfakerootdir = getenv("LIBVIRT_FAKE_ROOT_DIR"))) {
356 fprintf(stderr, "Missing LIBVIRT_FAKE_ROOT_DIR env variable\n");
357 abort();
360 if (fakerootdir && STREQ(fakerootdir, newfakerootdir))
361 return;
363 fakerootdir = newfakerootdir;
365 mock = getenv("VIR_CGROUP_MOCK_MODE");
366 if (mock) {
367 if (STREQ(mock, "unified")) {
368 unified = true;
369 } else if (STREQ(mock, "hybrid")) {
370 hybrid = true;
371 } else {
372 fprintf(stderr, "invalid mode '%s'\n", mock);
373 abort();
377 VIR_FREE(fakesysfscgroupdir);
379 if (virAsprintfQuiet(&fakesysfscgroupdir, "%s%s",
380 fakerootdir, SYSFS_CGROUP_PREFIX) < 0)
381 abort();
383 if (virFileMakePath(fakesysfscgroupdir) < 0) {
384 fprintf(stderr, "Cannot create %s\n", fakesysfscgroupdir);
385 abort();
388 # define MAKE_CONTROLLER(subpath) \
389 do { \
390 char *path; \
391 if (asprintf(&path, "%s/%s", fakesysfscgroupdir, subpath) < 0) \
392 abort(); \
393 if (make_controller(path, 0755) < 0) { \
394 fprintf(stderr, "Cannot initialize %s\n", path); \
395 free(path); \
396 abort(); \
398 free(path); \
399 } while (0)
401 if (unified) {
402 MAKE_CONTROLLER("");
403 } else if (hybrid) {
404 MAKE_CONTROLLER("unified");
405 MAKE_CONTROLLER("cpuset");
406 MAKE_CONTROLLER("freezer");
407 } else {
408 MAKE_CONTROLLER("cpu");
409 MAKE_CONTROLLER("cpuacct");
410 MAKE_CONTROLLER("cpu,cpuacct");
411 MAKE_CONTROLLER("cpuset");
412 MAKE_CONTROLLER("blkio");
413 MAKE_CONTROLLER("memory");
414 MAKE_CONTROLLER("freezer");
416 if (make_file(fakesysfscgroupdir,
417 SYSFS_CPU_PRESENT_MOCKED, "8-23,48-159\n") < 0)
418 abort();
423 FILE *fopen(const char *path, const char *mode)
425 char *filepath = NULL;
426 const char *type = NULL;
427 FILE *rc = NULL;
428 const char *filename = getenv("VIR_CGROUP_MOCK_FILENAME");
430 init_syms();
432 if (STREQ(path, "/proc/mounts")) {
433 if (STREQ(mode, "r")) {
434 type = "mounts";
435 } else {
436 errno = EACCES;
437 return NULL;
440 if (STREQ(path, "/proc/cgroups")) {
441 if (STREQ(mode, "r")) {
442 type = "cgroups";
443 } else {
444 errno = EACCES;
445 return NULL;
448 if (STREQ(path, "/proc/self/cgroup")) {
449 if (STREQ(mode, "r")) {
450 type = "self.cgroup";
451 } else {
452 errno = EACCES;
453 return NULL;
457 if (type) {
458 if (!filename) {
459 errno = EACCES;
460 return NULL;
462 if (virAsprintfQuiet(&filepath, "%s/vircgroupdata/%s.%s",
463 abs_srcdir, filename, type) < 0) {
464 abort();
466 rc = real_fopen(filepath, mode);
467 free(filepath);
468 return rc;
471 return real_fopen(path, mode);
474 int access(const char *path, int mode)
476 int ret;
478 init_syms();
480 if (STRPREFIX(path, SYSFS_CGROUP_PREFIX)) {
481 init_sysfs();
482 char *newpath;
483 if (asprintf(&newpath, "%s%s",
484 fakesysfscgroupdir,
485 path + strlen(SYSFS_CGROUP_PREFIX)) < 0) {
486 errno = ENOMEM;
487 return -1;
489 ret = real_access(newpath, mode);
490 free(newpath);
491 } else if (STREQ(path, "/proc/cgroups") ||
492 STREQ(path, "/proc/self/cgroup") ||
493 STREQ(path, SYSFS_CPU_PRESENT)) {
494 /* These files are readable for all. */
495 ret = (mode == F_OK || mode == R_OK) ? 0 : -1;
496 } else if (STREQ(path, "/proc/mounts")) {
497 /* This one is accessible anytime for anybody. In fact, it's just
498 * a symlink to /proc/self/mounts. */
499 ret = 0;
500 } else {
501 ret = real_access(path, mode);
503 return ret;
506 # define VIR_MOCK_STAT_HOOK \
507 do { \
508 if (STRPREFIX(path, fakedevicedir0)) { \
509 sb->st_mode = S_IFBLK; \
510 sb->st_rdev = makedev(8, 0); \
511 return 0; \
512 } else if (STRPREFIX(path, fakedevicedir1)) { \
513 sb->st_mode = S_IFBLK; \
514 sb->st_rdev = makedev(9, 0); \
515 return 0; \
517 } while (0)
519 # include "virmockstathelpers.c"
521 static int
522 virMockStatRedirect(const char *path, char **newpath)
524 if (STREQ(path, SYSFS_CPU_PRESENT)) {
525 init_sysfs();
526 if (asprintf(newpath, "%s/%s",
527 fakesysfscgroupdir,
528 SYSFS_CPU_PRESENT_MOCKED) < 0)
529 return -1;
530 } else if (STRPREFIX(path, SYSFS_CGROUP_PREFIX)) {
531 init_sysfs();
532 if (asprintf(newpath, "%s%s",
533 fakesysfscgroupdir,
534 path + strlen(SYSFS_CGROUP_PREFIX)) < 0)
535 return -1;
537 return 0;
541 int mkdir(const char *path, mode_t mode)
543 int ret;
545 init_syms();
547 if (STRPREFIX(path, SYSFS_CGROUP_PREFIX)) {
548 init_sysfs();
549 char *newpath;
550 if (asprintf(&newpath, "%s%s",
551 fakesysfscgroupdir,
552 path + strlen(SYSFS_CGROUP_PREFIX)) < 0) {
553 errno = ENOMEM;
554 return -1;
556 ret = make_controller(newpath, mode);
557 free(newpath);
558 } else {
559 ret = real_mkdir(path, mode);
561 return ret;
564 int open(const char *path, int flags, ...)
566 int ret;
567 char *newpath = NULL;
569 init_syms();
571 if (STREQ(path, SYSFS_CPU_PRESENT)) {
572 init_sysfs();
573 if (asprintf(&newpath, "%s/%s",
574 fakesysfscgroupdir,
575 SYSFS_CPU_PRESENT_MOCKED) < 0) {
576 errno = ENOMEM;
577 return -1;
581 if (STRPREFIX(path, SYSFS_CGROUP_PREFIX)) {
582 init_sysfs();
583 if (asprintf(&newpath, "%s%s",
584 fakesysfscgroupdir,
585 path + strlen(SYSFS_CGROUP_PREFIX)) < 0) {
586 errno = ENOMEM;
587 return -1;
590 if (flags & O_CREAT) {
591 va_list ap;
592 mode_t mode;
593 va_start(ap, flags);
594 mode = (mode_t) va_arg(ap, int);
595 va_end(ap);
596 ret = real_open(newpath ? newpath : path, flags, mode);
597 } else {
598 ret = real_open(newpath ? newpath : path, flags);
600 free(newpath);
601 return ret;
603 #else
604 /* Nothing to override on non-__linux__ platforms */
605 #endif