#!/usr/bin/env bash
# Inventory System
# Author: Carsten Schoene
# $LastChangedDate$
# $Rev$
#
# Default options (can be changed by inventory-system.conf)
DEBUG="yes"
TARGETURL="http://localhost/isdf.php"
ADMINMAIL="root@localhost"
#################################################################
# read optional configuration file
[ -f /etc/inventory-system.conf ] && . /etc/inventory-system.conf
#################################################################
REQUIRED_COMMANDS="
awk
cat
id
sed
grep
find
sort
tail
head
expr
ifconfig
ethtool
dmidecode
lshw
uname
curl
uuidgen
virt-what
hostname
ip
ls
df
date
modprobe
ipmitool
getopt
readlink
fdisk
dmsetup
free
strings
"

PKGMGR_COMMANDS="
rpm
dpkg
dpkg-query
apt
yum
zypper
"

# clean old logfile
rm -f /tmp/inventory-system.log

# mail alerts / debug messages
function mailalerts {
        if [ -s /tmp/inventory-system.log ] ; then
		if [ "${ADMINMAIL}" != "" ] ; then
			mail -s "Inventory System log from `hostname -f`" ${ADMINMAIL} < /tmp/inventory-system.log
		fi
	fi
}

# print debug messages to STDERR
function debug {
        if [ "${DEBUG}" == "yes" ] ; then
                echo "DEBUG: $@" >&2
		echo "DEBUG: $@" >> /tmp/inventory-system.log
        fi
}

# check required commands
for CMD in ${REQUIRED_COMMANDS} ; do
        CMDNAME=`echo ${CMD} | awk '{print toupper($1) }' | sed -e s@"-"@""@g`
        export $(eval "echo ${CMDNAME}")=`which ${CMD} 2>/dev/null`
        if [ -z "${!CMDNAME}" ] ; then
                debug "Command: ${CMD} not found!"
                exit 1
        else
                debug "Found command $(echo $CMDNAME) in ${!CMDNAME}"
        fi
done

# check for package manager commands
for CMD in ${PKGMGR_COMMANDS} ; do
	CMDNAME=`echo ${CMD} | awk '{print toupper($1) }' | sed -e s@"-"@""@g`
	export $(eval "echo ${CMDNAME}")=`which ${CMD} 2>/dev/null`
	if [ -z "${!CMDNAME}" ] ; then
		debug "Command: ${CMD} not found, skipped!"
		# no exit here because not all commands are available on every os
	else
		debug "Found command $(echo $CMDNAME) in ${!CMDNAME}"
	fi
done

# check if we are running as root
MYUID=`${ID} -u`
if [ "${MYUID}" != "0" ] ; then
	echo "Please start as user 'root'"
	exit 1
fi

# script usage
function usage {
	echo "Usage: $0 [--help|--uuid|--all-disks|--disks|--systemtype|--serial|--ecode|--cpu|--mem|--product|--arch|--os|--kernel|--mgmtmac|--mgmtip|--update|--bios|--bmc]"
	echo -e "\t--help\t\tShows this help"
	echo -e "\t--uuid\t\tUUID of this system"
	echo -e "\t--disk\t\tRoot disk size of this system"
	echo -e "\t--all-disks\tAll disk devices with size"
	echo -e "\t--systemtype\tSystem image type"
	echo -e "\t--serial\tSystem serial number (Service Tag)"
	echo -e "\t--ecode\tDELL Express Service Code"
	echo -e "\t--cpu\t\tCPU type"
	echo -e "\t--mem\t\tAmount of memory installed in MB"
	echo -e "\t--product\tSystem model"
	echo -e "\t--arch\t\tSystem architecture"
	echo -e "\t--os\t\tOS version installed"
	echo -e "\t--kernel\tRunning kernel version"
	echo -e "\t--mgmtmac\tIPMI management MAC address"
	echo -e "\t--mgmtip\tIPMI management IP address"
	echo -e "\t--update\trun update of this script"
	echo -e "\t--bios\tCurrent BIOS version"
	echo -e "\t--bmc\tCurrent BMC firmware version"
	exit
}

RUN_FUNCTIONS=""
args=`${GETOPT} -a -o h -l help,uuid,disk,all-disks,systemtype,serial,ecode,cpu,mem,product,arch,os,kernel,mgmtmac,mgmtip,update,bios,bmc -- "$@"`
if [ $? != 0 ] ; then
        usage
fi

