diff options
Diffstat (limited to 'tests/virtualbox.h')
-rw-r--r-- | tests/virtualbox.h | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/tests/virtualbox.h b/tests/virtualbox.h new file mode 100644 index 00000000..2cc97001 --- /dev/null +++ b/tests/virtualbox.h @@ -0,0 +1,134 @@ +/* Determine whether the current system is running under VirtualBox/KVM. + Copyright (C) 2021-2024 Free Software Foundation, Inc. + + This file 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 file 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 program. If not, see <https://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2024. */ + +#ifdef __linux__ +# include <fcntl.h> +# include <string.h> +# include <unistd.h> +#endif + +/* This function determines whether the current system is Linux and running + under the VirtualBox emulator. */ +_GL_ATTRIBUTE_MAYBE_UNUSED static bool +is_running_under_virtualbox (void) +{ +#ifdef __linux__ + /* On distributions with systemd, this could be done through + test `systemd-detect-virt --vm` = oracle + More generally, it can be done through + test "`cat /sys/class/dmi/id/product_name`" = VirtualBox + This is what we do here. */ + char buf[4096]; + int fd = open ("/sys/class/dmi/id/product_name", O_RDONLY); + if (fd >= 0) + { + int n = read (fd, buf, sizeof (buf)); + close (fd); + if (n == 10 + 1 && memcmp (buf, "VirtualBox\n", 10 + 1) == 0) + return true; + } +#endif + + return false; +} + +/* This function determines whether the current system is Linux and running + under the VirtualBox emulator, with paravirtualization acceleration set to + "Default" or "KVM". */ +static bool +is_running_under_virtualbox_kvm (void) +{ +#ifdef __linux__ + if (is_running_under_virtualbox ()) + { + /* As root, one can determine this paravirtualization mode through + dmesg | grep -i kvm + which produces output like this: + [ 0.000000] Hypervisor detected: KVM + [ 0.000000] kvm-clock: Using msrs 4b564d01 and 4b564d00 + [ 0.000001] kvm-clock: using sched offset of 3736655524 cycles + [ 0.000004] clocksource: kvm-clock: mask: 0xffffffffffffffff max_cycles: 0x1cd42e4dffb, max_idle_ns: 881590591483 ns + [ 0.007355] Booting paravirtualized kernel on KVM + [ 0.213538] clocksource: Switched to clocksource kvm-clock + So, we test whether the file + /sys/devices/system/clocksource/clocksource0/available_clocksource + contains the word 'kvm-clock'. */ + char buf[4096 + 1]; + int fd = open ("/sys/devices/system/clocksource/clocksource0/available_clocksource", O_RDONLY); + if (fd >= 0) + { + int n = read (fd, buf, sizeof (buf) - 1); + close (fd); + if (n > 0) + { + buf[n] = '\0'; + char *saveptr; + char *word; + for (word = strtok_r (buf, " \n", &saveptr); + word != NULL; + word = strtok_r (NULL, " \n", &saveptr)) + { + if (strcmp (word, "kvm-clock") == 0) + return true; + } + } + } + } +#endif + + return false; +} + +/* This function returns the number of CPUs in the current system, assuming + it is Linux. */ +static int +num_cpus (void) +{ +#ifdef __linux__ + /* We could use sysconf (_SC_NPROCESSORS_CONF), which on glibc and musl libc + is implemented through sched_getaffinity(). But there are some + complications; see nproc.c. It's simpler to parse /proc/cpuinfo. + More precisely, it's sufficient to count the number of blank lines in + /proc/cpuinfo. */ + char buf[4096]; + int fd = open ("/proc/cpuinfo", O_RDONLY); + if (fd >= 0) + { + unsigned int blank_lines = 0; + bool last_char_was_newline = false; + for (;;) + { + int n = read (fd, buf, sizeof (buf)); + if (n <= 0) + break; + int i; + for (i = 0; i < n; i++) + { + if (last_char_was_newline && buf[i] == '\n') + blank_lines++; + last_char_was_newline = (buf[i] == '\n'); + } + } + close (fd); + if (blank_lines > 0) + return blank_lines; + } +#endif + + return 1; +} |