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-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;
}
|