eval set -- "$args"
for opt ; do
	case "$opt" in
		-h|--help)
			usage
		;;
		-u|--uuid)
			RUN_FUNCTIONS="${RUN_FUNCTIONS} get_system_uuid"
			shift
		;;
		-d|--disk)
			RUN_FUNCTIONS="${RUN_FUNCTIONS} get_system_disk_size_bootdev"
			shift
		;;
		--all-disks)
			RUN_FUNCTIONS="${RUN_FUNCTIONS} get_system_disk_sizes"
			shift
		;;
		-t|--systemtype)
			RUN_FUNCTIONS="${RUN_FUNCTIONS} get_system_type"
			shift
		;;
		-s|--serial)
			RUN_FUNCTIONS="${RUN_FUNCTIONS} get_system_serial"
			shift
		;;
		-e|--ecode)
			RUN_FUNCTIONS="${RUN_FUNCTIONS} get_system_dell_express_service_code"
			shift
		;;
		-c|--cpu)
			RUN_FUNCTIONS="${RUN_FUNCTIONS} get_system_cpu"
			shift
		;;
		-m|--mem)
			RUN_FUNCTIONS="${RUN_FUNCTIONS} get_system_memory"
			shift
		;;
		-p|--product)
			RUN_FUNCTIONS="${RUN_FUNCTIONS} get_system_productname"
			shift
		;;
		-a|--arch)
			RUN_FUNCTIONS="${RUN_FUNCTIONS} get_system_arch"
			shift
		;;
		-o|--os)
			RUN_FUNCTIONS="${RUN_FUNCTIONS} get_system_os"
			shift
		;;
		-k|--kernel)
			RUN_FUNCTIONS="${RUN_FUNCTIONS} get_system_kernelversion"
			shift
		;;
		-g|--mgmtmac)
			RUN_FUNCTIONS="${RUN_FUNCTIONS} get_system_mgmt_mac"
			shift
		;;
		-i|--mgmtip)
			RUN_FUNCTIONS="${RUN_FUNCTIONS} get_system_mgmt_ip"
			shift
		;;
		-u|--update)
			RUN_FUNCTIONS="${RUN_FUNCTIONS} autoupdate"
			shift
		;;
		-b|--bios)
			RUN_FUNCTIONS="${RUN_FUNCTIONS} get_system_biosversion"
			shift
		;;
		-B|--bmc)
			RUN_FUNCTIONS="${RUN_FUNCTIONS} get_system_mgmt_firmware"
			shift
		;;
		--)
			shift
			break
		;;
	esac
done

# function to check if called function is in DISABLE_FUNCTIONS
function is_disabled {
	FUNC_TO_CHECK=$1
	RETVAL=0
	for FUNC in ${DISABLE_FUNCTIONS} ; do
		if [ "${FUNC}" == "${FUNC_TO_CHECK}" ] ; then
			RETVAL=1
		fi
	done
	echo ${RETVAL}
}

# autoupdate function
function autoupdate {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	case `get_system_os` in
		Debian*|Ubuntu*|Raspbian*)
			PKG=`${DPKG} -S $0 | ${GREP} -v ^dpkg | ${AWK} -F: '{print $1}'`
			if [ -n "${PKG}" ] ; then
				if [ -n "${APT}" ] ; then
					${APT} -q -y update >/dev/null 2>&1
					${APT} -q -y install ${PKG} >/dev/null 2>&1
				fi
			fi
		;;
		*)
		        PKG=`${RPM} -qf --queryformat '%{name}\n' $0 | ${GREP} -v "^file /"`
		        if [ -n "${PKG}" ] ; then
                		if [ -n "${YUM}" ] && [ -f /etc/redhat-release ] ; then
		                        CUPD="`${YUM} check-update ${PK} | ${TAIL} -n1 | ${AWK} '{print $1}'`"
                		        if [ -n "${CUPD}" ] ; then
		                                ${YUM} -q -y update ${PKG}
                		        fi
		                elif [ -n "${ZYPPER}" ] && [ -f /etc/SuSE-release ] ; then
					LSB_RELEASE=$(which lsb_release 2>/dev/null)
					if [ -z "${LSB_RELEASE}" ]; then
						if [ -s /etc/os-release ] ; then
							. /etc/os-release
							REL=${VERSION_ID}
						fi
					else	
						REL=`${LSB_RELEASE} -r | ${AWK} '{print $NF}'`
					fi
					case ${REL} in
						11|11.1|11.2|11.3|11.4|12.1|12.2|12.3|13.1|13.2|42.1|42.2|42.3|15.0|15.1|15.2|15.3|15.4|15.5)
	        	        	        	CUPD="`${ZYPPER} -q lu | ${GREP} ${PKG}`"
	        	        	        	if [ -n "${CUPD}" ] ; then
			                                	${ZYPPER} -q -n update ${PKG}
		        		                fi
						;;
						10)
							CUPD="`${ZYPPER} -t lu -t package | ${GREP} ${PKG}`"
							if [ -n "${CUPD}" ] ; then
								${ZYPPER} -t -n install -y -t package ${PKG}
							fi
						;;
					esac
                		fi
		        fi
		;;
	esac
}

