#!/bin/ksh
# written by Olaf Bohlen, olbohlen@eenfach.de 2013-09-19
# This is the new information collector for Unix Systems
# it collects systems data and writes well-defined CSV files
# which can be imported to infotool or any other CMDB
# It is built to support various Unix OS types such as Solaris and Linux

# functions

my_error() {
    typeset message

    message="$1"
    
    # if we can write to stderr, send message to stderr - else stdout
    if [ -e /dev/fd/2 ]; then
	outdev="> /dev/fd/2"
    else
	outdev=""
    fi
    
    printf "E: %s", "${message}" ${outdev}
}

my_mail() {
    typeset messages
    typeset rcptto

    messages="$1"
    rcptto=user@company.com
    
    # for debugging purposes only

    echo "$1" | mailx -s "E: datacollector@$(uname -n)" ${rcptto}

}

my_abort() {
    typeset abort_code
    typeset abort_string

    abort_code=$1
    abort_string="$2"

    my_error "${abort_string}"
    my_mail "${abort_string}"

    exit ${abort_code}
}

dav_push() {
    # push files to webdav server
    typeset user
    typeset password
    typeset target_baseurl
    typeset localfile

    user="$1"
    password="$2"
    target_baseurl="$3"
    localfile="$4"
    
    curl -u "${user}:${password}" -k -T "${localfile}" "${target_baseurl}" 2>/dev/null >/dev/null
    if [ $? -ne 0 ]; then
	my_error "upload of ${localfile} to ${target_baseurl} failed" 
    fi
}

dav_prep() {
    # prepare directory structure on webdav server
    typeset user
    typeset password
    typeset target_baseurl

    user="$1"
    password="$2"
    target_baseurl="$3"

    if [ $(curl -u "${user}:${password}" -k -G -I "${target_baseurl}" 2>/dev/null | egrep -c "^HTTP/1.1 (200|301)") -lt 1 ]; then
	curl -u "${user}:${password}" -k -X MKCOL "${target_baseurl}" 2>/dev/null >/dev/null
    fi
}

check_update() {
    # check if a more recent version of this script is available
    typeset target_baseurl
    typeset remote_version

    target_baseurl=$1

    remote_version=$(curl -k -G "${target_baseurl}/version" 2>/dev/null)
    
    if [ ${remote_version} -gt ${VERSION} ]; then
	curl -k -G "${target_baseurl}/datacollector.ksh" >/usr/local/sbin/datacollector-update.ksh 2>/dev/null
	curl -k -G "${target_baseurl}/memconf" >/usr/local/bin/memconf 2>/dev/null
	chmod 755 /usr/local/bin/memconf
    fi
}

getcpu_SunOS() {
    typeset cpu_out
    typeset cpus
    typeset i
    typeset outfile

    outfile="$1"
    
    # print csv header
    printf "string implementation;int chip#;int coreid;int thread#;float clock_MHz;\n" >${outfile}

    # which strands are visible?
    cpus=$( /usr/sbin/psrinfo | nawk '{print $1}' )

    for i in ${cpus}; do
	cpu_out=$(kstat -p cpu_info:${i}:cpu_info${i})
	printf "${cpu_out}" | nawk '$1~/:implementation$/ { printf("%s;", $2)}' >>${outfile}
	printf "${cpu_out}" | nawk '$1~/:chip_id$/ { printf("%s;", $2)}' >>${outfile}
	printf "${cpu_out}" | nawk '$1~/:core_id$/ { printf("%s;", $2);out=1;} END { if(out!=1) { printf("0;")}}' >>${outfile}
	printf "${i};" >>${outfile}
	printf "${cpu_out}" | nawk '$1~/:clock_MHz$/ { printf("%s;", $2)}' >>${outfile}
	printf "\n" >>${outfile}
	i=$(( ${i} + 1 ))
    done
}

getcpu_Linux() {
    typeset cpu_out
    typeset num_cpus
    typeset i

    i=0

    outfile="$1"

    # print csv header

    printf "string implementation;int chip#;int coreid;int thread#;float clock_MHz;\n" >${outfile}

    # how many processors are visible?
    num_cpus=$( egrep -c "^processor" /proc/cpuinfo )

    while [ ${i} -lt ${num_cpus} ]; do
	cpu_out=$(gawk 'BEGIN { RS="\n\n"; FS="\n"; } { if($1~/processor.* '${i}'$/) { print $0 } }' </proc/cpuinfo)

	printf "${cpu_out}" | gawk -F ":" '$1~/^model name/ { printf("%s;", $2)}' >>${outfile}
	printf "${cpu_out}" | gawk -F ":" '$1~/^physical id/ { found=1; sub("^ ","",$2); printf("%s;", $2)} END { if(found!=1) {printf("'${i}';")}}' >>${outfile}
	printf "${cpu_out}" | gawk -F ":" '$1~/^core id/ { found=1; sub("^ ","",$2); printf("%s;", $2)} END { if(found!=1) {printf("'${i}';")}}' >>${outfile}
	printf "${i};" >>${outfile}
	printf "${cpu_out}" | gawk -F ":" '$1~/^cpu MHz/ { sub("^ ","",$2); printf("%s;", $2)}' >>${outfile}
	printf "\n" >>${outfile}
	i=$(( ${i} + 1 ))
    done
}

