19512fe85Sahl#!/usr/perl5/bin/perl
29512fe85Sahl#
39512fe85Sahl# CDDL HEADER START
49512fe85Sahl#
59512fe85Sahl# The contents of this file are subject to the terms of the
69512fe85Sahl# Common Development and Distribution License (the "License").
79512fe85Sahl# You may not use this file except in compliance with the License.
89512fe85Sahl#
99512fe85Sahl# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
109512fe85Sahl# or http://www.opensolaris.org/os/licensing.
119512fe85Sahl# See the License for the specific language governing permissions
129512fe85Sahl# and limitations under the License.
139512fe85Sahl#
149512fe85Sahl# When distributing Covered Code, include this CDDL HEADER in each
159512fe85Sahl# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
169512fe85Sahl# If applicable, add the following below this CDDL HEADER, with the
179512fe85Sahl# fields enclosed by brackets "[]" replaced with your own identifying
189512fe85Sahl# information: Portions Copyright [yyyy] [name of copyright owner]
199512fe85Sahl#
209512fe85Sahl# CDDL HEADER END
219512fe85Sahl#
229512fe85Sahl
239512fe85Sahl#
24e77b06d2Stomee# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
259512fe85Sahl# Use is subject to license terms.
269512fe85Sahl#
279512fe85Sahl
28*c090e5dfSBryan Cantrill#
29*c090e5dfSBryan Cantrill# Copyright (c) 2011, Joyent, Inc. All rights reserved.
30*c090e5dfSBryan Cantrill#
31df0345f7SJohn Sonnenscheinrequire 5.8.4;
329512fe85Sahl
339512fe85Sahluse File::Find;
349512fe85Sahluse File::Basename;
359512fe85Sahluse Getopt::Std;
369512fe85Sahluse Cwd;
3723b5c241Stomeeuse Cwd 'abs_path';
389512fe85Sahl
399512fe85Sahl$PNAME = $0;
409512fe85Sahl$PNAME =~ s:.*/::;
41*c090e5dfSBryan Cantrill$OPTSTR = 'abd:fFghi:jlnqsx:';
42*c090e5dfSBryan Cantrill$USAGE = "Usage: $PNAME [-abfFghjlnqs] [-d dir] [-i isa] "
439512fe85Sahl    . "[-x opt[=arg]] [file | dir ...]\n";
449512fe85Sahl($MACH = `uname -p`) =~ s/\W*\n//;
45c7158ae9Stariq($PLATFORM = `uname -i`) =~ s/\W*\n//;
469512fe85Sahl
479512fe85Sahl@dtrace_argv = ();
489512fe85Sahl
499512fe85Sahl$ksh_path = '/usr/bin/ksh';
509512fe85Sahl
519512fe85Sahl@files = ();
5223b5c241Stomee%exceptions = ();
53e77b06d2Stomee%results = ();
549512fe85Sahl$errs = 0;
559512fe85Sahl
569512fe85Sahl#
579512fe85Sahl# If no test files are specified on the command-line, execute a find on "."
589512fe85Sahl# and append any tst.*.d, tst.*.ksh, err.*.d or drp.*.d files found within
599512fe85Sahl# the directory tree.
609512fe85Sahl#
619512fe85Sahlsub wanted
629512fe85Sahl{
639512fe85Sahl	push(@files, $File::Find::name)
649512fe85Sahl	    if ($_ =~ /^(tst|err|drp)\..+\.(d|ksh)$/ && -f "$_");
659512fe85Sahl}
669512fe85Sahl
679512fe85Sahlsub dirname {
689512fe85Sahl	my($s) = @_;
699512fe85Sahl	my($i);
709512fe85Sahl
719512fe85Sahl	$s = substr($s, 0, $i) if (($i = rindex($s, '/')) != -1);
729512fe85Sahl	return $i == -1 ? '.' : $i == 0 ? '/' : $s;
739512fe85Sahl}
749512fe85Sahl
75*c090e5dfSBryan Cantrillsub inpath
76*c090e5dfSBryan Cantrill{
77*c090e5dfSBryan Cantrill	my ($exec) = (@_);
78*c090e5dfSBryan Cantrill	my @path = File::Spec->path();
79*c090e5dfSBryan Cantrill
80*c090e5dfSBryan Cantrill	for my $dir (@path) {
81*c090e5dfSBryan Cantrill		if (-x $dir . "/" . $exec) {
82*c090e5dfSBryan Cantrill			return 1;
83*c090e5dfSBryan Cantrill		}
84*c090e5dfSBryan Cantrill	}
85*c090e5dfSBryan Cantrill
86*c090e5dfSBryan Cantrill	return 0;
87*c090e5dfSBryan Cantrill}
88*c090e5dfSBryan Cantrill
899512fe85Sahlsub usage
909512fe85Sahl{
919512fe85Sahl	print $USAGE;
929512fe85Sahl	print "\t -a  execute test suite using anonymous enablings\n";
939512fe85Sahl	print "\t -b  execute bad ioctl test program\n";
949512fe85Sahl	print "\t -d  specify directory for test results files and cores\n";
959512fe85Sahl	print "\t -g  enable libumem debugging when running tests\n";
96e77b06d2Stomee	print "\t -f  force bypassed tests to run\n";
97*c090e5dfSBryan Cantrill	print "\t -F  force tests to be run, even if missing dependencies\n";
989512fe85Sahl	print "\t -h  display verbose usage message\n";
999512fe85Sahl	print "\t -i  specify ISA to test instead of isaexec(3C) default\n";
100e77b06d2Stomee	print "\t -j  execute test suite using jdtrace (Java API) only\n";
1019512fe85Sahl	print "\t -l  save log file of results and PIDs used by tests\n";
102e77b06d2Stomee	print "\t -n  execute test suite using dtrace(1m) only\n";
1039512fe85Sahl	print "\t -q  set quiet mode (only report errors and summary)\n";
1049512fe85Sahl	print "\t -s  save results files even for tests that pass\n";
1059512fe85Sahl	print "\t -x  pass corresponding -x argument to dtrace(1M)\n";
1069512fe85Sahl	exit(2);
1079512fe85Sahl}
1089512fe85Sahl
1099512fe85Sahlsub errmsg
1109512fe85Sahl{
1119512fe85Sahl	my($msg) = @_;
1129512fe85Sahl
1139512fe85Sahl	print STDERR $msg;
1149512fe85Sahl	print LOG $msg if ($opt_l);
1159512fe85Sahl	$errs++;
1169512fe85Sahl}
1179512fe85Sahl
1189512fe85Sahlsub fail
1199512fe85Sahl{
1209512fe85Sahl	my(@parms) = @_;
1219512fe85Sahl	my($msg) = $parms[0];
1229512fe85Sahl	my($errfile) = $parms[1];
1239512fe85Sahl	my($n) = 0;
1249512fe85Sahl	my($dest) = basename($file);
1259512fe85Sahl
1269512fe85Sahl	while (-d "$opt_d/failure.$n") {
1279512fe85Sahl		$n++;
1289512fe85Sahl	}
1299512fe85Sahl
1309512fe85Sahl	unless (mkdir "$opt_d/failure.$n") {
1319512fe85Sahl		warn "ERROR: failed to make directory $opt_d/failure.$n: $!\n";
1329512fe85Sahl		exit(125);
1339512fe85Sahl	}
1349512fe85Sahl
1359512fe85Sahl	open(README, ">$opt_d/failure.$n/README");
1369512fe85Sahl	print README "ERROR: " . $file . " " . $msg;
1379512fe85Sahl
1389512fe85Sahl	if (scalar @parms > 1) {
1399512fe85Sahl		print README "; see $errfile\n";
1409512fe85Sahl	} else {
1419512fe85Sahl		if (-f "$opt_d/$pid.core") {
1429512fe85Sahl			print README "; see $pid.core\n";
1439512fe85Sahl		} else {
1449512fe85Sahl			print README "\n";
1459512fe85Sahl		}
1469512fe85Sahl	}
1479512fe85Sahl
1489512fe85Sahl	close(README);
1499512fe85Sahl
1509512fe85Sahl	if (-f "$opt_d/$pid.out") {
1519512fe85Sahl		rename("$opt_d/$pid.out", "$opt_d/failure.$n/$pid.out");
1529512fe85Sahl		link("$file.out", "$opt_d/failure.$n/$dest.out");
1539512fe85Sahl	}
1549512fe85Sahl
1559512fe85Sahl	if (-f "$opt_d/$pid.err") {
1569512fe85Sahl		rename("$opt_d/$pid.err", "$opt_d/failure.$n/$pid.err");
1579512fe85Sahl		link("$file.err", "$opt_d/failure.$n/$dest.err");
1589512fe85Sahl	}
1599512fe85Sahl
1609512fe85Sahl	if (-f "$opt_d/$pid.core") {
1619512fe85Sahl		rename("$opt_d/$pid.core", "$opt_d/failure.$n/$pid.core");
1629512fe85Sahl	}
1639512fe85Sahl
1649512fe85Sahl	link("$file", "$opt_d/failure.$n/$dest");
1659512fe85Sahl
1669512fe85Sahl	$msg = "ERROR: " . $dest . " " . $msg;
1679512fe85Sahl
1689512fe85Sahl	if (scalar @parms > 1) {
1699512fe85Sahl		$msg = $msg . "; see $errfile in failure.$n\n";
1709512fe85Sahl	} else {
1719512fe85Sahl		$msg = $msg . "; details in failure.$n\n";
1729512fe85Sahl	}
1739512fe85Sahl
1749512fe85Sahl	errmsg($msg);
1759512fe85Sahl}
1769512fe85Sahl
1779512fe85Sahlsub logmsg
1789512fe85Sahl{
1799512fe85Sahl	my($msg) = @_;
1809512fe85Sahl
1819512fe85Sahl	print STDOUT $msg unless ($opt_q);
1829512fe85Sahl	print LOG $msg if ($opt_l);
1839512fe85Sahl}
1849512fe85Sahl
18523b5c241Stomee# Trim leading and trailing whitespace
18623b5c241Stomeesub trim {
18723b5c241Stomee	my($s) = @_;
18823b5c241Stomee
18923b5c241Stomee	$s =~ s/^\s*//;
19023b5c241Stomee	$s =~ s/\s*$//;
19123b5c241Stomee	return $s;
19223b5c241Stomee}
19323b5c241Stomee
194e77b06d2Stomee# Load exception set of skipped tests from the file at the given
195e77b06d2Stomee# pathname. The test names are assumed to be paths relative to $dt_tst,
196e77b06d2Stomee# for example: common/aggs/tst.neglquant.d, and specify tests to be
197e77b06d2Stomee# skipped.
19823b5c241Stomeesub load_exceptions {
19923b5c241Stomee	my($listfile) = @_;
20023b5c241Stomee	my($line) = "";
20123b5c241Stomee
202e77b06d2Stomee	%exceptions = ();
203e77b06d2Stomee	if (length($listfile) > 0) {
204e77b06d2Stomee		exit(123) unless open(STDIN, "<$listfile");
205e77b06d2Stomee		while (<STDIN>) {
206e77b06d2Stomee			chomp;
207e77b06d2Stomee			$line = $_;
208e77b06d2Stomee			# line is non-empty and not a comment
209e77b06d2Stomee			if ((length($line) > 0) && ($line =~ /^\s*[^\s#]/ )) {
210e77b06d2Stomee				$exceptions{trim($line)} = 1;
211e77b06d2Stomee			}
21223b5c241Stomee		}
21323b5c241Stomee	}
21423b5c241Stomee}
21523b5c241Stomee
216e77b06d2Stomee# Return 1 if the test is found in the exception set, 0 otherwise.
21723b5c241Stomeesub is_exception {
21823b5c241Stomee	my($file) = @_;
21923b5c241Stomee	my($i) = -1;
22023b5c241Stomee
221e77b06d2Stomee	if (scalar(keys(%exceptions)) == 0) {
222e77b06d2Stomee		return 0;
223e77b06d2Stomee	}
224e77b06d2Stomee
22523b5c241Stomee	# hash absolute pathname after $dt_tst/
22623b5c241Stomee	$file = abs_path($file);
22723b5c241Stomee	$i = index($file, $dt_tst);
22823b5c241Stomee	if ($i == 0) {
22923b5c241Stomee		$file = substr($file, length($dt_tst) + 1);
23023b5c241Stomee		return $exceptions{$file};
23123b5c241Stomee	}
23223b5c241Stomee	return 0;
23323b5c241Stomee}
23423b5c241Stomee
235e77b06d2Stomee#
236c7158ae9Stariq# Iterate over the set of test files specified on the command-line or by a find
237c7158ae9Stariq# on "$defdir/common", "$defdir/$MACH" and "$defdir/$PLATFORM" and execute each
238c7158ae9Stariq# one.  If the test file is executable, we fork and exec it. If the test is a
239c7158ae9Stariq# .ksh file, we run it with $ksh_path. Otherwise we run dtrace -s on it.  If
240c7158ae9Stariq# the file is named tst.* we assume it should return exit status 0.  If the
241c7158ae9Stariq# file is named err.* we assume it should return exit status 1.  If the file is
242c7158ae9Stariq# named err.D_[A-Z0-9]+[.*].d we use dtrace -xerrtags and examine stderr to
243c7158ae9Stariq# ensure that a matching error tag was produced.  If the file is named
244c7158ae9Stariq# drp.[A-Z0-9]+[.*].d we use dtrace -xdroptags and examine stderr to ensure
245c7158ae9Stariq# that a matching drop tag was produced.  If any *.out or *.err files are found
246c7158ae9Stariq# we perform output comparisons.
247e77b06d2Stomee#
248e77b06d2Stomee# run_tests takes two arguments: The first is the pathname of the dtrace
249e77b06d2Stomee# command to invoke when running the tests. The second is the pathname
250e77b06d2Stomee# of a file (may be the empty string) listing tests that ought to be
251e77b06d2Stomee# skipped (skipped tests are listed as paths relative to $dt_tst, for
252e77b06d2Stomee# example: common/aggs/tst.neglquant.d).
253e77b06d2Stomee#
254e77b06d2Stomeesub run_tests {
255e77b06d2Stomee	my($dtrace, $exceptions_path) = @_;
256e77b06d2Stomee	my($passed) = 0;
257e77b06d2Stomee	my($bypassed) = 0;
258e77b06d2Stomee	my($failed) = $errs;
259e77b06d2Stomee	my($total) = 0;
260e77b06d2Stomee
261*c090e5dfSBryan Cantrill	die "$PNAME: $dtrace not found; aborting\n" unless (-x "$dtrace");
262*c090e5dfSBryan Cantrill	logmsg("executing tests using $dtrace ...\n");
263e77b06d2Stomee
264e77b06d2Stomee	load_exceptions($exceptions_path);
265e77b06d2Stomee
266e77b06d2Stomee	foreach $file (sort @files) {
267e77b06d2Stomee		$file =~ m:.*/((.*)\.(\w+)):;
268e77b06d2Stomee		$name = $1;
269e77b06d2Stomee		$base = $2;
270e77b06d2Stomee		$ext = $3;
271e77b06d2Stomee
272e77b06d2Stomee		$dir = dirname($file);
273e77b06d2Stomee		$isksh = 0;
274e77b06d2Stomee		$tag = 0;
275e77b06d2Stomee		$droptag = 0;
276e77b06d2Stomee
277e77b06d2Stomee		if ($name =~ /^tst\./) {
278e77b06d2Stomee			$isksh = ($ext eq 'ksh');
279e77b06d2Stomee			$status = 0;
280e77b06d2Stomee		} elsif ($name =~ /^err\.(D_[A-Z0-9_]+)\./) {
281e77b06d2Stomee			$status = 1;
282e77b06d2Stomee			$tag = $1;
283e77b06d2Stomee		} elsif ($name =~ /^err\./) {
284e77b06d2Stomee			$status = 1;
285e77b06d2Stomee		} elsif ($name =~ /^drp\.([A-Z0-9_]+)\./) {
286e77b06d2Stomee			$status = 0;
287e77b06d2Stomee			$droptag = $1;
288e77b06d2Stomee		} else {
289e77b06d2Stomee			errmsg("ERROR: $file is not a valid test file name\n");
290e77b06d2Stomee			next;
291e77b06d2Stomee		}
292e77b06d2Stomee
293e77b06d2Stomee		$fullname = "$dir/$name";
294e77b06d2Stomee		$exe = "$dir/$base.exe";
295e77b06d2Stomee		$exe_pid = -1;
296e77b06d2Stomee
297e77b06d2Stomee		if ($opt_a && ($status != 0 || $tag != 0 || $droptag != 0 ||
298e77b06d2Stomee		    -x $exe || $isksh || -x $fullname)) {
299e77b06d2Stomee			$bypassed++;
300e77b06d2Stomee			next;
301e77b06d2Stomee		}
302e77b06d2Stomee
303e77b06d2Stomee		if (!$opt_f && is_exception("$dir/$name")) {
304e77b06d2Stomee			$bypassed++;
305e77b06d2Stomee			next;
306e77b06d2Stomee		}
307e77b06d2Stomee
308e77b06d2Stomee		if (!$isksh && -x $exe) {
309e77b06d2Stomee			if (($exe_pid = fork()) == -1) {
310e77b06d2Stomee				errmsg(
311e77b06d2Stomee				    "ERROR: failed to fork to run $exe: $!\n");
312e77b06d2Stomee				next;
313e77b06d2Stomee			}
314e77b06d2Stomee
315e77b06d2Stomee			if ($exe_pid == 0) {
316e77b06d2Stomee				open(STDIN, '</dev/null');
317e77b06d2Stomee
318e77b06d2Stomee				exec($exe);
319e77b06d2Stomee
320e77b06d2Stomee				warn "ERROR: failed to exec $exe: $!\n";
321e77b06d2Stomee			}
322e77b06d2Stomee		}
323e77b06d2Stomee
324e77b06d2Stomee		logmsg("testing $file ... ");
325e77b06d2Stomee
326e77b06d2Stomee		if (($pid = fork()) == -1) {
327e77b06d2Stomee			errmsg("ERROR: failed to fork to run test $file: $!\n");
328e77b06d2Stomee			next;
329e77b06d2Stomee		}
330e77b06d2Stomee
331e77b06d2Stomee		if ($pid == 0) {
332e77b06d2Stomee			open(STDIN, '</dev/null');
333e77b06d2Stomee			exit(125) unless open(STDOUT, ">$opt_d/$$.out");
334e77b06d2Stomee			exit(125) unless open(STDERR, ">$opt_d/$$.err");
335e77b06d2Stomee
336e77b06d2Stomee			unless (chdir($dir)) {
337e77b06d2Stomee				warn "ERROR: failed to chdir for $file: $!\n";
338e77b06d2Stomee				exit(126);
339e77b06d2Stomee			}
340e77b06d2Stomee
341e77b06d2Stomee			push(@dtrace_argv, '-xerrtags') if ($tag);
342e77b06d2Stomee			push(@dtrace_argv, '-xdroptags') if ($droptag);
343e77b06d2Stomee			push(@dtrace_argv, $exe_pid) if ($exe_pid != -1);
344e77b06d2Stomee
345e77b06d2Stomee			if ($isksh) {
346e77b06d2Stomee				exit(123) unless open(STDIN, "<$name");
347e77b06d2Stomee				exec("$ksh_path /dev/stdin $dtrace");
348e77b06d2Stomee			} elsif (-x $name) {
349e77b06d2Stomee				warn "ERROR: $name is executable\n";
350e77b06d2Stomee				exit(1);
351e77b06d2Stomee			} else {
352e77b06d2Stomee				if ($tag == 0 && $status == $0 && $opt_a) {
353e77b06d2Stomee					push(@dtrace_argv, '-A');
354e77b06d2Stomee				}
355e77b06d2Stomee
356e77b06d2Stomee				push(@dtrace_argv, '-C');
357e77b06d2Stomee				push(@dtrace_argv, '-s');
358e77b06d2Stomee				push(@dtrace_argv, $name);
359e77b06d2Stomee				exec($dtrace, @dtrace_argv);
360e77b06d2Stomee			}
361e77b06d2Stomee
362e77b06d2Stomee			warn "ERROR: failed to exec for $file: $!\n";
363e77b06d2Stomee			exit(127);
364e77b06d2Stomee		}
365e77b06d2Stomee
366e77b06d2Stomee		if (waitpid($pid, 0) == -1) {
367e77b06d2Stomee			errmsg("ERROR: timed out waiting for $file\n");
368e77b06d2Stomee			kill(9, $exe_pid) if ($exe_pid != -1);
369e77b06d2Stomee			kill(9, $pid);
370e77b06d2Stomee			next;
371e77b06d2Stomee		}
372e77b06d2Stomee
373e77b06d2Stomee		kill(9, $exe_pid) if ($exe_pid != -1);
374e77b06d2Stomee
375e77b06d2Stomee		if ($tag == 0 && $status == $0 && $opt_a) {
376e77b06d2Stomee			#
377e77b06d2Stomee			# We can chuck the earler output.
378e77b06d2Stomee			#
379e77b06d2Stomee			unlink($pid . '.out');
380e77b06d2Stomee			unlink($pid . '.err');
381e77b06d2Stomee
382e77b06d2Stomee			#
383e77b06d2Stomee			# This is an anonymous enabling.  We need to get
384e77b06d2Stomee			# the module unloaded.
385e77b06d2Stomee			#
386e77b06d2Stomee			system("dtrace -ae 1> /dev/null 2> /dev/null");
387e77b06d2Stomee			system("svcadm disable -s " .
388e77b06d2Stomee			    "svc:/network/nfs/mapid:default");
389e77b06d2Stomee			system("modunload -i 0 ; modunload -i 0 ; " .
390e77b06d2Stomee			    "modunload -i 0");
391e77b06d2Stomee			if (!system("modinfo | grep dtrace")) {
392e77b06d2Stomee				warn "ERROR: couldn't unload dtrace\n";
393e77b06d2Stomee				system("svcadm enable " .
394e77b06d2Stomee				    "-s svc:/network/nfs/mapid:default");
395e77b06d2Stomee				exit(124);
396e77b06d2Stomee			}
397e77b06d2Stomee
398e77b06d2Stomee			#
399e77b06d2Stomee			# DTrace is gone.  Now update_drv(1M), and rip
400e77b06d2Stomee			# everything out again.
401e77b06d2Stomee			#
402e77b06d2Stomee			system("update_drv dtrace");
403e77b06d2Stomee			system("dtrace -ae 1> /dev/null 2> /dev/null");
404e77b06d2Stomee			system("modunload -i 0 ; modunload -i 0 ; " .
405e77b06d2Stomee			    "modunload -i 0");
406e77b06d2Stomee			if (!system("modinfo | grep dtrace")) {
407e77b06d2Stomee				warn "ERROR: couldn't unload dtrace\n";
408e77b06d2Stomee				system("svcadm enable " .
409e77b06d2Stomee				    "-s svc:/network/nfs/mapid:default");
410e77b06d2Stomee				exit(124);
411e77b06d2Stomee			}
412e77b06d2Stomee
413e77b06d2Stomee			#
414e77b06d2Stomee			# Now bring DTrace back in.
415e77b06d2Stomee			#
416e77b06d2Stomee			system("sync ; sync");
417e77b06d2Stomee			system("dtrace -l -n bogusprobe 1> /dev/null " .
418e77b06d2Stomee			    "2> /dev/null");
419e77b06d2Stomee			system("svcadm enable -s " .
420e77b06d2Stomee			    "svc:/network/nfs/mapid:default");
421e77b06d2Stomee
422e77b06d2Stomee			#
423e77b06d2Stomee			# That should have caused DTrace to reload with
424e77b06d2Stomee			# the new configuration file.  Now we can try to
425e77b06d2Stomee			# snag our anonymous state.
426e77b06d2Stomee			#
427e77b06d2Stomee			if (($pid = fork()) == -1) {
428e77b06d2Stomee				errmsg("ERROR: failed to fork to run " .
429e77b06d2Stomee				    "test $file: $!\n");
430e77b06d2Stomee				next;
431e77b06d2Stomee			}
432e77b06d2Stomee
433e77b06d2Stomee			if ($pid == 0) {
434e77b06d2Stomee				open(STDIN, '</dev/null');
435e77b06d2Stomee				exit(125) unless open(STDOUT, ">$opt_d/$$.out");
436e77b06d2Stomee				exit(125) unless open(STDERR, ">$opt_d/$$.err");
437e77b06d2Stomee
438e77b06d2Stomee				push(@dtrace_argv, '-a');
439e77b06d2Stomee
440e77b06d2Stomee				unless (chdir($dir)) {
441e77b06d2Stomee					warn "ERROR: failed to chdir " .
442e77b06d2Stomee					    "for $file: $!\n";
443e77b06d2Stomee					exit(126);
444e77b06d2Stomee				}
445e77b06d2Stomee
446e77b06d2Stomee				exec($dtrace, @dtrace_argv);
447e77b06d2Stomee				warn "ERROR: failed to exec for $file: $!\n";
448e77b06d2Stomee				exit(127);
449e77b06d2Stomee			}
450e77b06d2Stomee
451e77b06d2Stomee			if (waitpid($pid, 0) == -1) {
452e77b06d2Stomee				errmsg("ERROR: timed out waiting for $file\n");
453e77b06d2Stomee				kill(9, $pid);
454e77b06d2Stomee				next;
455e77b06d2Stomee			}
456e77b06d2Stomee		}
457e77b06d2Stomee
458e77b06d2Stomee		logmsg("[$pid]\n");
459e77b06d2Stomee		$wstat = $?;
460e77b06d2Stomee		$wifexited = ($wstat & 0xFF) == 0;
461e77b06d2Stomee		$wexitstat = ($wstat >> 8) & 0xFF;
462e77b06d2Stomee		$wtermsig = ($wstat & 0x7F);
463e77b06d2Stomee
464e77b06d2Stomee		if (!$wifexited) {
465e77b06d2Stomee			fail("died from signal $wtermsig");
466e77b06d2Stomee			next;
467e77b06d2Stomee		}
468e77b06d2Stomee
469e77b06d2Stomee		if ($wexitstat == 125) {
470e77b06d2Stomee			die "$PNAME: failed to create output file in $opt_d " .
471e77b06d2Stomee			    "(cd elsewhere or use -d)\n";
472e77b06d2Stomee		}
473e77b06d2Stomee
474e77b06d2Stomee		if ($wexitstat != $status) {
475e77b06d2Stomee			fail("returned $wexitstat instead of $status");
476e77b06d2Stomee			next;
477e77b06d2Stomee		}
478e77b06d2Stomee
479e77b06d2Stomee		if (-f "$file.out" &&
480e77b06d2Stomee		    system("cmp -s $file.out $opt_d/$pid.out") != 0) {
481e77b06d2Stomee			fail("stdout mismatch", "$pid.out");
482e77b06d2Stomee			next;
483e77b06d2Stomee		}
484e77b06d2Stomee
485e77b06d2Stomee		if (-f "$file.err" &&
486e77b06d2Stomee		    system("cmp -s $file.err $opt_d/$pid.err") != 0) {
487e77b06d2Stomee			fail("stderr mismatch: see $pid.err");
488e77b06d2Stomee			next;
489e77b06d2Stomee		}
490e77b06d2Stomee
491e77b06d2Stomee		if ($tag) {
492e77b06d2Stomee			open(TSTERR, "<$opt_d/$pid.err");
493e77b06d2Stomee			$tsterr = <TSTERR>;
494e77b06d2Stomee			close(TSTERR);
495e77b06d2Stomee
496e77b06d2Stomee			unless ($tsterr =~ /: \[$tag\] line \d+:/) {
497e77b06d2Stomee				fail("errtag mismatch: see $pid.err");
498e77b06d2Stomee				next;
499e77b06d2Stomee			}
500e77b06d2Stomee		}
501e77b06d2Stomee
502e77b06d2Stomee		if ($droptag) {
503e77b06d2Stomee			$found = 0;
504e77b06d2Stomee			open(TSTERR, "<$opt_d/$pid.err");
505e77b06d2Stomee
506e77b06d2Stomee			while (<TSTERR>) {
507e77b06d2Stomee				if (/\[$droptag\] /) {
508e77b06d2Stomee					$found = 1;
509e77b06d2Stomee					last;
510e77b06d2Stomee				}
511e77b06d2Stomee			}
512e77b06d2Stomee
513e77b06d2Stomee			close (TSTERR);
514e77b06d2Stomee
515e77b06d2Stomee			unless ($found) {
516e77b06d2Stomee				fail("droptag mismatch: see $pid.err");
517e77b06d2Stomee				next;
518e77b06d2Stomee			}
519e77b06d2Stomee		}
520e77b06d2Stomee
521e77b06d2Stomee		unless ($opt_s) {
522e77b06d2Stomee			unlink($pid . '.out');
523e77b06d2Stomee			unlink($pid . '.err');
524e77b06d2Stomee		}
525e77b06d2Stomee	}
526e77b06d2Stomee
527e77b06d2Stomee	if ($opt_a) {
528e77b06d2Stomee		#
529e77b06d2Stomee		# If we're running with anonymous enablings, we need to
530e77b06d2Stomee		# restore the .conf file.
531e77b06d2Stomee		#
532e77b06d2Stomee		system("dtrace -A 1> /dev/null 2> /dev/null");
533e77b06d2Stomee		system("dtrace -ae 1> /dev/null 2> /dev/null");
534e77b06d2Stomee		system("modunload -i 0 ; modunload -i 0 ; modunload -i 0");
535e77b06d2Stomee		system("update_drv dtrace");
536e77b06d2Stomee	}
537e77b06d2Stomee
538e77b06d2Stomee	$total = scalar(@files);
539e77b06d2Stomee	$failed = $errs - $failed;
540e77b06d2Stomee	$passed = ($total - $failed - $bypassed);
541e77b06d2Stomee	$results{$dtrace} = {
542e77b06d2Stomee		"passed" => $passed,
543e77b06d2Stomee		"bypassed" => $bypassed,
544e77b06d2Stomee		"failed" => $failed,
545e77b06d2Stomee		"total" => $total
546e77b06d2Stomee	};
547e77b06d2Stomee}
548e77b06d2Stomee
54923b5c241Stomeedie $USAGE unless (getopts($OPTSTR));
5509512fe85Sahlusage() if ($opt_h);
5519512fe85Sahl
5529512fe85Sahlforeach $arg (@ARGV) {
5539512fe85Sahl	if (-f $arg) {
5549512fe85Sahl		push(@files, $arg);
5559512fe85Sahl	} elsif (-d $arg) {
5569512fe85Sahl		find(\&wanted, $arg);
5579512fe85Sahl	} else {
5589512fe85Sahl		die "$PNAME: $arg is not a valid file or directory\n";
5599512fe85Sahl	}
5609512fe85Sahl}
5619512fe85Sahl
56223b5c241Stomee$dt_tst = '/opt/SUNWdtrt/tst';
56323b5c241Stomee$dt_bin = '/opt/SUNWdtrt/bin';
56423b5c241Stomee$defdir = -d $dt_tst ? $dt_tst : '.';
56523b5c241Stomee$bindir = -d $dt_bin ? $dt_bin : '.';
5669512fe85Sahl
567*c090e5dfSBryan Cantrillif (!$opt_F) {
568*c090e5dfSBryan Cantrill	my @dependencies = ("gcc", "make", "java", "perl");
569*c090e5dfSBryan Cantrill
570*c090e5dfSBryan Cantrill	for my $dep (@dependencies) {
571*c090e5dfSBryan Cantrill		if (!inpath($dep)) {
572*c090e5dfSBryan Cantrill			die "$PNAME: '$dep' not found (use -F to force run)\n";
573*c090e5dfSBryan Cantrill		}
574*c090e5dfSBryan Cantrill	}
575*c090e5dfSBryan Cantrill}
576*c090e5dfSBryan Cantrill
5779512fe85Sahlfind(\&wanted, "$defdir/common") if (scalar(@ARGV) == 0);
5789512fe85Sahlfind(\&wanted, "$defdir/$MACH") if (scalar(@ARGV) == 0);
579c7158ae9Stariqfind(\&wanted, "$defdir/$PLATFORM") if (scalar(@ARGV) == 0);
580*c090e5dfSBryan Cantrill
5819512fe85Sahldie $USAGE if (scalar(@files) == 0);
5829512fe85Sahl
583e77b06d2Stomee$dtrace_path = '/usr/sbin/dtrace';
584e77b06d2Stomee$jdtrace_path = "$bindir/jdtrace";
585e77b06d2Stomee
586e77b06d2Stomee%exception_lists = ("$jdtrace_path" => "$bindir/exception.lst");
587e77b06d2Stomee
588e77b06d2Stomeeif ($opt_j || $opt_n || $opt_i) {
589e77b06d2Stomee	@dtrace_cmds = ();
590e77b06d2Stomee	push(@dtrace_cmds, $dtrace_path) if ($opt_n);
591e77b06d2Stomee	push(@dtrace_cmds, $jdtrace_path) if ($opt_j);
592e77b06d2Stomee	push(@dtrace_cmds, "/usr/sbin/$opt_i/dtrace") if ($opt_i);
593e77b06d2Stomee} else {
594*c090e5dfSBryan Cantrill	@dtrace_cmds = ($dtrace_path);
595e77b06d2Stomee}
596e77b06d2Stomee
5979512fe85Sahlif ($opt_d) {
5989512fe85Sahl	die "$PNAME: -d arg must be absolute path\n" unless ($opt_d =~ /^\//);
5999512fe85Sahl	die "$PNAME: -d arg $opt_d is not a directory\n" unless (-d "$opt_d");
6009512fe85Sahl	system("coreadm -p $opt_d/%p.core");
6019512fe85Sahl} else {
6029512fe85Sahl	my $dir = getcwd;
6039512fe85Sahl	system("coreadm -p $dir/%p.core");
6049512fe85Sahl	$opt_d = '.';
6059512fe85Sahl}
6069512fe85Sahl
6079512fe85Sahlif ($opt_x) {
6089512fe85Sahl	push(@dtrace_argv, '-x');
6099512fe85Sahl	push(@dtrace_argv, $opt_x);
6109512fe85Sahl}
6119512fe85Sahl
6129512fe85Sahldie "$PNAME: failed to open $PNAME.$$.log: $!\n"
6139512fe85Sahl    unless (!$opt_l || open(LOG, ">$PNAME.$$.log"));
6149512fe85Sahl
6159512fe85Sahlif ($opt_g) {
6169512fe85Sahl	$ENV{'UMEM_DEBUG'} = 'default,verbose';
6179512fe85Sahl	$ENV{'UMEM_LOGGING'} = 'fail,contents';
6189512fe85Sahl	$ENV{'LD_PRELOAD'} = 'libumem.so';
6199512fe85Sahl}
6209512fe85Sahl
6219512fe85Sahlif ($opt_b) {
6229512fe85Sahl	logmsg("badioctl'ing ... ");
6239512fe85Sahl
6249512fe85Sahl	if (($badioctl = fork()) == -1) {
6259512fe85Sahl		errmsg("ERROR: failed to fork to run badioctl: $!\n");
6269512fe85Sahl		next;
6279512fe85Sahl	}
6289512fe85Sahl
6299512fe85Sahl	if ($badioctl == 0) {
6309512fe85Sahl		open(STDIN, '</dev/null');
6319512fe85Sahl		exit(125) unless open(STDOUT, ">$opt_d/$$.out");
6329512fe85Sahl		exit(125) unless open(STDERR, ">$opt_d/$$.err");
6339512fe85Sahl
6349512fe85Sahl		exec($bindir . "/badioctl");
6359512fe85Sahl		warn "ERROR: failed to exec badioctl: $!\n";
6369512fe85Sahl		exit(127);
6379512fe85Sahl	}
6389512fe85Sahl
6399512fe85Sahl
6409512fe85Sahl	logmsg("[$badioctl]\n");
6419512fe85Sahl
6429512fe85Sahl	#
6439512fe85Sahl	# If we're going to be bad, we're just going to iterate over each
6449512fe85Sahl	# test file.
6459512fe85Sahl	#
6469512fe85Sahl	foreach $file (sort @files) {
6479512fe85Sahl		($name = $file) =~ s:.*/::;
6489512fe85Sahl		$dir = dirname($file);
6499512fe85Sahl
6509512fe85Sahl		if (!($name =~ /^tst\./ && $name =~ /\.d$/)) {
6519512fe85Sahl			next;
6529512fe85Sahl		}
6539512fe85Sahl
6549512fe85Sahl		logmsg("baddof'ing $file ... ");
6559512fe85Sahl
6569512fe85Sahl		if (($pid = fork()) == -1) {
6579512fe85Sahl			errmsg("ERROR: failed to fork to run baddof: $!\n");
6589512fe85Sahl			next;
6599512fe85Sahl		}
6609512fe85Sahl
6619512fe85Sahl		if ($pid == 0) {
6629512fe85Sahl			open(STDIN, '</dev/null');
6639512fe85Sahl			exit(125) unless open(STDOUT, ">$opt_d/$$.out");
6649512fe85Sahl			exit(125) unless open(STDERR, ">$opt_d/$$.err");
6659512fe85Sahl
6669512fe85Sahl			unless (chdir($dir)) {
6679512fe85Sahl				warn "ERROR: failed to chdir for $file: $!\n";
6689512fe85Sahl				exit(126);
6699512fe85Sahl			}
6709512fe85Sahl
6719512fe85Sahl			exec($bindir . "/baddof", $name);
6729512fe85Sahl
6739512fe85Sahl			warn "ERROR: failed to exec for $file: $!\n";
6749512fe85Sahl			exit(127);
6759512fe85Sahl		}
6769512fe85Sahl
6779512fe85Sahl		sleep 60;
6789512fe85Sahl		kill(9, $pid);
6799512fe85Sahl		waitpid($pid, 0);
6809512fe85Sahl
6819512fe85Sahl		logmsg("[$pid]\n");
6829512fe85Sahl
6839512fe85Sahl		unless ($opt_s) {
6849512fe85Sahl			unlink($pid . '.out');
6859512fe85Sahl			unlink($pid . '.err');
6869512fe85Sahl		}
6879512fe85Sahl	}
6889512fe85Sahl
6899512fe85Sahl	kill(9, $badioctl);
6909512fe85Sahl	waitpid($badioctl, 0);
6919512fe85Sahl
6929512fe85Sahl	unless ($opt_s) {
6939512fe85Sahl		unlink($badioctl . '.out');
6949512fe85Sahl		unlink($badioctl . '.err');
6959512fe85Sahl	}
6969512fe85Sahl
6979512fe85Sahl	exit(0);
6989512fe85Sahl}
6999512fe85Sahl
7009512fe85Sahl#
701e77b06d2Stomee# Run all the tests specified on the command-line (the entire test suite
702e77b06d2Stomee# by default) once for each dtrace command tested, skipping any tests
703e77b06d2Stomee# not valid for that command.
7049512fe85Sahl#
705e77b06d2Stomeeforeach $dtrace_cmd (@dtrace_cmds) {
706e77b06d2Stomee	run_tests($dtrace_cmd, $exception_lists{$dtrace_cmd});
7079512fe85Sahl}
7089512fe85Sahl
7099512fe85Sahl$opt_q = 0; # force final summary to appear regardless of -q option
7109512fe85Sahl
7119512fe85Sahllogmsg("\n==== TEST RESULTS ====\n");
712e77b06d2Stomeeforeach $key (keys %results) {
713e77b06d2Stomee	my $passed = $results{$key}{"passed"};
714e77b06d2Stomee	my $bypassed = $results{$key}{"bypassed"};
715e77b06d2Stomee	my $failed = $results{$key}{"failed"};
716e77b06d2Stomee	my $total = $results{$key}{"total"};
717e77b06d2Stomee
718e77b06d2Stomee	logmsg("\n     mode: " . $key . "\n");
719e77b06d2Stomee	logmsg("   passed: " . $passed . "\n");
720e77b06d2Stomee	if ($bypassed) {
721e77b06d2Stomee		logmsg(" bypassed: " . $bypassed . "\n");
722e77b06d2Stomee	}
723e77b06d2Stomee	logmsg("   failed: " . $failed . "\n");
724e77b06d2Stomee	logmsg("    total: " . $total . "\n");
7259512fe85Sahl}
7269512fe85Sahl
7279512fe85Sahlexit($errs != 0);
728