# get product name
function get_system_productname {
        [ "`is_disabled $FUNCNAME`" == "1" ] && return
        case `get_system_type` in
                xen-dom0|baremetal|kvm|vmware|lxc)
                        PRODNAME=`${DMIDECODE} -s system-product-name`
			if [ -z "${PRODNAME}" ] && [ -e /sys/firmware/devicetree/base/model ] ; then
				PRODNAME=$(${STRINGS} /sys/firmware/devicetree/base/model)
			fi
                ;;
                *)
                        PRODNAME="n/a"
                ;;
        esac
        debug "SYSTEM-PRODUCTNAME: ${PRODNAME}"
        echo ${PRODNAME}
}

# get unique system uuid
function get_system_uuid {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	# newer systems have uuid integrated
	
	# workaround for DELL CloudEdge Servers with duplicate UUIDs
	case `get_system_productname` in
		"PowerEdge C61*"|C61*)
			UUID=""
		;;
		*)
			UUID=`${LSHW} -quiet -C system | ${GREP} "configuration:" | ${GREP} -i uuid | ${SED} -e 's@.*[ \s]uuid=@@i' | ${AWK} '{print toupper($1)}'`
		;;
	esac

	# for older systems or virtual create one and save it for later use
	if [ "${UUID}" == "" ] ; then
		if [ ! -s /etc/system-inventory.uuid ] ; then
			UUID=`${UUIDGEN} -t | ${AWK} '{print toupper($1)}'`
			echo ${UUID} > /etc/system-inventory.uuid
		else
			UUID=`${CAT} /etc/system-inventory.uuid`
		fi
	fi
	echo ${UUID}
}

# get list of MAC addresses from lshw
function get_system_macs {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	${LSHW} -quiet -C network | ${GREP} serial: | ${AWK} '{print tolower($NF)}' | ${SORT} -u | \
	${GREP} -i -E '([0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2})'
}

# get interface name from MAC address
function get_iface_name_from_mac {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	MAC=${1}
	debug ${MAC}
	if [ -d /sys/class/net ] ; then
		${FIND} -L /sys/class/net -maxdepth 2 -name address -exec ${GREP} -iH ${MAC} {} \; 2>/dev/null | ${AWK} -F/ '{print $5}' | ${HEAD} -n1
	else
		${IFCONFIG} -a | ${GREP} -i ${MAC} | ${AWK} '{print $1}' | ${HEAD} -n1
	fi
}

# get link state for interface from ethtool
function get_iface_link_state {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	IFACE=${1}
	debug ${IFACE}
	${ETHTOOL} ${IFACE} | ${GREP} -i "Link detected:" | ${AWK} '{print tolower($NF)}'
}

# get system type
function get_system_type {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	RETVAL=`${VIRTWHAT}`
	if [ $? == 0 ] ; then
		TYPE=`${VIRTWHAT} | ${TAIL} -n1`
		if [ "${TYPE}" == "" ] ; then
			TYPE="baremetal"
		elif [ "${TYPE}" == "xen-hvm" ] ; then
			if [ -f /proc/xen/privcmd ] ; then
				TYPE="xen-dom0"
			fi
		fi
		debug "SYSTEM-TYPE: ${TYPE}"
		echo ${TYPE}
	else
		debug "VIRT-WHAT ERROR: ${RETVAL}"
	fi
}

# read serialnumber / service tag with dmidecode
function get_system_serial {
        [ "`is_disabled $FUNCNAME`" == "1" ] && return
        case `get_system_type` in
                xen-dom0|baremetal|kvm|vmware|lxc)
                        SYSSERIAL=`${DMIDECODE} -s system-serial-number`
                ;;
		*)
			SYSSERIAL="n/a"
		;;
        esac
	debug "SYSTEM-SERIAL: ${SYSSERIAL}"
	echo ${SYSSERIAL}
}