getram_SunOS() {
    typeset outfile;
    typeset mem_out;
    typeset m_psrinfo;

    outfile="$1"
    
    if [ -x /usr/sbin/psrinfo-illumos ]; then
	m_psrinfo=/usr/sbin/psrinfo-illumos
    else
	m_psrinfo=/usr/sbin/psrinfo
    fi

    printf "string slot;int size_MB;string description;\n" >${outfile}

    if [ x$(/usr/bin/zonename 2>/dev/null) == "x" -o x$(/usr/bin/zonename 2>/dev/null) == "xglobal" ]; then
	case $(uname -m) in
	    sun4u) 
		# unfortunately the APL (M3k, M4k, M5k and maybe larger) need special
		# parsing, as slots are not visible to the OS due to hardware
		# partitioning
		
		if ${m_psrinfo} -pv | grep SPARC64-VII >/dev/null 2>&1; then
		    # we are on a APL box
		    mem_out=$(${MEMCONF});
		    printf "${mem_out}" | nawk '$5~/[M|G]B$/ { 
  for(i=1;i<=$6;i++) { 
    printf("%s;%i;%s\n", "LSB"$1"GRP"$2"S"i, $5, "Virtual Slot APL M-Series") 
  } 
}' >>${outfile}
		else
		    # generic sun4u
		    mem_out=$(${MEMCONF});
		    printf "${mem_out}" | nawk -F ":" '$2~/SDRAM/ {
  split($2, descr, " ");
  if(descr[2]~/GB/) {
    size=descr[1]*1024;
  }
  if(descr[2]~/MB/) {
    size=descr[1];
  }
  printf("%s;%i;%s;\n", $1, size, $2);
}' >>${outfile}
		fi
		    ;;

	    sun4v) 
		# check if we are in a control/primary domain, if not skip memconf 
		# as it will not produce useful memory output there
		ctrl_dom=$(/usr/sbin/virtinfo -c current get -H -o value control-role logical-domain 2>/dev/null)
		if [ x${ctrl_dom} == xtrue -o x${ctrl_dom} == x ]; then
		    mem_out=$(${MEMCONF});
		    printf "${mem_out}" | nawk '$1~/^socket$/ {
  size=substr($0, match($0, "[0-9]*GB"), RLENGTH);
  descr=substr($0, match($0, "has a"));
  sub("GB$","",size);
  sub("^has a","",descr);
  size=size*1024;
  printf("%s;%i;%s;\n", $2, size, descr)}' >>${outfile}
		    printf "${mem_out}" | nawk -F ":" '$1~/empty sockets/ {
  if($2!~/None/) {
    banks=split($2, bank, " "); 
    for(i=1;i<=banks; i++) { 
      sub("^ ","",bank[i]); 
      printf("%s;0;empty;\n",bank[i]); 
    } 
  } 
}' >>${outfile}
		else
		    # we are in a non-control ldom, so prtdiag/memconf will not work correctly
		    mem_out=$( /usr/sbin/prtconf 2>/dev/null | nawk '$1~/^Memory/ { print $3 }' )
		    printf "virtual slot;%i;memory in ldoms cannot be matched to slots;\n" ${mem_out} >>${outfile}

		fi
		
		;;

	    sun4us) mem_out=$(${MEMCONF});
		printf "${mem_out}" | nawk '$1~/^SLOT/ {
  size=substr($0, match($0, "[0-9]*GB"), RLENGTH);
  descr=substr($0, match($0, "has a"));
  sub("GB$","",size);
  sub("^has a","",descr);
  size=size*1024;
  printf("%s;%i;%s;\n", $1, size, descr)}' >>${outfile}
		;;

	    i86pc) mem_out=$(${MEMCONF});
		printf "${mem_out}" | nawk -F ":" '$0~/(DIMM|DDR)/ && $1!~/^empty/ {
  size=substr($0, match($0, "[0-9]*MB"), RLENGTH);
  descr=substr($0, match($0, ":"));
  sub("MB$","",size);
  sub("^:","",descr);
  printf("%s;%i;%s;\n", $1, size, descr)}' >>${outfile}
		printf "${mem_out}" | nawk -F ":" '$1~/empty memory sockets/ {
  if($2!~/None/) {
    banks=split($2, bank, ",");
    for(i=1;i<=banks; i++) { 
      sub("^ ","",bank[i]); 
      printf("%s;0;empty;\n",bank[i]); 
    } 
  } 
}' >>${outfile}
		;;

	    *)
		my_abort 254 "Unsupported SunOS hardware"
		;;
	esac
    else
	# we are in a non-global zone, so prtdiag/memconf will not work
	mem_out=$( /usr/sbin/prtconf 2>/dev/null | nawk '$1~/^Memory/ { print $3 }' )
	printf "virtual slot;%i;memory in zones cannot be matched to slots;\n" ${mem_out} >>${outfile}
    fi
}

getram_Linux() {
    typeset outfile;
    typeset mem_out;
    typeset mem_total;
    
    outfile="$1";

    printf "string slot;int size_MB;string description;\n" >${outfile}

    mem_out=$(${MEMCONF});
    
    if [ $( printf "${mem_out}" | grep -c DIMM ) -eq 0 ]; then
	# we have no DIMM reports, so lets look up for total memory
	mem_total=$(cat /proc/meminfo | gawk '$1~/^MemTotal:/ { printf("%d\n",$2/1024) }')
	printf "virtual slot;%i;unable to retrieve memory per DIMM;\n" $(( ${mem_total}+ 0 )) >>${outfile}
    else
	printf "${mem_out}" | gawk -F ":" '$0~/DIMM/ && $1!~/^empty/ {
  sizemb=substr($0, match($0, "[0-9]*[ ]?MB"), RLENGTH);
  sizegb=substr($0, match($0, "[0-9]*[ ]?GB"), RLENGTH);
  size=sizemb + (sizegb * 1024);
  descr=substr($0, match($0, ":"));
  sub("MB$","",size);
  sub("^:","",descr);
  printf("%s;%i;%s;\n", $1, size, descr)
}' >>${outfile}
	printf "${mem_out}" | gawk -F ":" '$1~/empty memory sockets/ {
  if($2!~/^None$/ && $0!~/,/) {
    banks=split($2, bank, " ");
    for(i=1;i<=banks; i++) { 
      sub("^ ","",bank[i]);
      printf("%s;0;empty;\n",bank[i]); 
    } 
  } else
  if($2!~/^None$/ && $0~/,/) {
    banks=split($2, bank, ",");
    for(i=1;i<=banks; i++) {
      sub("^ ","",bank[i]);
      printf("%s;0;empty;\n",bank[i]);
    }
  } 
}' >>${outfile}
    fi
}

