#!/bin/bash
#
# send_inventory
# sendet einige HW-Infos in der Form
#
# SCHLUESSEL;Wert[;weitere Werte]
#
# HOSTNAME;<Short>;<FQDN>
# NET;<MAC-Addr>;<IP-Addr/Len>[;<IP-Addr/Len>...]   pro Netzkarte
# IPSTATIC;<interface>;<IP-Addr/Len>                pro Static Netzkarte
# IPDHCP;<interface>;<IP-Addr/len>                  pro DHCP Netzkarte mit 1. IP-Addresse
# DEFROUTE;<router>;<src-IP>
# DNSSERVER;<IP-Addr>[,<IP-Addr>...]
# NETCARD;<Vendor>;<Model>;<Device>;<MAC-Addr>
# MEM;<Memory in MByte>
# MEMSOCK;<Num Memory Slots>;<Filled Memory Slots>
# CPUS;<CPU Sockets>;<CPU Model>;<Cores per CPU>;<HT Cores per CPU>
# CPUC;<CPU Cores>;<MHz>;<kB Cach>;<HT Cores>
# CPUSOCK;<Num Sockets>;<Filled Sockets>
# [VM;yes]
# PARTITION;<Mountpoint|Swap>;<total>;<used>;<free>;[<mountopts>];<DAS|SAN|VG|MD>;<SerialNumber|name>;<partsize>     pro Partition
# NFS;<Mountpoint>;<total>;<used>;<free>;[<mountopts>];<nfs|nfs4>;<source>
# DASDISK;<SerialNumber>;<total>;<alloc>;<free from alloc>;<SCSI>;<sdx>
# SANDISK;<SerialNumber>;<total>;<alloc>;<free from alloc>;<SCSI>;<sdx>
# DAS;<total GByte>;<alloc>;<used>;<free from alloc>;<free from alloc - adj>
# SAN;<total GByte>;<alloc>;<used>;<free from alloc>;<free from alloc - adj>
# FC;<WWN>                                         pro FC-Karte
# FCCARD;<Vendor>;<Model>;<Device>;<WWN>
# SCSICARD;<Vendor>;<Model>;<Device>
# IDEINTERFACE;<Vendor>;<Model>;<Device>
# TAPE;<Vendor>;<Model>;<Device>;[<Serial>]
# HOSTID;<hostid>
# BS;<BS Name>;<BS Version>;<Patchlevel>;<Long Name>;<arch>
# FIREWALL;on|off;<open Ports>
# SYSTEM|BOARD;Manufacturer;Product;Version;Serial
# CHASSIS;Manufacturer;Version;Serial;Type
# BIOS;Vendor;Version;Date
# SERVICEBOARD;<MAC-Addr>;<IP-Addr/Len>;<def-GW>
# CLUSTER;<Cluster-Software>;<Clustername>;<node1>[;<noden>...]
# CLUSTERRES;<name>[;IP:<ip>...][;FS:<mountpkt>...]                pro Paket
# CLUSTERRESNODES;<name>;<defnode>[;<altnode>]                     pro Paket
# LDAP;<base>;<host>[;...]
# KERBEROS;<realm>;<kdc>[;...]
# GRUBPWD;<yes|no>
# POSTFIXRELAYHOST;<relayhost>
# BOOTTIME;<boottime>
# LASTPATCHDATE;<LAST-SW-INST-TS>
# TPHP;$(cat /sys/kernel/mm/transparent_hugepage/enabled)
# SERVICE;<program>;<listen-ip>:<port>[;...]                       for each program
# SOFTWARE;<longname>;<name>;<version>;<release>;<Arch>;<vendor>;<installdate>;<repository>  for each rpm/deb-package
######################################################################################
#
if [[ $# -lt 2 ]]; then
  DT="`date '+%F %H:%M:00%:z'`"
else
  DT="$1 $2"
fi
#
DAT=/tmp/Inventory-`hostname`.csv
#
export LANG=C
#
export PATH=/bin:/sbin:/usr/sbin:/usr/bin:$PATH
#
if which python3 &>/dev/null; then
  PYTHON3=$(which python3)
elif which python3.6 &>/dev/null; then
  PYTHON3=$(which python3.6)
else
  unset PYTHON3
fi
#
(
#################################################################################
# HOSTNAME
echo "HOSTNAME;`hostname`;`hostname -f`"
#
#################################################################################
# NET
ip addr | awk '
/^[0-9]*: / { i = $1 + 0
              if( m < i )
                m = i
            }
$1 == "link/ether" { hw[i] = $2 }
$1 == "inet"       { if( ip[i] != "" )
                       ip[i] = ip[i] ";" $2
                     else
                       ip[i] = $2
                   }
END { for( i = 0; i <= m; i++ )
      { if( hw[i] != "" )
          print "NET;" hw[i] ";" ip[i]
      }
    }'
#
#################################################################################
# IPSTATIC IPDHCP
if [[ -d /etc/netplan && -n "$PYTHON3" ]] && ls /etc/netplan/*.yaml &>/dev/null; then
  for f in  /etc/netplan/*.yaml; do
    $PYTHON3 -c "import yaml

with open('$f') as f:
  data = yaml.safe_load(f)
  network = data.get('network')
  if network:
    ether = network.get('ethernets')
    if ether:
      for key, value in ether.items():
        addr = value.get('addresses')
        if not addr:
          addr = ''
        else:
          addr = ';'+';'.join(map(str,addr))
        if value.get('dhcp4'):
          print(str(key)+' DHCP '+addr)
        else:
          print(str(key)+' STATIC '+addr)
"
  done | while read dev stat ips; do
    if [[ "$stat" == "DHCP" ]]; then
      echo "IPDHCP;$dev;$(ip a show $dev | sed -n '/global secondary/d;s/ *inet \([^ ]*\) .*/\1/p')$ips"
    else
      echo "IPSTATIC;$dev$ips"
    fi
  done
else
  awk '$1 == "iface" { if( adr && type && nm )
                  { split(nm, a, ".")
                    nb = 32-log(1+and(4294967295,compl(a[1]*16777216+a[2]*65536+a[3]*256+a[4])))/log(2)
                    printf("IP%s;%s;%s/%d\n", type, iface, adr, nb)
                    adr = type = nm = ""
                  }
                  iface = $2
                  type = toupper($4)
                }
    $1 == "address" { adr = $2 }
    $1 == "netmask" { nm = $2 }
    END { if( adr && type && nm )
          { split(nm, a, ".")
            nb = 32-log(1+and(4294967295,compl(a[1]*16777216+a[2]*65536+a[3]*256+a[4])))/log(2)
            printf("IP%s;%s;%s/%d\n", type, iface, adr, nb)
          }
        }' /etc/network/interfaces
fi
#
# Defaultroute with src-address
defr=$(ip r | sed -n 's/^default via \([^ ]*\) .*/\1/p')
#
read a b c d <<<"${defr//./ }"
if [[ -n "$a" && -n "$b" && -n "$c" && -n "$d" ]]; then 
  #
  r=$(( $a * 16777216 + $b * 65536 + $c * 256 + $d ))
  sec=$(ip a | sed -n 's/\./\\./g;s| *inet \([^/]*\)/.* scope global secondary .*|src \1 |p')
  #
  while read i m s; do
    read a b c d <<<"${i//./ }"
    t=$(( $a * 16777216 + $b * 65536 + $c * 256 + $d ))
    mb=$(( ~(4294967295 >> $m) & 4294967295 ))
    if [[ $t -eq $(( $mb & $r )) ]]; then
      echo "DEFROUTE;$defr;$s"
    fi
  done < <(ip r | grep -v "${sec:-IGNORE}" | sed -n 's|^\([^/]*\)/\([0-9]*\) .* src \([0-9.]*\).*$|\1 \2 \3|p')
fi
#
#################################################################################
# DNSSERVER
if grep -q '^nameserver' /etc/resolv.conf; then
  echo "DNSSERVER"$(awk '$1 == "nameserver" {printf(";%s", $2)}' /etc/resolv.conf)
fi
#################################################################################
# NETCARD FCCARD
(
if cd /sys/class; then
  if [[ -f /usr/share/pci.ids ]]; then
    PCIIDSCMD='cat /usr/share/pci.ids'
  elif [[ -f /usr/share/pci.ids.gz ]]; then
    PCIIDSCMD='zcat /usr/share/pci.ids.gz'
  elif [[ -f /usr/share/hwdata/pci.ids ]]; then
    PCIIDSCMD='cat /usr/share/hwdata/pci.ids'
  elif [[ -f /usr/share/hwdata/pci.ids.gz ]]; then
    PCIIDSCMD='zcat /usr/share/hwdata/pci.ids.gz'
  elif [[ -f /usr/share/misc/pci.ids ]]; then
    PCIIDSCMD='cat /usr/share/misc/pci.ids'
  elif [[ -f /usr/share/misc/pci.ids.gz ]]; then
    PCIIDSCMD='zcat /usr/share/misc/pci.ids.gz'
  fi
  if [[ -n "$PCIIDSCMD" ]]; then
    for i in net/* fc_host/* scsi_host/*; do
      readlink -f $i
    done | awk '
{ if( match($0, "(/sys/devices/pci[^/]*/[^/]*/)([^/]*/)(.*)", a) )
  { if( card[a[1]] )
    { if( !pf[a[1]a[2]]++ )
        path[a[1]":"++pn[a[1]]] = a[1] a[2] a[3]
    }
    else
    { card[a[1]] = a[1] a[2]
      i = split(a[3], b, "/")
      type[a[1]] = b[i-1]
      pn[a[1]] = 1
      if( !pf[a[1]a[2]]++ )
        path[a[1]":"1] = a[1] a[2] a[3]
    }
  }
}
END { for( i in card )
      { if( type[i] == "net" )
        { printf("NETCARD %s %s", i, card[i])
          for( n = 1; n <= pn[i]; n++ )
            printf(" %s/address", path[i":"n])
          printf("\n")
        }
        else if( type[i] == "scsi_host" )
        { if( card[i] ~ "ata" )
            print "IDEINTERFACE " i " " card[i]
          else
            print "SCSICARD " i " " card[i]
        }
        else if( type[i] == "fc_host" )
        { printf("FCCARD %s %s", i, card[i])
          for( n = 1; n <= pn[i]; n++ )
            printf(" %s/port_name", path[i":"n])
          printf("\n")
        }
      }
    }
' | while read t s c d; do
      if [[ $t = 'NETCARD' || $t = 'FCCARD' ]]; then
        DETS=`awk 'BEGIN{ORS=";"};{print}' $d | sort -u`
      else
        DETS=''
      fi
      if [[ -f $c/vendor ]]; then
        echo "$t `cat $c/vendor` `cat $c/device` `cat $c/subsystem_vendor` `cat $c/subsystem_device` ${DETS%;}"
      else
        echo "$t `cat $s/vendor` `cat $s/device` `cat $s/subsystem_vendor` `cat $s/subsystem_device` ${DETS%;}"
      fi
    done | awk -v pcicmd="$PCIIDSCMD" '
BEGIN { while( (pcicmd | getline p) > 0 )
        { if( match(p, /^([0-9a-f][0-9a-f][0-9a-f][0-9a-f]) *(.*)/, v) )
          { vc = v[1]
            vend[vc] = v[2]
            vdc = ""
          }
          else if( match(p, /^\t([0-9a-f][0-9a-f][0-9a-f][0-9a-f]) *(.*)/, d) )
          { if( vc != "" )
            { vdc = vc d[1]
              dev[vdc] = d[2]
            }
          }
          else if( match(p, /^\t\t([0-9a-f][0-9a-f][0-9a-f][0-9a-f]) *([0-9a-f][0-9a-f][0-9a-f][0-9a-f]) *(.*)/, s) )
          { if( vdc != "" )
              subc[vdc s[1] s[2]] = s[3]
          }
        }
        close(pcicmd)
      }
{ gsub("0x", "")
  if( vend[$4] && subc[$2 $3 $4 $5] )
    print $1 ";" vend[$2] ";" vend[$4] " " subc[$2 $3 $4 $5] ";" dev[$2 $3] ";" $6
  else if( subc[$2 $3 $4 $5] )
    print $1 ";" vend[$2] ";" subc[$2 $3 $4 $5] ";" dev[$2 $3] ";" $6
  else if( vend[$4] && dev[$4 $5] )
    print $1 ";" vend[$2] ";" vend[$4] " " dev[$4 $5] ";" dev[$2 $3] ";" $6
  else
    print $1 ";" vend[$2] ";" vend[$4] dev[$4 $5] " Device;" dev[$2 $3] ";" $6
}'
  fi
fi
)
#
#################################################################################
# MEM
unset MBSD MBSH
if which dmidecode &>/dev/null; then
  MBSD=$(dmidecode -t 17 | awk '$1 == "Size:" { if( $3 == "MB" ) sum += $2; else if( $3 == "GB" ) sum += ($2*1024) };END{if(sum>0)print sum}')
