#!/usr/bin/perl -w

# imvirt - I'm virtualized?
#
# $Id: imvirt 11 2008-11-25 12:13:13Z liske $
#
# Authors:
#   Thomas Liske <liske@ibh.de>
#
# Copyright Holder:
#   2008 (C) IBH IT-Service GmbH [http://www.ibh.de/]
#
# License:
#   This program 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 2 of the License, or
#   (at your option) any later version.
#
#   This program 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 this package; if not, write to the Free Software
#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
#

##
#
# Outputs:
#   Xen
#   VirtualBox
#   Virtual Machine
#   VMware
#   QEMU
#
# If no virtualization has been detected:
#   Physical
#
##

use strict;

my $dmidecode = '/usr/sbin/dmidecode';
my $cmd = '$dmidecode -t system';

my $dmesg = '/bin/dmesg | head -n 750';

# paravirtualized Xen - very simple ;)
if(-d '/proc/xen') {
    print "Xen\n";
    exit 0;
}

# dmidecode needs root to work :(
if (-r '/dev/mem' && -x $dmidecode) {
    my $sysprod = `$dmidecode -s system-product-name`;
    if ($sysprod =~ /^VMware/) {
	print "VMware\n";
	exit 0;
    }

    if ($sysprod =~ /^Virtual Machine/) {
	print "Virtual Machine\n";
	exit 0;
    }

    my $biosvend = `$dmidecode -s bios-vendor`;
    if ($biosvend =~ /^QEMU/) {
	print "QEMU\n";
	exit 0;
    }

    # virtualized Xen
    if ($biosvend =~ /^Xen/) {
	print "Xen\n";
	exit 0;
    }
}

# Let's parse some logs & /proc files for well known strings
my %msgmap = (
    'VMware vmxnet virtual NIC driver' => 'VMware',
    'Vendor: VMware\s+Model: Virtual disk' => 'VMware',
    'Vendor: VMware,\s+Model: VMware Virtual ' => 'VMware',
    ': VMware Virtual IDE CDROM Drive' => 'VMware',

    ' QEMUAPIC ' => 'QEMU',
    'QEMU Virtual CPU' => 'QEMU',
    ': QEMU HARDDISK,' => 'QEMU',
    ': QEMU CD-ROM,' => 'QEMU',

    ': Virtual HD,' => 'Virtual Machine',
    ': Virtual CD,' => 'Virtual Machine',

    ' VBOXBIOS ' => 'VirtualBox',
    ': VBOX HARDDISK,' => 'VirtualBox',
    ': VBOX CD-ROM,' => 'VirtualBox',

    'Xen virtual console successfully installed' => 'Xen',
    'Xen reported:' => 'Xen',
    'Xen: 0000000000000000 - 0000000020000000' => 'Xen',
    'xen-vbd: registered block device' => 'Xen',
    'ACPI: RSDP \(v\d+\s+Xen ' => 'Xen',
    'ACPI: XSDT \(v\d+\s+Xen ' => 'Xen',
    'ACPI: FADT \(v\d+\s+Xen ' => 'Xen',
    'ACPI: MADT \(v\d+\s+Xen ' => 'Xen',
    'ACPI: HPET \(v\d+\s+Xen ' => 'Xen',
    'ACPI: SSDT \(v\d+\s+Xen ' => 'Xen',
    'ACPI: DSDT \(v\d+\s+Xen ' => 'Xen',
);

if (open(HDMSG, '/var/log/dmesg')) {
    while(<HDMSG>) {
	foreach my $str (keys %msgmap) {
	    if (/$str/) {
		print "$msgmap{$str}\n";
		exit 0;
	    }
	}
    }
    close(HDMSG);
}

# Read kernel ringbuffer directly
if (open(HDMSG, '$dmesg |')) {
    while(<HDMSG>) {
	foreach my $str (keys %msgmap) {
	    if (/$str/) {
		print "$msgmap{$str}\n";
		exit 0;
	    }
	}
    }
    close(HDMSG);
}

if (open(HSCSI, '/proc/scsi/scsi')) {
    while(<HSCSI>) {
	foreach my $str (keys %msgmap) {
	    if (/$str/) {
		print "$msgmap{$str}\n";
		exit 0;
	    }
	}
    }
    close(HSCSI);
}

print "Physical\n";
exit 0;