getrelease_SunOS() {
    typeset outfile;
    typeset patchlevel;
    typeset platform;
    typeset osname;
    typeset version;

    outfile="$1";

    printf "string OSName;string version;string platform;string patchlevel;\n" >${outfile}

    if [ x$(uname -r) = x5.11 ]; then
	patchlevel=$( pkg info entire | nawk '$1~/^Branch:$/ { print $NF }' )
	platform=$( nawk '$0~/(SPARC|X86)/ { printf("%s\n", substr($0, match($0, "(SPARC|X86)"), RLENGTH)); }' </etc/release )
	osname=$( nawk '{ printf("%s\n", substr($0, match($0, "(Solaris|Open[a-z,A-Z]*)"), RLENGTH)); }' </etc/release )
	version=$( nawk '{ printf("%s\n", substr($0, match($0, "(Solaris [0-9,\.]*|Open[a-z,A-Z,0-9]* [A-Z,a-z,0-9]*)"), RLENGTH)); }' </etc/release )
	printf "%s;%s;%s;%s;\n" "${osname}" "${version}" "${platform}" "${patchlevel}" >>${outfile}
    else
	head -1 /etc/release | nawk '{
  osname=substr($0, match($0, "(Solaris|Open[a-z,A-Z]*)"), RLENGTH);
  platform=substr($0, match($0, "(SPARC|X86)"), RLENGTH);
  patchlevel=substr($0, match($0, "(oi_[a-z,0-9,\.]*[0-9]|s(7|8|9|10)[sx][a-z,A-Z,0-9,_]*)"), RLENGTH);
  version=substr($0, match($0, "(Solaris [0-9,\.]*|Open[a-z,A-Z,0-9]* [A-Z,a-z,0-9]*)"), RLENGTH);
  if(patchlevel=="") {
    patchlevel=version;
  }
  printf("%s;%s;%s;%s;\n", osname, version, platform, patchlevel);
}' >>${outfile}
    fi

}

getrelease_Linux() {
    typeset outfile;
    typeset vendor;
    typeset arch;
    typeset model;

    outfile="$1";

    printf "string OSName;string version;string platform;string patchlevel;\n" >${outfile}

     if [ -e /etc/SuSE-release ]; then
 	gawk '{ 
   if($1~/^VERSION$/) {
     version=$NF;
   }
   if($1~/^PATCHLEVEL$/) {
     patchlevel=$NF;
   }
   if($1~/^SUSE$/) {
     platform=substr($NF, match($NF, "[a-z,A-Z,0-9,_,-]+"), RLENGTH);
     osname=substr($0, match($0, "[A-Z,a-z]* [A-Z,a-z]* [A-Z,a-z]* [A-Z,a-z]*"), RLENGTH);
   }
 }
 END {
   printf("%s;%s;%s;%s;\n", osname, version, platform, patchlevel);
 }' </etc/SuSE-release >>${outfile}
     else if [ -e /etc/redhat-release ]; then
 	arch=$(uname -m)
 	gawk '{
   if($1~/^Red$/) {
     osname=substr($0, match($0, "[A-Z,a-z]+ [A-Z,a-z]+ [A-Z,a-z]+ [A-Z,a-z]+ [A-Z,a-z]+"), RLENGTH);
     version=substr($0, match($0, "[0-9]+[.]"), RLENGTH-1)
     patchlevel=substr($0, match($0, "[.][0-9]+")+1, RLENGTH-1);
     "uname -m" | getline arch;
   }
 }
 END {
   printf("%s;%s;%s;%s;\n", osname, version, arch, patchlevel);
 }' </etc/redhat-release >>${outfile}
     fi
  fi    
}