fi
if which hwinfo &>/dev/null; then
  MBSH=$(hwinfo --memory | awk '/Memory Size:/ { if( $4 == "MB" ) sum += $3; else if( $4 == "GB" ) sum += ($3*1024) };END{if(sum>0)print sum}')
fi
MBS=$(awk '/^DirectMap4k|^DirectMap2M/{s+=$2}; /^MemTotal:/{mt=$2}; END {printf("%.0f\n", (s>mt?s:mt)/1024)}' /proc/meminfo)
if [[ ${MBSD:-0} -gt ${MBS:-0} ]]; then
  MBS=$MBSD
fi
if [[ ${MBSH:-0} -gt ${MBS:-0} ]]; then
  MBS=$MBSH
fi
if [[ -n "$MBS" ]]; then
  echo "MEM;$MBS"
fi
#
#################################################################################
# CPUS, CPUC
awk 'BEGIN    { pr = 0
                mhz = 0
              }
/^processor/  { pr++ }
/vendor_id/   { gsub(".*: *", "")
                v = $0
              }
/physical id/ { p[$NF] = 1
                pi = $NF
              }
/core id/     { c[$NF] = 1
                gc[pi":"$NF] = 1
              }
/model name/  { gsub(".*: *", "")
                m = $0
              }
/cache size/  { if( $NF == "KB" )
                  cs = $(NF-1)
                if( $NF == "MB" )
                  cs = $(NF-1)*1024
              }
