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