From f95052e5e6111f526acf86bb885bd7e6da3defd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dag-Erling=20Sm=C3=B8rgrav?= Date: Fri, 20 Aug 2004 08:10:30 +0000 Subject: [PATCH] Copy open_locked() from tinderbox.pl and use it to optionally acquire a lock file upon startup. If this fails, tbmaster will simply terminate. --- tools/tools/tinderbox/tbmaster.1 | 9 +++-- tools/tools/tinderbox/tbmaster.pl | 57 ++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/tools/tools/tinderbox/tbmaster.1 b/tools/tools/tinderbox/tbmaster.1 index 96d90e3da6df..d8001d559e8d 100644 --- a/tools/tools/tinderbox/tbmaster.1 +++ b/tools/tools/tinderbox/tbmaster.1 @@ -27,7 +27,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 21, 2004 +.Dd August 18, 2004 .Dt TBMASTER 1 .Os .Sh NAME @@ -45,7 +45,7 @@ runs, generates log summaries, and mails out failure reports. .Pp The following options are recognized: .Bl -tag -width 12n -.It Fl c Ar CONFIG , Fl -config Ns = Ns Ar CONFIG +.It Fl c Ar NAME , Fl -config Ns = Ns Ar NAME The name of the configuration to use. If specified multiple times, all listed configurations will be run in sequence. @@ -56,6 +56,11 @@ Dumps the configuration and exits without running the tinderbox. The directory where configuration files are located. The default is .Pa $HOME/etc . +.It Fl l Ar FILE +The name of a file to lock upon startup. +If the lock is already held by another process, +.Nm +will terminate immediately rather than block. .El .Ss Configuration The diff --git a/tools/tools/tinderbox/tbmaster.pl b/tools/tools/tinderbox/tbmaster.pl index 687d940214de..fbba91e7a2e7 100644 --- a/tools/tools/tinderbox/tbmaster.pl +++ b/tools/tools/tinderbox/tbmaster.pl @@ -42,6 +42,8 @@ my $COPYRIGHT = "Copyright (c) 2003 Dag-Erling Sm my @configs; # Names of requested configations my $dump; # Dump configuration and exit my $etcdir; # Configuration directory +my $lockfile; # Lock file name +my $lock; # Lock file descriptor my %INITIAL_CONFIG = ( 'BRANCHES' => [ 'CURRENT' ], @@ -348,6 +350,46 @@ sub tinderbox($$$) { rename("$logfile.brief.$$", "$logfile.brief"); } +### +### Open and lock a file reliably +### +sub open_locked($;$$) { + my $fn = shift; # File name + my $flags = shift; # Open flags + my $mode = shift; # File mode + + local *FILE; # File handle + my (@sb1, @sb2); # File status + + for (;; close(FILE)) { + sysopen(FILE, $fn, $flags || O_RDONLY, $mode || 0640) + or last; + if (!(@sb1 = stat(FILE))) { + # Huh? shouldn't happen + warning("$fn: stat(): $!"); + last; + } + if (!flock(FILE, LOCK_EX|LOCK_NB)) { + # A failure here means the file can't be locked, or + # something really weird happened, so just give up. + warning("$fn: flock(): $!"); + last; + } + if (!(@sb2 = stat($fn))) { + # File was pulled from under our feet, though it may + # reappear in the next pass + next; + } + if ($sb1[0] != $sb2[0] || $sb1[1] != $sb2[1]) { + # File changed under our feet, try again + next; + } + return *FILE{IO}; + } + close(FILE); + return undef; +} + ### ### Print a usage message and exit ### @@ -363,8 +405,9 @@ Options: -d, --dump Dump the processed configuration Parameters: - -c, --config=FILE Configuration name + -c, --config=NAME Configuration name -e, --etcdir=DIR Configuration directory + -l, --lockfile=FILE Lock file name Report bugs to . "); @@ -448,6 +491,7 @@ MAIN:{ "c|config=s" => \@configs, "d|dump" => \$dump, "e|etcdir=s" => \$etcdir, + "l|lockfile=s" => \$lockfile, ) or usage(); if (@ARGV) { usage(); @@ -475,6 +519,17 @@ MAIN:{ $configs[$n] = $1; } + # Acquire lock + if (defined($lockfile)) { + if ($lockfile !~ m/^([\w\/\.-]+)$/) { + die("invalid lockfile\n"); + } + $lockfile = $1; + $lock = open_locked($lockfile, O_CREAT, 0600) + or die("unable to acquire lock on $lockfile"); + # Lock will be released upon termination. + } + # Run all specified or implied configurations foreach my $config (@configs) { tbmaster($config);