xref: /illumos-gate/usr/src/cmd/fm/scripts/fmsim.ksh (revision 08855964b9970604433f7b19dcd71cf5af5e5f14)
1#!/bin/ksh -p
2#
3# CDDL HEADER START
4#
5# The contents of this file are subject to the terms of the
6# Common Development and Distribution License (the "License").
7# You may not use this file except in compliance with the License.
8#
9# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10# or http://www.opensolaris.org/os/licensing.
11# See the License for the specific language governing permissions
12# and limitations under the License.
13#
14# When distributing Covered Code, include this CDDL HEADER in each
15# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16# If applicable, add the following below this CDDL HEADER, with the
17# fields enclosed by brackets "[]" replaced with your own identifying
18# information: Portions Copyright [yyyy] [name of copyright owner]
19#
20# CDDL HEADER END
21#
22#
23# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24# Use is subject to license terms.
25#
26
27export PATH=/usr/bin:/usr/sbin:/usr/ccs/bin
28unset ENV TMPDIR
29umask 022
30cwd=$PWD
31
32isa=$(uname -p)
33if [[ $isa = sparc ]]; then
34	isa64=sparcv9
35elif [[ $isa = i386 ]]; then
36	isa64=amd64
37else
38	isa64=unknown
39fi
40
41if [[ -n "$CODEMGR_WS" ]]; then
42	sysroot=$CODEMGR_WS/proto/root_$isa
43elif [[ -n "$ROOT" ]]; then
44	sysroot=$ROOT
45else
46	sysroot=/
47fi
48
49quote=
50eol='\'
51files=
52
53simchan=com.sun:fm:fmd$$
54simroot=/tmp/fmd.$$
55simscript=run
56simpid=
57
58truss_cmd=
59truss_args=
60dump_args=
61inj_args=
62fmd_args=
63
64opt_h=false
65opt_i=false
66opt_s=false
67opt_w=false
68opt_x=false
69
70function cp_so
71{
72	nm -ghp $1 2>/dev/null | while read addr type name; do
73		[[ $type != T ]] && continue
74		case $name in
75		_fmd_init)        cp $1 $2/usr/lib/fm/fmd/plugins; return ;;
76		fmd_fmri_nvl2str) cp $1 $2/usr/lib/fm/fmd/schemes; return ;;
77		topo_load)        cp $1 $2/usr/lib/fm/topo/plugins; return ;;
78		esac
79	done
80	die "\nunknown .so type -- $1"
81}
82
83function cp_topo
84{
85	mkdir -p $2/usr/lib/fm/topo/maps
86	cp $1 $2/usr/lib/fm/topo/maps;
87	for platdir in $2/usr/platform/*/lib/fm/topo/maps; do
88		rm -f $platdir/* 2>/dev/null
89	done
90}
91
92function list_cmds
93{
94	for cmd in fmadm fmdump fmstat; do
95		echo usr/sbin/$cmd
96	done
97}
98
99function wait_status
100{
101	if [[ $1 -gt 128 ]]; then
102		sig=$(kill -l $(($1 - 128)))
103		die "fmd terminated from signal $sig (see $simroot)"
104	elif [[ $1 -ne 0 ]]; then
105		die "fmd terminated with status $1 (see $simroot)"
106	fi
107}
108
109function wait_prompt
110{
111	echo "fmsim: [ Press return to $* ] \c"
112	mode=$(stty -g)
113	stty -echo -isig min 1 time 0
114	read s; echo
115	stty $mode
116}
117
118function die
119{
120	echo "fmsim: $*" >& 2
121	$opt_w && wait_prompt exit
122	[[ -n "$simpid" ]] && exit 1 || exit 2
123}
124
125while [[ $# -gt 0 ]]; do
126	OPTIND=1; while getopts ':d:D:ehio:st:vVwx' c; do
127		case "$c" in
128		d)
129			simroot=$OPTARG
130			;;
131		D)
132			truss_cmd=dtrace
133			truss_args="-s $OPTARG -c"
134			quote="'"; eol=""
135			;;
136		e|v|V)
137			dump_args="$dump_args -$c"
138			;;
139		h|i|s|w|x)
140			eval opt_$c'='true
141			;;
142		o)
143			fmd_args="$fmd_args -o $OPTARG"
144			;;
145		t)
146			truss_cmd=truss
147			truss_args="$OPTARG"
148			;;
149		:)
150			die "option requires an argument -- $OPTARG"
151			;;
152		*)
153			die "illegal option -- $OPTARG"
154			;;
155		esac
156	done
157	let OPTIND="$OPTIND - 1"; shift $OPTIND
158
159	if [[ $# -gt 0 ]]; then
160		if [[ -d $1 ]]; then
161			files="$files $1/*"
162		else
163			files="$files $1"
164		fi
165		shift
166	fi
167done
168
169for file in $files; do
170	[[ -r $file ]] || die "input file is missing or not readable -- $file"
171done
172
173if $opt_h || [[ -z "$files" && $opt_i = false ]]; then
174	echo "Usage: fmsim [-ehisvVwx] [-d dir] [-D a.d] [-o opt=val]" \
175	    "[-t args] [file ...]"
176
177	echo "\t-d  set the simulation root directory to the given location"
178	echo "\t-D  start fmd(8) using dtrace(8) and specified D script"
179	echo "\t-e  display error log content instead of fault log content"
180	echo "\t-h  display usage information for fmsim and exit"
181	echo "\t-i  set interactive mode: do not stop after sending events"
182	echo "\t-o  set fmd(8) option to specified value during simulation"
183	echo "\t-s  set up simulation world but do not actually run simulation"
184	echo "\t-t  start fmd(8) using truss(1) and specified arguments"
185	echo "\t-v  set verbose mode: display additional event detail"
186	echo "\t-V  set very verbose mode: display complete event contents"
187	echo "\t-w  wait for a keypress after simulation completes"
188	echo "\t-x  delete simulation world if simulation is successful"
189
190	exit 0
191fi
192
193echo "fmsim: creating simulation world $simroot ... \c"
194[[ -d $simroot ]] || mkdir -p $simroot || exit 1
195cd $simroot || exit 1
196echo "done."
197
198echo "fmsim: populating /var ... \c"
199mkdir -p -m 0755 var/fm/fmd
200mkdir -p -m 0700 var/fm/fmd/ckpt
201mkdir -p -m 0700 var/fm/fmd/rsrc
202mkdir -p -m 0700 var/fm/fmd/xprt
203echo "done."
204
205echo "fmsim: populating /usr/lib/fm from $sysroot ... \c"
206(cd $sysroot && find usr/lib/fm -depth -print | cpio -pdmu $simroot)
207
208for platdir in $sysroot/usr/platform/*/lib/fm; do
209	[[ -d $platdir ]] && platdir=${platdir#$sysroot} || continue
210	echo "fmsim: populating $platdir from $sysroot ... \c"
211	(cd $sysroot && find ${platdir#/} -depth -print | cpio -pdmu $simroot)
212done
213
214echo "fmsim: populating /usr/lib/locale/$LANG from $sysroot ... \c"
215(cd $sysroot && find usr/lib/locale/$LANG -depth -print | cpio -pdmu $simroot)
216
217echo "fmsim: populating /usr/sbin from $sysroot ... \c"
218(cd $sysroot && list_cmds | cpio -pdmu $simroot)
219
220echo "fmsim: adding customizations:\c"
221cd $cwd || exit $1
222
223for file in $files; do
224	base=$(basename $file)
225	case $base in
226	*.cmd)	die "\neversholt command file not yet supported -- $file" ;;
227	fmd.conf) cp $file $simroot/etc/fm/fmd ;;
228	*.conf)	cp $file $simroot/usr/lib/fm/fmd/plugins ;;
229	*.dict)	cp $file $simroot/usr/lib/fm/dict ;;
230	*.eft) cp $file $simroot/usr/lib/fm/eft ;;
231	*.esc)	die "\neversholt source file not yet supported -- $file" ;;
232	*.inj)	inj_args="$inj_args $file" ;;
233	*.log)	inj_args="$inj_args $file" ;;
234	*log)	inj_args="$inj_args $file" ;;
235	*.mo)	cp $file $simroot/usr/lib/locale/$LANG/LC_MESSAGES ;;
236	*.so)	cp_so $file $simroot ;;
237	*.topo) die "\n .topo files not supported -- $file" ;;
238	*.xml) cp_topo $file $simroot ;;
239	*)	die "\nunknown file type or suffix -- $file" ;;
240	esac
241	echo " $base\c"
242done
243
244cd $simroot || exit 1
245echo " done."
246
247echo "fmsim: generating script ... \c"
248cat >$simscript <<EOS
249#!/bin/ksh -p
250#
251# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
252# Use is subject to license terms.
253#
254#ident	"@(#)fmsim.ksh	1.5	06/10/11 SMI"
255
256#
257# fmsim(8) script generated for $simroot $(date)
258#
259
260export LD_LIBRARY_PATH=$simroot/usr/lib:$simroot/usr/lib/fm
261export LD_LIBRARY_PATH_64=$simroot/usr/lib/64:$simroot/usr/lib/fm/$isa64
262
263export _THREAD_ERROR_DETECTION=2
264
265exec $truss_cmd $truss_args $quote./usr/lib/fm/fmd/fmd -R $simroot $eol
266    -o fg=true -o clock=simulated $eol
267    -o rpc.adm.prog=0 -o rpc.adm.path=$simroot/rpc $eol
268    -o sysevent-transport:device=/dev/null $eol
269    -o sysevent-transport:channel=$simchan $fmd_args$quote
270
271EOS
272
273chmod 0555 $simscript
274echo "done."
275
276if $opt_s; then
277	echo "fmsim: simulation is saved in $simroot"
278	exit 0
279fi
280
281export LD_LIBRARY_PATH=$simroot/usr/lib:$simroot/usr/lib/fm
282export LD_LIBRARY_PATH_64=$simroot/usr/lib/64:$simroot/usr/lib/fm/$isa64
283
284echo "fmsim: simulation $$ running fmd(8)\c"
285./usr/lib/fm/fmd/fmd -V | cut -d: -f2
286
287./$simscript &
288simpid=$!
289trap '' INT HUP
290cd $cwd
291i=0
292
293while [[ ! -s $simroot/rpc ]]; do
294	[[ $i -ge 30 ]] && kill -9 $simpid >/dev/null 2>&1
295	kill -0 $simpid >/dev/null 2>&1 || break
296	let i="$i + 1"
297	sleep 1
298done
299
300kill -0 $simpid >/dev/null 2>&1 || {
301	wait $simpid
302	wait_status $?
303}
304
305echo "fmsim: rpc adm requests can rendezvous at" $(<$simroot/rpc)
306echo "fmsim: injectors should use channel $simchan"
307echo "fmsim: debuggers should attach to PID $simpid"
308
309for arg in $inj_args; do
310	echo "fmsim: injecting events from $arg ... \c"
311	$simroot/usr/lib/fm/fmd/fminject -q -c $simchan $arg || {
312		echo "fmsim: fminject failed for $arg: aborting simulation" >& 2
313		kill $simpid >/dev/null 2>&1
314	}
315	echo "done."
316done
317
318if [[ $opt_i = false ]]; then
319	echo "fmsim: injecting event to advance to end-of-time ... \c"
320	echo 'endhrtime;' | $simroot/usr/lib/fm/fmd/fminject -q -c $simchan -
321	echo "done."
322fi
323
324wait $simpid
325status=$?
326
327if [[ -f $simroot/var/fm/fmd/errlog ]]; then
328	echo; $simroot/usr/sbin/fmdump -R $simroot $dump_args; echo
329fi
330
331wait_status $status
332$opt_w && wait_prompt exit
333$opt_x && rm -rf $simroot
334
335exit 0
336