gethardware_SunOS() {
    typeset outfile;
    typeset hardwaretype;
    typeset prtdiag_out;
    typeset productid;
    typeset sn;
    typeset hostid;
    
    outfile="$1";

    # default is "Other" when we can't figure out LDOM/Zone
    hardwaretype="Other";

    printf "string vendor;string arch;string systemtype;string hardwaretype;string serialnumber;string productid;string hostid;\n" >${outfile}
    hostid=$(/usr/bin/hostid)
    # if we are in a zone, skip this step and print generic data
    if [ x$(/usr/bin/zonename 2>/dev/null) == x -o x$(/usr/bin/zonename 2>/dev/null) == xglobal ]; then
	case $(uname -p) in
	    sparc)
		# are we running in a LDOM?
		if [ $(/usr/sbin/virtinfo -a 2>/dev/null | egrep -c "Domain role:.*LDoms" ) -gt 0 ]; then
		    # this is an LDom
		    hardwaretype="LDom"
		fi

		# there is no SKU number on sparc, so we just set it to whatever uname -i reports
		productid=$(uname -i)

		prtdiag_out=$(/usr/sbin/prtdiag -v)
	     
		case $(uname -m) in
		    sun4u)
			sn=$(/usr/sbin/eeprom | nawk '$2~/ChassisSerialNumber/ { print $3 }')
			;;
		    sun4us)
			sn=$(/usr/sbin/eeprom | nawk '$2~/ChassisSerialNumber/ { print $3 }')
			;;
		    sun4v) 
			sn=$(printf "${prtdiag_out}" | nawk '{if($0~/^Chassis Serial Number$/) { getline bars; getline sn; printf("%s\n", sn) } }')
			;;
		    *) my_abort 253 "Unsupported SPARC Platform";;
		esac
		# check if sn is still empty, then try sneep as last resort
		if [ x$sn == x ]; then
		    sn=$(/usr/sbin/sneep)
		fi

		printf "${prtdiag_out}" | head -1 | nawk '{
  if($0~/sun4us/) {
    vendor="Fujitsu Siemens";
    arch="sun4us";
    model=substr($0, match($0, "PRIME.*"));
  }
  if($0~/sun4u /) {
    vendor="Oracle Corporation";
    arch="sun4u";
    model=substr($0, match($0, "sun4u .*")+6, RLENGTH-6);
  }
  if($0~/sun4v /) {
    vendor="Oracle Corporation";
    arch="sun4v";
    model=substr($0, match($0, "sun4v .*")+6, RLENGTH-6);
  }
  
}
END {
  printf("%s;%s;%s;'${hardwaretype}';'${sn}';'${productid}';'${hostid}'\n", vendor, arch, model);
}' >>${outfile}
		;;
	    
	    i386)
		smbios_out=$(/usr/sbin/smbios -t SMB_TYPE_SYSTEM | sed -e 's,^[ ]*,,g;s,: ,:,g;s,[ ]*$,,g');
		vendor=$(printf "${smbios_out}" | egrep "^Manufacturer:" | cut -d ':' -f 2- )
		model=$(printf "${smbios_out}" | egrep "^Product:" | cut -d ':' -f 2- )
		arch=$(uname -m);
		sn=$(printf "${smbios_out}" | egrep "^Serial" | cut -d ':' -f 2- )
		productid=$(printf "${smbios_out}" | egrep "^SKU" | cut -d ':' -f 2- )
		printf "%s;%s;%s;Other;%s;%s;%s;\n" "${vendor}" "${arch}" "${model}" "${sn}" "${productid}" "${hostid}" >>${outfile}
		;;

	    *)
		my_abort 253 "Unsupported SunOS Platform"
		;;
	esac
    else
	# zonename reported not global or empty output, so we are in a zone
	printf "Virtual Vendor;%s;Solaris Container;Zone;%s;;%s;\n" $(uname -p) $(/usr/sbin/sneep) $(/usr/bin/hostid) >>${outfile}
    fi
}

gethardware_Linux() {
    typeset outfile;
    typeset dmidecode_out;
    typeset arch;
    typeset vendor;
    typeset model;
    typeset hardwaretype;
    typeset productid;
    typeset sn;
    typeset hostid;

    outfile="$1";

    printf "string vendor;string arch;string systemtype;string hardwaretype;string serialnumber;string productid;string hostid;\n" >${outfile}

    # default hardware-type is Other, until KVM/VMware is detected
    hardwaretype="Other"

    hostid=$(/usr/bin/hostid)

    dmidecode_out=$(/usr/sbin/dmidecode -t system | sed -e 's,: ,:,g;s,[ ]*$,,g')


    vendor=$(printf "${dmidecode_out}" | egrep "Manufacturer:" | cut -d ':' -f 2- )
    model=$(printf "${dmidecode_out}" | egrep "Product Name:" | cut -d ':' -f 2- )
    productid=$(printf "${dmidecode_out}" | egrep "SKU Number:" | cut -d ':' -f 2- )
    sn=$(printf "${dmidecode_out}" | egrep "Serial Number:" | cut -d ':' -f 2- )
    arch=$(uname -m);
    
    # if sn is empty or "Not specified", then try to get sn from hald
    if [ "x${sn}" == "x" -o "x${sn}" == "xNot Specified" ]; then
	sn=$(/usr/bin/hal-get-property --key system.hardware.serial --udi '/org/freedesktop/Hal/devices/computer')
    fi
    
    if [ "x${vendor}" == "xBochs" ]; then
	hardwaretype="KVM"
    fi
    if [ "x${vendor}" == "xQEMU" ]; then
	hardwaretype="KVM"
    fi
    if [ "x${vendor}" == "xVMware, Inc." ]; then
	hardwaretype="VMware"
    fi

    printf "%s;%s;%s;%s;%s;%s;%s;\n" "${vendor}" "${arch}" "${model}" "${hardwaretype}" "${sn}" "${productid}" "${hostid}" >>${outfile}
    
}

getunamesr() {
    typeset outfile;
    
    outfile="$1";

    printf "string kernelname;string release;\n" >${outfile}

    printf "%s;%s;\n" $(uname -sr) >>${outfile}
}

getunamesr_SunOS() {
    getunamesr "$1"
}

getunamesr_Linux() {
    getunamesr "$1"
}

getstatus() {
    typeset outfile;

    outfile="$1";

    printf "string timestamp;string generator;int version;string svnid;\n" >${outfile}

    printf "%s;%s;%i;%s;\n" "$(date +'%Y-%m-%d %H:%M:%S')" "$(basename $0)" ${VERSION} "${SVNVERSION}" >>${outfile};
}

getstatus_SunOS() {
    getstatus "$1"
}

getstatus_Linux() {
    getstatus "$1"
}