/cpu MHz/     { if( $NF > mhz )
                  mhz = $NF
              }
END { for( i in p )
        pa++
      for( i in c )
        ca++
      for( i in gc )
        gca++
      if( pa > 0 && ca > 0 )
      { printf("CPUS;%d;%s;%d;%d\n", pa, m ? m : v, ca, pr/pa)
        printf("CPUC;%d;%d;%d;%d\n", gca, mhz, cs, pr)
      }
      else
      { print "CPUS;" pr ";" (m ? m : v)
        printf("CPUC;%d;%d;%d\n", pr, mhz, cs)
      }
    }' /proc/cpuinfo
#
#################################################################################
# VM
if which lspci &>/dev/null && lspci | grep -qi 'System peripheral: .*Virtual'; then
  echo "VM;yes"
elif grep -qi 'model name.*: QEMU' /proc/cpuinfo; then
  echo "VM;yes"
fi
#
#################################################################################
# Disk infos
$(dirname $0)/inventory_get_disks.sh
#
#################################################################################
# NFS Mounts
df -TPm -t nfs4 -t nfs -t cifs 2>/dev/null | awk '$t ~ "nfs|cifs" && $7 !~ /\/\.snapshot/ { printf("%s %s %f %f %f %s\n", $1, $2, $3/1024, $4/1024, $5/1024, $7)}' | while read f t s u a m; do
  moptions=$(sed -n "s|^$f $m $t \\([^ ]*\\) .*|\\1|p" /proc/mounts)
  echo "NFS;$m;$s;$u;$a;$moptions;$t;$f"
done
#
#################################################################################
# FC
sed 's/0x/FC;/' /sys/class/fc_host/host?/port_name 2>/dev/null
#
#################################################################################
# HOSTID
echo "HOSTID;`/usr/bin/hostid`"
#
#################################################################################
# BS
if [[ `uname -m` = 'x86_64' ]]; then
  BITS='64bit'
else
  BITS='32bit'
fi
if [[ -f /etc/os-release ]]; then
  if [[ -f /etc/redhat-release ]]; then
    RHPN=$(sed -n '1{s/ *$//g;p}' /etc/redhat-release)
  fi
  if [[ -f /etc/debian_version ]] && grep -q '^[0-9]*\.[0-9]*$' /etc/debian_version; then
    DV=$(</etc/debian_version)
  else
    unset DV
  fi
  awk -F '=' -v rhpn="$RHPN" -v dv="$DV" '
        { gsub("\"", "", $2)
          a[$1] = $2
        }
    END { split(dv ? dv : a["VERSION_ID"], va, ".")
          printf("BS;%s;%s;%s;%s;'$BITS'\n", a["NAME"], va[1], va[2], rhpn ? rhpn : a["PRETTY_NAME"])
        }' /etc/os-release
elif [[ -f /etc/SuSE-release ]]; then
  awk -F ' *= *' '
  /SUSE/ { ln = $0
           if( $NF ~ "x86_64" || $NF ~ "s390x" )
             a = "64bit"
           else
             a = "32bit"
           if( $0 ~ "Enterprise Server" )
             n = "SLES"
           else
           { gsub(" [0-9].*", "")
             n = $0
           }
         }
  $1 == "VERSION" { v = $2 }
  $1 == "PATCHLEVEL" { p = $2 }
  END { printf("BS;%s;%s;%s;%s;%s\n", n, v, p, ln, a) }
  ' /etc/SuSE-release