# get system cpu type
function get_system_cpu {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	case `get_system_arch` in
		aarch*|armv7*|armv6*)
			CPU=`${GREP} -E '(^model name|^Processor)' /proc/cpuinfo | ${SORT} -u | ${AWK} -F": " '{print $2}'`
		;;
		*)
			CPU=`${LSHW} -quiet -C processor | ${GREP} "product:" | ${SORT} -u | ${AWK} -F"product: " '{ print $NF}' | ${HEAD} -n1 | ${SED} -e 's@\s\+@ @g'`
			if [ -n "`echo ${CPU} | ${GREP} -i -E '(O.E.M.|OEM|^Xeon$|^Emulex)'`" ] ; then
				CPU=`${LSHW} -quiet -C processor | ${GREP} "version:" | ${SORT} -u | ${AWK} -F"version: " '{ print $NF}' | ${GREP} -v  -E '(^[0-9])' | ${HEAD} -n1 | ${SED} -e 's@\s\+@ @g'`
			fi
		;;
	esac
	debug "SYSTEM-CPU: ${CPU}"
	echo ${CPU}
}

# get system memory in MB
function get_system_memory {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	INSTMEM=0
	case `get_system_arch` in
		aarch*|armv7*|armv6*)
			INSTMEM=`${FREE} -m | ${GREP} ^Mem: | ${AWK} '{print $2}'`
		;;
		*)
		case `get_system_type` in
			xen|xen-domU|openvz|lxc)
				INSTMEM=`${CAT} /proc/meminfo | ${GREP} "^MemTotal:" | ${AWK} '{print int($2/1024)}'`
			;;
			*)
			for MODULE in `${DMIDECODE} -t memory | ${GREP} -E '\<Size:.*[MG]B$' | ${GREP} -iv -E '(No Module Installed|Maximum)' | ${AWK} '{print $(NF-1)}'`
			do
				# if the module size is given in GB, multiply with 1024, 128GB is the maximum size per module which is currently (2017) available
				if [ ${MODULE} -le 128 ] ; then
					MODULE=`${EXPR} ${MODULE} \* 1024`
				fi
				INSTMEM=`${EXPR} ${INSTMEM} + ${MODULE}`
			done
		
			;;
		esac
		;;
	esac
	debug "SYSTEM-MEMORY: ${INSTMEM}"
	echo ${INSTMEM}
}