getvirtualsystems_SunOS() {
    typeset outfile;
    typeset zone;
    typeset ctrl_dom;
    typeset ldname;
    typeset ldstate;
    typeset ldflags;
    typeset ldcons;
    typeset ldvcpu;
    typeset ldmem;
    typeset ldrest;
    typeset ldpath;

    outfile="$1";
    
    # check if zoneadm exists...if not, bail out silently
    [ -x /usr/sbin/zoneadm ] || return 0

    # check if we are in the global zone, if not, bail out silently
    if [ x$(/usr/bin/zonename 2>/dev/null) != xglobal ]; then
	return 0
    fi

    printf "int id;string name;string status;string path;string brand;string ip;bool oracapped;int cpucap;int memcapbytes;int swapcapbytes;\n" >${outfile}

    # generate a list of zones and iterate over this list:
    for zone in $(zoneadm list -ci | egrep -v "^global$"); do
	# basic zone info: id, name, status, path, brand, ip-type...
	zoneadm -z ${zone} list -v | nawk '$1!~/^(ID|0)$/ { zoneid=$1;if($1~/^-$/) zoneid=""; printf("%s;%s;%s;%s;%s;%s;",zoneid,$2,$3,$4,$5,$6)}' >>${outfile}
	# capped-container? num of threads
	zonecfg -z ${zone} info dedicated-cpu | nawk -F ':' '
        BEGIN {
          capped="false";
        }
        { 
          if($1~/ncpus/) { 
            ncpus=$2+0;
            capped="true";
          }
        } END {
          printf("%s;%i;",capped,ncpus);
        }' >>${outfile}
	# capped ram, capped swap
	zonecfg -z ${zone} info capped-memory | nawk -F ':' '
        { 
          if($1~/physical/) {
            physmem=$2;
            multiple=1;
            if(physmem~/K$/) multiple=1024;
            if(physmem~/M$/) multiple=1024*1024;
            if(physmem~/G$/) multiple=1024*1024*1024;
            if(physmem~/T$/) multiple=1024*1024*1024*1024;
            physbytes=physmem*multiple;
          }
          if($1~/swap/) {
            swapmem=$2;
            multiple=1;
            if(swapmem~/K.$/) multiple=1024;
            if(swapmem~/M.$/) multiple=1024*1024;
            if(swapmem~/G.$/) multiple=1024*1024*1024;
            if(swapmem~/T.$/) multiple=1024*1024*1024*1024;
            swapbytes=swapmem*multiple;
          }
        } END { 
          printf("%s;%s;\n",physbytes,swapbytes); 
        }' >>${outfile}

    done

    # are we also serving ldoms?
    # first check for ldm command, else bail out
    [ -x /usr/sbin/ldm ] || return 0
    [ -x /usr/sbin/virtinfo ] || return 0
    
    # are we a control/primary domain?
    ctrl_dom=$(/usr/sbin/virtinfo -c current get -H -o value control-role logical-domain 2>/dev/null)
    if [ x${ctrl_dom} == xtrue ]; then
	/usr/sbin/ldm list -p 2>/dev/null | egrep "^DOMAIN" | \
	  sed -e 's,|[a-z,_]*=, ,g;s,^DOMAIN ,,g' | \
          while read ldname ldstate ldflags ldcons ldvcpu ldmem ldrest; do
	    # get disk path of ldom
	    ldpath=$(ldm list -p -o disk ${ldname} | nawk -F '|' '$1~/^VDISK$/ && $5~/disk@0/ { print $3 }' | sed -e 's/^vol=//g')
	    if [ x${ldname} == xprimary ]; then
		ldname=$(uname -n)
		ldcons=4999
	    fi 
	    printf "%s;%s;%s;%s;LDOM;excl;true;%s;%s;;\n" "${ldcons}" "${ldname}" "${ldstate}" "${ldpath}" "${ldvcpu}" "$(( ${ldmem} / 1024 / 1024 ))" >>${outfile}
	  done
    fi
}

