Fix formating of disk tools output
[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 this tool is being executed
37 on.  It can be executed as normal user to collect some basic information or
38 with root permissions to collect as much information as possible.  By
39 default, a file named grml-hwinfo-TIMESTAMP.tar.bz2 storing all collected
40 information will be created in the current working directory. Alternatively,
41 you can have it create a directory with all information.
42
43 Options:
44
45   -b, --both                 Create directory + file grml-hwinfo-TIMESTAMP.tar.bz2
46   -d, --directory            Create grml-hwinfo-TIMESTAMP as a directory (no file)
47   -f, --file                 Create grml-hwinfo-TIMESTAMP.tar.bz2 [default action]
48   -h, --help                 Display this help message
49   --output-directory <dir>   Store output files in specified directory
50   --output-file <file>       Store output in specified filename (tar.bz2 format)
51 "
52 }
53
54 CMDLINE_OPTS=output-directory:,output-file:,both,directory,file,help
55 _opt_temp=$(getopt --name grml-hwinfo -o +bdfh --long $CMDLINE_OPTS -- "$@")
56 if [ $? -ne 0 ]; then
57   echo "Try 'grml-hwinfo --help' for more information." >&2
58   exit 1
59 fi
60 eval set -- "$_opt_temp"
61
62 while :; do
63   case "$1" in
64   --help|-h)
65     usage ; exit 0
66     ;;
67   --output-directory)
68     shift; OUTDIRNAME="$1"
69     GENERATE_DIRECTORY='1'
70     _opt_output_directory=true
71     $_opt_output_file && GENERATE_FILE='1' || GENERATE_FILE=''
72     ;;
73   --output-file)
74     shift; OUTFILE="$1"
75     GENERATE_FILE='1'
76     _opt_output_file=true
77     $_opt_output_directory && GENERATE_DIRECTORY='1' || GENERATE_DIRECTORY=''
78     ;;
79   -d|--directory)
80     GENERATE_DIRECTORY='1'
81     GENERATE_FILE=''
82     ;;
83   -f|--file)
84     GENERATE_DIRECTORY=''
85     GENERATE_FILE='1'
86     ;;
87   -b|--both)
88     GENERATE_DIRECTORY='1'
89     GENERATE_FILE='1'
90     ;;
91   --)
92     shift; break
93     ;;
94   *)
95     echo "Internal getopt error!" >&2
96     exit 1
97     ;;
98   esac
99   shift
100 done
101
102 # Generate output/temporary directory name & path, and output file path
103 [ -n "$OUTDIRNAME" ] || OUTDIRNAME="grml-hwinfo-${DATE}"
104 OUTDIR="${WORKING_DIR}/${OUTDIRNAME}"
105 mkdir "${OUTDIR}" || { echo 'Directory "'${OUTDIR}'" already exists, aborting.'>&2 ; exit 1; }
106
107 if [ -n "$GENERATE_FILE" ] ; then
108    [ -n "$OUTFILE" ] && OUTFILE_="$OUTFILE" || OUTFILE_="${OUTDIR}.tar.bz2"
109    [ -e "${OUTFILE_}" ] && { echo 'File "'${OUTFILE_}'" already exists, aborting.'>&2 ; rm -r "${OUTDIR}"; exit 1; }
110    OUTFILE=${OUTFILE_}
111    touch "${OUTFILE}"
112 fi
113
114 if [ "$(id -u)" != "0" ] ; then
115    NOTROOT=1
116    echo "W: Running without root permissions. Not all data will be collected."
117 fi
118
119 # check whether a binary is available and executable
120 exectest() {
121 if [ -z "$1" ] ; then
122    echo 'Usage: exectest <binary>'>&2
123    return 1
124 else
125    if test -e "$(which $1)" ; then
126      return 0
127    else
128      grep -q "^$1"'$' missing_tools 2>/dev/null || echo "$1" >> missing_tools
129      return 1
130    fi
131 fi
132 }
133
134 # echo a list of all disks and their size
135 # taken from http://cvs.debian.org/fai/lib/disk-info
136 diskandsize() {
137     local isdisk major minor blocks device suffix
138     while read major minor blocks device suffix; do
139         isdisk=1
140         # skip ide cdrom
141         [ -f /proc/ide/$device/media ] && grep -q cdrom /proc/ide/$device/media && isdisk=0
142         [ "$isdisk" -eq 1 ] && echo "$device $blocks"
143     done
144 }
145
146 list_disks() {
147 # print only every second entry; used by disk_info
148 i=0
149 for ent in $@; do
150     if [ "$i" -eq 0 ]; then
151         echo $ent
152         i=1
153     else
154         i=0
155     fi
156 done
157 }
158
159 disk_info() {
160     # the variable holds a space separated list of devices and their block size
161     device_size=`grep -E ' cciss/c.d.$| ida/c.d.$| rd/c.d.$| hd.$| sd.$|/disc$' /proc/partitions | diskandsize`
162     # a list of all local disks, without size
163     disklist=`list_disks $device_size`
164 }
165
166
167 cd "${OUTDIR}" || exit 1
168 (
169   [ -n "$GENERATE_FILE" ]      && echo "Output file:      $OUTFILE"
170   [ -n "$GENERATE_DIRECTORY" ] && echo "Output directory: $OUTDIR"
171   echo
172   echo "This might take a few seconds/minutes. Please be patient..."
173
174 # some sysinfo
175   date > date
176   if [ -r /etc/grml_version ] ; then
177      cat /etc/grml_version > grml_version
178   fi
179   if [ -r /etc/debian_version ] ; then
180      cat /etc/debian_version > debian_version
181   fi
182   uname -a > uname
183
184 # disks / devices
185   [ -f /proc/scsi/scsi ] && cat /proc/scsi/scsi > scsi
186   (lspci; lspci -n) | sort > lspci
187   [ -r /proc/bus/pnp ] && lspnp > lspnp
188   [ -r /proc/bus/usb ] && lsusb > lsusb
189   cat /proc/partitions > partitions
190   find /proc/ide/ -name geometry -exec grep . {} \; > proc_ide 2>/dev/null
191   df -h > df 2>/dev/null
192   for i in free lsmod mount lsdev ; do
193       exectest $i  && $i > $i
194   done
195   swapon -s > swapon 2>swapon.error
196
197 # proc stuff
198   for i in cpuinfo interrupts cmdline devices dma fb iomem ioports \
199     mdstat meminfo modules mtrr pci version ; do
200     [ -r /proc/$i ] && cat /proc/$i > proc_$i
201   done
202   exectest sysdump  && sysdump > sysdump 2>sysdump.error
203 # for sysnet in `find /proc/sys/net/*/ -type f | grep -v flush`; do cat $sysnet >> sysnet ; done
204
205 # log
206   dmesg > dmesg.cur
207
208 # hwinfo
209   exectest discover && discover -v --type-summary --enable-bus all > discover 2> discover.2
210   exectest hwinfo   && hwinfo log=hwinfo
211   exectest numactl  && numactl --hardware > numactl
212   exectest x86info  && x86info > x86info 2>x86info.2
213
214 # net stuff
215   exectest ifconfig  && ifconfig -v -a  > ifconfig
216   exectest ip        && ip route show   > ip_route
217   exectest ip        && ip link show    > ip_link
218   exectest route     && route -n        > route
219
220 # software
221   if exectest dpkg ; then
222      dpkg --get-selections   > dpkg_get_selections
223      COLUMNS=300 dpkg --list > dpkg_list
224   fi
225
226 # power management
227   exectest laptop-detect  && laptop-detect >/dev/null 2>/dev/null && echo "0" > laptop_detected
228   exectest acpi_available && acpi_available && cat /proc/acpi/info > acpi_info
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 # not available:
261 # sysinfo -class device -level all
262
263 # as root:
264 if [ -n "$NOTROOT" ] ; then
265    echo "not running as root" > root
266 else
267    echo "running as root" > root
268    disk_info
269    exectest sfdisk     && sfdisk -d > sfdisk 2>sfdisk.error
270    exectest dmidecode  && dmidecode > dmidecode
271
272    exectest dconf && dconf -o dconf
273
274    if [ -x /usr/share/doc/lm-sensors/examples/eeprom/decode-dimms.pl ] ; then
275       /usr/share/doc/lm-sensors/examples/eeprom/decode-dimms.pl > decode-dimms 2>decode-dimms.error
276    fi
277
278    # proxmox
279    exectest qm && qm list > qm 2>qm.error
280    # libvirt
281    exectest virsh && virsh list >virsh 2>virsh.error
282    # openvz
283    exectest vzlist && vzlist >vzlist 2>vzlist.error
284    # vserver
285    exectest vserver-stat && vserver-stat >vserver-stat 2>vserver-stat.error
286
287    exectest mdadm && mdadm --detail /dev/md[0-9]* >> mdadm 2>mdadm.error
288
289    # LVM
290    exectest pvs && pvs > pvs 2>pvs.error
291    exectest vgs && vgs > vgs 2>vgs.error
292    exectest lvs && lvs > lvs 2>lvs.error
293    exectest lvdisplay && lvdisplay > lvdisplay 2>lvdisplay.error
294
295    exectest dmsetup && dmsetup ls > dmsetup_ls 2>dmsetup_ls.error
296
297    for disk in $disklist; do
298      if exectest smartctl ; then
299        echo -e "smartctl -a /dev/${disk}:\n" >> smartctl
300        smartctl -a /dev/$disk >> smartctl
301        echo -e "\n\n" >> smartctl
302      fi
303
304      if exectest hdparm ; then
305        echo -e "hdparm -iv /dev/${disk}:\n" >> hdparm
306        hdparm -iv /dev/$disk >> hdparm
307        echo -e "\n\n" >> hdparm
308      fi
309
310      if exectest fdisk ; then
311        echo -e "fdisk -lu /dev/${disk}:\n" >> fdisk
312        fdisk -lu /dev/$disk >>fdisk 2>>fdisk.error
313        echo -e "\n\n" >> fdisk
314      fi
315
316      if exectest parted ; then
317        echo -e "parted -s /dev/${disk}:\n" >> parted
318        parted -s /dev/$disk print >> parted
319        echo -e "\n\n" >> parted
320      fi
321
322      if exectest sdparm ; then
323        echo -e "sdparm --all --long /dev/${disk}:\n" >> sdparm
324        sdparm --all --long /dev/$disk >> sdparm
325        echo -e "\n\n" >> sdparm
326      fi
327
328      file -s /dev/$disk?* | grep -v ": empty" >> file_disk
329    done
330 fi
331 )
332
333 # get rid of empty files
334 for file in *; do
335   test -s $file || rm $file
336 done
337
338 echo
339
340 cd "${WORKING_DIR}"
341
342 # create tarball
343 if [ -n "$GENERATE_FILE" ] ; then
344   tar jcf "${OUTFILE}" "${OUTDIRNAME}"
345   [ -r "$OUTFILE" ] && echo "$OUTFILE ("$(ls -ahl "$OUTFILE" | awk '{print $5}')") has been generated."
346 fi
347
348 # remove (temporary) output directory if needed, else keep it, as it doubles
349 # as the real output directory.
350 if [ -z "$GENERATE_DIRECTORY" ] ; then
351   rm -r "${OUTDIR}"
352 else
353   [ -r "${OUTDIR}" ] && echo "${OUTDIR} has been generated."
354 fi
355
356 exit 0
357
358 ## END OF FILE##################################################################