Provide output of verbose lspci run in file lspci_verbose
[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 # defaults
27 GENERATE_FILE='1'
28 GENERATE_DIRECTORY=''
29 _opt_output_directory=false
30 _opt_output_file=false
31 _opt_quiet=false
32 _opt_force=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   -q, --quiet                Don't display informational text (useful for cron usage)
49   --force                    Don't abort but overwrite possibly existing output file
50   --output-directory <dir>   Store output files in specified directory
51   --output-file <file>       Store output in specified filename (tar.XX format)
52   "
53 }
54
55 CMDLINE_OPTS=output-directory:,output-file:,both,directory,file,help,quiet,force
56 _opt_temp=$(getopt --name grml-hwinfo -o +bdfhq --long $CMDLINE_OPTS -- "$@")
57 if [ $? -ne 0 ]; then
58   echo "Try 'grml-hwinfo --help' for more information." >&2
59   exit 1
60 fi
61 eval set -- "$_opt_temp"
62
63 while :; do
64   case "$1" in
65   --help|-h)
66     usage ; exit 0
67     ;;
68   --output-directory)
69     shift; OUTDIRNAME="$1"
70     GENERATE_DIRECTORY='1'
71     _opt_output_directory=true
72     $_opt_output_file && GENERATE_FILE='1' || GENERATE_FILE=''
73     ;;
74   --output-file)
75     shift; OUTFILE="$1"
76     GENERATE_FILE='1'
77     _opt_output_file=true
78     $_opt_output_directory && GENERATE_DIRECTORY='1' || GENERATE_DIRECTORY=''
79     ;;
80   -d|--directory)
81     GENERATE_DIRECTORY='1'
82     GENERATE_FILE=''
83     ;;
84   -f|--file)
85     GENERATE_DIRECTORY=''
86     GENERATE_FILE='1'
87     ;;
88   -b|--both)
89     GENERATE_DIRECTORY='1'
90     GENERATE_FILE='1'
91     ;;
92   -q|--quiet)
93     _opt_quiet=true
94     ;;
95   --force)
96     _opt_force=true
97     ;;
98   --)
99     shift; break
100     ;;
101   *)
102     echo "Internal getopt error!" >&2
103     exit 1
104     ;;
105   esac
106   shift
107 done
108
109 if ! $_opt_quiet ; then
110   echo "$PN ${VERSION} - collect hardware information"
111 fi
112
113 # Generate output/temporary directory name & path, and output file path
114 [ -n "$OUTDIRNAME" ] || OUTDIRNAME="grml-hwinfo-${DATE}"
115 if $_opt_output_directory ; then
116   OUTDIR="${OUTDIRNAME}"
117 else
118   OUTDIR="${WORKING_DIR}/${OUTDIRNAME}"
119 fi
120
121 if $_opt_force ; then
122   mkdir -p "${OUTDIR}"
123 else
124   mkdir "${OUTDIR}" || { echo "Directory '${OUTDIR}' already exists, aborting." >&2 ; exit 1; }
125 fi
126
127 if [ -n "$GENERATE_FILE" ] ; then
128   [ -n "$OUTFILE" ] && OUTFILE_="$OUTFILE" || OUTFILE_="${OUTDIR}.tar.bz2"
129   if ! $_opt_force ; then
130     [ -e "${OUTFILE_}" ] && { echo "File '${OUTFILE_}' already exists, aborting." >&2 ; rm -r "${OUTDIR}"; exit 1; }
131   fi
132   OUTFILE=${OUTFILE_}
133   touch "${OUTFILE}"
134 fi
135
136 if [ "$(id -u)" != "0" ] ; then
137   NOTROOT=1
138   $_opt_quiet || echo "W: Running without root permissions. Not all data will be collected."
139 fi
140
141 # check whether a binary is available and executable
142 exectest() {
143   if [ -z "$1" ] ; then
144     echo 'Usage: exectest <binary>'>&2
145     return 1
146   else
147     if test -e "$(which "$1")" ; then
148       return 0
149     else
150       if ! grep -q "^$1"'$' missing_tools 2>/dev/null ; then
151         $_opt_quiet || echo "$1" >> missing_tools
152       fi
153       return 1
154     fi
155   fi
156 }
157
158 # based on https://github.com/faiproject/fai/blob/master/lib/fai-disk-info
159 checkdisk() {
160   local isdisk device
161   while read _ _ _ device _ ; do
162     isdisk=1
163     # skip CDROMs
164     [ "$(stat -c %G /dev/"${device}")" = "disk" ] || isdisk=0
165     [ "$isdisk" -eq 1 ] && echo "$device"
166   done
167 }
168
169 disk_info() {
170   # the variable holds a newline separated list of devices
171   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)
172 }
173
174
175 cd "${OUTDIR}" || exit 1
176 (
177   if ! $_opt_quiet ; then
178     [ -n "$GENERATE_FILE" ]      && echo "Output file:      $OUTFILE"
179     [ -n "$GENERATE_DIRECTORY" ] && echo "Output directory: $OUTDIR"
180     echo
181     echo "This might take a few seconds/minutes. Please be patient..."
182   fi
183
184   # some sysinfo
185   date > ./date
186   if [ -r /etc/grml_version ] ; then
187      cat /etc/grml_version > grml_version
188   fi
189   if [ -r /etc/debian_version ] ; then
190      cat /etc/debian_version > debian_version
191   fi
192   uname -a > ./uname
193
194   # disks / devices
195   [ -f /proc/scsi/scsi ] && cat /proc/scsi/scsi > scsi
196   exectest lspci && lspci -nn > ./lspci
197   exectest lspci && lspci -vvnn > ./lspci_verbose
198   cat /proc/partitions > partitions
199   find /proc/ide/ -name geometry -exec grep . {} \; > proc_ide 2>/dev/null
200   df -h > ./df 2>/dev/null
201   for i in free lsmod mount lsdev lspnp lsusb ; do
202     exectest $i && $i > ./$i
203   done
204   swapon -s > ./swapon 2>./swapon.error
205
206   # proc stuff
207   for i in cpuinfo interrupts cmdline devices dma fb iomem ioports \
208     mdstat meminfo modules mtrr pci version ; do
209     [ -r /proc/$i ] && cat /proc/$i > proc_$i
210   done
211   exectest sysdump  && sysdump > ./sysdump 2>./sysdump.error
212
213   # log
214   dmesg > dmesg.cur
215
216   # hwinfo
217   exectest discover && discover -v --type-summary --enable-bus all > ./discover 2>./discover.error
218   exectest hwinfo   && hwinfo log=hwinfo
219   exectest numactl  && numactl --hardware > ./numactl
220   exectest x86info  && x86info > ./x86info 2>./x86info.error
221   exectest lscpu    && lscpu > ./lscpu
222
223   # EFI
224   exectest efibootmgr && efibootmgr -v > efibootmgr
225
226   # net stuff, net-tools:
227   exectest ifconfig && ifconfig -v -a > ./ifconfig
228   exectest route    && route -n       > ./route
229
230   # net stuff, iproute:
231   exectest ip && ip addrlabel list > ip_addrlabel
232   exectest ip && ip addr show      > ip_addr
233   exectest ip && ip link show      > ip_link
234   exectest ip && ip maddr show     > ip_maddr
235   exectest ip && ip mroute show    > ip_mroute
236   exectest ip && ip mrule show     > ip_mrule 2>ip_mrule.error
237   exectest ip && ip neigh show     > ip_neigh
238   exectest ip && ip netns list     > ip_netns
239   exectest ip && ip ntable show    > ip_ntable
240   exectest ip && ip route show     > ip_route
241   exectest ip && if [ -r /etc/iproute2/rt_tables ] ; then
242                    grep -v '^#' /etc/iproute2/rt_tables | while read table _ ; do
243                      ip route show table "${table}" > "ip_route_table_${table}"
244                    done
245                  fi
246   exectest ip && ip rule show      > ip_rule
247   exectest ip && ip tunnel show    > ip_tunnel
248   exectest ip && ip tuntap show    > ip_tuntap
249
250   # software
251   if exectest dpkg ; then
252     dpkg --get-selections   > dpkg_get_selections
253     COLUMNS=300 dpkg --list > dpkg_list
254   fi
255
256   # power management
257   exectest laptop-detect  && laptop-detect >/dev/null 2>/dev/null && echo "0" > laptop_detected
258   if [ -r /proc/acpi/info ] ; then
259     cat /proc/acpi/info > acpi_info
260   fi
261
262   if exectest acpi ; then
263     acpi > ./acpi 2>acpi.error
264     acpi --everything > ./acpi.everything 2>./acpi.everything.error
265     acpi -v > ./acpi.version
266   fi
267   [ -r /proc/apm/ ] && apm > ./apm
268
269   if exectest mcelog ; then
270     mcelog > ./mcelog 2>./mcelog.error
271   fi
272
273   # kernel stuff
274   if [ -r /proc/config.gz ] ; then
275     zcat /proc/config.gz > kernelconfig
276   else
277     [ -r "/boot/config-${UNAME}" ] && cat "/boot/config-${UNAME}" > kernelconfig
278   fi
279
280   exectest dpkg && COLUMNS=1000 dpkg -l "linux-image-${UNAME}" 2>running_kernel.error \
281            | grep "linux-image-${UNAME}" | tr -s ' ' > running_kernel 2>>running_kernel.error
282   dpkg -S "/boot/vmlinuz-$(uname -r)" >> running_kernel 2>>running_kernel.error
283
284   # X stuff
285   if [ -n "${DISPLAY}" ] ; then
286     exectest xviddetect  && xviddetect         > ./xviddetect
287     exectest xvidtune    && xvidtune -show     > ./xdivtune
288     exectest xrandr      && xrandr             > ./xrandr
289     exectest xdpyinfo    && xdpyinfo           > ./xdpyinfo
290     X -version > x_version 2>&1
291   fi
292
293   for i in Xorg.0.log Xorg.7.log Xorg.8.log XFree86.0.log XFree86.7.log XFree86.8.log dmesg ; do
294     cp /var/log/$i log_$i 2>/dev/null
295   done
296
297   cp /etc/X11/xorg.conf    xorg.conf    2>/dev/null
298   cp /etc/modules          modules      2>/dev/null
299   cp /etc/X11/XF86Config-4 XF86Config-4 2>/dev/null
300
301   # as root:
302   if [ -n "$NOTROOT" ] ; then
303     echo "not running as root" > root
304   else
305     echo "running as root" > root
306     disk_info
307     exectest sfdisk     && sfdisk -d > ./sfdisk 2>./sfdisk.error
308     exectest dmidecode  && dmidecode > ./dmidecode
309
310     exectest dconf && dconf -o dconf
311
312     if exectest mcelog ; then
313       mcelog --dmi > mcelog_dmi 2>mcelog_dmi.error
314     fi
315
316     if exectest edac-util ; then
317       edac-util > ./edac-util 2>./edac-util.error
318       edac-util --report=full > edac-util_report 2>edac-util_report.error
319     fi
320
321     if exectest decode-dimms ; then
322       decode-dimms > ./decode-dimms 2>./decode-dimms.error
323     elif [ -x /usr/share/doc/lm-sensors/examples/eeprom/decode-dimms.pl ] ; then
324       /usr/share/doc/lm-sensors/examples/eeprom/decode-dimms.pl > decode-dimms 2>decode-dimms.error
325     fi
326
327     if exectest acpidump ; then
328       acpidump > ./acpidump 2>./acpidump.error
329     fi
330
331     # proxmox
332     exectest qm && qm list > ./qm 2>./qm.error
333     # libvirt
334     exectest virsh && virsh list >./virsh 2>./virsh.error
335     # openvz
336     exectest vzlist && vzlist >./vzlist 2>./vzlist.error
337     # vserver
338     exectest vserver-stat && vserver-stat >./vserver-stat 2>./vserver-stat.error
339
340     exectest mdadm && mdadm --detail /dev/md[0-9]* >> ./mdadm 2>./mdadm.error
341
342     # LVM
343     exectest pvs && pvs > ./pvs 2>./pvs.error
344     exectest vgs && vgs > ./vgs 2>./vgs.error
345     exectest lvs && lvs > ./lvs 2>./lvs.error
346     exectest lvdisplay && lvdisplay > ./lvdisplay 2>./lvdisplay.error
347
348     exectest dmsetup && dmsetup ls > dmsetup_ls 2>dmsetup_ls.error
349     exectest dmsetup && dmsetup ls --tree > dmsetup_ls_tree 2>dmsetup_ls_tree.error
350     exectest lsblk && lsblk > ./lsblk 2>./lsblk.error
351
352     # iSCSI
353     if exectest iscsiadm ; then
354       iscsiadm -m session > iscsiadm_session 2>iscsiadm_session.error
355       iscsiadm -m fw > iscsiadm_fw 2>iscsiadm_fw.error
356       iscsiadm -m host > iscsiadm_host 2>iscsiadm_host.error
357       iscsiadm -m iface > iscsiadm_iface 2>iscsiadm_iface.error
358       iscsiadm -m node > iscsiadm_node 2>iscsiadm_node.error
359       iscsiadm -m discovery > iscsiadm_discovery 2>iscsiadm_discovery.error
360     fi
361
362     if exectest lsscsi ; then
363       lsscsi    > ./lsscsi 2>./lsscsi.error
364       lsscsi -t > ./lsscsi_transport 2>./lsscsi_transport.error
365     fi
366
367     for disk in $disklist; do
368       if exectest smartctl ; then
369         echo -e "smartctl -a /dev/${disk}:\n" >> smartctl
370         smartctl -a "/dev/$disk" >> ./smartctl
371         echo -e "\n\n" >> ./smartctl
372       fi
373
374       if exectest hdparm ; then
375         echo -e "hdparm -iv /dev/${disk}:\n" >> hdparm
376         hdparm -iv "/dev/$disk" >> ./hdparm 2>> ./hdparm.error
377         echo -e "\n\n" >> hdparm
378       fi
379
380       if exectest fdisk ; then
381         echo -e "fdisk -lu /dev/${disk}:\n" >> fdisk
382         fdisk -lu "/dev/$disk" >> ./fdisk 2>> ./fdisk.error
383         echo -e "\n\n" >> fdisk
384       fi
385
386       if exectest parted ; then
387         echo -e "parted -s /dev/${disk}:\n" >> parted
388         parted -s "/dev/$disk" print >> ./parted
389         echo -e "\n\n" >> parted
390       fi
391
392       if exectest sdparm ; then
393         echo -e "sdparm --all --long /dev/${disk}:\n" >> sdparm
394         sdparm --all --long "/dev/$disk" >> ./sdparm
395         echo -e "\n\n" >> sdparm
396       fi
397
398       if exectest sg_inq ; then
399         echo -e "sg_inq /dev/${disk}:\n" >> sg_inq
400         sg_inq "/dev/$disk" >> ./sg_inq 2>> ./sg_inq.error
401         echo -e "\n\n" >> sg_inq
402       fi
403
404       file -s "/dev/${disk}"?* | grep -v ": empty" >> file_disk
405     done
406   fi
407 )
408
409 # get rid of empty files
410 for file in *.error ; do
411   test -s "$file" || rm -- "$file"
412 done
413
414 $_opt_quiet || echo
415
416 cd "${WORKING_DIR}"
417
418 # create tarball
419 if [ -n "$GENERATE_FILE" ] ; then
420   tar acf "${OUTFILE}" "${OUTDIRNAME}"
421   if ! $_opt_quiet ; then
422     # shellcheck disable=SC2012
423     [ -r "$OUTFILE" ] && echo "$OUTFILE ($(ls -ahl -- "$OUTFILE" | awk '{print $5}')) has been generated."
424   fi
425 fi
426
427 # remove (temporary) output directory if needed, else keep it, as it doubles
428 # as the real output directory.
429 if [ -z "$GENERATE_DIRECTORY" ] ; then
430   rm -r "${OUTDIR}"
431 else
432   if ! $_opt_quiet ; then
433     [ -r "${OUTDIR}" ] && echo "${OUTDIR} has been generated."
434   fi
435 fi
436
437 exit 0
438
439 ## END OF FILE##################################################################