elif [[ -f /etc/redhat-release ]]; then
  V=`sed 's/^Red Hat .* release \([^ ]*\) .*$/\1/' /etc/redhat-release`
  if [[ -n "$V" ]]; then
    echo "BS;Red Hat;$V;;`head -1 /etc/redhat-release`;$BITS"
  else
    echo "BS;;;;`head -1 /etc/redhat-release`;$BITS"
  fi
elif which lsb_release &>/dev/null; then
  lsb_release -a 2>/dev/null | awk -F ' *= *' '
  /DISTRIB_ID/ { n = $2 }
  /DISTRIB_RELEASE/ { v = $2 }
  /DISTRIB_DESCRIPTION/ { gsub("\"", "", $2); d = $2 }
  END { print "BS;" n ";" v ";;" d ";'$BITS'" }
  '
elif [[ -f /etc/debian_version ]]; then
  R=`head -1 /etc/debian_version`
  echo "BS;Debian;;;$R;$BITS"
else
  R=`cat /etc/*-release 2>/dev/null | head -1`
  if [[ -n "$R" ]]; then
    echo "BS;;;;$R;$BITS"
  fi
fi
#
#################################################################################
# FIREWALL
if /usr/sbin/iptables -L >/dev/null 2>&1; then
  if /usr/sbin/iptables -L | egrep -q "DROP|REJECT"; then
    echo "FIREWALL;on"
  else
    echo "FIREWALL;off"
  fi
fi
#
#################################################################################
# MEMSOCK CPUSOCK SYSTEM BOARD CHASSIS BIOS
if [[ -f /proc/sysinfo ]] && grep -q '^LPAR' /proc/sysinfo; then
  awk -F ': *' '
/Manufacturer:/      { gsub(" *$", "", $2); manufacturer = $2 }
/Type:/              { gsub(" *$", "", $2); type = $2 }
/Model:/             { gsub(" *$", "", $2); gsub("  *", " ", $2); model = $2 }
/LPAR Number:/       { gsub(" *$", "", $2); lparno = $2 }
/LPAR Name:/         { gsub(" *$", "", $2); lparname = $2 }
/VM00 Name:/         { gsub(" *$", "", $2); vmname = $2 }
END { print "SYSTEM;" manufacturer ";" model ";None;" lparno " " lparname " " vmname
    }' /proc/sysinfo
elif which dmidecode >/dev/null 2>&1; then
  dmidecode | awk -F ' *: *' '
/^[A-Za-z]/                   { m = $0 }
m == "BIOS Information"       { if( $1 ~ "Vendor" || $1 ~ "Version" )
                                { gsub("[[:blank:]]", "", $1)
                                  i[$1] = $2
                                }
                                else if( $1 ~ "Date" )
                                { gsub("[^0-9/.]","",$2)
                                  cd = "date -d \""$2"\" \"+%F\""
                                  cd | getline i["Date"]
                                  close(cd)
                                }
                              }
m == "System Information"     { if( $1 ~ "Manufacturer" || $1 ~ "Product" || $1 ~ "Version" || $1 ~ "Serial" )
                                { gsub("[[:blank:]]", "", $1)
                                  s[$1] = $2
                                }
                              }
m == "Base Board Information" { if( $1 ~ "Manufacturer" || $1 ~ "Product" || $1 ~ "Version" || $1 ~ "Serial" )
                                { gsub("[[:blank:]]", "", $1)
                                  b[$1] = $2
                                }
                              }
m == "Chassis Information"    { if( $1 ~ "Manufacturer" || $1 ~ "Version" || $1 ~ "Serial" || $1 ~ "Type" )
                                { gsub("[[:blank:]]", "", $1)
                                  c[$1] = $2
                                }
                              }