# get the disk size of boot device
function get_system_disk_size_bootdev {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	case `get_system_type` in
		openvz)
			SIZE=`LANG=C ${DF} / | ${GREP} -v ^Filesystem| ${AWK} '{print $2 / 1024}'`
			debug "SYSTEM-ROOTDEV-SIZE: ${SIZE}"
			echo ${SIZE}
		;;
		kvm)
			ROOTDEV=`${READLINK} -f /dev/root`
			if [ -z "${ROOTDEV}" ] || [ ! -e "${ROOTDEV}" ] ; then
				if [ -d /dev/disk/by-uuid/ ] ; then
					UUID=`${GREP} -E '(^UUID=.*\s/\s.*)' /etc/fstab | ${SED} -r 's@^UUID=(.*)\s/\s.*@\1@'`
					ROOTDEV=`${READLINK} -e $(${LS} -1A /dev/disk/by-uuid/${UUID})`
				else
					ROOTDEV=`${GREP} -E '(^/dev/.*\s/\s.*)' /etc/fstab | ${SED} -r 's@^(/dev/x?[hsv]d[a-z].*)\s/\s.*@\1@'`
				fi
			fi
			if [ "${ROOTDEV}" == "/dev/root" ] ; then
				# on kvm /dev/root is not always a symlink - ugly hack
				MAJOR=`${DMSETUP} deps /dev/root | ${AWK} -F": " '{print $2}' | ${AWK}  -F, '{print $1}' | ${SED} -e 's@(@@'`
				DEV=`${LS} -al /dev/ | ${GREP} -E '(disk\s*${MAJOR},\s*0)' | ${AWK} '{print $NF}' | ${HEAD} -n1`
				if [ -b /dev/${DEV} ] ; then
					RD=/dev/${DEV}
				else
					# fallback to partition
					RD=/dev/root
				fi
			else
				RD=`echo ${ROOTDEV} | ${SED} -r 's@(/dev/x?[hsv]d[a-z]).*@\1@'`
			fi
			SECCHECK=`LANG=C ${FDISK} -l ${RD} 2>/dev/null | ${GREP} "^Disk /" | ${GREP} sectors$`
			if [ -z "${SECCHECK}" ] ; then
				# / 1000 nicht / 1024 bei physikalischen Festplatten
        	                SIZE=`LANG=C ${FDISK} -l ${RD} 2>/dev/null | ${GREP} "^Disk /" | ${AWK} '{ print int($(NF-1)/1000/1000) }'`
			else
				SIZE=`LANG=C ${FDISK} -l ${RD} 2>/dev/null | ${GREP} "^Disk /" | ${AWK} '{ print int($(NF-3)/1000/1000) }'`
			fi
			debug "SYSTEM-ROOT-DEV: ${RD}"
			debug "SYSTEM-ROOTDEV-SIZE: ${SIZE}"
			echo ${SIZE}
		;;
		*)
			ROOTDEV=`${READLINK} -f /dev/root`
			if [ -z "${ROOTDEV}" ] || [ ! -e "${ROOTDEV}" ] ; then
				UUID=`${GREP} -E '(^UUID=.*\s/\s.*)' /etc/fstab | ${SED} -r 's@^UUID=(.*)\s/\s.*@\1@'`
				ROOTDEV=`${READLINK} -e $(${LS} -1A /dev/disk/by-uuid/${UUID})`
				if [ -z "${UUID}" ] || [ ! -e "${ROOTDEV}" ] ; then
					PARTUUID=`${GREP} -E '(^PARTUUID=.*\s/\s.*)' /etc/fstab | ${SED} -r 's@^PARTUUID=(.*)\s/\s.*@\1@'`
					ROOTDEV=`${READLINK} -e $(${LS} -1A /dev/disk/by-partuuid/${PARTUUID})`
				fi
			else
				ROOTDEV=`${GREP} -E '(^/dev/.*\s/\s.*)' /etc/fstab | ${SED} -r 's@^(/dev/.*)\s/\s.*@\1@'`
			fi
			# HP
			HP_ROOTDISK=`echo ${ROOTDEV} | ${GREP} "/dev/cciss" | ${SED} -r 's@(/dev/cciss/c[0-9]d[0-9]).*@\1@'`
			# linux software raid
			MD_ROOTDISK=`echo ${ROOTDEV} | ${GREP} "/dev/md" | ${SED} -r 's@(/dev/md[0-9]).*@\1@'`
			# linux lvm
			LV_ROOTDISK=`echo ${ROOTDEV} | ${GREP} "/dev/dm-" | ${SED} -r 's@(/dev/dm-[0-9]).*@\1@'`
			# block device
			BL_ROOTDISK=`echo ${ROOTDEV} | ${SED} -r 's@(/dev/x?[hsv]d[a-z]).*@\1@'`
			# eMMC
			MMC_ROOTDISK=`echo ${ROOTDEV} | ${SED} -r 's@(/dev/mmcblk[0-9]).*@\1@'`
			if [ -n "${HP_ROOTDISK}" ] ; then
				# hp Raid
				RD=${HP_ROOTDISK}
			elif [ -n "${MD_ROOTDISK}" ] ; then
				# linux software raid
				RD=${MD_ROOTDISK}
			elif [ -n "${MMC_ROOTDISK}" ] ; then
				# eMMC device
				RD=${MMC_ROOTDISK}
			elif [ -n "${LV_ROOTDISK}" ] ; then
				# linux lvm
				# on HP
				HP_RD=`${LS} -1A /sys/block/${LV_ROOTDISK}/slaves/ 2>/dev/null | ${GREP} "/dev/cciss" | ${SED} -r 's@(/dev/cciss/c[0-9]d[0-9]).*@\1@'`
				# on linux softraid
				MD_RD=`${LS} -1A /sys/block/${LV_ROOTDISK}/slaves/ 2>/dev/null | ${GREP} "/dev/md" | ${SED} -r 's@(/dev/md[0-9]).*@\1@'`
				# on block device
				B_RD=`${LS} -1A /sys/block/${LV_ROOTDISK}/slaves/ 2>/dev/null | ${SED} -r 's@(/dev/x?[hsv]d[a-z]).*@\1@'`

				if [ -n "${HP_RD}" ] ; then
					# hp raid
					RD=${HP_RD}
				elif [ -n "${MD_RD}" ] ; then
					# linux software raid
					RD=${MD_RD}
				else
					# block device
					RD=${B_RD}
				fi
			else
				# linux block device
				RD=${BL_ROOTDISK}
			fi
			# / 1000 nicht / 1024 bei physikalischen Festplatten
			SECCHECK=`LANG=C ${FDISK} -l ${RD} 2>/dev/null | ${GREP} "^Disk /" | ${GREP} sectors$`
			if [ -z "${SECCHECK}" ] ; then
				# / 1000 nicht / 1024 bei physikalischen Festplatten
        	                SIZE=`LANG=C ${FDISK} -l ${RD} 2>/dev/null | ${GREP} "^Disk /" | ${AWK} '{ print int($(NF-1)/1000/1000) }'`
			else
				SIZE=`LANG=C ${FDISK} -l ${RD} 2>/dev/null | ${GREP} "^Disk /" | ${AWK} '{ print int($(NF-3)/1000/1000) }'`
			fi

			debug "SYSTEM-ROOT-DEV: ${RD}"
			debug "SYSTEM-ROOTDEV-SIZE: ${SIZE}"
			echo ${SIZE}
		;;
	esac
}

