1#!/bin/bash
2# We use some bash-isms (getopts?)
3
4# Copyright (C) 2007 Red Hat, Inc. All rights reserved.
5#
6# This file is part of LVM2.
7#
8# This copyrighted material is made available to anyone wishing to use,
9# modify, copy, or redistribute it subject to the terms and conditions
10# of the GNU General Public License v.2.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program; if not, write to the Free Software Foundation,
14# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15
16# lvm_dump: This script is used to collect pertinent information for
17#           the debugging of lvm issues.
18
19# following external commands are used throughout the script
20# echo and test are internal in bash at least
21MKDIR=mkdir # need -p
22TAR=tar # need czf
23RM=rm # need -rf
24CP=cp
25TAIL=tail # we need -n
26LS=ls # need -la
27PS=ps # need alx
28SED=sed
29DD=dd
30CUT=cut
31DATE=date
32BASENAME=basename
33UNAME=uname
34
35# user may override lvm and dmsetup location by setting LVM_BINARY
36# and DMSETUP_BINARY respectively
37LVM=${LVM_BINARY-lvm}
38DMSETUP=${DMSETUP_BINARY-dmsetup}
39
40die() {
41    code=$1; shift
42    echo "$@" 1>&2
43    exit $code
44}
45
46"$LVM" version >& /dev/null || die 2 "Could not run lvm binary '$LVM'"
47"$DMSETUP" version >& /dev/null || DMSETUP=:
48
49function usage {
50	echo "$0 [options]"
51	echo "    -h print this message"
52	echo "    -a advanced collection - warning: if lvm is already hung,"
53	echo "       then this script may hang as well if -a is used"
54	echo "    -m gather LVM metadata from the PVs"
55	echo "    -d <directory> dump into a directory instead of tarball"
56	echo "    -c if running clvmd, gather cluster data as well"
57	echo ""
58
59	exit 1
60}
61
62advanced=0
63clustered=0
64metadata=0
65while getopts :acd:hm opt; do
66	case $opt in
67		s)      sysreport=1 ;;
68		a)	advanced=1 ;;
69		c)	clustered=1 ;;
70		d)	userdir=$OPTARG ;;
71		h)	usage ;;
72		m)	metadata=1 ;;
73		:)	echo "$0: $OPTARG requires a value:"; usage ;;
74		\?)     echo "$0: unknown option $OPTARG"; usage ;;
75		*)	usage ;;
76	esac
77done
78
79NOW=`$DATE -u +%G%m%d%k%M%S | /usr/bin/tr -d ' '`
80if test -n "$userdir"; then
81	dir="$userdir"
82else
83	dirbase="lvmdump-$HOSTNAME-$NOW"
84	dir="$HOME/$dirbase"
85fi
86
87test -e $dir && die 3 "Fatal: $dir already exists"
88$MKDIR -p $dir || die 4 "Fatal: could not create $dir"
89
90log="$dir/lvmdump.log"
91
92myecho() {
93	echo "$@"
94	echo "$@" >> "$log"
95}
96
97log() {
98	echo "$@" >> "$log"
99	eval "$@"
100}
101
102warnings() {
103	if test "$UID" != "0" && test "$EUID" != "0"; then
104		myecho "WARNING! Running as non-privileged user, dump is likely incomplete!"
105	elif test "$DMSETUP" = ":"; then
106		myecho "WARNING! Could not run dmsetup, dump is likely incomplete."
107	fi
108}
109
110warnings
111
112myecho "Creating dump directory: $dir"
113echo " "
114
115if (( $advanced )); then
116	myecho "Gathering LVM volume info..."
117
118	myecho "  vgscan..."
119	log "\"$LVM\" vgscan -vvvv > \"$dir/vgscan\" 2>&1"
120
121	myecho "  pvscan..."
122	log "\"$LVM\" pvscan -v >> \"$dir/pvscan\" 2>> \"$log\""
123
124	myecho "  lvs..."
125	log "\"$LVM\" lvs -a -o +devices >> \"$dir/lvs\" 2>> \"$log\""
126
127	myecho "  pvs..."
128	log "\"$LVM\" pvs -a -v > \"$dir/pvs\" 2>> \"$log\""
129
130	myecho "  vgs..."
131	log "\"$LVM\" vgs -v > \"$dir/vgs\" 2>> \"$log\""
132fi
133
134if (( $clustered )); then
135	myecho "Gathering cluster info..."
136
137	{
138	for i in nodes status services; do
139		cap_i=$(echo $i|tr a-z A-Z)
140		printf "$cap_i:\n----------------------------------\n"
141		log "cman_tool $i 2>> \"$log\""
142		echo
143	done
144
145	echo "LOCKS:"
146	echo "----------------------------------"
147	if [ -f /proc/cluster/dlm_locks ]
148	then
149		echo clvmd > /proc/cluster/dlm_locks
150		cat /proc/cluster/dlm_locks
151		echo
152		echo "RESOURCE DIR:"
153		cat /proc/cluster/dlm_dir
154		echo
155		echo "DEBUG LOG:"
156		cat /proc/cluster/dlm_debug
157		echo
158	fi
159	if [ -f /debug/dlm/clvmd ]
160	then
161		cat /debug/dlm/clvmd
162		echo
163		echo "WAITERS:"
164		cat /debug/dlm/clvmd_waiters
165		echo
166		echo "MASTER:"
167		cat /debug/dlm/clvmd_master
168	fi
169	} > $dir/cluster_info
170fi
171
172myecho "Gathering LVM & device-mapper version info..."
173echo "LVM VERSION:" > "$dir/versions"
174"$LVM" lvs --version >> "$dir/versions" 2>> "$log"
175echo "DEVICE MAPPER VERSION:" >> "$dir/versions"
176"$DMSETUP" --version >> "$dir/versions" 2>> "$log"
177echo "KERNEL VERSION:" >> "$dir/versions"
178"$UNAME" -a >> "$dir/versions" 2>> "$log"
179echo "DM TARGETS VERSIONS:" >> "$dir/versions"
180"$DMSETUP" targets >> "$dir/versions" 2>> "$log"
181
182myecho "Gathering dmsetup info..."
183log "\"$DMSETUP\" info -c > \"$dir/dmsetup_info\" 2>> \"$log\""
184log "\"$DMSETUP\" table > \"$dir/dmsetup_table\" 2>> \"$log\""
185log "\"$DMSETUP\" status > \"$dir/dmsetup_status\" 2>> \"$log\""
186
187myecho "Gathering process info..."
188log "$PS alx > \"$dir/ps_info\" 2>> \"$log\""
189
190myecho "Gathering console messages..."
191log "$TAIL -n 75 /var/log/messages > \"$dir/messages\" 2>> \"$log\""
192
193myecho "Gathering /etc/lvm info..."
194log "$CP -a /etc/lvm \"$dir/lvm\" 2>> \"$log\""
195
196myecho "Gathering /dev listing..."
197log "$LS -laR /dev > \"$dir/dev_listing\" 2>> \"$log\""
198
199myecho "Gathering /sys/block listing..."
200log "$LS -laR /sys/block > \"$dir/sysblock_listing\"  2>> \"$log\""
201log "$LS -laR /sys/devices/virtual/block >> \"$dir/sysblock_listing\"  2>> \"$log\""
202
203if (( $metadata )); then
204	myecho "Gathering LVM metadata from Physical Volumes..."
205
206	log "$MKDIR -p \"$dir/metadata\""
207
208	pvs="$("$LVM" pvs --separator , --noheadings --units s --nosuffix -o \
209	    name,pe_start 2>> "$log" | $SED -e 's/^ *//')"
210	for line in $pvs
211	do
212		test -z "$line" && continue
213		pv="$(echo $line | $CUT -d, -f1)"
214		pe_start="$(echo $line | $CUT -d, -f2)"
215		name="$($BASENAME "$pv")"
216		myecho "  $pv"
217		log "$DD if=$pv \"of=$dir/metadata/$name\" bs=512 count=$pe_start 2>> \"$log\""
218	done
219fi
220
221if test -z "$userdir"; then
222	lvm_dump="$dirbase.tgz"
223	myecho "Creating report tarball in $HOME/$lvm_dump..."
224fi
225
226warnings
227
228if test -z "$userdir"; then
229	cd "$HOME"
230	"$TAR" czf "$lvm_dump" "$dirbase" 2>/dev/null
231	"$RM" -rf "$dir"
232fi
233
234exit 0
235
236