m == "Processor Information"  { if( $1 ~ "Manufacturer" )
                                { psock++
                                  if( $2 !~ "^00" )
                                    psockf++
                                }
                              }
m == "Memory Module Information" { if( $1 ~ "Size" )
                                   { msock++
                                     if( $2 + 0 > 0 )
                                       msockf++
                                   }
                                 }
END { print "MEMSOCK;" msock ";" msockf
      print "CPUSOCK;" psock ";" psockf
      print "SYSTEM;" s["Manufacturer"] ";" s["ProductName"] ";" s["Version"] ";" s["SerialNumber"]
      print "BOARD;" b["Manufacturer"] ";" b["ProductName"] ";" b["Version"] ";" b["SerialNumber"]
      print "CHASSIS;" c["Manufacturer"] ";" c["Version"] ";" c["SerialNumber"] ";" c["Type"]
      print "BIOS;" i["Vendor"] ";" i["Version"] ";" i["Date"]
    }
'
elif which hwinfo >/dev/null 2>&1; then
  hwinfo --bios | awk -F ' *: *' '
/BIOS Info/,/System Info/ { if( $1 ~ "Vendor" || $1 ~ "Version" )
                            { gsub("\"", "", $2)
                              gsub(" ", "", $1)
                              i[$1] = $2
                            }
                            else if( $1 ~ "Date" )
                            { gsub("[^0-9/.]","",$2)
                              cd = "date -d \""$2"\" \"+%F\""
                              cd | getline i["Date"]
                              close(cd)
                            }
                          }
/System Info/,/Board Info/{ if( $1 ~ "Manufacturer" || $1 ~ "Product" || $1 ~ "Version" || $1 ~ "Serial" )
                            { gsub("\"", "", $2)
                              gsub(" ", "", $1)
                              s[$1] = $2
                            }
                          }
/Board Info/,/Chassis Info/{ if( $1 ~ "Manufacturer" || $1 ~ "Product" || $1 ~ "Version" || $1 ~ "Serial" )
                             { gsub("\"", "", $2)
                               gsub(" ", "", $1)
                               b[$1] = $2
                             }
                           }
/Chassis Info/,/Processor Info/{ if( $1 ~ "Manufacturer" || $1 ~ "Version" || $1 ~ "Serial" || $1 ~ "Type" )
                                 { gsub("\"", "", $2)
                                   gsub(" ", "", $1)
                                   c[$1] = $2
                                 }
                               }
/Processor Info/,/Cache Info/ { if( $1 ~ "Socket Status" )
                                { psock++
                                  if( $2 ~ "Populated" )
                                    psockf++
                                }
                              }
/Memory Device/,/Memory Array Mapping/ { if( $1 ~ "Size" )
                                         { msock++
                                           if( $2 + 0 > 0 )
                                             msockf++
                                         }
                                       }
END { print "MEMSOCK;" msock ";" msockf
      print "CPUSOCK;" psock ";" psockf
      print "SYSTEM;" s["Manufacturer"] ";" s["Product"] ";" s["Version"] ";" s["Serial"]
      print "BOARD;" b["Manufacturer"] ";" b["Product"] ";" b["Version"] ";" b["Serial"]
      print "CHASSIS;" c["Manufacturer"] ";" c["Version"] ";" c["Serial"] ";" c["Type"]
      print "BIOS;" i["Vendor"] ";" i["Version"] ";" i["Date"]
    }
'
elif which lshal >/dev/null 2>&1; then
  lshal --show /org/freedesktop/Hal/devices/computer | awk -F ' = ' '
