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