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