getvirtualsystems_Linux() {
    typeset outfile;
    typeset vsys;
    typeset osname;
    typeset onepath;
    typeset virshout;
    typeset cpucap;
    typeset memcap;

    outfile="$1";

    # check if virsh exists...if not, bail out silently
    [ -x /usr/bin/virsh ] || return 0

    printf "int id;string name;string status;string path;string brand;string ip;bool oracapped;int cpucap;int memcapbytes;int swapcapbytes;\n" >${outfile}

    virshout=$(virsh list)

    for vsys in $(virsh list | gawk '$1~/[0-9]+/ { print $2 }'); do
	if [ $( echo ${vsys} | egrep -c "^one-" ) -gt 0  ]; then
	    onepath=$(ls -l $(virsh dumpxml ${vsys} | gawk -F \' '$0~/<source (dev|file)=.\/opt\/one\/datastores.*disk.0/ { print $2 }') | gawk '{ print $NF}')
	    osname=$(echo ${onepath} | cut -d '_' -f 2)
	else
	    osname=${vsys}
	    onepath=$(virsh dumpxml ${vsys} | gawk -F \' ' $0~/<source (dev|file)=.\/dev\/mapper/ { print $2 }' | head -1)
	fi
        #partitioning info
	cpucap=$(virsh dumpxml ${vsys} | gawk -F "[<>]" '$2~/^vcpu/ {print $3}')
	# no swap limiting...
	#virsh dumpxml one-601 | gawk -F '[<>'\'']' '$0~/memory/ { print $3" "$5 }'
        #KiB 16777216
	memcap=$( virsh dumpxml ${vsys} | gawk -F '[<>'\'']' '$0~/memory/ { physmem=$5; multiple=1; if($3~/^K/) multiple=1024; if($3~/^M/) multiple=1024*1024; if($3~/^G/) multiple=1024*1024*1024; if($3~/^T/) multiple=1024*1024*1024*1024; print physmem*multiple; }' )

	printf "${virshout}\n" | gawk '$2~/^'${vsys}'$/ { printf("%s;'${osname}';%s;'${onepath}';KVM;excl;false;'${cpucap}';'${memcap}';;\n",$1,$3) }' >>${outfile}
    done
    
}

getinterfaces4_SunOS() {
    typeset outfile;
    typeset iflist;
    typeset iface;
    typeset ifacep;
    typeset iftype;
    typeset lowerlink;
    typeset ether;
    typeset mtu;
    typeset ipaddr;
    typeset netmask;
    typeset broadcast;
    typeset iflags;
    typeset ipmpgrp;
    typeset grouptype
    typeset vlanid;
    typeset ifspeed;
    typeset duplex;

    outfile="$1";

    # this function prints out the configuration of the systems network interfaces (name, mac, ip, etc)

    # print header line
    printf "string linkname;string type;string lowerlinkname;string macaddr;int mtu;int vlanid;int ifspeed;string duplex;string ipaddr;string netmask;string broadcast;string flags;string grouptype;string group;\n" >${outfile}
   
    # get list of all ifconfig'd interfaces (yes, there may be more in the system)
    iflist=$(ifconfig -a4 | nawk '$1~/:$/ { nic=$1; sub(":$","",nic); print nic }')

    for iface in ${iflist}; do
	# we set ifacep here to the interface-name, without the trailing :n virtual interface
	ifacep=${iface%:*}

	# get mac addr
	ether=$(ifconfig ${ifacep} | nawk '$1~/^ether$/ { print $2 }')

	# is this interface part of a ipmp group?
	ipmpgrp=$(ifconfig ${iface} | nawk '$1~/^groupname$/ { print $2 }')

	# if we have a ipmp group set, set grouptype to "IPMP" (on linux, it will be "BOND")
	if ! [ x${ipmpgrp} = x ]; then
	    grouptype="IPMP"
	fi

	# get ip addr
	ipaddr=$(ifconfig ${iface} | nawk '$1~/^inet$/ { print $2 }')

	# get netmask and convert it from hex to dec
	netmask=$(printf "%d.%d.%d.%d\n" $(ifconfig ${iface} | nawk '$1~/^inet$/ {  printf("0x%s 0x%s 0x%s 0x%s\n", substr($4,1,2), substr($4,3,2), substr($4,5,2), substr($4,7,2))}'))

	# get broadcast
	broadcast=$(ifconfig ${iface} | nawk '$1~/^inet$/ { print $6 }')

	# get interface flags 
	iflags=$(ifconfig ${iface} | nawk '$2~/^flags/ { split($2,flags,"(<|>)"); printf("%s\n",flags[2])}')

	# get the mtu
	mtu=$(ifconfig ${iface} | nawk '$0~/ mtu / { split(substr($0,match($0," mtu ")),a," "); print a[2]; }')

	# here we gather interface stats which require release-dependend methods
	# get interface type: this can be various: a vnic (crossbow) or phys, while phys simply means it can be a virtualized physical adapter like vnet in ldoms
	# note: this is a feature on illumos, OpenSolaris and Solaris11 and up - for Solaris 10 and lower, we will always report "legacy"
	case $(uname -r) in
	    5.11)
		if [ $(ifconfig ${ifacep} | egrep -c "flags=.*LOOPBACK" ) -gt 0 ]; then
		    iftype="loopback"
		else 
		    if [ $(ifconfig ${ifacep} | egrep -c "flags=.*IPMP" ) -gt 0 ]; then
			iftype="ipmp"
		    else
			iftype=$(dladm show-link -p -o class ${ifacep})
		    fi
		fi
		case "${iftype}" in
		    vnic)
			lowerlink=$(dladm show-vnic -p -o over ${ifacep})
			ifspeed=$(dladm show-vnic -p -o speed ${ifacep})
			duplex="" # vnics have no duplex setting
			vlanid=$(dladm show-vnic -p -o vid ${ifacep})
			;;
		    aggr)
			lowerlink=$(dladm show-aggr -x -p -o port ${ifacep})
			ifspeed=$(dladm show-aggr -x -p -o speed ${ifacep} | head -1 | sed -e 's/Mb$//g')
			duplex=$(dladm show-aggr -x -p -o duplex ${ifacep} | head -1)
			vlanid=0 # this is always 0, as a aggr has no vlan id by itself and is always in the switch-ports native vlan (whatever that is, for the host it is 0 unless vlan tagged)
			;;
		    phys)
			lowerlink="" # this is a physical (or full virtualized) adapter and has no lower-links
			ifspeed=$(dladm show-phys -p -o speed ${ifacep})
			duplex=$(dladm show-phys -p -o duplex ${ifacep})
			vlanid=0 # this is always 0, as a phys has no vlan id by itself and is always in the switch-ports native vlan (whatever that is, for the host it is 0 unless vlan tagged)
			;;
		esac
		;;
	    5.10)
		if dladm show-link 2>&1 >/dev/null; then
		    # in branded zones, this one will not work...
		    iftype=$(dladm show-link ${ifacep} | nawk '{print $3}')
		    lowerlink=""
		    ifspeed=$(dladm show-dev ${ifacep} | nawk '{print $5}')
		    duplex=$(dladm show-dev ${ifacep} | nawk '{print $NF}')
		    # ok, this is a hack. tagged interfaces get a special instance on solaris: vlanid*100+physicalinstance
		    # this will always return the correct vlan
		    vlanid=$( echo ${ifacep} | nawk '{printf("%d\n", substr($0,match($0,"[0-9]+$"))/1000) }' )
		else
		    
		    if [ $(ifconfig ${ifacep} | egrep -c "flags=.*LOOPBACK" ) -gt 0 ]; then
			iftype="loopback"
		    else 
			if [ $(ifconfig ${ifacep} | egrep -c "flags=.*IPMP" ) -gt 0 ]; then
			    iftype="ipmp"
			else
			    iftype="" # we can't figure out what type the interface is
			fi
		    fi
		    lowerlink=""
		    ifspeed=$(kstat -p ::${ifacep}:ifspeed | nawk '{ printf("%d\n", $NF/1000/1000) }')
		    duplex="" # we can't figure out the duplex setting
		    # ok, this is a hack. tagged interfaces get a special instance on solaris: vlanid*100+physicalinstance
		    # this will always return the correct vlan
		    vlanid=$( echo ${ifacep} | nawk '{printf("%d\n", substr($0,match($0,"[0-9]+$"))/1000) }' )
		fi
		;;
	    5.9)
		iftype="legacy"
		lowerlink=""
		ifspeed=$(kstat -p ::${ifacep}:ifspeed | nawk '{ printf("%d\n", $NF/1000/1000) }')
		duplex="" # we can't figure out the duplex setting		
		# ok, this is a hack. tagged interfaces get a special instance on solaris: vlanid*100+physicalinstance
		# this will always return the correct vlan
		vlanid=$( echo ${ifacep} | nawk '{printf("%d\n", substr($0,match($0,"[0-9]+$"))/1000) }' )
		;;
	    *)
		# unsupported, so we print empty values
	        iftype=""
		lowerlink=""
		ifspeed=""
		duplex=""
		vlanid=""
		;;
	esac
	
	printf "%s;%s;%s;%s;%i;%i;%i;%s;%s;%s;%s;%s;%s;%s;\n" "${iface}" "${iftype}" "${lowerlink}" "${ether}" $(( ${mtu} + 0 )) $(( ${vlanid} + 0 )) $(( ${ifspeed} + 0 )) "${duplex}" "${ipaddr}" "${netmask}" "${broadcast}" "${iflags}" "${grouptype}" "${ipmpgrp}" >> ${outfile}
    done
    
}

