Release new version 0.9.0
[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   if [ -r /proc/acpi/info ] ; then
226     cat /proc/acpi/info > acpi_info
227   fi
228
229   exectest acpi && acpi > acpi 2> acpi.error && acpi -v > acpi.version
230   [ -r /proc/apm/ ] && apm > apm
231
232   # kernel stuff
233   if [ -r /proc/config.gz ] ; then
234     zcat /proc/config.gz > kernelconfig
235   else
236     [ -r /boot/config-$UNAME ] && cat /boot/config-$UNAME > kernelconfig
237   fi
238
239   exectest dpkg && COLUMNS=1000 dpkg -l linux-image-$UNAME 2>running_kernel.error \
240            | grep linux-image-$UNAME | tr -s ' ' > running_kernel 2>>running_kernel.error
241   dpkg -S /boot/vmlinuz-$(uname -r) >> running_kernel 2>>running_kernel.error
242
243   # X stuff
244   if [ -n "${DISPLAY}" ] ; then
245     exectest xviddetect  && xviddetect         > xviddetect
246     exectest xvidtune    && xvidtune -show     > xdivtune
247     exectest xrandr      && xrandr             > xrandr
248     exectest xdpyinfo    && xdpyinfo           > xdpyinfo
249     X -version > x_version 2>&1
250   fi
251
252   for i in Xorg.0.log Xorg.7.log Xorg.8.log XFree86.0.log XFree86.7.log XFree86.8.log dmesg ; do
253     cp /var/log/$i log_$i 2>/dev/null
254   done
255
256   cp /etc/X11/xorg.conf    xorg.conf    2>/dev/null
257   cp /etc/modules          modules      2>/dev/null
258   cp /etc/X11/XF86Config-4 XF86Config-4 2>/dev/null
259
260   # as root:
261   if [ -n "$NOTROOT" ] ; then
262     echo "not running as root" > root
263   else
264     echo "running as root" > root
265     disk_info
266     exectest sfdisk     && sfdisk -d > sfdisk 2>sfdisk.error
267     exectest dmidecode  && dmidecode > dmidecode
268
269     exectest dconf && dconf -o dconf
270
271     if [ -x /usr/share/doc/lm-sensors/examples/eeprom/decode-dimms.pl ] ; then
272       /usr/share/doc/lm-sensors/examples/eeprom/decode-dimms.pl > decode-dimms 2>decode-dimms.error
273     fi
274
275     # proxmox
276     exectest qm && qm list > qm 2>qm.error
277     # libvirt
278     exectest virsh && virsh list >virsh 2>virsh.error
279     # openvz
280     exectest vzlist && vzlist >vzlist 2>vzlist.error
281     # vserver
282     exectest vserver-stat && vserver-stat >vserver-stat 2>vserver-stat.error
283
284     exectest mdadm && mdadm --detail /dev/md[0-9]* >> mdadm 2>mdadm.error
285
286     # LVM
287     exectest pvs && pvs > pvs 2>pvs.error
288     exectest vgs && vgs > vgs 2>vgs.error
289     exectest lvs && lvs > lvs 2>lvs.error
290     exectest lvdisplay && lvdisplay > lvdisplay 2>lvdisplay.error
291
292     exectest dmsetup && dmsetup ls > dmsetup_ls 2>dmsetup_ls.error
293     exectest dmsetup && dmsetup ls --tree > dmsetup_ls_tree 2>dmsetup_ls_tree.error
294     exectest lsblk && lsblk > lsblk 2>lsblk.error
295
296     # iSCSI
297     if exectest iscsiadm ; then
298       iscsiadm -m session > iscsiadm_session 2>iscsiadm_session.error
299       iscsiadm -m fw > iscsiadm_fw 2>iscsiadm_fw.error
300       iscsiadm -m host > iscsiadm_host 2>iscsiadm_host.error
301       iscsiadm -m iface > iscsiadm_iface 2>iscsiadm_iface.error
302       iscsiadm -m node > iscsiadm_node 2>iscsiadm_node.error
303       iscsiadm -m discovery > iscsiadm_discovery 2>iscsiadm_discovery.error
304     fi
305
306     if exectest lsscsi ; then
307       lsscsi    > lsscsi 2>lsscsi.error
308       lsscsi -t > lsscsi_transport 2>lsscsi_transport.error
309     fi
310
311     for disk in $disklist; do
312       if exectest smartctl ; then
313         echo -e "smartctl -a /dev/${disk}:\n" >> smartctl
314         smartctl -a /dev/$disk >> smartctl
315         echo -e "\n\n" >> smartctl
316       fi
317
318       if exectest hdparm ; then
319         echo -e "hdparm -iv /dev/${disk}:\n" >> hdparm
320         hdparm -iv /dev/$disk >> hdparm
321         echo -e "\n\n" >> hdparm
322       fi
323
324       if exectest fdisk ; then
325         echo -e "fdisk -lu /dev/${disk}:\n" >> fdisk
326         fdisk -lu /dev/$disk >>fdisk 2>>fdisk.error
327         echo -e "\n\n" >> fdisk
328       fi
329
330       if exectest parted ; then
331         echo -e "parted -s /dev/${disk}:\n" >> parted
332         parted -s /dev/$disk print >> parted
333         echo -e "\n\n" >> parted
334       fi
335
336       if exectest sdparm ; then
337         echo -e "sdparm --all --long /dev/${disk}:\n" >> sdparm
338         sdparm --all --long /dev/$disk >> sdparm
339         echo -e "\n\n" >> sdparm
340       fi
341
342       if exectest sg_inq ; then
343         echo -e "sg_inq /dev/${disk}:\n" >> sg_inq
344         sg_inq /dev/$disk >> sg_inq
345         echo -e "\n\n" >> sg_inq
346       fi
347
348       file -s /dev/$disk?* | grep -v ": empty" >> file_disk
349     done
350   fi
351 )
352
353 # get rid of empty files
354 for file in *.error ; do
355   test -s $file || rm $file
356 done
357
358 echo
359
360 cd "${WORKING_DIR}"
361
362 # create tarball
363 if [ -n "$GENERATE_FILE" ] ; then
364   tar acf "${OUTFILE}" "${OUTDIRNAME}"
365   [ -r "$OUTFILE" ] && echo "$OUTFILE ("$(ls -ahl "$OUTFILE" | awk '{print $5}')") has been generated."
366 fi
367
368 # remove (temporary) output directory if needed, else keep it, as it doubles
369 # as the real output directory.
370 if [ -z "$GENERATE_DIRECTORY" ] ; then
371   rm -r "${OUTDIR}"
372 else
373   [ -r "${OUTDIR}" ] && echo "${OUTDIR} has been generated."
374 fi
375
376 exit 0
377
378 ## END OF FILE##################################################################