Branch
Hash :
7b089321
Author :
Date :
2025-01-01T09:24:36
maint: run 'make update-copyright'
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
/* Determine whether the current system is running under VirtualBox/KVM.
Copyright (C) 2021-2025 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;
}