#!/bin/bash # Filename: grml-hwinfo # Purpose: get hardware information # Authors: grml-team (grml.org), (c) Michael Prokop # 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 ################################################################################ # variables UNAME="$(uname -r)" PN="$(basename "$0")" [ -n "$WORKING_DIR" -a -d "$WORKING_DIR" ] || WORKING_DIR=$(pwd) VERSION='***UNRELEASED***' # 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)" # defaults GENERATE_FILE='1' GENERATE_DIRECTORY='' _opt_output_directory=false _opt_output_file=false _opt_quiet=false _opt_force=false usage() { echo " This tool collects information of the hardware it is being executed on. It can be executed as normal user to collect some basic information or (recommended) with root permissions to collect more system information. If executed without any options a file named grml-hwinfo-TIMESTAMP.tar.bz2 storing all collected information is created in the current working directory. Options: -b, --both Create directory + file grml-hwinfo-TIMESTAMP.tar.bz2 -d, --directory Create grml-hwinfo-TIMESTAMP as a directory (no file) -f, --file Create grml-hwinfo-TIMESTAMP.tar.bz2 [default action] -h, --help Display this help message -q, --quiet Don't display informational text (useful for cron usage) --force Don't abort but overwrite possibly existing output file --output-directory Store output files in specified directory --output-file Store output in specified filename (tar.XX format) " } CMDLINE_OPTS=output-directory:,output-file:,both,directory,file,help,quiet,force _opt_temp=$(getopt --name grml-hwinfo -o +bdfhq --long $CMDLINE_OPTS -- "$@") if [ $? -ne 0 ]; then echo "Try 'grml-hwinfo --help' for more information." >&2 exit 1 fi eval set -- "$_opt_temp" while :; do case "$1" in --help|-h) usage ; exit 0 ;; --output-directory) shift; OUTDIRNAME="$1" GENERATE_DIRECTORY='1' _opt_output_directory=true $_opt_output_file && GENERATE_FILE='1' || GENERATE_FILE='' ;; --output-file) shift; OUTFILE="$1" GENERATE_FILE='1' _opt_output_file=true $_opt_output_directory && GENERATE_DIRECTORY='1' || GENERATE_DIRECTORY='' ;; -d|--directory) GENERATE_DIRECTORY='1' GENERATE_FILE='' ;; -f|--file) GENERATE_DIRECTORY='' GENERATE_FILE='1' ;; -b|--both) GENERATE_DIRECTORY='1' GENERATE_FILE='1' ;; -q|--quiet) _opt_quiet=true ;; --force) _opt_force=true ;; --) shift; break ;; *) echo "Internal getopt error!" >&2 exit 1 ;; esac shift done if ! $_opt_quiet ; then echo "$PN ${VERSION} - collect hardware information" fi # Generate output/temporary directory name & path, and output file path [ -n "$OUTDIRNAME" ] || OUTDIRNAME="grml-hwinfo-${DATE}" if $_opt_output_directory ; then OUTDIR="${OUTDIRNAME}" else OUTDIR="${WORKING_DIR}/${OUTDIRNAME}" fi if $_opt_force ; then mkdir -p "${OUTDIR}" else mkdir "${OUTDIR}" || { echo "Directory '${OUTDIR}' already exists, aborting." >&2 ; exit 1; } fi if [ -n "$GENERATE_FILE" ] ; then [ -n "$OUTFILE" ] && OUTFILE_="$OUTFILE" || OUTFILE_="${OUTDIR}.tar.bz2" if ! $_opt_force ; then [ -e "${OUTFILE_}" ] && { echo "File '${OUTFILE_}' already exists, aborting." >&2 ; rm -r "${OUTDIR}"; exit 1; } fi OUTFILE=${OUTFILE_} touch "${OUTFILE}" fi if [ "$(id -u)" != "0" ] ; then NOTROOT=1 $_opt_quiet || 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 '>&2 return 1 else if test -e "$(which "$1")" ; then return 0 else if ! grep -q "^$1"'$' missing_tools 2>/dev/null ; then $_opt_quiet || echo "$1" >> missing_tools fi return 1 fi fi } # based on https://github.com/faiproject/fai/blob/master/lib/fai-disk-info checkdisk() { local isdisk device while read _ _ _ device _ ; do isdisk=1 # skip CDROMs [ "$(stat -c %G /dev/"${device}")" = "disk" ] || isdisk=0 [ "$isdisk" -eq 1 ] && echo "$device" done } disk_info() { # the variable holds a newline separated list of devices disklist=$(egrep ' etherd/e[[:digit:]]+\.[[:digit:]]+\b| i2o/hd.+\b| cciss/c.+d.+\b| ida/c.+d.+\b| rd/c.+d.+\b| fio.\b| hd.\b| sd[a-z]{1,2}\b|/disc\b| vd.\b| xvd.\b' /proc/partitions | checkdisk) } cd "${OUTDIR}" || exit 1 ( if ! $_opt_quiet ; then [ -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..." fi # 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 exectest lspci && lspci -nn > ./lspci 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 lspnp lsusb ; do exectest $i && $i > ./$i done swapon -s > ./swapon 2>./swapon.error # 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 # log dmesg > dmesg.cur # hwinfo exectest discover && discover -v --type-summary --enable-bus all > ./discover 2>./discover.error exectest hwinfo && hwinfo log=hwinfo exectest numactl && numactl --hardware > ./numactl exectest x86info && x86info > ./x86info 2>./x86info.error exectest lscpu && lscpu > ./lscpu # net stuff, net-tools: exectest ifconfig && ifconfig -v -a > ./ifconfig exectest route && route -n > ./route # net stuff, iproute: exectest ip && ip addrlabel list > ip_addrlabel exectest ip && ip addr show > ip_addr exectest ip && ip link show > ip_link exectest ip && ip maddr show > ip_maddr exectest ip && ip mroute show > ip_mroute exectest ip && ip mrule show > ip_mrule 2>ip_mrule.error exectest ip && ip neigh show > ip_neigh exectest ip && ip netns list > ip_netns exectest ip && ip ntable show > ip_ntable exectest ip && ip route show > ip_route exectest ip && if [ -r /etc/iproute2/rt_tables ] ; then grep -v '^#' /etc/iproute2/rt_tables | while read table _ ; do ip route show table "${table}" > "ip_route_table_${table}" done fi exectest ip && ip rule show > ip_rule exectest ip && ip tunnel show > ip_tunnel exectest ip && ip tuntap show > ip_tuntap # software if exectest dpkg ; then dpkg --get-selections > dpkg_get_selections COLUMNS=300 dpkg --list > dpkg_list fi # power management exectest laptop-detect && laptop-detect >/dev/null 2>/dev/null && echo "0" > laptop_detected if [ -r /proc/acpi/info ] ; then cat /proc/acpi/info > acpi_info fi if exectest acpi ; then acpi > ./acpi 2>acpi.error acpi --everything > ./acpi.everything 2>./acpi.everything.error acpi -v > ./acpi.version fi [ -r /proc/apm/ ] && apm > ./apm if exectest mcelog ; then mcelog > ./mcelog 2>./mcelog.error fi # kernel stuff if [ -r /proc/config.gz ] ; then zcat /proc/config.gz > kernelconfig else [ -r "/boot/config-${UNAME}" ] && cat "/boot/config-${UNAME}" > kernelconfig fi exectest dpkg && COLUMNS=1000 dpkg -l "linux-image-${UNAME}" 2>running_kernel.error \ | grep "linux-image-${UNAME}" | tr -s ' ' > running_kernel 2>>running_kernel.error dpkg -S "/boot/vmlinuz-$(uname -r)" >> running_kernel 2>>running_kernel.error # 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 # 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 dmidecode && dmidecode > ./dmidecode exectest dconf && dconf -o dconf if exectest mcelog ; then mcelog --dmi > mcelog_dmi 2>mcelog_dmi.error fi if exectest edac-util ; then edac-util > ./edac-util 2>./edac-util.error edac-util --report=full > edac-util_report 2>edac-util_report.error fi if exectest decode-dimms ; then decode-dimms > ./decode-dimms 2>./decode-dimms.error elif [ -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 # proxmox exectest qm && qm list > ./qm 2>./qm.error # libvirt exectest virsh && virsh list >./virsh 2>./virsh.error # openvz exectest vzlist && vzlist >./vzlist 2>./vzlist.error # vserver exectest vserver-stat && vserver-stat >./vserver-stat 2>./vserver-stat.error exectest mdadm && mdadm --detail /dev/md[0-9]* >> ./mdadm 2>./mdadm.error # LVM exectest pvs && pvs > ./pvs 2>./pvs.error exectest vgs && vgs > ./vgs 2>./vgs.error exectest lvs && lvs > ./lvs 2>./lvs.error exectest lvdisplay && lvdisplay > ./lvdisplay 2>./lvdisplay.error exectest dmsetup && dmsetup ls > dmsetup_ls 2>dmsetup_ls.error exectest dmsetup && dmsetup ls --tree > dmsetup_ls_tree 2>dmsetup_ls_tree.error exectest lsblk && lsblk > ./lsblk 2>./lsblk.error # iSCSI if exectest iscsiadm ; then iscsiadm -m session > iscsiadm_session 2>iscsiadm_session.error iscsiadm -m fw > iscsiadm_fw 2>iscsiadm_fw.error iscsiadm -m host > iscsiadm_host 2>iscsiadm_host.error iscsiadm -m iface > iscsiadm_iface 2>iscsiadm_iface.error iscsiadm -m node > iscsiadm_node 2>iscsiadm_node.error iscsiadm -m discovery > iscsiadm_discovery 2>iscsiadm_discovery.error fi if exectest lsscsi ; then lsscsi > ./lsscsi 2>./lsscsi.error lsscsi -t > ./lsscsi_transport 2>./lsscsi_transport.error fi for disk in $disklist; do if exectest smartctl ; then echo -e "smartctl -a /dev/${disk}:\n" >> smartctl smartctl -a "/dev/$disk" >> ./smartctl echo -e "\n\n" >> ./smartctl fi if exectest hdparm ; then echo -e "hdparm -iv /dev/${disk}:\n" >> hdparm hdparm -iv "/dev/$disk" >> ./hdparm 2>> ./hdparm.error echo -e "\n\n" >> hdparm fi if exectest fdisk ; then echo -e "fdisk -lu /dev/${disk}:\n" >> fdisk fdisk -lu "/dev/$disk" >> ./fdisk 2>> ./fdisk.error echo -e "\n\n" >> fdisk fi if exectest parted ; then echo -e "parted -s /dev/${disk}:\n" >> parted parted -s "/dev/$disk" print >> ./parted echo -e "\n\n" >> parted fi if exectest sdparm ; then echo -e "sdparm --all --long /dev/${disk}:\n" >> sdparm sdparm --all --long "/dev/$disk" >> ./sdparm echo -e "\n\n" >> sdparm fi if exectest sg_inq ; then echo -e "sg_inq /dev/${disk}:\n" >> sg_inq sg_inq "/dev/$disk" >> ./sg_inq 2>> ./sg_inq.error echo -e "\n\n" >> sg_inq fi file -s "/dev/${disk}"?* | grep -v ": empty" >> file_disk done fi ) # get rid of empty files for file in *.error ; do test -s "$file" || rm -- "$file" done $_opt_quiet || echo cd "${WORKING_DIR}" # create tarball if [ -n "$GENERATE_FILE" ] ; then tar acf "${OUTFILE}" "${OUTDIRNAME}" if ! $_opt_quiet ; then # shellcheck disable=SC2012 [ -r "$OUTFILE" ] && echo "$OUTFILE ($(ls -ahl -- "$OUTFILE" | awk '{print $5}')) has been generated." fi 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 if ! $_opt_quiet ; then [ -r "${OUTDIR}" ] && echo "${OUTDIR} has been generated." fi fi exit 0 ## END OF FILE##################################################################