#!/bin/sh
# Filename:      grml-hwinfo
# Purpose:       get hardware information
# Authors:       grml-team (grml.org), (c) Michael Prokop <mika@grml.org>
# Bug-Reports:   see http://grml.org/bugs/
# License:       This file is licensed under the GPL v2.
################################################################################
# Notice: Some ideas have been taken from
# http://club.black.co.at/david/hwdb/infodump
# by David Schmitt <david@schmitt.edv-bus.at>
################################################################################

# variables
UNAME="$(uname -r)"
PN="$(basename $0)"
[ -n "$WORKING_DIR" -a -d "$WORKING_DIR" ] || WORKING_DIR=$(pwd)
VERSION='0.4.1'

# data collection should not be affected by user locale
export LANG=C
export LC_ALL=C

TIMESTAMP='+%F--%H-%M-%S-%Z'
DATE="$(date $TIMESTAMP)"

echo "$PN ${VERSION} - collect hardware information"

GENERATE_FILE='1'
GENERATE_DIRECTORY=''

while getopts "hdf" args; do
  case "$args" in
  h) echo "
This tool collects information of the hardware this tool is being executed
on.  It can be executed as normal user to collect some basic information or
with root permissions to collect as much information as possible.  By
default, a file named grml-hwinfo-TIMESTAMP.tar.bz2 storing all collected
information will be created in the current working directory. Alternatively,
you can have it create a directory with all information.

Options:

  -h    Display this help message
  -f    Create grml-hwinfo-TIMESTAMP.tar.bz2
  -d    Create grml-hwinfo-TIMESTAMP as a directory
  -df   Create both, the directory and the file
"

  exit 0;;

  d)
  GENERATE_FILE=''
  GENERATE_DIRECTORY='1'
  ;;

  f) # generating file; default behaviour
  GENERATE_FILE='1'
  ;;

  esac
  done

# Generate output/temporary directory name & path, and output file path
OUTFILE=""
OUTDIRNAME="grml-hwinfo-${DATE}"
OUTDIR="${WORKING_DIR}/${OUTDIRNAME}"
mkdir "${OUTDIR}" || { echo 'Directory "'${OUTDIR}'" already exists, aborting.'>&2 ; exit 1; }

if [ -n "$GENERATE_FILE" ] ; then
   OUTFILE_="${OUTDIR}.tar.bz2"
   [ -e "${OUTFILE_}" ] && { echo 'File "'${OUTFILE_}'" already exists, aborting.'>&2 ; rm -r "${OUTDIR}"; exit 1; }
   OUTFILE=${OUTFILE_}
   touch "${OUTFILE}"
fi

if [ "$(id -u)" != "0" ] ; then
   NOTROOT=1
   echo "W: Running without root permissions. Not all data will be collected."
fi

# check whether a binary is available and executable
exectest() {
if [ -z "$1" ] ; then
   echo 'Usage: exectest <binary>'>&2
   return 1
else
   test -e "$(which $1)" && return 0 || return 1
fi
}

# echo a list of all disks and their size
# taken from http://cvs.debian.org/fai/lib/disk-info
diskandsize() {
    local isdisk major minor blocks device suffix
    while read major minor blocks device suffix; do
        isdisk=1
        # skip ide cdrom
        [ -f /proc/ide/$device/media ] && grep -q cdrom /proc/ide/$device/media && isdisk=0
        [ "$isdisk" -eq 1 ] && echo "$device $blocks"
    done
}

list_disks() {
# print only every second entry; used by disk_info
i=0
for ent in $@; do
    if [ "$i" -eq 0 ]; then
        echo $ent
        i=1
    else
        i=0
    fi
done
}

disk_info() {
    # the variable holds a space separated list of devices and their block size
    device_size=`grep -E ' cciss/c.d.$| ida/c.d.$| rd/c.d.$| hd.$| sd.$|/disc$' /proc/partitions | diskandsize`
    # a list of all local disks, without size
    disklist=`list_disks $device_size`
}