# get all (v)disks with sizes
function get_system_disk_sizes {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	SECCHECK=`LANG=C ${FDISK} -l 2>/dev/null | ${GREP} "^Disk /" | ${GREP} sectors$`
	if [ -z "${SECCHECK}" ] ; then
		DEV_SIZES=`LANG=C ${FDISK} -l 2>/dev/null | ${GREP} "^Disk /" | ${SORT} | ${AWK} '{print $2","int($(NF-1)/1000/1000)}' | ${SED} -e 's@:,@,@' | ${GREP} -E '(/dev/cciss/c[0-9]d[0-9]|/dev/x?[hsv]d[a-z],[0-9]{1,9}|/dev/mmcblk[0-9].*)'`
	else
		DEV_SIZES=`LANG=C ${FDISK} -l 2>/dev/null | ${GREP} "^Disk /" | ${SORT} | ${AWK} '{print $2","int($(NF-3)/1000/1000)}' | ${SED} -e 's@:,@,@' | ${GREP} -E '(/dev/cciss/c[0-9]d[0-9]|/dev/x?[hsv]d[a-z],[0-9]{1,9}|/dev/mmcblk[0-9].*)'`
	fi
	debug "SYSTEM-DEVS-SIZES: ${DEV_SIZES}"
	echo ${DEV_SIZES}
}

# get system vendor
function get_system_manufacturer {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	case `get_system_type` in
                xen-dom0|baremetal|kvm|vmware|lxc)
			SYSMANUF=`${DMIDECODE} -s system-manufacturer`
		;;
		*)
			SYSMANUF="n/a"
		;;
	esac
	debug "SYSTEM-MANUFACTURER: ${SYSMANUF}"
	echo ${SYSMANUF}
}

# get express service code for dell systems
function get_system_dell_express_service_code {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	if [ -n "`get_system_manufacturer | grep -i dell`" ] ; then
		ST=`get_system_serial`
		if [ -n "${ST}" ] ; then
			EC=$((36#${ST}))
			debug "SYSTEM-DELL-EXPRESS-SERVICE-CODE: ${EC}"
			echo "${EC}"
		fi
	fi
}
# get system bios version
function get_system_biosversion {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	case `get_system_type` in
                xen-dom0|baremetal|kvm|vmware|lxc)
			BIOSV=`${DMIDECODE} -s bios-version`
		;;
		*)
			BIOSV="n/a"
		;;
	esac
	debug "BIOS-VERSION: ${BIOSV}"
	echo ${BIOSV}
}

# get comma seperated list of ethernet devices (mac,iface,link)
function get_system_net_info {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
        for MAC in `get_system_macs` ; do
                IF=`get_iface_name_from_mac ${MAC}`
                IFL=`get_iface_link_state ${IF}`
                echo "${MAC},${IF},${IFL}"
        done
}

# get kernel version
function get_system_kernelversion {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	KERNEL=`${UNAME} -r`
	debug "KERNEL-VERSION: ${KERNEL}"
	echo ${KERNEL}
}

# get system architecture
function get_system_arch {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	SYSARCH=`${UNAME} -m`
	debug "SYSTEM-ARCHITECTURE: ${SYSARCH}"
	echo ${SYSARCH}
	
}

# get distribution
function get_system_os {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	LSB_RELEASE=$(which lsb_release 2>/dev/null)
	if [ -z "${LSB_RELEASE}" ]; then
		if [ -s /etc/os-release ] ; then
			. /etc/os-release
			OSREL="${NAME} ${VERSION_ID}"
		fi
	else
		OSREL=`${LSB_RELEASE} -d | ${AWK} -F":\t" '{print $NF}' | ${SED} -r -e 's#(.*)\(.*\)#\1#g'`
	fi
	debug "SYSTEM-OS: ${OSREL}"
	echo ${OSREL}
}