getinterfaces4_Linux() {
    typeset outfile;
    typeset iflist;
    typeset iface;
    typeset ifacebuf;
    typeset iftype;
    typeset lowerlink;
    typeset ether;
    typeset mtu;
    typeset ipaddr;
    typeset netmask;
    typeset broadcast;
    typeset iflags;
    typeset bondgrp;
    typeset grouptype
    typeset vlanid;
    typeset ifspeed;
    typeset duplex;

    outfile="$1";

    # this function prints out the configuration of the systems network interfaces (name, mac, ip, etc)

    # print header line
    printf "string linkname;string type;string lowerlinkname;string macaddr;int mtu;int vlanid;int ifspeed;string duplex;string ipaddr;string netmask;string broadcast;string flags;string grouptype;string group;\n" >${outfile}
    
    # get list of all interfaces

    iflist=$( /sbin/ifconfig -a | gawk '$0~/Link encap:/ { print $1 }' )

    for iface in ${iflist}; do 
	# store output in a buffer, so we just have to call ifconfig once for each interface in ${iflist}
	ifacebuf=$(/sbin/ifconfig ${iface} )
	ether=$( printf "${ifacebuf}\n" | gawk '$0~/ HWaddr / {macaddr=substr($0,match($0,"HWaddr ")); split(macaddr,a," "); printf("%s\n",a[2])}' )
	mtu=$( printf "${ifacebuf}\n" | gawk '$0~/ MTU:/ {mtu=substr($0,match($0,"MTU:")); split(mtu,a,"[ :]"); printf("%s\n",a[2])}' )
	ipaddr=$( printf "${ifacebuf}\n" | gawk '$0~/inet addr:/ {ip=substr($0,match($0,"inet addr:")); split(ip,a,"[ :]"); printf("%s\n",a[3])}' )
	netmask=$( printf "${ifacebuf}\n" | gawk '$0~/inet .*Mask:/ {mask=substr($0,match($0,"Mask:")); split(mask,a,"[ :]"); printf("%s\n",a[2])}' )
	broadcast=$( printf "${ifacebuf}\n" | gawk '$0~/inet .*Bcast:/ {bcast=substr($0,match($0,"Bcast:")); split(bcast,a,"[ :]"); printf("%s\n",a[2])}' )
	iflags=$( printf "${ifacebuf}\n" |  gawk '$0~/ MTU:/ {printf("%s\n",substr($0,0,match($0,"  MTU:")));}' | sed -r 's/(^[ ]+|[ ]+$)//g')
	if [ -f /proc/net/vlan/config ]; then
	    vlanid=$(( $( gawk '$1~/^'${iface}'$/ { print $3 }' </proc/net/vlan/config ) + 0 ))
	else
	    vlanid=0
	fi
	ifspeed=$( /sbin/ethtool ${iface} 2>/dev/null| gawk '$1~/^Speed:$/ { printf("%d\n", $2) }')
	duplex=$( /sbin/ethtool ${iface} | gawk '$1~/^Duplex:$/ { print $2 }' )
	
	# check if we are a loopback and can skip the rest
	if [ $( echo ${iflags} | grep -c "LOOPBACK" ) -gt 0 ]; then
	    iftype=loopback;
	else
	    # check for bonding interface
	    if [ -f /proc/net/bonding/${iface} ]; then
		grouptype="BOND"
		iftype="bond"
		bondgrp=${iface}
		lowerlink=$( gawk '$1~/^Slave$/ && $2~/^Interface:$/ { printf("%s ", $NF) }' /proc/net/bonding/${iface} )
	    fi

	    # the only way to check if this interface is part of a BOND, is checking
	    # for the "SLAVE" iflag and the iterating over all /proc/net/bonding/* 
	    # files and look for ifname in there
	    if [ $( echo ${iflags} | grep -c "SLAVE" ) -gt 0 ]; then
		for bondgrp in $(ls /proc/net/bonding); do
		    if [ x$(gawk '$0~/^Slave Interface: '${iface}'$/ { print $NF }' </proc/net/bonding/${bondgrp}) = x${iface} ]; then
			grouptype="BOND"
			break # we found our interface
		    fi
		done
	    fi

	    # check if we are a bridge
	    if [ -d /sys/class/net/${iface}/bridge ]; then
		iftype="bridge"
		lowerlink=$( brctl show ${iface} | gawk '$0!~/^bridge name/ { printf("%s ", $NF) }' )
	    fi
	fi
	printf "%s;%s;%s;%s;%i;%i;%i;%s;%s;%s;%s;%s;%s;%s;\n" "${iface}" "${iftype}" "${lowerlink}" "${ether}" $(( ${mtu} + 0 )) $(( ${vlanid} + 0 )) $(( ${ifspeed} + 0 )) "${duplex}" "${ipaddr}" "${netmask}" "${broadcast}" "${iflags}" "${grouptype}" "${bondgrp}" >> ${outfile}

	# clear ${ifacebuf} and stuff
	ifacebuf=""
	bond=""
	bondgrp=""
	grouptype=""
	iftype=""

    done
}

