Recommend acpica-tools package and provide acpidump output (as root)
[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   cat /proc/partitions > partitions
198   find /proc/ide/ -name geometry -exec grep . {} \; > proc_ide 2>/dev/null
199   df -h > ./df 2>/dev/null
200   for i in free lsmod mount lsdev lspnp lsusb ; do
201     exectest $i && $i > ./$i
202   done
203   swapon -s > ./swapon 2>./swapon.error
204
205   # proc stuff
206   for i in cpuinfo interrupts cmdline devices dma fb iomem ioports \
207     mdstat meminfo modules mtrr pci version ; do
208     [ -r /proc/$i ] && cat /proc/$i > proc_$i
209   done
210   exectest sysdump  && sysdump > ./sysdump 2>./sysdump.error
211
212   # log
213   dmesg > dmesg.cur
214
215   # hwinfo
216   exectest discover && discover -v --type-summary --enable-bus all > ./discover 2>./discover.error
217   exectest hwinfo   && hwinfo log=hwinfo
218   exectest numactl  && numactl --hardware > ./numactl
219   exectest x86info  && x86info > ./x86info 2>./x86info.error
220   exectest lscpu    && lscpu > ./lscpu
221
222   # EFI
223   exectest efibootmgr && efibootmgr -v > efibootmgr
224
225   # net stuff, net-tools:
226   exectest ifconfig && ifconfig -v -a > ./ifconfig
227   exectest route    && route -n       > ./route
228
229   # net stuff, iproute:
230   exectest ip && ip addrlabel list > ip_addrlabel
231   exectest ip && ip addr show      > ip_addr
232   exectest ip && ip link show      > ip_link
233   exectest ip && ip maddr show     > ip_maddr
234   exectest ip && ip mroute show    > ip_mroute
235   exectest ip && ip mrule show     > ip_mrule 2>ip_mrule.error
236   exectest ip && ip neigh show     > ip_neigh
237   exectest ip && ip netns list     > ip_netns
238   exectest ip && ip ntable show    > ip_ntable
239   exectest ip && ip route show     > ip_route
240   exectest ip && if [ -r /etc/iproute2/rt_tables ] ; then
241                    grep -v '^#' /etc/iproute2/rt_tables | while read table _ ; do
242                      ip route show table "${table}" > "ip_route_table_${table}"
243                    done
244                  fi
245   exectest ip && ip rule show      > ip_rule
246   exectest ip && ip tunnel show    > ip_tunnel
247   exectest ip && ip tuntap show    > ip_tuntap
248
249   # software
250   if exectest dpkg ; then
251     dpkg --get-selections   > dpkg_get_selections
252     COLUMNS=300 dpkg --list > dpkg_list
253   fi
254
255   # power management
256   exectest laptop-detect  && laptop-detect >/dev/null 2>/dev/null && echo "0" > laptop_detected
257   if [ -r /proc/acpi/info ] ; then
258     cat /proc/acpi/info > acpi_info
259   fi
260
261   if exectest acpi ; then
262     acpi > ./acpi 2>acpi.error
263     acpi --everything > ./acpi.everything 2>./acpi.everything.error
264     acpi -v > ./acpi.version
265   fi
266   [ -r /proc/apm/ ] && apm > ./apm
267
268   if exectest mcelog ; then
269     mcelog > ./mcelog 2>./mcelog.error
270   fi
271
272   # kernel stuff
273   if [ -r /proc/config.gz ] ; then
274     zcat /proc/config.gz > kernelconfig
275   else
276     [ -r "/boot/config-${UNAME}" ] && cat "/boot/config-${UNAME}" > kernelconfig
277   fi
278
279   exectest dpkg && COLUMNS=1000 dpkg -l "linux-image-${UNAME}" 2>running_kernel.error \
280            | grep "linux-image-${UNAME}" | tr -s ' ' > running_kernel 2>>running_kernel.error
281   dpkg -S "/boot/vmlinuz-$(uname -r)" >> running_kernel 2>>running_kernel.error
282
283   # X stuff
284   if [ -n "${DISPLAY}" ] ; then
285     exectest xviddetect  && xviddetect         > ./xviddetect
286     exectest xvidtune    && xvidtune -show     > ./xdivtune
287     exectest xrandr      && xrandr             > ./xrandr
288     exectest xdpyinfo    && xdpyinfo           > ./xdpyinfo
289     X -version > x_version 2>&1
290   fi
291
292   for i in Xorg.0.log Xorg.7.log Xorg.8.log XFree86.0.log XFree86.7.log XFree86.8.log dmesg ; do
293     cp /var/log/$i log_$i 2>/dev/null
294   done
295
296   cp /etc/X11/xorg.conf    xorg.conf    2>/dev/null
297   cp /etc/modules          modules      2>/dev/null
298   cp /etc/X11/XF86Config-4 XF86Config-4 2>/dev/null
299
300   # as root:
301   if [ -n "$NOTROOT" ] ; then
302     echo "not running as root" > root
303   else
304     echo "running as root" > root
305     disk_info
306     exectest sfdisk     && sfdisk -d > ./sfdisk 2>./sfdisk.error
307     exectest dmidecode  && dmidecode > ./dmidecode
308
309     exectest dconf && dconf -o dconf
310
311     if exectest mcelog ; then
312       mcelog --dmi > mcelog_dmi 2>mcelog_dmi.error
313     fi
314
315     if exectest edac-util ; then
316       edac-util > ./edac-util 2>./edac-util.error
317       edac-util --report=full > edac-util_report 2>edac-util_report.error
318     fi
319
320     if exectest decode-dimms ; then
321       decode-dimms > ./decode-dimms 2>./decode-dimms.error
322     elif [ -x /usr/share/doc/lm-sensors/examples/eeprom/decode-dimms.pl ] ; then
323       /usr/share/doc/lm-sensors/examples/eeprom/decode-dimms.pl > decode-dimms 2>decode-dimms.error
324     fi
325
326     if exectest acpidump ; then
327       acpidump > ./acpidump 2>./acpidump.error
328     fi
329
330     # proxmox
331     exectest qm && qm list > ./qm 2>./qm.error
332     # libvirt
333     exectest virsh && virsh list >./virsh 2>./virsh.error
334     # openvz
335     exectest vzlist && vzlist >./vzlist 2>./vzlist.error
336     # vserver
337     exectest vserver-stat && vserver-stat >./vserver-stat 2>./vserver-stat.error
338
339     exectest mdadm && mdadm --detail /dev/md[0-9]* >> ./mdadm 2>./mdadm.error
340
341     # LVM
342     exectest pvs && pvs > ./pvs 2>./pvs.error
343     exectest vgs && vgs > ./vgs 2>./vgs.error
344     exectest lvs && lvs > ./lvs 2>./lvs.error
345     exectest lvdisplay && lvdisplay > ./lvdisplay 2>./lvdisplay.error
346
347     exectest dmsetup && dmsetup ls > dmsetup_ls 2>dmsetup_ls.error
348     exectest dmsetup && dmsetup ls --tree > dmsetup_ls_tree 2>dmsetup_ls_tree.error
349     exectest lsblk && lsblk > ./lsblk 2>./lsblk.error
350
351     # iSCSI
352     if exectest iscsiadm ; then
353       iscsiadm -m session > iscsiadm_session 2>iscsiadm_session.error
354       iscsiadm -m fw > iscsiadm_fw 2>iscsiadm_fw.error
355       iscsiadm -m host > iscsiadm_host 2>iscsiadm_host.error
356       iscsiadm -m iface > iscsiadm_iface 2>iscsiadm_iface.error
357       iscsiadm -m node > iscsiadm_node 2>iscsiadm_node.error
358       iscsiadm -m discovery > iscsiadm_discovery 2>iscsiadm_discovery.error
359     fi
360
361     if exectest lsscsi ; then
362       lsscsi    > ./lsscsi 2>./lsscsi.error
363       lsscsi -t > ./lsscsi_transport 2>./lsscsi_transport.error
364     fi
365
366     for disk in $disklist; do
367       if exectest smartctl ; then
368         echo -e "smartctl -a /dev/${disk}:\n" >> smartctl
369         smartctl -a "/dev/$disk" >> ./smartctl
370         echo -e "\n\n" >> ./smartctl
371       fi
372
373       if exectest hdparm ; then
374         echo -e "hdparm -iv /dev/${disk}:\n" >> hdparm
375         hdparm -iv "/dev/$disk" >> ./hdparm 2>> ./hdparm.error
376         echo -e "\n\n" >> hdparm
377       fi
378
379       if exectest fdisk ; then
380         echo -e "fdisk -lu /dev/${disk}:\n" >> fdisk
381         fdisk -lu "/dev/$disk" >> ./fdisk 2>> ./fdisk.error
382         echo -e "\n\n" >> fdisk
383       fi
384
385       if exectest parted ; then
386         echo -e "parted -s /dev/${disk}:\n" >> parted
387         parted -s "/dev/$disk" print >> ./parted
388         echo -e "\n\n" >> parted
389       fi
390
391       if exectest sdparm ; then
392         echo -e "sdparm --all --long /dev/${disk}:\n" >> sdparm
393         sdparm --all --long "/dev/$disk" >> ./sdparm
394         echo -e "\n\n" >> sdparm
395       fi
396
397       if exectest sg_inq ; then
398         echo -e "sg_inq /dev/${disk}:\n" >> sg_inq
399         sg_inq "/dev/$disk" >> ./sg_inq 2>> ./sg_inq.error
400         echo -e "\n\n" >> sg_inq
401       fi
402
403       file -s "/dev/${disk}"?* | grep -v ": empty" >> file_disk
404     done
405   fi
406 )
407
408 # get rid of empty files
409 for file in *.error ; do
410   test -s "$file" || rm -- "$file"
411 done
412
413 $_opt_quiet || echo
414
415 cd "${WORKING_DIR}"
416
417 # create tarball
418 if [ -n "$GENERATE_FILE" ] ; then
419   tar acf "${OUTFILE}" "${OUTDIRNAME}"
420   if ! $_opt_quiet ; then
421     # shellcheck disable=SC2012
422     [ -r "$OUTFILE" ] && echo "$OUTFILE ($(ls -ahl -- "$OUTFILE" | awk '{print $5}')) has been generated."
423   fi
424 fi
425
426 # remove (temporary) output directory if needed, else keep it, as it doubles
427 # as the real output directory.
428 if [ -z "$GENERATE_DIRECTORY" ] ; then
429   rm -r "${OUTDIR}"
430 else
431   if ! $_opt_quiet ; then
432     [ -r "${OUTDIR}" ] && echo "${OUTDIR} has been generated."
433   fi
434 fi
435
436 exit 0
437
438 ## END OF FILE##################################################################