# get hostname
function get_system_hostname {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	HN=`${HOSTNAME} -f 2>/dev/null`
	if [ -z "${HN}" ] ; then
		if [ -s /etc/sysconfig/network ] && [ -f /etc/sysconfig/network ] ; then
			HN=`${CAT} /etc/sysconfig/network | ${GREP} ^HOSTNAME | ${AWK} -F= '{print $NF}'`
		elif [ -s /etc/HOSTNAME ] && [ -f /etc/HOSTNAME ] ; then
			HN=`${CAT} /etc/HOSTNAME`
		fi
	fi
	if [ -z "${HN}" ] ; then
		HN=`${HOSTNAME}`
	fi
	debug "SYSTEM-HOSTNAME: ${HN}"
	echo ${HN}
}

# get all system ipv4 addresses
function get_system_ipv4 {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	IPV4ADDR=`${IP} -4 addr show scope global | ${GREP} inet | ${AWK} '{print $2}' | ${AWK} -F/ '{print $1}' | ${SORT} -u`
	debug "SYSTEM-IPV4-ADDRESSES: ${IPV4ADDR}"
	echo ${IPV4ADDR}
}

# get all system ipv6 addresses
function get_system_ipv6 {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	IPV6ADDR=`${IP} -6 addr show scope global | ${GREP} inet | ${AWK} '{print $2}' | ${AWK} -F/ '{print $1}' | ${SORT} -u`
	debug "SYSTEM-IPV6-ADDRESSES: ${IPV6ADDR}"
	echo ${IPV6ADDR}
}

# get primary network interface from default route
function get_system_default_interface {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	INT=`${IP} -4 route show default | ${AWK} '{print $5}'`
	case `get_system_type` in
		openvz)		
			if [ "${INT}" == "venet0" ] ; then	
				INT="venet0:0"
			fi
		;;
	esac
	debug "SYSTEM-DEFAULT-IFACE: ${INT}"
	echo ${INT}
}

# get primary ip from interface
function get_system_default_interface_ip_from_int {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	DEVICE=${1}
	DEFAULTIP=`${IP} -4 addr show dev ${DEVICE} | ${GREP} ${DEVICE} | ${GREP} inet | ${HEAD} -n1 | ${AWK} '{print $2}' | ${AWK} -F/ '{print $1}'`
	debug "SYSTEM-DEFAULT-IP: ${DEFAULTIP}"
	echo ${DEFAULTIP}
}

# get system default ip
function get_system_default_ip {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	get_system_default_interface_ip_from_int `get_system_default_interface`
}

# get ipmi mac
function get_system_mgmt_mac {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	case `get_system_type` in
		xen-dom0|baremetal)
			${MODPROBE} ipmi_devintf >/dev/null 2>&1
			${MODPROBE} ipmi_si >/dev/null 2>&1
			if [ -c /dev/ipmi0 ] ; then
				${IPMITOOL} lan print 1 >/dev/null 2>&1
				if [ $? == 0 ] ; then
					MAC=`${IPMITOOL} lan print 1 | ${GREP} -E '(^MAC Address)' | ${AWK} '{print tolower($NF)}' | \
						${GREP} -i -E '([0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2})'`
				fi
				if [ -z "${MAC}" ] ; then
					${IPMITOOL} lan print 2 >/dev/null 2>&1
					if [ $? == 0 ] ; then
						MAC=`${IPMITOOL} lan print 2 | ${GREP} -E '(^MAC Address)' | ${AWK} '{print tolower($NF)}' | \
							${GREP} -i -E '([0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2})'`
					fi
					if [ -z "${MAC}" ] ; then
						MAC="none"
					fi
				fi
			else
				MAC="none"
			fi
		;;
		*)
			MAC="none"
		;;
	esac
	debug "SYSTEM-MGMT-MAC: ${MAC}"
	echo ${MAC}
}

# get ipmi ip
function get_system_mgmt_ip {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	case `get_system_type` in
		xen-dom0|baremetal)
			${MODPROBE} ipmi_devintf >/dev/null 2>&1
			${MODPROBE} ipmi_si >/dev/null 2>&1
			if [ -c /dev/ipmi0 ] ; then
				${IPMITOOL} lan print 1 >/dev/null 2>&1
				if [ $? == 0 ] ; then
					MGMTIP=`${IPMITOOL} lan print 1 | ${GREP} -E '(^IP Address)  ' | ${AWK} '{print $NF}'`
				fi
				if [ -z "${MGMTIP}" ] ; then
					${IPMITOOL} lan print 2 >/dev/null 2>&1
					if [ $? == 0 ] ; then
						MGMTIP=`${IPMITOOL} lan print 2 | ${GREP} -E '(^IP Address)  ' | ${AWK} '{print $NF}'`
					fi
					if [ -z "${MGMTIP}" ] ; then
						MGMTIP="none"
					fi
				fi
			else
				MGMTIP="none"
			fi
		;;
		*)
			MGMTIP="none"
		;;
	esac
	debug "SYSTEM-MGMT-IP: ${MGMTIP}"
	echo ${MGMTIP}
}

