#!/bin/sh -e # ***** BEGIN LICENSE BLOCK ***** # * Copyright (C) 2007-2009 Alexey Gladkov # * # * This program is free software; you can redistribute it and/or modify # * it under the terms of the GNU General Public License as published by # * the Free Software Foundation; either version 2 of the License, or # * (at your option) any later version. # * # * This program is distributed in the hope that it will be useful, # * but WITHOUT ANY WARRANTY; without even the implied warranty of # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # * GNU General Public License for more details. # * # * You should have received a copy of the GNU General Public License # * along with this program; if not, write to the Free Software # * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. # ***** END LICENSE BLOCK ***** WITHOUT_RC_COMPAT=1 . /etc/init.d/functions . shell-error . shell-args cwd="$PWD" outfile= begin_msg() { [ -z "$quiet" ] || return 0 [ -z "$*" ] || printf '%s ' "$*" } end_msg() { [ -z "$quiet" ] || return 0 if [ "$BOOTUP" = color ]; then local rc=$1 case "$rc" in 17) echo_passed ;; 0) echo_success ;; *) echo_failure ;; esac ||: fi echo } show_help() { local rc="${1:-0}" cat <; -q, --quiet Try to be more quiet; -v, --verbose Print a message for each action; -V, --version Print program version and exit; -h, --help Show this message. EOF exit "$rc" } print_version() { cat < Copyright (C) 2007-2009 Alexey Gladkov This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. EOF exit } timestamp() { printf '# ' > "$1" date >> "$1" 2>&1 } workdir= exit_handler() { local rc=$? trap - EXIT [ ! -d "$workdir" ] || rm -rf -- "$workdir" exit $rc } ################ ### Information ################ # Information about udev events in the system export no_save_udevtrigger= save_udevtrigger_msg='Obtaining kernel devices events' save_udevtrigger() { [ -z "$no_save_udevtrigger" ] || return 0 [ -n "$udevtrigger" ] || return 17 local r='hardware/sysreport.udevtrigger' timestamp "$r" printf "# '$udevtrigger --dry-run --verbose' output\n\n" >> "$r" $udevtrigger --dry-run --verbose >>"$r" 2>&1 || return } # Information about modules and device modaliases module_sysinfo() { local path="$1" module= params= module="${path##*/}" if [ -d "$path/parameters" ]; then for p in "$path/parameters"/*; do [ "$p" != "$path/parameters/*" ] || break [ -r "$p" ] && params="$params ${p##*/}=$(cat "$p")" || params="$params ${p##*/}=[ERROR: $p: Permission denied]" done fi printf "%s\t%s\n" "$module" "$params" } modalias_info() { local path="$1" p real_path if [ ! -e "$path/driver" ]; then printf "\t\n" return fi if ! real_path="$(readlink -ev "$path/driver/module" 2>/dev/null)"; then printf "\t\n" return fi module_sysinfo "$real_path" } export no_save_modalias= save_modalias_msg='Obtaining modalias' save_modalias() { [ -z "$no_save_modalias" ] || return 0 [ -n "$udevtrigger" ] || return 17 local p r='hardware/sysreport.modalias' timestamp "$r" printf "# Format: \n\n" >> "$r" $udevtrigger --dry-run --verbose | while read p; do p="${p#/sys/}" if [ -f "/sys/$p/modalias" ]; then modalias="$(cat "/sys/$p/modalias")" info="$(modalias_info "/sys/$p")" printf "%s\t%s\n" "$modalias" "$info" fi done >> "$r" } # Information about kernel modules and params via /sys export no_save_modules= save_modules_msg='Obtaining kernel modules and params via /sys' save_modules() { [ -z "$no_save_modules" ] || return 0 local r='hardware/sysreport.kmodules' timestamp "$r" printf '# Format: \n\n' >> "$r" local path= for path in /sys/module/*; do [ "$path" != "/sys/module/*" ] || break module_sysinfo "$path" done >> "$r" } # List all PCI devices export no_save_lspci= save_lspci_msg='Obtaining PCI device list' save_lspci() { local prog=/usr/bin/lspci [ -z "$no_save_lspci" ] || return 0 [ -x $prog ] || return 17 local r='hardware/sysreport.lspci' timestamp "$r" printf "# 'lspci -vvnn' output\n\n" >> "$r" LC_ALL=C $prog -vvnn >>"$r" 2>&1 || return } # Modules in the Linux Kernel export no_save_lsmod= save_lsmod_msg='Obtaining kernel modules list' save_lsmod() { local prog=/sbin/lsmod [ -z "$no_no_save_lspci" ] || return 0 [ -x $prog ] || return 17 local r='hardware/sysreport.lsmod' timestamp "$r" printf "# 'lsmod' output\n\n" >> "$r" LC_ALL=C $prog >>"$r" 2>&1 || return } # Information from the kernel ring buffer export no_save_dmesg= save_dmesg_msg='Obtaining kernel ring buffer' save_dmesg() { [ -z "$no_save_dmesg" ] || return 0 local r='hardware/sysreport.dmesg' timestamp "$r" printf "# 'dmesg' output\n\n" >> "$r" dmesg >>"$r" 2>&1 || return } # Information from syslog (kern.*) export no_save_syslog_kern= save_syslog_kern_msg='Obtaining syslog kernel messages' save_syslog_kern() { [ -z "$no_save_syslog_kern" ] || return 0 mkdir -p hardware/syslog/kernel for f in info warnings errors; do f="/var/log/kernel/$f" [ ! -f "$f" ] || cp -f -- "$f" hardware/syslog/kernel/ done } export no_save_commoninfo= save_commoninfo_msg='Obtaining system information' save_commoninfo() { [ -z "$no_save_commoninfo" ] || return 0 mkdir hardware/proc for n in \ cgroups \ config.gz \ cmdline \ cpuinfo \ crypto \ devices \ filesystems \ interrupts \ ioports \ ksyms \ mdstat \ meminfo \ partitions \ slabinfo \ stat \ swaps \ version \ bus/input/devices \ bus/input/handlers do [ -f "/proc/$n" ] || continue if [ -z "${n##*/*}" ]; then mkdir -p -- hardware/proc/"${n%/*}" cp -a "/proc/$n" hardware/proc/"${n%/*}" else cp -a "/proc/$n" hardware/proc/ fi done } # EVMS information export no_save_evmsinfo= save_evmsinfo_msg='Obtaining EVMS information' save_evmsinfo() { local prog=/sbin/evms_activate [ -z "$no_save_evmsinfo" ] || return 0 [ -x $prog ] || return 17 local r='hardware/sysreport.evmsplugins' timestamp "$r" LC_ALL=C $prog >> "$r" 2>&1 || return printf "# 'evms_query plugins -i' output\n\n" >> "$r" prog=/sbin/evms_query LC_ALL=C $prog plugins -i >> "$r" 2>&1 || return r='hardware/sysreport.evms' timestamp "$r" printf "# 'evms_query info' output\n\n" >> "$r" LC_ALL=C $prog info >> "$r" 2>&1 || return printf "\n# 'evms_query disks' output\n" >> "$r" LC_ALL=C $prog disks 2>&1 >> "$r" || return local d for d in `$prog disks`; do printf "\n# 'evms_query volumes $d' output\n" >> "$r" LC_ALL=C $prog volumes "$d" 2>&1 >> "$r" || return done for d in `$prog volumes`; do printf "\n# 'evms_query info $d' output\n" >> "$r" LC_ALL=C $prog info "$d" 2>&1 >> "$r" || return done [ ! -s /var/log/evms-engine.log ] || cp -p /var/log/evms-engine.log hardware/sysreport.evms-engine.log } # Partition table information via fdisk export no_save_fdisk= save_fdisk_msg='Obtaining FDISK information' save_fdisk() { local prog=/sbin/fdisk [ -z "$no_save_fdisk" ] || return 0 [ -x $prog ] || return 17 local r='hardware/sysreport.fdisk' timestamp "$r" printf "# 'fdisk -l' output\n\n" >> "$r" LC_ALL=C $prog -l >> "$r" 2>&1 || return } # Print detail of RAID devices. export no_save_raid= save_raid_msg='Obtaining RAID information' save_raid() { local prog=/sbin/mdadm [ -z "$no_save_raid" ] || return 0 [ -x $prog -a -f /proc/mdstat ] || return 17 local mdlist mdlist="$(sed -ne 's,^\(md[^[:space:]]\+\) :.*,/dev/\1,p' /proc/mdstat | sort | tr '\n' ' ')" [ -n "$mdlist" ] || return 17 local r='hardware/sysreport.raid' timestamp "$r" printf "# 'mdadm --detail %s' output\n\n" "$mdlist" >> "$r" LC_ALL=C $prog --detail $mdlist >> "$r" 2>&1 || return } # Attributes of a LVMs. export no_save_lvm= save_lvm_msg='Obtaining LVM information' save_lvm() { local prog=/sbin/lvm [ -z "$no_save_lvm" ] || return 0 [ -x $prog ] || return 17 local r='hardware/sysreport.lvm' timestamp "$r" for e in lvmdiskscan pvdisplay vgdisplay lvdisplay; do if [ -x "/sbin/$e" ]; then printf "\n# '%s' output\n\n" "$e" >> "$r" "$e" >> "$r" 2>&1 || return fi done } # VESA Display Data Channel (or DDC) export no_save_ddcprobe= save_ddcprobe_msg='Obtaining VESA Display Data Channel' save_ddcprobe() { local prog=/usr/sbin/ddcprobe [ -z "$no_save_ddcprobe" ] || return 0 [ -x $prog ] || return 17 local r='hardware/sysreport.ddcprobe' timestamp "$r" printf "# 'ddcprobe' output\n\n" >> "$r" LC_ALL=C $prog >> "$r" 2>&1 || return } # DMI (some say SMBIOS) table information export no_save_dmidecode= save_dmidecode_msg='Obtaining DMI table information' save_dmidecode() { local prog=/usr/sbin/dmidecode [ -z "$no_save_dmidecode" ] || return 0 [ -x $prog -a -r /dev/mem ] || return 17 local r='hardware/sysreport.dmidecode' timestamp "$r" printf "# 'dmidecode' output\n\n" >> "$r" LC_ALL=C $prog >> "$r" 2>&1 || return } # The "vital product data" information export no_save_vpddecode= save_vpddecode_msg='Obtaining vital product data' save_vpddecode() { local prog=/usr/sbin/vpddecode [ -z "$no_save_vpddecode" ] || return 0 [ -x $prog -a -r /dev/mem ] || return 17 local r='hardware/sysreport.vpddecode' timestamp "$r" printf "# 'vpddecode' output\n\n" >> "$r" LC_ALL=C $prog >> "$r" 2>&1 || return } # BIOS information export no_save_biosdecode= save_biosdecode_msg='Obtaining BIOS information' save_biosdecode() { local prog=/usr/sbin/biosdecode [ -z "$no_no_save_vpddecode" ] || return 0 [ -x $prog -a -r /dev/mem ] || return 17 local r='hardware/sysreport.biosdecode' timestamp "$r" printf "# 'biosdecode' output\n\n" >> "$r" LC_ALL=C $prog >> "$r" 2>&1 || return } # DSDT (Differentiated System Description Table) # This table contains the Differentiated Definition Block, # which supplies the information and configuration information # about the base system. It is always inserted into # the ACPI Namespace by the OS at boot time. export no_save_acpi_dsdt= save_acpi_dsdt_msg='Obtaining ACPI DSDT information' save_acpi_dsdt() { [ -z "$no_save_acpi_dsdt" ] || return 0 [ -r /proc/acpi/dsdt ] || return 17 local r='hardware/sysreport.acpi-dsdt' cp /proc/acpi/dsdt "$r" || return } export no_save_alsa_cards= save_alsa_cards_msg='Obtaining ALSA information' save_alsa_cards() { [ -z "$no_save_alsa_cards" ] || return 0 [ -d /proc/asound ] || return 17 local r='hardware/sysreport.asound' timestamp "$r" local f='/proc/asound/cards' printf "\n# 'cat %s'\n" "$f" >> "$r" cat "$f" 2>&1 >> "$r" || return find /proc/asound -iwholename '*/card*/codec#*' | while read f; do printf "\n# 'cat %s'\n" "$f" >> "$r" cat "$f" 2>&1 >> "$r" || return done printf \\n >> "$r" } # List USB devices export no_save_lsusb= save_lsusb_msg='Obtaining USB device list' save_lsusb() { local prog=/usr/sbin/lsusb [ -z "$no_save_lsusb" ] || return 0 [ -x $prog ] || return 17 local r='hardware/sysreport.lsusb' timestamp "$r" printf "# 'lsusb' output\n\n" >> "$r" LC_ALL=C $prog >> "$r" 2>&1 || return } # Print block device attributes export no_save_blkid= save_blkid_msg='Obtaining block device attributes' save_blkid() { local prog=/sbin/blkid [ -z "$no_save_blkid" ] || return 0 [ -x $prog ] || return 17 local r='hardware/sysreport.blkid' timestamp "$r" printf "# 'blkid' output\n\n" >> "$r" LC_ALL=C $prog >> "$r" 2>&1 || return } export no_save_xorg_logs= save_xorg_logs_msg="Obtaining Xorg log files" save_xorg_logs() { [ -z "$no_save_xorg_logs" ] || return 0 mkdir -p hardware/Xorg local log rc=0 for log in /var/log/Xorg.*.log; do [ "$log" != '/var/log/Xorg.*.log' ] || return 17 cp -a -- "$log" hardware/Xorg/ || rc=1 done return $rc } export no_save_rpmlist= save_rpmlist_msg="Obtaining installed RPM packages" save_rpmlist() { local prog=/bin/rpm [ -z "$no_save_rpmlist" ] || return 0 [ -x $prog ] || return 17 local r='system/sysreport.rpmlist' $prog -qa --qf='%{name} %{version} %{release}\n' >"$r" || return sort -o "$r" "$r" } export no_save_release= save_release_msg="Obtaining distribution release file" save_release() { local f [ -z "$no_save_release" ] || return 0 mkdir system/etc for f in /etc/*-release; do [ ! -L "$f" ] && [ -f "$f" ] || continue cp -aft system/etc/ -- "$f" done } save_env="$(printenv |sed -ne 's/^\(no_save_[a-z_]\+\)=.*/\1/pg' |sort -u)" getopt_save="$(printf %s "$save_env" |sed -e 's/^no_//' |tr _ - |tr -s '[:space:]' ',')" getopt_no_save="$(printf %s "$save_env" |tr _ - |tr -s '[:space:]' ',')" TEMP=`getopt -n $PROG -o o:,$getopt_common_opts -l outfile:,save:,no-save:,$getopt_save,$getopt_no_save,$getopt_common_longopts -- "$@"` || show_usage eval set -- "$TEMP" while :; do case "$1" in --save|--no-save) mode="$1" shift save_value= [ -n "${mode##--no-save*}" ] || save_value=1 if [ -n "$(printf %s "$1" |tr -d '[:alpha:],[:space:]')" ]; then message "$mode: invalid argument: $1" show_usage fi for arg in `printf %s "$1" |tr , ' '`; do name="no_save_$arg" if ! echo "$save_env" |grep -qs "^$name\$"; then message "$mode: invalid argument: $arg" show_usage fi eval "$name=$save_value" done ;; --save-|--no-save-) show_usage ;; --save-[a-z]*) arg="no_save_${1##--save-}" eval $arg= ;; --no-save-[a-z]*) arg="no_save_${1##--no-save-}" eval $arg=1 ;; -o|--outfile) shift; outfile="$1" ;; --) shift; break ;; *) parse_common_option "$1" ;; esac shift done trap exit_handler HUP PIPE INT QUIT TERM EXIT workdir="`mktemp -dt "$PROG.XXXXXXXXXX"`" cd "$workdir" mkdir hardware system udevtrigger= if type udevtrigger >/dev/null 2>&1; then udevtrigger='udevtrigger' elif type udevadm >/dev/null 2>&1; then udevtrigger='udevadm trigger' fi for f in $(printenv |sed -ne 's/^no_\(save_[a-z_]\+\)=.*/\1/pg' |sort -u); do eval msg="\${${f}_msg:-Obtaining unknown information}" begin_msg "$msg" "$f" && rc=0 || rc=$? end_msg "$rc" done [ -n "$(find -type f)" ] || exit 0 [ -n "$outfile" ] || outfile="$cwd/sysreport-$(date +"%Y%m%d").tar.bz2" begin_msg "Saving system information to ${outfile##*/}" tar -cjf "$outfile" * && rc=0 || rc=$? end_msg "$rc" printf '\n\nPlease submit %s to sysreport@altlinux.org\n\n' "$outfile"