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