getvmmap_SunOS() {
    typeset outfile;
    
    outfile="$1";

    # FIXME
    return 0
}

getvmmap_Linux() {
    typeset outfile;
    typeset onevmlist;
    typeset onevmid;
    typeset onevmname;
    typeset oneclusterid;
    typeset oneclustername;
    typeset onehostidlist;
    typeset onehostid;
    typeset onehostnamelist;
    typeset onerunhost;
    typeset memberid;

    outfile="$1";

    # this function generates a map of virtual machines and their 
    if ! [ -x /usr/bin/onevm ]; then
	# skip this function, as this is not a OpenNebula management node
	return 0
    fi

    # print header
    printf "string guestname;string clustername;string hostservers;string defaultserver;string switchmethod;\n" >${outfile}
    
    # get a list of all ONE VM IDs and store it in a cache file
    onevm list | gawk '$1~/^[0-9]+$/ { printf("%s %s\n",$4,$8)}' >${WORKDIR}/.onevmmap
    onevmlist=$( gawk '{ print $1 }' <${WORKDIR}/.onevmmap )
    
    # for every VM ID, we get the cluster id it is bound to
    for onevmname in ${onevmlist}; do
	# cache a map table for host names
	if ! [ -f ${WORKDIR}/.onehostmap ]; then
	    onehost list | gawk '{printf("%s %s\n",$2,$3)}' >${WORKDIR}/.onehostmap
	fi

	onerunhost=$( gawk '$1~/^'${onevmname}'$/ { print $2 }' <${WORKDIR}/.onevmmap )
	oneclustername=$( gawk '$1~/^'${onerunhost}'$/ { print $2 }' <${WORKDIR}/.onehostmap )
	onehostnamelist=$( gawk '$2~/^'${oneclustername}'$/ { printf("%s ",$1)}' <${WORKDIR}/.onehostmap )

	printf "%s;%s;%s;%s;%s;\n" "${onevmname}" "${oneclustername}" "${onehostnamelist}" "${onerunhost}" "OpenNebula" >>${outfile}
	# reset onehostnamelist
	onehostnamelist=""
    done

    # clean up cache files
    rm -f ${WORKDIR}/.onehostmap
    rm -f ${WORKDIR}/.onevmmap
}

valid_SunOS() {
    return 0;
}

valid_Linux() {
    return 0;
}

valid_AIX() {
    return 42;
}

# main #
########

# static and global defines
HOSTNAME=$(uname -n)
MEMCONF=/usr/local/bin/memconf
WORKDIR=/var/tmp/datacollectorwdir
WEBBASE="https://download-server/software"
DAVBASE="https://dataserver/infostore"
WEBUSER="upload"
WEBPASS="PASSWORD"
PATH="$PATH:/usr/sfw/bin:/opt/sfw/bin:/usr/local/bin"

# DO NOT CHANGE
VERSION=13
SVNVERSION='$Id: $'
# local variables
typeset workfile

# create workdir if not exists
mkdir -p /${WORKDIR}
# clean up workdir
rm -f /${WORKDIR}/* 2>&1 >/dev/null

# check if memconf exists - if not, copy from webserver

if ! [ -x /usr/local/bin/memconf ]; then
    mkdir -p /usr/local/bin
    curl -k -G ${WEBBASE}/memconf >/usr/local/bin/memconf 2>/dev/null
    chmod 755 /usr/local/bin/memconf
fi

unames=$(uname -s)
if ! [ valid_${unames} ]; then
	my_abort 255 "Unsupported OS"
fi

# generate system outputs
getcpu_${unames} ${WORKDIR}/${HOSTNAME}.cpu.csv
getram_${unames} ${WORKDIR}/${HOSTNAME}.ram.csv
getrelease_${unames} ${WORKDIR}/${HOSTNAME}.release.csv
gethardware_${unames} ${WORKDIR}/${HOSTNAME}.hardware.csv
getunamesr_${unames} ${WORKDIR}/${HOSTNAME}.unamesr.csv
getvirtualsystems_${unames} ${WORKDIR}/${HOSTNAME}.virtualsystems.csv
getinterfaces4_${unames} ${WORKDIR}/${HOSTNAME}.interfaces.csv
getstatus_${unames} ${WORKDIR}/${HOSTNAME}.status.csv
getvmmap_${unames} ${WORKDIR}/${HOSTNAME}.vmmap.csv

# prepare webdav directory structure
dav_prep "${WEBUSER}" "${WEBPASS}" "${DAVBASE}/${HOSTNAME}"
# push all resulting outputs to webdav server for infotool
for workfile in ${WORKDIR}/*csv; do
    dav_push "${WEBUSER}" "${WEBPASS}" ${DAVBASE}/${HOSTNAME}/ ${workfile}
done

# finally check for an update of this script and activate for next call
check_update ${WEBBASE}
if [ -f /usr/local/sbin/datacollector-update.ksh ]; then
    chmod 755 /usr/local/sbin/datacollector-update.ksh
    mv /usr/local/sbin/datacollector-update.ksh /usr/local/sbin/datacollector.ksh
    exit $?
fi