/system.board.product/ { sub("'"'"'", "", $2)
                           sub("'"'"'.*", "", $2)
                           boproduct = $2
                         }
/system.board.serial/ { sub("'"'"'", "", $2)
                           sub("'"'"'.*", "", $2)
                           boserial = $2
                         }
/system.board.vendor/ { sub("'"'"'", "", $2)
                           sub("'"'"'.*", "", $2)
                           bovendor = $2
                         }
/system.board.version/ { sub("'"'"'", "", $2)
                           sub("'"'"'.*", "", $2)
                           boversion = $2
                         }
/system.chassis.manufacturer/ { sub("'"'"'", "", $2)
                           sub("'"'"'.*", "", $2)
                           chmanufacturer = $2
                         }
/system.chassis.version/ { sub("'"'"'", "", $2)
                           sub("'"'"'.*", "", $2)
                           chversion = $2
                         }
/system.chassis.serial/ { sub("'"'"'", "", $2)
                           sub("'"'"'.*", "", $2)
                           chserial = $2
                         }
/system.chassis.type/ { sub("'"'"'", "", $2)
                           sub("'"'"'.*", "", $2)
                           chtype = $2
                         }
/system.firmware.release_date/ { sub("'"'"'", "", $2)
                           sub("'"'"'.*", "", $2)
                           fwdate = $2
                         }
/system.firmware.vendor/ { sub("'"'"'", "", $2)
                           sub("'"'"'.*", "", $2)
                           fwvendor = $2
                         }
/system.firmware.version/ { sub("'"'"'", "", $2)
                           sub("'"'"'.*", "", $2)
                           fwversion = $2
                         }
/system.hardware.product/ { sub("'"'"'", "", $2)
                           sub("'"'"'.*", "", $2)
                           hwproduct = $2
                         }
/system.hardware.serial/ { sub("'"'"'", "", $2)
                           sub("'"'"'.*", "", $2)
                           hwserial = $2
                         }
/system.hardware.vendor/ { sub("'"'"'", "", $2)
                           sub("'"'"'.*", "", $2)
                           hwvendor = $2
                         }
/system.hardware.version/ { sub("'"'"'", "", $2)
                           sub("'"'"'.*", "", $2)
                           hwversion = $2
                         }
END { print "SYSTEM;" hwvendor ";" hwproduct ";" hwversion ";" hwserial
      print "BOARD;" bovendor ";" boproduct ";" boversion ";" boserial
      print "CHASSIS;" chmanufacturer ";" chversion ";" chserial ";" chtype
      print "BIOS;" fwvendor ";" fwversion ";" fwdate
    }'
fi
#
#################################################################################
#  SERVICEBOARD
if [[ -x /usr/bin/ipmitool ]]; then
  /usr/bin/ipmitool lan print 2>/dev/null | awk -F ' *: *' '
$1 == "IP Address"         { ip = $2 }
$1 == "Subnet Mask"        { split($2,a,".")
                             len=32-log(4294967296-a[1]*16777216-a[2]*65536-a[3]*256-a[4])/log(2) }
$1 == "MAC Address"        { gsub("MAC Address *: *", "", $0)
                             mac = $0
                           }
$1 == "Default Gateway IP" { gw = $2 }
END { if( ip mask mac != "" )
      { print "SERVICEBOARD;" mac ";" ip "/" len ";" gw
      }
    }
'
fi
#
#################################################################################
# LDAP
[[ -f /etc/ldap.conf ]] && awk '$1 == "host" {for(i=2;i<=NF;i++)h=h";"$i}
     $1 == "base" {b=$2}
END {print "LDAP;" b h}' /etc/ldap.conf
#
#################################################################################
# KERBEROS
[[ -f /etc/krb5.conf ]] && sed 's/^[ \t]*//g;s/[ \t]*$//g' /etc/krb5.conf | awk -F '[ \t]*=[ \t]*' '
$1 == "[libdefaults]" { m = $1 }
$1 == "[realms]" { m = $1 }
$1 == "default_realm" && m == "[libdefaults]" { dr = $2 }
m == "[realms]" && $1 == dr { r = 1 }
$0 ~ "}" { r = 0 }
r == 1 && $1 == "kdc" { kdc = kdc ";" $2 }
END {if( dr && kdc ) print "KERBEROS;" dr kdc}'
#
#################################################################################
# GRUBPWD
if [[ -f /boot/grub/menu.lst ]]; then
  if grep -q '^password' /boot/grub/menu.lst; then
    echo "GRUBPWD;yes"
  else
    echo "GRUBPWD;no"
  fi
fi
#
#################################################################################
# POSTFIXRELAYHOST
[[ -f "/etc/postfix/main.cf" ]] && awk -F ' *= *' '$1 == "relayhost" { print "POSTFIXRELAYHOST;" $2}' /etc/postfix/main.cf
#
#################################################################################
# BOOTTIME
echo "$(date '+%s.%N') $(cat /proc/uptime)" | awk '{print "BOOTTIME;" strftime("%F %T", int($1 -$2 + 0.5))}'
#
#################################################################################
# Transparent Huge Pages
echo "TPHP;$(</sys/kernel/mm/transparent_hugepage/enabled)"
#
#####################################################################
# listen services
if which ss &>/dev/null; then
  if ss -HOh &>/dev/null; then
    ss -ntlpHO
  else
    ss -ntlp
  fi | awk '
$1 == "LISTEN" && $6 ~ "^users:" {
    if( split($6, a, "\"") >= 3 )
    { prg = a[2]
      l[prg] = l[prg] ";" $4
    }
  }
END { for( i in l )
        print "SERVICE;" i l[i]
    }'
elif which netstat &>/dev/null; then
  netstat -ntlp | awk '
$6 == "LISTEN" { if( split($NF, a, "/") == 2 )
                   prg = a[2]
                 else
                   prg = $NF
                 l[prg] = l[prg] ";" $4
               }
END { for( i in l )
        print "SERVICE;" i l[i]
    }'
fi
#####################################################################
if [[ -x /usr/bin/dpkg-query ]]; then
  if [[ -f /var/log/dpkg.log ]]; then
    PKGTMP=/dev/shm/ulssinvpkgs.lst.tmp
    awk '/ status installed /{gsub(":.*", "", $5); p[$5] = $1 " " $2};END {for(i in p)print p[i], i}' /var/log/dpkg.log >$PKGTMP
  else
    unset insttime
  fi
  /usr/bin/dpkg-query -f '${Status};${Package};${Version};${Architecture};${Maintainer}\n' -W | awk -F ';' '$1 == "install ok installed" { split($3, v, "-");printf("%s %s %s-%s;%s;%s;%s;%s;%s\n", $2, $3, $2, $3, $2, v[1], v[2], $4, $5)}' | while read p v t; do
    aptsources=$(apt-cache madison $p | sed -n "/ *$p *| *$v *|/{s/[^|]*|[^|]*| *//;p;q}")
    if [[ -n "$PKGTMP" ]]; then
      insttime=$(sed -n "s/ $p\$//p" "$PKGTMP")
    fi
    echo "SOFTWARE;$t;$insttime;$aptsources"
  done | sort -u
fi
#
) >$DAT
send_server_doku Inventory "Short System Status for ServerDB.
HOSTNAME;<Short>;<FQDN>
NET;<HW-Addr>;<IP-Addr/Len>[;<IP-Addr/Len>...]
NETCARD;<MAC-Addr>;<Vendor>;<Model>
MEM;<Memory in MByte>
MEMSOCK;<Num Memory Slots>;<Filled Memory Slots>
CPUS;<CPU Sockets>;<CPU Model>;<Cores per CPU>;<HT Cores per CPU>
CPUC;<CPU Cores>;<MHz>;<kB Cach>;<HT Cores>
[VM;yes]
CPUSOCK;<Num Sockets>;<Filled Sockets>
PARTITION;<Mountpoint|swap>;<total GByte>;<used GByte>;<free GByte>     per partition
DASDISK;<SerialNumber>;<total GByte>;<alloc LVM/FS GByte>;<free LVM/FS GByte>
SANDISK;<SerialNumber>;<total GByte>;<alloc LVM/FS GByte>;<free LVM/FS GByte>
DAS;<total GByte>;<alloc FS GByte>;<used FS GByte>;<free FS GByte>
SAN;<total GByte>;<alloc FS GByte>;<used FS GByte>;<free FS GByte>
FC;<WWN>
FCCARD;<WWN>;<Vendor>;<Model>
TAPE;<Vendor>;<Model>;[<Serial>]
HOSTID;<hostid>
BS;<BS Name>;<BS Version>;<Patchlevel>;<BS Longname>;32bit|64bit
FIREWALL;on|off;<open Ports>
SYSTEM|BOARD;Manufacturer;Product;Version;Serial
CHASSIS;Manufacturer;Version;Serial;Type
CLUSTER;<Clustersoftware>;<Clustername>;<Nodes>;<Packages>
SOFTWARE;<longname>;<name>;<version>;<release>;<Arch>;<vendor>;<installdate>;<repository>" $DT $DAT
#
# IP-Static / IP-DHCP to ULS
sed -n 's/^IPDHCP;\([^;]*\);\([^;]*\).*/DHCP \1 \2/p;s/^IPSTATIC;\([^;]*\);\([^;]*\).*/Static \1 \2/p' $DAT | while read a b c; do
  send_test_value 'System' "Network:$b" 'Bootproto' $DT "$a" ''
  send_test_value 'System' "Network:$b" 'IP' $DT "$c" '_'
done
