#
# $Id: sync_tests,v 1.3 1997/09/24 00:36:01 naamato Exp $
#


if ( $#ARGV < 4 ) {
	print "usage: $0 syncfile tstnam tstnum tstseq othersyncfiles ...\n";
	exit 1;
}

# cleanup if we are quit
$SIG{__DIE__} = \&quit_handler;
$SIG{INT} = \&quit_handler;
$SIG{QUIT} = \&quit_handler;

$verbose=1;

#
# get args
#
( $this_file, $test_name, $test_number, $test_sequence, @sync_files ) = @ARGV;

$gated_sync_dir=$ENV{"gated_sync_dir"};
if ($gated_sync_dir eq "") {
	die "\$gated_sync_dir must be set";
}

#
# create sync file and check for other sync files before giving up
# lock on directory.
#

$lockfilename="$gated_sync_dir/flockfile";

# open lock file with create/append
if (! open(LOCK_FILE, ">>$lockfilename")) {
	die "Can't open sync file $lockfilename";
}

if (&lock_file(*LOCK_FILE) != 0) {
	die "Can't get flock";
}

chmod(664, $lockfilename);

if (! open(SYNC_FILE, ">$this_file")) {
	die "can\'t open sync file $this_file";
}
print SYNC_FILE "$test_name $test_number $test_sequence\n";
close(SYNC_FILE);

#
# check all for all remaining lock files 
# 
foreach $node ( @sync_files ) {
	# work around nfs bug, this causes sync otherwise
	# stat returns stale information, e.g. file could
	# be unlinked
	if (open(NODE, "<$node")) {
		close(NODE);
	}

	if ( ! -e $node ) {
		# node is not running
		push(@temp_list, $node);
		next;
	}

	if (! open(NODE, "<$node")) {
		die "can't open $node\n";
	}
	# read first line 
	$_ = <NODE>;

	close(NODE);

	@resp = split;
	if ( $#resp < 2 ) {
		# shouldn't happen 
		print "$0: error: corrupt sync file: \"@resp\" $node\n";
		exit(2);
	}
	if ( $test_name ne $resp[0] || $test_number ne $resp[1]
	    || $test_sequence ne $resp[2] ) {
		push(@temp_list, $node);
	}
}

#
# release directory lock
#
if (&unlock_file(*LOCK_FILE) != 0) {
	die "Can't release flock";
}

#
# If we found everyone then we delete all the sync files
# otherwise we wait for our file to be deleted
#

if ($#temp_list < 0) {
	#
	# grab directory lock
	#
	if (&lock_file(*LOCK_FILE) != 0) {
		die "Can't get flock";
	}
	$did_this=0;
	foreach $file (@sync_files) {
		if ($this_file eq $file) {
			$did_this=1;
		}
		if ( ($nunlk = unlink($file)) != 1 ) {
			die "in loop can't remove sync file $file $nunlk";
		}
	}
	if ($did_this == 0) {
		if ( unlink($this_file) != 1 ) {
			die "out loop can't remove sync file $file";
		}
	}
} else {
	#
	# get list of nodes name. (do basename)
	#

	foreach $node ( @temp_list ) {
		@components = split(/\//, $node);
		@components = split(/\./, $components[$#components]);
		push(@node_name_list, $components[0]);
	}

	if ($verbose) {
		print "Waiting to synchronize with @node_name_list.\n";
	}

	while (1) {
		#
		# grab directory lock
		#
		if (&lock_file(*LOCK_FILE) != 0) {
			die "Can't get flock";
		}

		# work around nfs bug this causes syncing of caches so -e works
		if (open(NODE, "<$this_file")) {
			close(NODE);
		}

		if ( ! -e $this_file ) {
			last;
		}

		#
		# release directory lock
		#
		if (&unlock_file(*LOCK_FILE) != 0) {
			die "Can't release flock";
		}
	}
}

#
# release directory lock
#
if (&unlock_file(*LOCK_FILE) != 0) {
	die "Can't release flock";
}

close(LOCK_FILE);

#
# subroutines
#

use Fcntl;

sub lock_file ()
{
	local ( $FILE ) = @_;
	local ( $arg );

	# print STDOUT "locking $FILE\n";
        
	# short: l_type, l_whence; long: l_start, l_len, l_pad[6]
	$arg = pack("ssllllllll", &F_WRLCK, 0, 0, 1, 0, 0, 0, 0, 0, 0);

	fcntl($FILE, &F_SETLKW, $arg);
}

sub unlock_file ()
{
	local ( $FILE ) = @_;
	local ( $arg );
        
	# short: l_type, l_whence; long: l_start, l_len, l_pad[6]
	$arg = pack("ssllllllll", &F_UNLCK, 0, 0, 1, 0, 0, 0, 0, 0, 0);

	# print STDOUT "unlocking $FILE\n";

	fcntl($FILE, &F_SETLKW, $arg);
}

sub quit_handler ()
{
	unlink("$this_file");
}