cd "${OUTDIR}" || exit 1
(
  [ -n "$GENERATE_FILE" ]      && echo "Output file:      $OUTFILE"
  [ -n "$GENERATE_DIRECTORY" ] && echo "Output directory: $OUTDIR"
  echo
  echo "This might take a few seconds/minutes. Please be patient..."

# some sysinfo
  date > date
  if [ -r /etc/grml_version ] ; then
     cat /etc/grml_version > grml_version
  fi
  if [ -r /etc/debian_version ] ; then
     cat /etc/debian_version > debian_version
  fi
  uname -a > uname

# disks / devices
  [ -f /proc/scsi/scsi ] && cat /proc/scsi/scsi > scsi
  (lspci; lspci -n) | sort > lspci
  [ -r /proc/bus/pnp ] && lspnp > lspnp
  [ -r /proc/bus/usb ] && lsusb > lsusb
  cat /proc/partitions > partitions
  find /proc/ide/ -name geometry -exec grep . {} \; > proc_ide 2>/dev/null
  df -h > df 2>/dev/null
  for i in free lsmod mount lsdev ; do
      exectest $i  && $i > $i
  done

# proc stuff
  for i in cpuinfo interrupts cmdline devices dma fb iomem ioports \
    mdstat meminfo modules mtrr pci version ; do
    [ -r /proc/$i ] && cat /proc/$i > proc_$i
  done
  exectest sysdump  && sysdump > sysdump 2>sysdump.error
# for sysnet in `find /proc/sys/net/*/ -type f | grep -v flush`; do cat $sysnet >> sysnet ; done

# log
  dmesg > dmesg.cur

# hwinfo
  exectest discover && discover -v --type-summary --enable-bus all > discover 2> discover.2
  exectest hwinfo   && hwinfo log=hwinfo
  exectest x86info  && x86info > x86info 2>x86info.2

# net stuff
  exectest ifconfig  && ifconfig -v -a  > ifconfig
  exectest ip        && ip route show   > ip_route
  exectest ip        && ip link show    > ip_link
  exectest route     && route -n        > route

# software
  if exectest dpkg ; then
     dpkg --get-selections   > dpkg_get_selections
     COLUMNS=300 dpkg --list > dpkg_list
     COLUMNS=1000 dpkg -l linux-image-$UNAME | grep linux-image-$UNAME | tr -s ' ' > running_kernel
  fi

# power management
  exectest laptop-detect  && laptop-detect >/dev/null 2>/dev/null && echo "0" > laptop_detected
  exectest acpi_available && acpi_available && cat /proc/acpi/info > acpi_info
  exectest acpi && acpi > acpi 2> acpi.error && acpi -v > acpi.version
  [ -r /proc/apm/ ] && apm > apm

# kernel stuff
  if [ -r /proc/config.gz ] ; then
     zcat /proc/config.gz > kernelconfig
  else
     [ -r /boot/config-$UNAME ] && cat /boot/config-$UNAME > kernelconfig
  fi

# X stuff
  if [ -n "${DISPLAY}" ] ; then
     exectest xviddetect  && xviddetect         > xviddetect
     exectest xvidtune    && xvidtune -show     > xdivtune
     exectest xrandr      && xrandr             > xrandr
     exectest xdpyinfo    && xdpyinfo           > xdpyinfo
     X -version > x_version 2>&1
  fi

  for i in Xorg.0.log Xorg.7.log Xorg.8.log XFree86.0.log XFree86.7.log XFree86.8.log dmesg ; do
      cp /var/log/$i log_$i 2>/dev/null
  done

  cp /etc/X11/xorg.conf    xorg.conf    2>/dev/null
  cp /etc/modules          modules      2>/dev/null
  cp /etc/X11/XF86Config-4 XF86Config-4 2>/dev/null

# not available:
# sysinfo -class device -level all

# as root:
if [ -n "$NOTROOT" ] ; then
   echo "not running as root" > root
else
   echo "running as root" > root
   disk_info
   exectest sfdisk     && sfdisk -d > sfdisk 2>sfdisk.error
   exectest ddcprobe   && ddcprobe  > ddcprobe
   exectest dmidecode  && dmidecode > dmidecode

   exectest dconf && dconf -o dconf

   if [ -x /usr/share/doc/lm-sensors/examples/eeprom/decode-dimms.pl ] ; then
      /usr/share/doc/lm-sensors/examples/eeprom/decode-dimms.pl > decode-dimms 2>decode-dimms.error
   fi

   for disk in $disklist; do
      exectest smartctl  && echo "smartctl -a /dev/$disk :\n" >> smartctl && smartctl -a /dev/$disk       >> smartctl             && echo "\n\n" >> smartctl
      exectest hdparm    && echo "hdparm -iv  /dev/$disk :\n" >> hdparm   && hdparm -iv  /dev/$disk       >> hdparm               && echo "\n\n" >> hdparm
      exectest fdisk     && echo "fdisk -lu   /dev/$disk :\n" >> fdisk    && fdisk -lu   /dev/$disk       >> fdisk 2>>fdisk.error && echo "\n\n" >> fdisk
      exectest parted    && echo "parted -s   /dev/$disk :\n" >> parted   && parted -s   /dev/$disk print >> parted               && echo "\n\n" >> parted
      file -s /dev/$disk?* | grep -v ": empty" >> file_disk
   done
fi
)

echo

cd "${WORKING_DIR}"

# create tarball
if [ -n "$GENERATE_FILE" ] ; then
  tar jcf "${OUTFILE}" "${OUTDIRNAME}"
  [ -r "$OUTFILE" ] && echo "$OUTFILE ("$(ls -ahl "$OUTFILE" | awk '{print $5}')") has been generated."
fi

# remove (temporary) output directory if needed, else keep it, as it doubles
# as the real output directory.
if [ -z "$GENERATE_DIRECTORY" ] ; then
  rm -r "${OUTDIR}"
else
  [ -r "${OUTDIR}" ] && echo "${OUTDIR} has been generated."
fi

exit 0

## END OF FILE##################################################################
