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