Created
September 21, 2012 00:41
-
-
Save ssokolow/3759156 to your computer and use it in GitHub Desktop.
Novice-safe shell script for gathering data to report bugs in Linux games
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
# dash-Compatible Linux Configuration Dumper for Troubleshooting Games | |
# (Sort of like DxDiag but for Linux) | |
# | |
# Get and contribute updates to this script at: https://gist.github.com/3759156 | |
# | |
# NOTE: Please test changes on as many of the following shells as possible: | |
# dash, bash, pdksh, busybox, ash, zsh | |
# | |
# TODO: | |
# - Confirm that the presence or absence of S3 Texture Compression support is | |
# included in existing read-outs. If feasible, list it separately for easy | |
# recognition by users should the developers ask them to check. | |
# - Linking and crash logs: | |
# - Provide support for taking the relative path to the game binary (both | |
# hard-coded and as an argument) | |
# - If the game binary is provided, include the binary format (eg. ELF64) and | |
# data about the system's supported binary formats in the readout. | |
# - If the game binary is provided, include the ldd output in the log | |
# - Support a --log-crash flag which causes it to also run the game under gdb | |
# and automatically collect the output of "bt full". | |
# - Compositing and window management: | |
# - Find a way to detect whether a compositor like Compiz is running | |
# 1. log into KDE 4 | |
# 2. (xrandr -q -v ; xdpyinfo -queryExtensions -ext all; glxinfo -t -v -l) 2>&1 1>log.txt` | |
# 3. toggle compositing, log them again, and diff the logs to see if | |
# anything reliable shows up. | |
# - Find a generic mechanism for detecting the active WM (eg. How does | |
# fusion-icon do it?) | |
# - Design tests for whether Compiz and Kwin are set to suspend compositing | |
# for fullscreen windows. | |
# - Audio: | |
# - A list of audio devices (input and output, waveform, midi, and mixers) | |
# - Which audio devices are default? | |
# - Are the PulseAudio, OSS4, JACK, etc. daemons installed? | |
# - Are the PulseAudio, JACK, CUSE ossproxy, etc. daemons running? | |
# - A list of installed libpulse/libjack/etc. to clarify ld and dlopen behavior | |
# (locate libpulse | fgrep .so | xargs ls -l) | |
# - Use lsof or equivalent to check what's hanging on the soundcard endpoints | |
# - Is pasuspender installed? | |
# - Is another application using pasuspender to block the sound card? | |
# - What else can cause audio issues? | |
# - Input Devices: | |
# - List of connected Joystics | |
# - List of XInput devices | |
# - Find a way to detect off-calibration joysticks which could cause in-game | |
# menus to cycle wildly. (Known problem with some USB-PS2 controller bridges | |
# and at least the official Windows drivers for 3DConnexion Space Navigators) | |
# - Look into whether any other kind of input debugging data would be | |
# worth gathering | |
# - Decide what network-related data would be useful. | |
# - Compare my output to Steam's output as shown at | |
# http://phoronix.com/forums/showthread.php?p=369297#post369297 | |
# | |
# Known Bugs: | |
# - busybox's free is ignorant of memory used for opportunistic disk caching. | |
# - The version of busybox included with the OpenPandora misunderstands | |
# the command `df -h /` | |
# | |
# Copyright (c) 2012 Stephan Sokolow | |
# | |
# Permission is hereby granted, free of charge, to any person obtaining a copy | |
# of this software and associated documentation files (the "Software"), to | |
# deal in the Software without restriction, including without limitation the | |
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | |
# sell copies of the Software, and to permit persons to whom the Software is | |
# furnished to do so, subject to the following conditions: | |
# | |
# The above copyright notice and this permission notice shall be included in | |
# all copies or substantial portions of the Software. | |
# | |
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | |
# IN THE SOFTWARE. | |
# Edit these as appropriate to your specific debugging needs | |
DUMP_FILE=~/game_troubleshooting_dump.txt | |
REQUIRE_CMDS="glxinfo" | |
# ---=== Respawn self early if necessary ===--- | |
# Since we don't read from stdin anyway, it's reasonable to assume that, if | |
# it's not a TTY, the user must need a terminal window to see our output. | |
# (As opposed to being intentionally piped or redirected by the user) | |
if [ ! -t 0 ]; then | |
for CMD in x-terminal-emulator urxvt uxterm rxvt xterm; do | |
if type "$CMD" 1>/dev/null 2>&1; then | |
exec "$CMD" -e "$0" --wait | |
fi | |
done | |
fi | |
# Redirect stdout to the dump file to avoid repetitive output redirects | |
exec > "$DUMP_FILE" | |
# ---=== Function Declarations ===--- | |
posix_check() { | |
if ! type "$1" 1>/dev/null 2>&1; then | |
echo "ERROR: Your system is either broken or not POSIX-compatible." 1>&2 | |
echo " Please run this in a shell that provides the $1 command." 1>&2 | |
exit 1 | |
fi | |
} | |
prefer_cmd() { | |
if ! type "$1" 1>/dev/null 2>&1; then | |
printf "$3 $1 missing.\n" | |
printf "WARNING: %s is not installed. $3\n" "$1" 1>&2 | |
printf " (It is often found in a package with a name like '%s')\n\n" "$2" 1>&2 | |
local REQUIRE_CMDS=" $REQUIRE_CMDS " | |
case $REQUIRE_CMDS in *" $1 "*) | |
printf "ERROR: The data gathered by "$1" is required. Please install it and try again.\n\n" 1>&2 | |
exit 2 | |
;; | |
esac | |
return 1 | |
fi | |
} | |
#FIXME: This breaks on the version of BusyBox provided by the OpenPandora | |
# (because they misunderstand `df -h /` to match only dev nodes) | |
# Implement some kind of line-counting and condense into one awk expr. | |
# http://www.catonmat.net/blog/awk-one-liners-explained-part-one/ | |
# http://mywiki.wooledge.org/BashFAQ/094 | |
show_free() { | |
if [ -z "$2" ]; then | |
name="$1" | |
else | |
name="$2" | |
fi | |
# The "grep %" strips off the long device paths that busybox or bad luck | |
# can use to word-wrap the rows. | |
# The first awk ensures the second awk will count fields properly if | |
# word-wrap occurred. | |
fspace="`LC_ALL=C df -h \"$1\" | grep % | awk '{ getline; printf \"x%s\", $0 }' | awk '{ print $4 }'`" | |
# We need the "grep %" so long device paths like those in busybox won't | |
# break things when they trigger word-wrap | |
printf "%-20s: %s\n" "$name" "$fspace" | |
} | |
# Check for basic system sanity to be ridiculously thorough | |
posix_check type | |
posix_check printf | |
posix_check cat | |
posix_check grep | |
posix_check sed | |
posix_check awk | |
# Get the OS name and platform architecture strings since they're not included | |
# in the kernel version | |
if prefer_cmd uname coreutils "Cannot read platform string. This system may be very broken or not Linux."; then | |
printf "Platform:\n %s %s\n\n" "`uname -o`" "`uname -m`" | |
fi | |
# Get the kernel version (an all-around useful thing to know) | |
printf "Kernel Version:\n" | |
cat /proc/version | sed 's@^@ @' | |
printf "\n=== distro release version ===\n\n" | |
if type lsb_release 1>/dev/null 2>&1; then | |
lsb_release -a 2>/dev/null | |
elif [ -e /etc/lsb-release ]; then | |
cat /etc/lsb-release | |
else | |
printf "WARNING: No Linux Standards Base release metadata found.\n" 1>&2 | |
printf " Verify the distro name and version before submitting.\n\n" 1>&2 | |
grep '' /etc/issue /etc/*_release /etc/*-release /etc/*_version /etc/*-version 2>|/dev/null | |
fi | |
printf "\n=== desktop environment ===\n\n" | |
printf "DESKTOP_SESSION : %s\n" "$DESKTOP_SESSION" | |
printf "XDG_CURRENT_DESKTOP : %s\n" "$XDG_CURRENT_DESKTOP" | |
printf "\n=== SDL environment ===\n\n" | |
set | grep -a SDL_ | |
# Get the CPU model in case it's incompatible with the build options | |
printf "\n=== cpu information (per core) ===\n\n" | |
if [ -e /proc/cpuinfo ]; then | |
cpuinfo=`cat /proc/cpuinfo | grep -E '^(processor|model name|flags|cpu MHz|$)'` | |
if [ -z "$cpuinfo" ]; then | |
cat /proc/cpuinfo | |
printf "\n" | |
else | |
printf "%s\n\n" "$cpuinfo" | |
fi | |
else | |
printf "ERROR: /proc/cpuinfo not found! (Non-Linux platform?)\n\n" | |
printf "WARNING: /proc/cpuinfo not found! This script only supports Linux.\n" 1>&2 | |
fi | |
if [ -e /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies ]; then ( | |
printf 'CPU Frequency Scaling:\n' | |
cd /sys/devices/system/cpu | |
for CPU in cpu*; do | |
( | |
# Skip folders not corresponding to individual CPUs | |
# (Can't use continue here in pdksh) | |
if [ -e "$CPU/cpufreq" ]; then | |
cd "$CPU/cpufreq" | |
printf " $CPU:\n" | |
grep '' scaling_min_freq scaling_max_freq scaling_governor | sed 's@^@ @' | |
fi | |
) | |
done ) | |
printf '\n' | |
else | |
printf "Unable to query CPU frequency scaling settings\n\n" | |
fi | |
# Get the memory stats in case the user is experiencing an OOM-related crash | |
# TODO: Find some way to detect busybox and warn about the +/- buffers issue | |
if prefer_cmd free procps "This system may be very broken or not Linux."; then | |
printf "=== memory information (in megabytes) ===\n\n" | |
free -m | |
elif [ -e /proc/meminfo ]; then | |
printf "=== memory information (fallback) ===\n\n" | |
cat /proc/meminfo | grep -E '^(MemTotal|MemFree|Buffers|Cached|SwapTotal|SwapFree)' | |
else | |
printf "=== memory information ===\n\n" | |
printf "Unable to retrieve memory statistics (Non-Linux platform?)\n\n" | |
printf "ERROR: Neither /usr/bin/free nor /proc/meminfo exist!\n" 1>&2 | |
fi | |
# Record the free disk space in places known to cause death by failure to write | |
printf "\n=== free disk space ===\n\n" | |
show_free / | |
show_free /tmp | |
show_free /var/tmp | |
show_free /var/log | |
show_free ~ "User Home Directory" | |
show_free "$0" "Game Directory" | |
printf "\n" | |
# Try to look up the video driver used by X.org | |
if [ -e /var/log/Xorg.0.log ]; then | |
printf "=== X.org Drivers Used ===\n" | |
# Source: http://askubuntu.com/a/28037 | |
x_drivers=`egrep -i " connected|card detect|primary dev|rgb weight|default visual is" /var/log/Xorg.0.log | sed 's@^@ @'` | |
if [ -z "$x_drivers" ]; then | |
continue | |
fi | |
printf "%s" "$x_drivers" | |
printf '\n\n' | |
elif type glxinfo 1>/dev/null 2>&1; then | |
printf "=== X.org Drivers Used (glxinfo) ===\n" | |
glxinfo | grep -i vendor | |
printf '\n' | |
printf "WARNING: Detection of in-use video drivers is vague. /var/log/Xorg.0.log is missing!\n" 1>&2 | |
else | |
printf "Unable to detect in-use video drivers. /var/log/Xorg.0.log does not exist.\n\n" | |
printf "WARNING: Unable to detect in-use video drivers. glxinfo and /var/log/Xorg.0.log are missing!\n" 1>&2 | |
fi | |
if prefer_cmd lspci pciutils "Unable to identify video card model and kernel driver."; then | |
printf "=== video card details ===\n\n" | |
for X in `lspci | grep VGA | cut -d' ' -f1`; do | |
lspci -v -s "$X" | grep -E '(VGA|Subsystem|Kernel|^$)' | |
done | |
fi | |
if prefer_cmd xrandr x11-server-utils "Unable to detect available monitor resolutions."; then | |
printf "=== available monitor resolutions ===\n\n" | |
xrandr 2>/dev/null | |
fi | |
if prefer_cmd xdpyinfo x11-utils "Unable to check for Xinerama (multi-monitor) data."; then | |
printf "\nXinerama Info:\n" | |
xdpyinfo -ext XINERAMA 2>/dev/null | grep head | sed 's@^@ @' | |
fi | |
if prefer_cmd glxinfo mesa-utils "Unable to dump OpenGL data for debugging 2D/3D acceleration."; then | |
printf "\n=== glxinfo output ===\n\n" | |
glxinfo | |
fi | |
# Weird, misconfigured locale settings have been known to cause problems | |
printf "\n=== language and localization ===\n\n" | |
if type locale 1>/dev/null 2>&1; then | |
locale | |
else | |
set | grep -a LANG | |
set | grep -a LC_ | |
fi | |
printf "\n=== diagnostic script info ===\n\n" | |
printf "Novice-safe shell script for gathering data to report bugs in Linux games\n\n" | |
printf "Source:\n https://gist.github.com/3759156\n" | |
# XXX: If you know another robust way to pin down this script's version, I'm all ears. | |
if type sha1sum 1>/dev/null 2>&1; then | |
printf "Version Hash (SHA1):\n %s\n" "`sha1sum \"$0\" | cut -d' ' -f1`" | |
elif type md5sum 1>/dev/null 2>&1; then | |
printf "Version Hash (MD5):\n %s\n" "`md5sum \"$0\" | cut -d' ' -f1`" | |
else | |
printf " Unable to identify script version\n" | |
printf " WARNING: You are advised to re-run this script with sha1sum or md5sum installed so it can note its own version.\n" 1>&2 | |
fi | |
printf '\nThis Report Generated: %s' "`date -R`" | |
printf "Data gathered. Please attach this file to your bug report:\n %s\n" "$DUMP_FILE" 1>&2 | |
# In case we exec'd ourself into a terminal | |
if [ "$1" = "--wait" ]; then | |
printf '\nPress Enter to close this window... ' 1>&2 | |
read throwaway | |
fi | |
# vim: set noexpandtab sw=4 sts=4 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment