cdist configuration management
Latest manual: https://www.cdi.st/manual/latest/
Home page: https://www.cdi.st
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
983 lines
20 KiB
983 lines
20 KiB
#!/bin/sh -e |
|
# |
|
# 2021 Dennis Camera (cdist at dtnr.ch) |
|
# |
|
# This file is part of cdist. |
|
# |
|
# cdist is free software: you can redistribute it and/or modify |
|
# it under the terms of the GNU General Public License as published by |
|
# the Free Software Foundation, either version 3 of the License, or |
|
# (at your option) any later version. |
|
# |
|
# cdist 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 General Public License for more details. |
|
# |
|
# You should have received a copy of the GNU General Public License |
|
# along with cdist. If not, see <http://www.gnu.org/licenses/>. |
|
# |
|
# This explorer tries to determine what type of machine the target to be |
|
# configured is (container, virtual machine, bare-metal). |
|
# |
|
# It will print one line for each layer it can detect. |
|
# The format of all lines is: TYPE[ VERB VENDOR] |
|
# |
|
# VERB does not have a special meaning, it is just for better readability. |
|
# |
|
# e.g. |
|
# container |
|
# container on lxc |
|
# virtual by kvm-spapr |
|
# |
|
# The third word of each line (except the first) can be composed of different |
|
# parts concatenated with a `-' (minus) character, with each component being |
|
# a specification of the previous, e.g.: |
|
# - lxc-libvirt (LXC container, managed by libvirt) |
|
# - lpar-s390 / lpar-power (LPAR running on IBM S/390 or POWER, respectively) |
|
# - xen-hvm / xen-pv (Xen HVM vs para-virtualization) |
|
# |
|
# If this explorer cannot collect enough information about virtualization it |
|
# will fall back to 'physical'. |
|
# |
|
|
|
# Add /sbin and /usr/sbin to the path so we can find system |
|
# binaries like dmidecode. |
|
PATH=$(getconf PATH 2>/dev/null) || PATH='/usr/bin:/bin' |
|
PATH="/sbin:/usr/sbin:${PATH}" |
|
export PATH |
|
|
|
arch=$(uname -m | sed -e 's/i.86/i386/' -e 's/arm.*/arm/') |
|
uname_s=$(uname -s) |
|
|
|
|
|
is_command() { command -v "$1" >/dev/null 2>&1; } |
|
|
|
files_same() { |
|
# shellcheck disable=SC2012 |
|
LC_ALL=C df -P "$1" "$2" 2>/dev/null | { |
|
read -r _ # skip header line |
|
read -r fs1 _ _ _ _ mp1 |
|
read -r fs2 _ _ _ _ mp2 |
|
test "${fs1}" = "${fs2}" -a "${mp1}" = "${mp2}" || return 1 |
|
} && |
|
ls -1Ldi "$1" "$2" 2>/dev/null | { |
|
read -r ino1 _ |
|
read -r ino2 _ |
|
test "${ino1}" = "${ino2}" || return 1 |
|
} |
|
} |
|
|
|
is_oneof() ( |
|
x=$1; shift |
|
for y |
|
do |
|
test "${x}" = "${y}" || continue |
|
return 0 |
|
done |
|
return 1 |
|
) |
|
|
|
tolower() { LC_ALL=C tr '[:upper:]' '[:lower:]'; } |
|
|
|
# shellcheck disable=SC2086 |
|
glob_exists() { set -- $1; test -e "$1"; } |
|
|
|
get_dmi_field() { |
|
if is_oneof "${uname_s}" NetBSD |
|
then |
|
case $1 |
|
in |
|
(system-manufacturer) _mib=machdep.dmi.system-vendor ;; |
|
(system-product-name) _mib=machdep.dmi.system-product ;; |
|
(system-version|system-uuid) _mib=machdep.dmi.$1 ;; |
|
(bios-vendor|bios-version) _mib=machdep.dmi.$1 ;; |
|
(biod-release-date) _mib=machdep.dmi.bios-date ;; |
|
(*) _mib= ;; |
|
esac |
|
|
|
test -n "${_mib}" && get_sysctl "${_mib}" | grep -e . && return |
|
fi |
|
|
|
if is_command dmidecode |
|
then |
|
dmidecode -s "$1" |
|
elif test -d "${dmi_sysfs-}" |
|
then |
|
case $1 |
|
in |
|
(system-manufacturer) _filename=sys_vendor ;; |
|
(system-product-name) _filename=product_name ;; |
|
(*) _filename=$(echo "$1" | tr - _) ;; |
|
esac |
|
if test -r "${dmi_sysfs-}/${_filename}" |
|
then |
|
cat "${dmi_sysfs}/${_filename}" |
|
fi |
|
unset _filename |
|
elif test "${uname_s}" = OpenBSD |
|
then |
|
# NOTE: something similar to system-manufacutrer and system-product-name |
|
# is available on OpenBSD in sysctl |
|
case $1 |
|
in |
|
(system-manufacturer) _mib=hw.vendor ;; |
|
(system-product-name) _mib=hw.product ;; |
|
(*) _mib= ;; |
|
esac |
|
|
|
test -n "${_mib}" && get_sysctl "${_mib}" | grep -e . && return |
|
fi |
|
|
|
return 1 |
|
} |
|
|
|
has_cpuinfo() { test -e /proc/cpuinfo; } |
|
|
|
get_sysctl() { |
|
is_command sysctl && sysctl -n "$1" 2>/dev/null |
|
} |
|
|
|
detected_layer() { |
|
test -n "${_toplayer:-}" || echo "${_toplayer:=${1:?}}" |
|
} |
|
|
|
|
|
# Check for chroot |
|
|
|
has_chroot_systemd() { |
|
is_command systemd-detect-virt && systemd-detect-virt --help | grep -q -e '^ -r' |
|
} |
|
|
|
check_chroot_systemd() { |
|
systemd-detect-virt -r |
|
} |
|
|
|
has_chroot_debian_ischroot() { |
|
is_command ischroot |
|
} |
|
|
|
check_chroot_debian_ischroot() { |
|
ischroot --default-false |
|
} |
|
|
|
has_chroot_procfs() { |
|
test -d /proc/ |
|
} |
|
|
|
check_chroot_procfs() { |
|
test -e /proc/1/root && ! files_same /proc/1/root / |
|
} |
|
|
|
# Check for container |
|
|
|
has_ct_systemd() { |
|
is_command systemd-detect-virt && systemd-detect-virt --help | grep -q -e '^ -c' |
|
} |
|
|
|
check_ct_systemd() ( |
|
_ctengine=$(systemd-detect-virt -c 2>/dev/null) && |
|
case ${_ctengine} |
|
in |
|
(''|'none') |
|
return 1 ;; |
|
('container-other') |
|
return 0 ;; |
|
('systemd-nspawn') |
|
echo systemd_nspawn ;; |
|
(*) |
|
echo "${_ctengine}" ;; |
|
esac |
|
) |
|
|
|
has_ct_pid_1() { |
|
test -r /run/systemd/container -o -r /proc/1/environ |
|
} |
|
|
|
translate_container_name() { |
|
case $1 |
|
in |
|
('lxc') |
|
echo lxc ;; |
|
('lxc-libvirt') |
|
echo lxc-libvirt ;; |
|
('podman') |
|
echo podman ;; |
|
('systemd-nspawn') |
|
echo systemd_nspawn ;; |
|
(*) |
|
return 1 ;; |
|
esac |
|
return 0 |
|
} |
|
|
|
check_ct_pid_1() { |
|
if test -r /run/systemd/container |
|
then |
|
translate_container_name "$(head -n1 /run/systemd/container)" \ |
|
&& return 0 |
|
fi |
|
|
|
if test -r /proc/1/environ |
|
then |
|
translate_container_name "$( |
|
LC_ALL=C tr '\000' '\n' </proc/1/environ \ |
|
| sed -n -e 's/^container=//p')" \ |
|
&& return 0 |
|
fi |
|
|
|
return 1 |
|
} |
|
|
|
has_ct_cgroup() { |
|
test -r /proc/self/cgroup |
|
} |
|
|
|
check_ct_cgroup() { |
|
if grep -q -e ':/docker/' /proc/self/cgroup |
|
then |
|
echo docker |
|
elif grep -q -e ':/lxc/.*\.libvirt-lxc$' /proc/self/cgroup |
|
then |
|
echo libvirt-lxc |
|
elif grep -q -F '/libpod-' /proc/self/cgroup |
|
then |
|
echo podman |
|
else |
|
return 1 |
|
fi |
|
} |
|
|
|
check_ct_files() { |
|
if test -e /.dockerenv -o -e /run/.dockerenv -o -e /.dockerinit |
|
then |
|
echo docker |
|
elif test -f /run/.containerenv |
|
then |
|
# https://github.com/containers/podman/issues/3586#issuecomment-661918679 |
|
echo podman |
|
elif test -d /proc/vz -a ! -d /proc/bc -a -f /proc/user_beancounters \ |
|
|| test -d /.cpt_hardlink_dir_*/ |
|
then |
|
# Virtuozzo / OpenVZ |
|
# |
|
# /proc/vz: always exists if OpenVZ kernel is running |
|
# /proc/bc: exists only on node (not inside container) |
|
# /proc/user_beancounters - exists inside container |
|
# |
|
# /.cpt_hardlink_dir_*/ may be (?) created by vzctl: |
|
# https://github.com/kolyshkin/vzctl/commit/09e974f |
|
|
|
echo openvz |
|
elif grep -qie 'Microsoft\|WSL' /proc/sys/kernel/osrelease /proc/version 2>/dev/null |
|
then |
|
# https://github.com/Microsoft/WSL/issues/423#issuecomment-221627364 |
|
echo wsl |
|
elif test -d /var/.cagefs |
|
then |
|
# https://docs.cloudlinux.com/cloudlinux_os_components/#cagefs |
|
# CageFS is not "really" a container, but it isn't a chroot either. |
|
echo cagefs |
|
elif test -e /proc/self/status && grep -q -e '^VxID: [0-9]\{1,\}' /proc/self/status |
|
then |
|
# Linux-VServer |
|
if grep -q -x -F 'VxID: 0' /proc/self/status |
|
then |
|
# host |
|
return 1 |
|
else |
|
# guest |
|
echo linux_vserver |
|
fi |
|
else |
|
return 1 |
|
fi |
|
} |
|
|
|
check_ct_os_specific() ( |
|
if jailed=$(get_sysctl security.jail.jailed) && test "${jailed}" = 1 |
|
then |
|
# FreeBSD jail |
|
echo jail |
|
return 0 |
|
fi |
|
|
|
if is_command zonename && test "$(zonename)" != global |
|
then |
|
# Solaris zone |
|
echo zone |
|
return 0 |
|
fi |
|
|
|
return 1 |
|
) |
|
|
|
|
|
# Check for hypervisor |
|
|
|
guess_hypervisor_from_cpu_model() { |
|
case $1 |
|
in |
|
(*\ KVM\ *) |
|
echo kvm ;; |
|
(*\ QEMU\ *|QEMU\ *) |
|
echo qemu ;; |
|
(*) |
|
return 1 ;; |
|
esac |
|
} |
|
|
|
has_vm_systemd() { |
|
is_command systemd-detect-virt && systemd-detect-virt --help | grep -q -e '^ -v' |
|
} |
|
|
|
check_vm_systemd() ( |
|
_hypervisor=$(systemd-detect-virt -v 2>/dev/null) && |
|
case ${_hypervisor} |
|
in |
|
(''|'none') |
|
return 1 ;; |
|
('amazon') |
|
echo aws ;; |
|
('bochs') |
|
echo kvm ;; |
|
('microsoft') |
|
# assumption |
|
echo hyperv ;; |
|
('oracle') |
|
echo virtualbox ;; |
|
('vm-other') |
|
return 0 ;; |
|
(*) |
|
echo "${_hypervisor}" ;; |
|
esac |
|
) |
|
|
|
has_vm_cpuinfo() { has_cpuinfo; } |
|
|
|
check_vm_cpuinfo() { |
|
if grep -q -F 'User Mode Linux' /proc/cpuinfo \ |
|
|| grep -q -F 'UML' /proc/cpuinfo |
|
then |
|
# User Mode Linux |
|
echo uml |
|
elif grep -q -e '^vendor_id.*: PowerVM Lx86' /proc/cpuinfo |
|
then |
|
# IBM PowerVM Lx86 (Linux/x86 emulator) |
|
echo powervm_lx86 |
|
elif grep -q -e '^vendor_id.*: IBM/S390' /proc/cpuinfo |
|
then |
|
# IBM SystemZ (S/390) |
|
if test -f /proc/sysinfo |
|
then |
|
if grep -q -e '^VM[0-9]* Control Program: KVM/Linux' /proc/sysinfo |
|
then |
|
echo kvm-s390 |
|
return 0 |
|
elif grep -q -e '^VM[0-9]* Control Program: z/VM' /proc/sysinfo |
|
then |
|
echo zvm |
|
return 0 |
|
elif grep -q -e '^LPAR ' /proc/sysinfo |
|
then |
|
echo zvm-lpar |
|
return 0 |
|
fi |
|
fi |
|
return 1 |
|
else |
|
if grep -q -e '^model name.*:' /proc/cpuinfo |
|
then |
|
sed -n -e 's/^model name[^:]*: *//p' /proc/cpuinfo \ |
|
| while read -r _cpu_model |
|
do |
|
guess_hypervisor_from_cpu_model "${_cpu_model}" |
|
done \ |
|
| sort \ |
|
| uniq -c \ |
|
| awk ' |
|
{ if ($1 > most_c) { most_c = $1; most_s = $2 } } |
|
END { |
|
if (most_s) print most_s |
|
exit !most_s |
|
}' \ |
|
&& return 0 |
|
fi |
|
return 1 |
|
fi |
|
} |
|
|
|
check_vm_arch_specific() { |
|
case ${arch} |
|
in |
|
(ppc64|ppc64le) |
|
# Check PPC64 LPAR, KVM |
|
|
|
# example /proc/cpuinfo line indicating 'not baremetal' |
|
# platform : pSeries |
|
# |
|
# example /proc/ppc64/lparcfg systemtype line |
|
# system_type=IBM pSeries (emulated by qemu) |
|
|
|
if has_cpuinfo && grep -q -e 'platform.**pSeries' /proc/cpuinfo |
|
then |
|
if test -e /proc/ppc64/lparcfg |
|
then |
|
# Assume LPAR, now detect shared or dedicated |
|
if grep -q -x -F 'shared_processor_mode=1' /proc/ppc64/lparcfg |
|
then |
|
echo powervm-shared |
|
return 0 |
|
else |
|
echo powervm-dedicated |
|
return 0 |
|
fi |
|
fi |
|
fi |
|
;; |
|
(sparc*) |
|
# Check for SPARC LDoms |
|
|
|
if test -e /dev/mdesc |
|
then |
|
if test -d /sys/class/vlds/ctrl -a -d /sys/class/vlds/sp |
|
then |
|
# control LDom |
|
return 1 |
|
else |
|
# guest LDom |
|
echo ldom-sparc |
|
fi |
|
|
|
# MDPROP=/usr/lib/ldoms/mdprop.py |
|
# if test -x "${MDPROP}" |
|
# then |
|
# if test -n "$("${MDPROP}" -v iodevice device-type=pciex)" |
|
# then |
|
# echo ldoms-root |
|
# echo ldoms-io |
|
# elif test -n "$("${MDPROP}" -v iov-device vf-id=0)" |
|
# then |
|
# echo ldoms-io |
|
# fi |
|
# fi |
|
return 0 |
|
fi |
|
;; |
|
(i?86|x86*|amd64|i86pc) |
|
# VMM CPUID flag denotes that this system is running under a VMM |
|
if is_oneof "${uname_s}" Darwin |
|
then |
|
get_sysctl machdep.cpu.features | tr ' ' '\n' | grep -qixF VMM \ |
|
&& return 0 |
|
fi |
|
if has_cpuinfo \ |
|
&& grep -q -i -e '^flags.*:.*\(hypervisor\|vmm\)' /proc/cpuinfo |
|
then |
|
return 0 |
|
fi |
|
;; |
|
(ia64) |
|
if test -d /sys/bus/xen -a ! -d /sys/bus/xen-backend |
|
then |
|
# PV-on-HVM drivers installed in a Xen guest |
|
echo xen-hvm |
|
return 0 |
|
fi |
|
;; |
|
esac |
|
return 1 |
|
} |
|
|
|
has_vm_dmi() { |
|
# Check for various products in SMBIOS/DMI. |
|
# Note that DMI doesn't exist on all architectures (only x86 and some ARM). |
|
# On other architectures the $dmi variable will be empty. |
|
|
|
if test -d /sys/class/dmi/id/ |
|
then |
|
dmi_sysfs=/sys/class/dmi/id |
|
elif test -d /sys/devices/virtual/dmi/id/ |
|
then |
|
dmi_sysfs=/sys/devices/virtual/dmi/id |
|
fi |
|
|
|
# shellcheck disable=SC2015 |
|
{ |
|
is_command dmidecode \ |
|
&& ( |
|
# dmidecode needs to exit 0 and not print the No SMBIOS/DMI line |
|
dmi_out=$(dmidecode 2>&1) \ |
|
&& ! printf '%s\n' "${dmi_out}" \ |
|
| grep -qF 'No SMBIOS nor DMI entry point found, sorry.' |
|
) \ |
|
|| test -d "${dmi_sysfs}" |
|
} |
|
} |
|
|
|
check_vm_dmi() { |
|
case $(get_dmi_field system-product-name) |
|
in |
|
(*.metal) |
|
if test "$(get_dmi_field system-manufacturer)" = 'Amazon EC2' |
|
then |
|
# AWS EC2 bare metal -> no virtualisation |
|
return 1 |
|
fi |
|
;; |
|
('BHYVE') |
|
echo bhyve |
|
return 0 |
|
;; |
|
('Google Compute Engine') |
|
echo gce |
|
return 0 |
|
;; |
|
('RHEV Hypervisor') |
|
# Red Hat Enterprise Virtualization |
|
echo rhev |
|
return 0 |
|
;; |
|
('KVM'|'Bochs'|'KVM Virtual Machine') |
|
echo kvm |
|
return 0 |
|
;; |
|
('Parallels Virtual Platform') |
|
echo parallels |
|
return 0 |
|
;; |
|
('VirtualBox') |
|
echo virtualbox |
|
return 0 |
|
;; |
|
('VMware Virtual Platform') |
|
echo vmware |
|
return 0 |
|
;; |
|
esac |
|
|
|
case $(get_dmi_field system-manufacturer) |
|
in |
|
('Alibaba'*) |
|
case $(get_dmi_field system-product-name) |
|
in |
|
('Alibaba Cloud ECS') |
|
echo alibaba-ecs |
|
;; |
|
(*) |
|
echo alibaba |
|
;; |
|
esac |
|
return 0 |
|
;; |
|
('Amazon EC2') |
|
# AWS on bare-metal or KVM |
|
echo aws-ec2 |
|
return 0 |
|
;; |
|
('innotek GmbH'|'Oracle Corporation') |
|
echo virtualbox |
|
return 0 |
|
;; |
|
('Joyent') |
|
if test "$(get_dmi_field system-product-name)" = 'SmartDC HVM' |
|
then |
|
# SmartOS KVM |
|
echo kvm-smartdc_hvm |
|
return 0 |
|
fi |
|
;; |
|
('Microsoft Corporation'*) |
|
if test "$(get_dmi_field system-product-name)" = 'Virtual Machine' |
|
then |
|
if test -e /proc/irq/7/hyperv \ |
|
|| expr "$(get_dmi_field bios-version)" : 'VRTUAL.*' >/dev/null |
|
then |
|
echo hyperv |
|
return 0 |
|
fi |
|
|
|
case $(get_dmi_field system-version) |
|
in |
|
(VPC[0-9]*|VS2005*|*[Vv]irtual*[Pp][Cc]*) |
|
echo virtualpc |
|
return 0 |
|
;; |
|
(*) |
|
echo hyperv |
|
return 0 |
|
;; |
|
esac |
|
fi |
|
;; |
|
('Nutanix') |
|
# Nutanix AHV. Similar to KVM. |
|
if test "$(get_dmi_field system-product-name)" = 'AHV' |
|
then |
|
echo nutanix_ahv |
|
return 0 |
|
fi |
|
;; |
|
('oVirt') |
|
echo ovirt |
|
return 0 |
|
;; |
|
('Parallels Software International Inc.') |
|
echo parallels |
|
return 0 |
|
;; |
|
('QEMU') |
|
echo qemu |
|
return 0 |
|
;; |
|
('VMware, Inc.') |
|
echo vmware |
|
return 0 |
|
;; |
|
esac |
|
|
|
case $(get_dmi_field bios-vendor) |
|
in |
|
('Amazon EC2') |
|
# AWS on bare-metal or KVM |
|
echo aws-ec2 |
|
return 0 |
|
;; |
|
('BHYVE') |
|
echo bhyve |
|
return 0 |
|
;; |
|
('innotek GmbH') |
|
echo virtualbox |
|
return 0 |
|
;; |
|
('Parallels Software International Inc.') |
|
echo parallels |
|
return 0 |
|
;; |
|
('Xen') |
|
if get_dmi_field bios-version | grep -q -e '\([0-9]\{1,\}\.\)\{2\}amazon' |
|
then |
|
# AWS on Xen |
|
echo aws-xen |
|
return 0 |
|
fi |
|
;; |
|
esac |
|
|
|
return 1 |
|
} |
|
|
|
check_vm_hyp_specific() { |
|
if is_command vmware-checkvm && vmware-checkvm >/dev/null |
|
then |
|
# vmware-checkvm is provided by VMware's open-vm-tools |
|
echo vmware |
|
return 0 |
|
elif test -d /proc/xen |
|
then |
|
test -r /proc/xen/capabilities && |
|
if grep -q -F 'control_d' /proc/xen/capabilities 2>/dev/null |
|
then |
|
# Xen dom0 |
|
return 1 |
|
else |
|
# Xen domU |
|
echo xen |
|
return 0 |
|
fi |
|
fi |
|
return 1 |
|
} |
|
|
|
has_vm_dt() { |
|
# OpenFirmware/Das U-Boot device-tree |
|
test -d /proc/device-tree |
|
} |
|
|
|
check_vm_dt() { |
|
case ${arch} |
|
in |
|
(arm|aarch64) |
|
if test -r /proc/device-tree/hypervisor/compatible |
|
then |
|
if grep -q -F 'xen' /proc/device-tree/hypervisor/compatible |
|
then |
|
echo xen |
|
return 0 |
|
elif grep -q -F 'vmware' /proc/device-tree/hypervisor/compatible |
|
then |
|
# e.g. VMware ESXi on ARM |
|
echo vmware |
|
return 0 |
|
fi |
|
fi |
|
if glob_exists /proc/device-tree/fw-cfg@*/compatible |
|
then |
|
# qemu,fw-cfg-mmio |
|
sed -e 's/,.*$//' /proc/device-tree/fw-cfg@*/compatible | head -n1 |
|
return 0 |
|
fi |
|
if grep -q -F 'dummy-virt' /proc/device-tree/compatible |
|
then |
|
echo lkvm |
|
return 0 |
|
fi |
|
;; |
|
(ppc64*) |
|
if test -d /proc/device-tree/hypervisor \ |
|
&& grep -qF 'linux,kvm' /proc/device-tree/hypervisor/compatible |
|
then |
|
# We are running as a spapr KVM guest on ppc64 |
|
echo kvm-spapr |
|
return 0 |
|
fi |
|
if test -r /proc/device-tree/ibm,partition-name \ |
|
&& test -r /proc/device-tree/hmc-managed\? \ |
|
&& test -r /proc/device-tree/chosen/qemu,graphic-width |
|
then |
|
echo powervm |
|
fi |
|
;; |
|
esac |
|
return 1 |
|
} |
|
|
|
has_vm_sys_hypervisor() { |
|
test -d /sys/hypervisor/ |
|
} |
|
|
|
check_vm_sys_hypervisor() { |
|
test -r /sys/hypervisor/type && |
|
case $(head -n1 /sys/hypervisor/type) |
|
in |
|
(xen) |
|
# Ordinary kernel with pv_ops. There does not seem to be |
|
# enough information at present to tell whether this is dom0 |
|
# or domU. |
|
echo xen |
|
return 0 |
|
;; |
|
esac |
|
return 1 |
|
} |
|
|
|
check_vm_os_specific() { |
|
_hyp_generic=false |
|
|
|
case ${uname_s} |
|
in |
|
(Darwin) |
|
if hv_vmm_present=$(get_sysctl kern.hv_vmm_present) \ |
|
&& test "${hv_vmm_present}" -ne 0 |
|
then |
|
_hyp_generic=true |
|
fi |
|
;; |
|
(FreeBSD) |
|
# FreeBSD does not have /proc/cpuinfo even when procfs is used. |
|
# Instead there is a sysctl kern.vm_guest. |
|
# Which is 'none' if physical, else the virtualisation. |
|
vm_guest=$(get_sysctl kern.vm_guest | tolower) && |
|
case ${vm_guest} |
|
in |
|
(none) ;; |
|
(generic) _hyp_generic=true ;; |
|
(*) |
|
# kernel could detect hypervisor |
|
case ${vm_guest} |
|
in |
|
(hv) echo hyperv ;; |
|
(vbox) echo virtualbox ;; |
|
(*) echo "${vm_guest}" ;; |
|
esac |
|
return 0 |
|
;; |
|
esac |
|
;; |
|
(NetBSD) |
|
machdep_hv=$(get_sysctl machdep.hypervisor | tolower) && |
|
case ${machdep_hv} |
|
in |
|
(none) ;; |
|
(generic) _hyp_generic=true ;; |
|
(*) |
|
# kernel could detect hypervisor |
|
case ${machdep_hv} |
|
in |
|
(hyper-v) echo hyperv ;; |
|
(xenhvm*) echo xen-hvm ;; |
|
(xenpv*) echo xen-pv ;; |
|
(xen*) echo xen ;; |
|
(*) echo "${machdep_hv}" ;; |
|
esac |
|
return 0 |
|
;; |
|
esac |
|
;; |
|
(OpenBSD) |
|
if is_command hostctl && glob_exists /dev/pvbus[0-9]* |
|
then |
|
for _pvbus in /dev/pvbus[0-9]* |
|
do |
|
_h_out=$(hostctl -f "${_pvbus}" -t 2>/dev/null) || continue |
|
case $(expr "${_h_out}" : '[^:]*: *\(.*\)$') |
|
in |
|
(KVM) echo kvm ;; |
|
(Hyper-V) echo hyperv ;; |
|
(VMware) echo vmware ;; |
|
(Xen) echo xen ;; |
|
(bhyve) echo bhyve ;; |
|
(OpenBSD) echo openbsd_vmm ;; |
|
esac |
|
return 0 |
|
done |
|
fi |
|
;; |
|
(SunOS) |
|
diag_conf=$(prtdiag | sed -n -e 's/.*Configuration: *//p' -e '/^$/q') |
|
# NOTE: Don't use -e or -F in Solaris grep |
|
if printf '%s\n' "${diag_conf}" | grep -q -i QEMU |
|
then |
|
echo qemu |
|
return 0 |
|
elif printf '%s\n' "${diag_conf}" | grep -q -i VMware |
|
then |
|
echo vmware |
|
return 0 |
|
fi |
|
;; |
|
(Linux) |
|
if is_command dmesg |
|
then |
|
while read -r line |
|
do |
|
case ${line} |
|
in |
|
('Booting paravirtualized kernel on ') |
|
case $(expr "${line}" : '.* kernel on \(.*\)') |
|
in |
|
('Xen') |
|
echo xen-pv; return 0 ;; |
|
('bare hardware') |
|
return 1 ;; |
|
esac |
|
;; |
|
('Hypervisor detected') |
|
case $(expr "${line}" : '.*: *\(.*\)') |
|
in |
|
('ACRN') |
|
echo acrn ;; |
|
('Jailhouse') |
|
echo jailhouse ;; |
|
('KVM') |
|
echo kvm ;; |
|
('Microsoft Hyper-V') |
|
echo hyperv ;; |
|
('VMware') |
|
echo vmware ;; |
|
('Xen HVM') |
|
echo xen-hvm ;; |
|
('Xen PV') |
|
echo xen-pv ;; |
|
esac |
|
return 0 |
|
;; |
|
(lpar:*' under hypervisor') |
|
return 0 ;; |
|
esac |
|
done <<-EOF |
|
$(dmesg 2>/dev/null | awk ' |
|
/Booting paravirtualized kernel on / |
|
/Hypervisor detected: / |
|
/lpar: .* under hypervisor/ |
|
') |
|
EOF |
|
fi |
|
esac |
|
|
|
# Try to guess hypervisor based on CPU model (sysctl hw.model if available) |
|
if cpu_model=$(get_sysctl hw.model) |
|
then |
|
guess_hypervisor_from_cpu_model "${cpu_model}" && return 0 |
|
fi |
|
|
|
if ${_hyp_generic} |
|
then |
|
# cannot say which hypervisor, but one was detected |
|
return 0 |
|
else |
|
return 1 |
|
fi |
|
} |
|
|
|
run_stage() { |
|
if type "has_$1_$2" >/dev/null 2>&1 |
|
then |
|
"has_$1_$2" |
|
else |
|
true |
|
fi \ |
|
&& "check_$1_$2" |
|
} |
|
|
|
|
|
# Execute chroot stages |
|
|
|
for stage in \ |
|
procfs debian_ischroot systemd |
|
do |
|
run_stage chroot ${stage} || continue |
|
detected_layer 'chroot' |
|
echo chroot |
|
break |
|
done |
|
|
|
|
|
# Execute container stages |
|
|
|
for stage in \ |
|
systemd pid_1 cgroup files os_specific |
|
do |
|
ctengine=$(run_stage ct ${stage}) || continue |
|
detected_layer 'container' |
|
is_contained=true |
|
if test -n "${ctengine}" |
|
then |
|
echo container on "${ctengine}" |
|
break |
|
fi |
|
done |
|
if ${is_contained:-false} && test -z "${ctengine}" |
|
then |
|
# none of the stages could determine the specific container engine, but |
|
# we are running in some container. |
|
echo container |
|
fi |
|
|
|
|
|
# Execute virtual machine / hypervisor stages |
|
|
|
for stage in \ |
|
systemd os_specific hyp_specific sys_hypervisor dt dmi cpuinfo arch_specific |
|
do |
|
hypervisor=$(run_stage vm ${stage}) || continue |
|
detected_layer 'virtual machine' |
|
is_virtual=true |
|
if test -n "${hypervisor}" |
|
then |
|
echo virtual by "${hypervisor}" |
|
break |
|
fi |
|
done |
|
if ${is_virtual:-false} && test -z "${hypervisor}" |
|
then |
|
# none of the stages could determine the specific hypervisor, but |
|
# we are virtual. |
|
echo virtual |
|
fi |
|
|
|
|
|
# Fallback |
|
|
|
detected_layer physical
|
|
|