Support lscpu, lsblk and dmsetup ls --tree
[grml-hwinfo.git] / grml-hwinfo
1 #!/bin/bash
2 # Filename:      grml-hwinfo
3 # Purpose:       get hardware information
4 # Authors:       grml-team (grml.org), (c) Michael Prokop <mika@grml.org>
5 # Bug-Reports:   see http://grml.org/bugs/
6 # License:       This file is licensed under the GPL v2.
7 ################################################################################
8 # Notice: Some ideas have been taken from
9 # http://club.black.co.at/david/hwdb/infodump
10 # by David Schmitt <david@schmitt.edv-bus.at>
11 ################################################################################
12
13 # variables
14 UNAME="$(uname -r)"
15 PN="$(basename $0)"
16 [ -n "$WORKING_DIR" -a -d "$WORKING_DIR" ] || WORKING_DIR=$(pwd)
17 VERSION='***UNRELEASED***'
18
19 # data collection should not be affected by user locale
20 export LANG=C
21 export LC_ALL=C
22
23 TIMESTAMP='+%F--%H-%M-%S-%Z'
24 DATE="$(date $TIMESTAMP)"
25
26 echo "$PN ${VERSION} - collect hardware information"
27
28 # defaults
29 GENERATE_FILE='1'
30 GENERATE_DIRECTORY=''
31 _opt_output_directory=false
32 _opt_output_file=false
33
34 usage() {
35   echo "
36   This tool collects information of the hardware it is being executed on.
37   It can be executed as normal user to collect some basic information or
38   (recommended) with root permissions to collect more system information.
39   If executed without any options a file named grml-hwinfo-TIMESTAMP.tar.bz2
40   storing all collected information is created in the current working directory.
41
42   Options:
43
44   -b, --both                 Create directory + file grml-hwinfo-TIMESTAMP.tar.bz2
45   -d, --directory            Create grml-hwinfo-TIMESTAMP as a directory (no file)
46   -f, --file                 Create grml-hwinfo-TIMESTAMP.tar.bz2 [default action]
47   -h, --help                 Display this help message
48   --output-directory <dir>   Store output files in specified directory
49   --output-file <file>       Store output in specified filename (tar.bz2 format)
50   "
51 }
52
53 CMDLINE_OPTS=output-directory:,output-file:,both,directory,file,help
54 _opt_temp=$(getopt --name grml-hwinfo -o +bdfh --long $CMDLINE_OPTS -- "$@")
55 if [ $? -ne 0 ]; then
56   echo "Try 'grml-hwinfo --help' for more information." >&2
57   exit 1
58 fi
59 eval set -- "$_opt_temp"
60
61 while :; do
62   case "$1" in
63   --help|-h)
64     usage ; exit 0
65     ;;
66   --output-directory)
67     shift; OUTDIRNAME="$1"
68     GENERATE_DIRECTORY='1'
69     _opt_output_directory=true
70     $_opt_output_file && GENERATE_FILE='1' || GENERATE_FILE=''
71     ;;
72   --output-file)
73     shift; OUTFILE="$1"
74     GENERATE_FILE='1'
75     _opt_output_file=true
76     $_opt_output_directory && GENERATE_DIRECTORY='1' || GENERATE_DIRECTORY=''
77     ;;
78   -d|--directory)
79     GENERATE_DIRECTORY='1'
80     GENERATE_FILE=''
81     ;;
82   -f|--file)
83     GENERATE_DIRECTORY=''
84     GENERATE_FILE='1'
85     ;;
86   -b|--both)
87     GENERATE_DIRECTORY='1'
88     GENERATE_FILE='1'
89     ;;
90   --)
91     shift; break
92     ;;
93   *)
94     echo "Internal getopt error!" >&2
95     exit 1
96     ;;
97   esac
98   shift
99 done
100
101 # Generate output/temporary directory name & path, and output file path
102 [ -n "$OUTDIRNAME" ] || OUTDIRNAME="grml-hwinfo-${DATE}"
103 OUTDIR="${WORKING_DIR}/${OUTDIRNAME}"
104 mkdir "${OUTDIR}" || { echo 'Directory "'${OUTDIR}'" already exists, aborting.'>&2 ; exit 1; }
105
106 if [ -n "$GENERATE_FILE" ] ; then
107   [ -n "$OUTFILE" ] && OUTFILE_="$OUTFILE" || OUTFILE_="${OUTDIR}.tar.bz2"
108   [ -e "${OUTFILE_}" ] && { echo 'File "'${OUTFILE_}'" already exists, aborting.'>&2 ; rm -r "${OUTDIR}"; exit 1; }
109   OUTFILE=${OUTFILE_}
110   touch "${OUTFILE}"
111 fi
112
113 if [ "$(id -u)" != "0" ] ; then
114   NOTROOT=1
115   echo "W: Running without root permissions. Not all data will be collected."
116 fi
117
118 # check whether a binary is available and executable
119 exectest() {
120   if [ -z "$1" ] ; then
121     echo 'Usage: exectest <binary>'>&2
122     return 1
123   else
124     if test -e "$(which $1)" ; then
125       return 0
126     else
127       grep -q "^$1"'$' missing_tools 2>/dev/null || echo "$1" >> missing_tools
128       return 1
129     fi
130   fi
131 }
132
133 # echo a list of all disks and their size
134 # taken from http://cvs.debian.org/fai/lib/disk-info
135 diskandsize() {
136   local isdisk major minor blocks device suffix
137   while read major minor blocks device suffix; do
138     isdisk=1
139     # skip ide cdrom
140     [ -f /proc/ide/$device/media ] && grep -q cdrom /proc/ide/$device/media && isdisk=0
141     [ "$isdisk" -eq 1 ] && echo "$device $blocks"
142   done
143 }
144
145 list_disks() {
146   # print only every second entry; used by disk_info
147   i=0
148   for ent in $@; do
149     if [ "$i" -eq 0 ]; then
150       echo $ent
151       i=1
152     else
153       i=0
154     fi
155   done
156 }
157
158 disk_info() {
159   # the variable holds a space separated list of devices and their block size
160   device_size=`grep -E ' cciss/c.d.$| ida/c.d.$| rd/c.d.$| hd.$| sd.$|/disc$' /proc/partitions | diskandsize`
161   # a list of all local disks, without size
162   disklist=`list_disks $device_size`
163 }
164
165
166 cd "${OUTDIR}" || exit 1
167 (
168   [ -n "$GENERATE_FILE" ]      && echo "Output file:      $OUTFILE"
169   [ -n "$GENERATE_DIRECTORY" ] && echo "Output directory: $OUTDIR"
170   echo
171   echo "This might take a few seconds/minutes. Please be patient..."
172
173   # some sysinfo
174   date > date
175   if [ -r /etc/grml_version ] ; then
176      cat /etc/grml_version > grml_version
177   fi
178   if [ -r /etc/debian_version ] ; then
179      cat /etc/debian_version > debian_version
180   fi
181   uname -a > uname
182
183   # disks / devices
184   [ -f /proc/scsi/scsi ] && cat /proc/scsi/scsi > scsi
185   exectest lspci && lspci -nn > lspci
186   cat /proc/partitions > partitions
187   find /proc/ide/ -name geometry -exec grep . {} \; > proc_ide 2>/dev/null
188   df -h > df 2>/dev/null
189   for i in free lsmod mount lsdev lspnp lsusb ; do
190     exectest $i && $i > $i
191   done
192   swapon -s > swapon 2>swapon.error
193
194   # proc stuff
195   for i in cpuinfo interrupts cmdline devices dma fb iomem ioports \
196     mdstat meminfo modules mtrr pci version ; do
197     [ -r /proc/$i ] && cat /proc/$i > proc_$i
198   done
199   exectest sysdump  && sysdump > sysdump 2>sysdump.error
200
201   # log
202   dmesg > dmesg.cur
203
204   # hwinfo
205   exectest discover && discover -v --type-summary --enable-bus all > discover 2> discover.2
206   exectest hwinfo   && hwinfo log=hwinfo
207   exectest numactl  && numactl --hardware > numactl
208   exectest x86info  && x86info > x86info 2>x86info.2
209   exectest lscpu    && lscpu > lscpu
210
211   # net stuff
212   exectest ifconfig  && ifconfig -v -a  > ifconfig
213   exectest ip        && ip route show   > ip_route
214   exectest ip        && ip link show    > ip_link
215   exectest route     && route -n        > route
216
217   # software
218   if exectest dpkg ; then
219     dpkg --get-selections   > dpkg_get_selections
220     COLUMNS=300 dpkg --list > dpkg_list
221   fi
222
223   # power management
224   exectest laptop-detect  && laptop-detect >/dev/null 2>/dev/null && echo "0" > laptop_detected
225   exectest acpi_available && acpi_available && cat /proc/acpi/info > acpi_info
226   exectest acpi && acpi > acpi 2> acpi.error && acpi -v > acpi.version
227   [ -r /proc/apm/ ] && apm > apm
228
229   # kernel stuff
230   if [ -r /proc/config.gz ] ; then
231     zcat /proc/config.gz > kernelconfig
232   else
233     [ -r /boot/config-$UNAME ] && cat /boot/config-$UNAME > kernelconfig
234   fi
235
236   exectest dpkg && COLUMNS=1000 dpkg -l linux-image-$UNAME 2>running_kernel.error \
237            | grep linux-image-$UNAME | tr -s ' ' > running_kernel 2>>running_kernel.error
238   dpkg -S /boot/vmlinuz-$(uname -r) >> running_kernel 2>>running_kernel.error
239
240   # X stuff
241   if [ -n "${DISPLAY}" ] ; then
242     exectest xviddetect  && xviddetect         > xviddetect
243     exectest xvidtune    && xvidtune -show     > xdivtune
244     exectest xrandr      && xrandr             > xrandr
245     exectest xdpyinfo    && xdpyinfo           > xdpyinfo
246     X -version > x_version 2>&1
247   fi
248
249   for i in Xorg.0.log Xorg.7.log Xorg.8.log XFree86.0.log XFree86.7.log XFree86.8.log dmesg ; do
250     cp /var/log/$i log_$i 2>/dev/null
251   done
252
253   cp /etc/X11/xorg.conf    xorg.conf    2>/dev/null
254   cp /etc/modules          modules      2>/dev/null
255   cp /etc/X11/XF86Config-4 XF86Config-4 2>/dev/null
256
257   # as root:
258   if [ -n "$NOTROOT" ] ; then
259     echo "not running as root" > root
260   else
261     echo "running as root" > root
262     disk_info
263     exectest sfdisk     && sfdisk -d > sfdisk 2>sfdisk.error
264     exectest dmidecode  && dmidecode > dmidecode
265
266     exectest dconf && dconf -o dconf
267
268     if [ -x /usr/share/doc/lm-sensors/examples/eeprom/decode-dimms.pl ] ; then
269       /usr/share/doc/lm-sensors/examples/eeprom/decode-dimms.pl > decode-dimms 2>decode-dimms.error
270     fi
271
272     # proxmox
273     exectest qm && qm list > qm 2>qm.error
274     # libvirt
275     exectest virsh && virsh list >virsh 2>virsh.error
276     # openvz
277     exectest vzlist && vzlist >vzlist 2>vzlist.error
278     # vserver
279     exectest vserver-stat && vserver-stat >vserver-stat 2>vserver-stat.error
280
281     exectest mdadm && mdadm --detail /dev/md[0-9]* >> mdadm 2>mdadm.error
282
283     # LVM
284     exectest pvs && pvs > pvs 2>pvs.error
285     exectest vgs && vgs > vgs 2>vgs.error
286     exectest lvs && lvs > lvs 2>lvs.error
287     exectest lvdisplay && lvdisplay > lvdisplay 2>lvdisplay.error
288
289     exectest dmsetup && dmsetup ls > dmsetup_ls 2>dmsetup_ls.error
290     exectest dmsetup && dmsetup ls --tree > dmsetup_ls_tree 2>dmsetup_ls_tree.error
291     exectest lsblk && lsblk > lsblk 2>lsblk.error
292
293     # iSCSI
294     if exectest iscsiadm ; then
295       iscsiadm -m session > iscsiadm_session 2>iscsiadm_session.error
296       iscsiadm -m fw > iscsiadm_fw 2>iscsiadm_fw.error
297       iscsiadm -m host > iscsiadm_host 2>iscsiadm_host.error
298       iscsiadm -m iface > iscsiadm_iface 2>iscsiadm_iface.error
299       iscsiadm -m node > iscsiadm_node 2>iscsiadm_node.error
300       iscsiadm -m discovery > iscsiadm_discovery 2>iscsiadm_discovery.error
301     fi
302
303     if exectest lsscsi ; then
304       lsscsi    > lsscsi 2>lsscsi.error
305       lsscsi -t > lsscsi_transport 2>lsscsi_transport.error
306     fi
307
308     for disk in $disklist; do
309       if exectest smartctl ; then
310         echo -e "smartctl -a /dev/${disk}:\n" >> smartctl
311         smartctl -a /dev/$disk >> smartctl
312         echo -e "\n\n" >> smartctl
313       fi
314
315       if exectest hdparm ; then
316         echo -e "hdparm -iv /dev/${disk}:\n" >> hdparm
317         hdparm -iv /dev/$disk >> hdparm
318         echo -e "\n\n" >> hdparm
319       fi
320
321       if exectest fdisk ; then
322         echo -e "fdisk -lu /dev/${disk}:\n" >> fdisk
323         fdisk -lu /dev/$disk >>fdisk 2>>fdisk.error
324         echo -e "\n\n" >> fdisk
325       fi
326
327       if exectest parted ; then
328         echo -e "parted -s /dev/${disk}:\n" >> parted
329         parted -s /dev/$disk print >> parted
330         echo -e "\n\n" >> parted
331       fi
332
333       if exectest sdparm ; then
334         echo -e "sdparm --all --long /dev/${disk}:\n" >> sdparm
335         sdparm --all --long /dev/$disk >> sdparm
336         echo -e "\n\n" >> sdparm
337       fi
338
339       file -s /dev/$disk?* | grep -v ": empty" >> file_disk
340     done
341   fi
342 )
343
344 # get rid of empty files
345 for file in *.error ; do
346   test -s $file || rm $file
347 done
348
349 echo
350
351 cd "${WORKING_DIR}"
352
353 # create tarball
354 if [ -n "$GENERATE_FILE" ] ; then
355   tar acf "${OUTFILE}" "${OUTDIRNAME}"
356   [ -r "$OUTFILE" ] && echo "$OUTFILE ("$(ls -ahl "$OUTFILE" | awk '{print $5}')") has been generated."
357 fi
358
359 # remove (temporary) output directory if needed, else keep it, as it doubles
360 # as the real output directory.
361 if [ -z "$GENERATE_DIRECTORY" ] ; then
362   rm -r "${OUTDIR}"
363 else
364   [ -r "${OUTDIR}" ] && echo "${OUTDIR} has been generated."
365 fi
366
367 exit 0
368
369 ## END OF FILE##################################################################