# get ipmi firmware
function get_system_mgmt_firmware {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	case `get_system_type` in
		xen-dom0|baremetal)
			${MODPROBE} ipmi_devintf >/dev/null 2>&1
			${MODPROBE} ipmi_si >/dev/null 2>&1
			if [ -c /dev/ipmi0 ] ; then
				${IPMITOOL} mc info >/dev/null 2>&1
				if [ $? == 0 ] ; then
					MGMTFIRM=`${IPMITOOL} mc info | ${GREP} "^Firmware Revision" | ${AWK} '{print $NF}'`
				fi
				if [ -z "${MGMTFIRM}" ] ; then
					MGMTFIRM="none"
				fi
			else
				MGMTFIRM="none"
			fi
		;;
		*)
			MGMTFIRM="none"
		;;
	esac
	debug "SYSTEM-MGMT-FIRMWARE: ${MGMTFIRM}"
	echo ${MGMTFIRM}
}

# get rpm package list
function get_system_software {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	case `get_system_os` in
		Debian*|Ubuntu*|Raspbian*)
			PACKAGES=`${DPKGQUERY} -W -f '${Package}-${Version}.${Architecture} ' | ${SED} -e s@"\+"@"_"@g`
		;;
		*)
			if [ -n "${RPM}" ] ; then
				PACKAGES=`${RPM} -qa --queryformat '%{name}-%{version}-%{release}.%{arch} '`
			else
				PACKAGES=""
			fi
		;;
	esac
	debug "SYSTEM-SOFTWARE: ${PACKAGES}"
	echo ${PACKAGES}
}

# get current date
function get_system_date {
	[ "`is_disabled $FUNCNAME`" == "1" ] && return
	LANG=C
	DATUM=`${DATE}`
	debug "SYSTEM-DATE: ${DATUM}"
	echo ${DATUM}
}
	
# encode url parameters
rawurlencode() {
	local string="${1}"
	local strlen=${#string}
	local encoded=""

	for (( pos=0 ; pos<strlen ; pos++ )); do
		c=${string:$pos:1}
		case "$c" in
			[-_.~a-zA-Z0-9] )
				o="${c}"
			;;
			* )
				printf -v o '%%%02x' "'$c"
		esac
		encoded+="${o}"
	done
	echo "${encoded}"    # You can either set a return variable (FASTER) 
	REPLY="${encoded}"   #+or echo the result (EASIER)... or both... :p
}

# decode url parameters
rawurldecode() {
	printf -v REPLY '%b' "${1//%/\\x}"
	echo "${REPLY}"    # You can either set a return variable (FASTER) 
	REPLY="${decoded}"   #+or echo the result (EASIER)... or both... :p
}


# include custom functions
if [ -d /etc/inventory-system.d ] ; then
	for FILE in `${LS} -1A /etc/inventory-system.d/*.sh`
	do
		if [ -f ${FILE} ] ; then
			. ${FILE}
		fi
	done
fi

# build request
function build_request {
	request=""
	for VAR in get_system_uuid \
		get_system_serial \
		get_system_disk_size_bootdev \
		get_system_disk_sizes \
		get_system_cpu \
		get_system_memory \
		get_system_manufacturer \
		get_system_dell_express_service_code \
		get_system_productname \
		get_system_biosversion \
		get_system_net_info \
		get_system_default_ip \
		get_system_ipv4 \
		get_system_ipv6 \
		get_system_hostname \
		get_system_mgmt_mac \
		get_system_mgmt_ip \
		get_system_mgmt_firmware \
		get_system_type \
		get_system_kernelversion \
		get_system_arch \
		get_system_os \
		get_system_software \
		get_system_date \
		${CUSTOM_FUNCTIONS} ; do
		request="${request}${VAR}="`rawurlencode "\`${VAR}\`"`
		request="${request}&"
	done
	debug ${request}
	echo ${request}
}

###### now output system data ######
if [ -n "${RUN_FUNCTIONS}" ] ; then
        for FUNC in ${RUN_FUNCTIONS} ; do
                ${FUNC}
        done
        exit
else
	if [ -n "`echo ${TARGETURL} | grep ^https`" ] ; then
		${CURL} -s -k -d "`build_request`" ${TARGETURL} >/dev/null
	else
		${CURL} -s -d "`build_request`" ${TARGETURL} >/dev/null
	fi
	if [ $? != 0 ] ; then
		debug "Data upload failed!"
	fi
	mailalerts
fi

