Commit 21b37a35 authored by Leigh Stoller's avatar Leigh Stoller

Add serialization (the usual locking code) to prevent corruption of

the .htpasswd file on ops. Note that I have disabled registration and
password changes from the twiki interface on ops for now. I'll think
about this as needed.
parent 98ad1058
......@@ -6,6 +6,7 @@
#
use English;
use Getopt::Std;
use Fcntl ':flock';
#
# Add a user to the wiki on ops. Also allow update of password.
......@@ -29,6 +30,7 @@ my $BOSSNODE = "@BOSSNODE@";
my $WIKISUPPORT = @WIKISUPPORT@;
my $SSH = "$TB/bin/sshtb";
my $WIKIPROXY = "$TB/sbin/wikiproxy";
my $lockfile = "/var/tmp/testbed_wikiuser_lockfile";
#
# Untaint the path
......@@ -102,6 +104,70 @@ else {
die("Bad data in user: $user.");
}
#
# We need to serialize this script to avoid a trashed map file. Use
# a dummy file in /var/tmp, opened for writing and flock'ed.
#
if (1) {
open(LOCK, ">>$lockfile") || fatal("Couldn't open $lockfile\n");
$count = 0;
if (flock(LOCK, LOCK_EX|LOCK_NB) == 0) {
#
# If we don't get it the first time, we wait for:
# 1) The lock to become free, in which case we do our thing
# 2) The time on the lock to change, in which case we wait for that process
# to finish
#
my $oldlocktime = (stat(LOCK))[9];
my $gotlock = 0;
while (1) {
print "Another exports update in progress, ".
"waiting for it to finish\n";
if (flock(LOCK, LOCK_EX|LOCK_NB) != 0) {
# OK, got the lock, we can do what we're supposed to
$gotlock = 1;
last;
}
$locktime = (stat(LOCK))[9];
if ($locktime != $oldlocktime) {
$oldlocktime = $locktime;
last;
}
if ($count++ > 20) {
fatal("Could not get the lock after a long time!\n");
}
sleep(1);
}
$count = 0;
#
# If we didn't get the lock, wait for the processes that did to finish
#
if (!$gotlock) {
while (1) {
if ((stat(LOCK))[9] != $oldlocktime) {
exit(0);
}
if (flock(LOCK, LOCK_EX|LOCK_NB) != 0) {
close(LOCK);
exit(0);
}
if ($count++ > 30) {
fatal("Process with the lock did not finish ".
"after a long time!\n");
}
sleep(1);
}
}
}
}
#
# Perl-style touch(1)
#
my $now = time;
utime $now, $now, $lockfile;
#
# This script always does the right thing, so no permission checks.
# In fact, all it does it call over to ops to run a script over there.
......@@ -123,6 +189,10 @@ if (!$query_result->numrows) {
my ($wikiname,$usr_name,$usr_email) = $query_result->fetchrow_array();
if (!defined($wikiname)) {
# In update mode, do nothing if no wikiname.
exit(0)
if ($update);
my @tokens = split(/\s+|-/, $usr_name);
#
......
......@@ -6,6 +6,7 @@
#
use English;
use Getopt::Std;
use Fcntl ':flock';
#
# Delete a user from the wiki
......@@ -28,6 +29,7 @@ my $BOSSNODE = "@BOSSNODE@";
my $WIKISUPPORT = @WIKISUPPORT@;
my $SSH = "$TB/bin/sshtb";
my $WIKIPROXY = "$TB/sbin/wikiproxy";
my $lockfile = "/var/tmp/testbed_wikiuser_lockfile";
#
# Untaint the path
......@@ -98,6 +100,70 @@ else {
die("Bad data in user: $user.");
}
#
# We need to serialize this script to avoid a trashed map file. Use
# a dummy file in /var/tmp, opened for writing and flock'ed.
#
if (1) {
open(LOCK, ">>$lockfile") || fatal("Couldn't open $lockfile\n");
$count = 0;
if (flock(LOCK, LOCK_EX|LOCK_NB) == 0) {
#
# If we don't get it the first time, we wait for:
# 1) The lock to become free, in which case we do our thing
# 2) The time on the lock to change, in which case we wait for that process
# to finish
#
my $oldlocktime = (stat(LOCK))[9];
my $gotlock = 0;
while (1) {
print "Another exports update in progress, ".
"waiting for it to finish\n";
if (flock(LOCK, LOCK_EX|LOCK_NB) != 0) {
# OK, got the lock, we can do what we're supposed to
$gotlock = 1;
last;
}
$locktime = (stat(LOCK))[9];
if ($locktime != $oldlocktime) {
$oldlocktime = $locktime;
last;
}
if ($count++ > 20) {
fatal("Could not get the lock after a long time!\n");
}
sleep(1);
}
$count = 0;
#
# If we didn't get the lock, wait for the processes that did to finish
#
if (!$gotlock) {
while (1) {
if ((stat(LOCK))[9] != $oldlocktime) {
exit(0);
}
if (flock(LOCK, LOCK_EX|LOCK_NB) != 0) {
close(LOCK);
exit(0);
}
if ($count++ > 30) {
fatal("Process with the lock did not finish ".
"after a long time!\n");
}
sleep(1);
}
}
}
}
#
# Perl-style touch(1)
#
my $now = time;
utime $now, $now, $lockfile;
#
# This script always does the right thing, so no permission checks.
# In fact, all it does it call over to ops to run a script over there.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment