Commit 6dacee9d authored by Mike Hibler's avatar Mike Hibler

Merge remote branch 'central/master'

parents 4aeedc82 3a9d0ae9
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2000-2003, 2005, 2006, 2007 University of Utah and the Flux Group.
* Copyright (c) 2000-2010 University of Utah and the Flux Group.
* All rights reserved.
*/
......@@ -10,6 +10,7 @@
#include <arpa/inet.h>
#include <fcntl.h>
#include <stdio.h>
#include <paths.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
......@@ -19,6 +20,7 @@
#include <errno.h>
#include <mysql/mysql.h>
#include <sys/time.h>
#include <signal.h>
#include <grp.h>
#include "capdecls.h"
#include "config.h"
......@@ -29,6 +31,9 @@
static int debug = 0;
static int portnum = SERVERPORT;
static gid_t admingid;
char *Pidname;
void sigterm(int);
void cleanup(void);
char *usagestr =
"usage: capserver [-d] [-p #]\n"
......@@ -53,6 +58,8 @@ main(int argc, char **argv)
struct sockaddr_in name;
struct timeval timeout;
struct group *group;
struct sigaction sa;
sigset_t actionsigmask;
while ((ch = getopt(argc, argv, "dp:")) != -1)
switch(ch) {
......@@ -84,6 +91,15 @@ main(int argc, char **argv)
exit(1);
}
sigemptyset(&actionsigmask);
sigaddset(&actionsigmask, SIGINT);
sigaddset(&actionsigmask, SIGTERM);
memset(&sa, 0, sizeof sa);
sa.sa_handler = sigterm;
sa.sa_mask = actionsigmask;
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
/*
* Grab the GID for the default group.
*/
......@@ -129,6 +145,19 @@ main(int argc, char **argv)
}
syslog(LOG_NOTICE, "listening on TCP port %d", ntohs(name.sin_port));
if (!getuid()) {
FILE *fp;
char mybuf[BUFSIZ];
sprintf(mybuf, "%s/capserver.pid", _PATH_VARRUN);
fp = fopen(mybuf, "w");
if (fp != NULL) {
fprintf(fp, "%d\n", getpid());
(void) fclose(fp);
Pidname = strdup(mybuf);
}
}
while (1) {
struct sockaddr_in client;
int clientsock, length = sizeof(client);
......@@ -295,6 +324,22 @@ main(int argc, char **argv)
}
close(tcpsock);
syslog(LOG_NOTICE, "daemon terminating");
cleanup();
exit(0);
}
void
sigterm(int sig)
{
cleanup();
exit(0);
}
void
cleanup(void)
{
syslog(LOG_NOTICE, "daemon exiting by signal");
if (Pidname)
(void) unlink(Pidname);
}
......@@ -2,7 +2,7 @@
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2007, 2009 University of Utah and the Flux Group.
# Copyright (c) 2000-2010 University of Utah and the Flux Group.
# All rights reserved.
#
use strict;
......@@ -21,6 +21,7 @@ my $optlist = "d";
# Configure variables
#
my $testbed_srcdir = "@top_srcdir@";
my $DBNAME = "@TBDBNAME@";
# Locals
my $dbfill = "sql/database-fill.sql";
......@@ -30,7 +31,7 @@ my $tempdifffile = "/tmp/dbdiff.$$";
my $tempnewfile = "/tmp/dbdiff.new.$$";
my $tempoldfile = "/tmp/dbdiff.old.$$";
my $exitcode = 0;
my $debug = 0;
my $debug = 1;
my %options = ();
if (! getopts($optlist, \%options)) {
......@@ -87,9 +88,9 @@ if (!$?) {
print "*** Your installed database is out of date with $dbfill\n";
print " Differences are listed in $tempdifffile\n"
if ($debug);
print " To bring it up to date, run: \n";
print " mysqldump tbdb > tbdb.backup\n";
print " (cd db; mysql tbdb < $master_fill)\n";
print " As a safety measure, you will not be able to install until this\n";
print " is resolved.\n";
unlink($tempdifffile)
if (!$debug);
exit(1);
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2009 University of Utah and the Flux Group.
# Copyright (c) 2009-2010 University of Utah and the Flux Group.
# All rights reserved.
#
use strict;
......@@ -13,16 +13,20 @@ use Getopt::Std;
#
sub usage()
{
print STDERR "Usage: dbupdate [-s | -f] <dbname> [<version>]\n";
print STDERR "Usage: dbupdate [-v] [-s] [-f] <dbname> [<version>]\n";
exit(-1);
}
my $optlist = "dsf";
my $optlist = "dsfvp:q";
my $debug = 0;
my $force = 0;
my $single = 0;
my $verify = 0;
my $quiet = 0;
my $path;
my $dbname;
my $version;
my $dbnumber = 0; # XXX Core emulab code is very rigid.
my $verify_count = 0;
#
# Configure variables
......@@ -30,6 +34,7 @@ my $dbnumber = 0; # XXX Core emulab code is very rigid.
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $DEFDBNAME = "@TBDBNAME@";
my $testbed_srcdir = "@top_srcdir@";
# Protos
sub Fatal($);
......@@ -44,11 +49,24 @@ delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
$| = 1;
# Load the Testbed support stuff.
use lib "@prefix@/lib";
#
# Do not modify the include path if it was specified when invoked.
# This allows update to run from the build tree.
#
BEGIN
{
eval "require emdbi";
if ($@) {
unshift(@INC, "@prefix@/lib");
}
}
use emdbi;
use libtestbed;
# Need this below.
my $objdir = `/bin/pwd`;
chomp($objdir);
#
# Parse command arguments.
#
......@@ -62,6 +80,17 @@ if (defined($options{"d"})) {
if (defined($options{"f"})) {
$force = 1;
}
if (defined($options{"q"})) {
$quiet = 1;
}
if (defined($options{"v"})) {
$verify = 1;
}
if (defined($options{"p"})) {
$path = $options{"p"};
chdir($path) or
Fatal("$path does not exist");
}
if (defined($options{"s"})) {
$single = 1;
if (@ARGV != 2) {
......@@ -172,6 +201,12 @@ foreach my $file (@files) {
my $revision = join(".", @dots);
$revision .= (@dots ? "." : "") . $file;
if ($verify) {
print "Need DB update $fullpath\n";
$verify_count++;
next;
}
print "Processing update $fullpath\n";
# Undefine this to make sure we get a new version each file.
......@@ -193,7 +228,18 @@ foreach my $file (@files) {
"where name='dbrev'")
if (!$single && !$force);
}
if ($verify) {
exit($verify_count)
if (!$verify_count || $quiet);
my $updatedir = "$testbed_srcdir/sql/updates";
$updatedir =~ s/^\.\.\///;
print "*** Your have DB update scripts that have not been run.\n";
print " As a safety measure, you will not be able to install until\n";
print " this is resolved.\n";
exit($verify_count);
}
exit(0);
sub Fatal($)
......@@ -203,3 +249,4 @@ sub Fatal($)
die("*** $0:\n".
" $msg\n");
}
......@@ -2,7 +2,7 @@
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2009 University of Utah and the Flux Group.
# Copyright (c) 2000-2010 University of Utah and the Flux Group.
# All rights reserved.
#
use strict;
......@@ -58,25 +58,9 @@ my $diff = (system("$schemadiff $db_schema $master_schema") >> 8);
unlink($db_schema);
if ($diff) {
my $objdir = `/bin/pwd`;
chomp($objdir);
print << "EOSTR";
The schema from $master_schema differs from
the running database. As a safety measure, you will not be able to
install until this is resolved.
If you are a user of the emulab software outside of Utah, this is
probably because your database was created for an older version of the
emulab software. You can update your database by:
boss> cd /your/srcdir/sql/updates
boss> perl $objdir/dbupdate $DBNAME
Be sure look in /your/srcdir/doc/UPDATING for any other instructions.
EOSTR
print "*** Your DB schema are out of date with $master_schema\n";
print " As a safety measure, you will not be able to install until\n";
print " this is resolved.\n";
exit(1);
} else {
exit(0);
......
......@@ -82,15 +82,9 @@ my $diff = (system("$sitevarsdiff $db_sitevars $master_sitevars") >> 8);
unlink($db_sitevars);
if ($diff) {
print << "EOSTR";
The sitevariables from $master_sitevars differs from
the running database. As a safety measure, you will not be able to install
until this is resolved. Please see the SQL statements above.
EOSTR
print "*** Your sitevariables are out of date with $master_sitevars.\n";
print " As a safety measure, you will not be able to install until\n";
print " this is resolved.\n";
exit(1);
} else {
exit(0);
......
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2009 University of Utah and the Flux Group.
# Copyright (c) 2000-2010 University of Utah and the Flux Group.
# All rights reserved.
#
......@@ -12,7 +12,8 @@ SUBDIR = install
include $(OBJDIR)/Makeconf
ifeq ($(STANDALONE_CLEARINGHOUSE),0)
TARGETS = boss-install ops-install fs-install dump-descriptors load-descriptors
TARGETS = libinstall.pm boss-install ops-install fs-install dump-descriptors \
load-descriptors update-install update-testbed
else
TARGETS = clrhouse-install
endif
......@@ -25,7 +26,10 @@ all: $(TARGETS)
include $(TESTBED_SRCDIR)/GNUmakerules
install: $(INSTALL_LIBDIR)/libinstall.pm
install: $(INSTALL_LIBDIR)/libinstall.pm \
$(INSTALL_SBINDIR)/update-install \
$(INSTALL_SBINDIR)/update-testbed
clean:
rm -f boss-install ops-install fs-install
rm -f boss-install ops-install fs-install update-install
rm -f update-testbed
......@@ -66,7 +66,6 @@ my $PWD = "/bin/pwd";
my $PW = "/usr/sbin/pw";
my $PATCH = "/usr/bin/patch";
my $SSH_KEYGEN = "/usr/bin/ssh-keygen";
my $PKG_INFO = "/usr/sbin/pkg_info";
my $PKG_ADD = "/usr/sbin/pkg_add";
my $PKG_DEL = "/usr/sbin/pkg_delete";
my $TOUCH = "/usr/bin/touch";
......@@ -87,8 +86,6 @@ my $MYSQLDUMP = "/usr/local/bin/mysqldump";
my $MYSQLINSTALL = "/usr/local/bin/mysql_install_db";
my $MYSQLDBDIR = "/var/db/mysql";
my $GMAKE = "/usr/local/bin/gmake";
#
# Some files we edit/create
#
......@@ -170,17 +167,13 @@ my $NAMED_PIDFILE = "/var/run/named.pid";
#
# Some directories we care about
#
my $LOGDIR = "$PREFIX/log";
my $MYSQL_LOGDIR = "$LOGDIR/mysql";
my $RCDIR = "/usr/local/etc/rc.d";
my $USERSVAR_DIR = "$PREFIX/usersvar";
my $OPSDIR_DIR = "$PREFIX/opsdir";
my $PORTSDIR = "/usr/ports";
my $PORTSMISCDIR = "$PORTSDIR/misc";
my $MIBPATH = "/usr/local/share/snmp/mibs";
my $TFTP_DIR = "$PREFIX/tftpboot";
my $TFTP_PROJ_DIR = "$TFTP_DIR/proj";
my $VARRUN = "/var/run";
my $ETCSSH = "/etc/ssh";
#
......
......@@ -142,12 +142,10 @@ my $PW = "/usr/sbin/pw";
my $PATCH = "/usr/bin/patch";
my $NEWALIASES = "/usr/bin/newaliases";
my $SH = "/bin/sh";
my $PKG_INFO = "/usr/sbin/pkg_info";
my $PKG_ADD = "/usr/sbin/pkg_add";
my $PWD = "/bin/pwd";
my $CP = "/bin/cp";
my $MV = "/bin/mv";
my $GMAKE = "/usr/local/bin/gmake";
my $ENV = "/usr/bin/env";
my $QUOTAON = "/usr/sbin/quotaon";
......@@ -175,11 +173,8 @@ my $SMBCONF_HEAD = "$SMBCONF_FILE.head";
#
my $LIST_DIR = "/etc/mail/lists";
my $TIPLOG_DIR = "/var/log/tiplogs";
my $PORTSDIR = "/usr/ports";
my $PORTSMISCDIR = "$PORTSDIR/misc";
my $SRCDIR = '@srcdir@';
my $RCDIR = "/usr/local/etc/rc.d";
my $VARRUN = "/var/run";
#
# And some lists that we use
......
......@@ -4,12 +4,31 @@
# Copyright (c) 2003-2010 University of Utah and the Flux Group.
# All rights reserved.
#
#
# A simple library for use in the installation scripts, to make them seem a
# little more legitimate, instead of the quick hacks they are.
# A simple library for use in the installation scripts, to make them
# seem a little more legitimate, instead of the quick hacks they are.
#
use POSIX qw(strftime);
use Exporter;
use vars qw(@EXPORT $TOP_OBJDIR
$TBROOT $LOGDIR $MAINSITE $PGENISUPPORT $GMAKE $PKG_INFO
$PORTSDIR $VARRUN $RCDIR);
@EXPORT = qw($TOP_OBJDIR
$TBROOT $LOGDIR $MAINSITE $PGENISUPPORT $GMAKE $PKG_INFO
$PORTSDIR $VARRUN $RCDIR);
# Configure variables
$TBROOT = "@prefix@";
$LOGDIR = "$TBROOT/log";
$MAINSITE = @TBMAINSITE@;
$PGENISUPPORT = @PROTOGENI_SUPPORT@;
$GMAKE = "/usr/local/bin/gmake";
$PKG_INFO = "/usr/sbin/pkg_info";
$PORTSDIR = "/usr/ports";
$VARRUN = "/var/run";
$RCDIR = "/usr/local/etc/rc.d";
#
# Make sure that output gets printed right away
......@@ -32,11 +51,24 @@ my $updatemode = 0;
# Used by update-install to bump the version number.
sub SET_TESTBED_VERSION($) { $updatemode = $MAGIC_TESTBED_VERSION = $_[0]; }
# Set by update-install.
my $impotent = 0;
my $logfp;
sub SET_IMPOTENT_MODE($) { $impotent = 1; $logfp = $_[0]; };
#
# Some programs we may call
#
my $FETCH = "/usr/bin/fetch";
#
# Figure out which directory we live in, so that some stages can do thing
# relative to it.
#
$TOP_OBJDIR = `/usr/bin/dirname $0`;
chomp $TOP_OBJDIR;
$TOP_OBJDIR = "$TOP_OBJDIR/..";
#
# Let's pretend perl's exception mechanism has a sane name for the function
# that raises an exception
......@@ -44,7 +76,7 @@ my $FETCH = "/usr/bin/fetch";
sub throw(@) {
die @_,"\n";
}
#
# Start a new installation phase
#
......@@ -80,12 +112,15 @@ sub Phase($$$) {
print "\n";
}
printf "%-50s", $descrstring;
printf $logfp "%-50s", $descrstring
if ($impotent);
#
# Clear these, as we don't want to see the outputs of previous phases
#
@libinstall::lastExecOutput = ();
$libinstall::lastCommand = undef;
@libinstall::loglines = ();
#
# Cool! TWO levels of Perl Hell just for me!
......@@ -110,6 +145,8 @@ sub Phase($$$) {
SWITCH: for ($@) {
(/^skip$/) && do {
print "[ Skipped ($libinstall::reason) ]\n";
print $logfp "[ Skipped ($libinstall::reason) ]\n"
if ($impotent && defined($logfp));
$$parentSkipped++;
$libinstall::phaseResults{$name} = $_;
last SWITCH;
......@@ -138,10 +175,24 @@ sub Phase($$$) {
if ($hasSubPhase && $skipped && ($nonSkipped == 0)) {
print "[ Skipped ] ($stamp)\n";
print $logfp "[ Skipped ]\n"
if ($impotent && defined($logfp));
$libinstall::phaseResults{$name} = "skip";
$$parentSkipped++;
} else {
print "[ Succeeded ] ($stamp)\n";
if ($impotent) {
if (defined($logfp)) {
print $logfp "[ $libinstall::reason ]\n";
print $logfp
"> " . join("\n> ", @libinstall::loglines) . "\n"
if (@libinstall::loglines);
}
print "[ $libinstall::reason ]\n";
}
else {
print "[ Succeeded ] ($stamp)\n";
}
$$parentNonSkipped++;
$libinstall::phaseResults{$name} = "succeed";
}
......@@ -221,6 +272,38 @@ sub PhaseWasSkipped($) {
($libinstall::phaseResults{$phase} =~ /^skip$/));
}
#
# For impotent mode.
#
sub PhaseWouldHave($) {
($libinstall::reason) = (@_);
throw "succeed";
}
#
# Also for impotent mode; detailed logging.
#
sub PhaseLog(@) {
(@libinstall::loglines) = (@_);
}
#
# Also for impotent mode; log differences to a file.
#
sub DiffFiles($$) {
my ($src,$dst) = @_;
return
if (!$impotent);
if (! -e $dst) {
my $stuff = `cat $src`;
PhaseLog(split('\n', $stuff));
}
my $diff = `diff $src $dst`;
PhaseLog(split('\n', $diff));
}
#
# Check to see if the phase is already done, as evidenced by the existance of
# a file
......@@ -272,11 +355,41 @@ sub DoneIfIdentical($$) {
if (!-e $filename1 || !-e $filename2) {
return;
}
if (!ExecQuiet("cmp -s $filename1 $filename2")) {
system("cmp -s $filename1 $filename2");
if (! $?) {
PhaseSkip("Files $filename1 and $filename2 are identical");
}
}
#
# Done if package installed.
#
sub DoneIfPackageInstalled($) {
my ($pname) = @_;
my $foo = `$PKG_INFO -x $pname`;
if (! $?) {
PhaseSkip("already installed");
}
}
#
# Backup a file or fail.
#
sub BackUpFileFatal($)
{
my ($filename) = @_;
my $suffix = time();
my $backup = $filename . "-" . $suffix;
PhaseFail("$filename does not exist")
if (! -e $filename);
PhaseFail("$filename already exists")
if (-e $backup);
ExecQuietFatal("/bin/cp -p $filename $backup")
if (!$impotent);
}
#
# Check to see if filesystem already mounted
#
......@@ -317,6 +430,12 @@ sub DoneIfMounted($)
#
sub AppendToFile($@) {
my ($filename, @lines) = @_;
if ($impotent) {
PhaseLog(@lines);
PhaseWouldHave("append to $filename");
return undef;
}
if (!-e $filename) {
return "File $filename does not exist";
}
......@@ -349,6 +468,12 @@ sub AppendToFileFatal($@) {
#
sub CreateFile($;@) {
my ($filename,@lines) = @_;
if ($impotent) {
PhaseLog(@lines);
PhaseWouldHave("create $filename");
return undef;
}
if (-e $filename) {
return "File $filename already exists";
}
......@@ -385,6 +510,12 @@ sub ExecQuiet(@) {
# Use a pipe read, so that we save away the output
#
my $commandstr = join(" ",@_);
if ($impotent) {
PhaseWouldHave("exec($commandstr)");
return 0;
}
my @output = ();
open(PIPE,"$commandstr 2>&1 |") or return -1;
while (<PIPE>) {
......@@ -415,14 +546,14 @@ sub ExecQuietFatal(@) {
}
#
# HUP a daemon, if it's PID file exists. If we can't kill it, we assume that
# Signal a daemon, if it's PID file exists. If we can't kill it, we assume that
# it's because it wasn't running, and skip the phase. Fails if it has trouble
# reading the pid file.
# Takes the name of the daemon as an argument, and assumes
# that the pid file is /var/run/$name.pid
#
sub HUPDaemon($) {
my ($name) = @_;
sub SignalDaemon($$) {
my ($name,$sig) = @_;
my $pidfile = "/var/run/$name.pid";
PhaseSkip("$name is not running") unless (-e $pidfile);
open(PID,$pidfile) or PhaseFail("Unable to open pidfile $pidfile");
......@@ -431,17 +562,34 @@ sub HUPDaemon($) {
close PID;
PhaseFail("Bad pid ($pid) in $pidfile\n") unless ($pid =~ /^\d+$/);
if (!kill 1, $pid) {
PhaseSkip("$name does not seem to be running");
if ($impotent) {
PhaseWouldHave("signal($sig) $name");
return;
}
if (!kill($sig, $pid)) {
PhaseSkip("$name is not running");
}
}
sub HUPDaemon($) {
my ($name) = @_;
SignalDaemon($name, 'HUP');
}
#
# Fetch a file from the network, using any protocol supported by fetch(1).
# Arguments are URL and a local filename. Retunrns 1 if succesful, 0 if not.
#
sub FetchFile($$) {
my ($URL, $localname) = @_;
if ($impotent) {
PhaseLog("$URL --> $filename");
PhaseWouldHave("fetch $URL");
return 1;
}
if (ExecQuiet("$FETCH -o $localname $URL")) {
return 0;
} else {
......
......@@ -42,7 +42,6 @@ my $CVSSUPPORT = @CVSSUPPORT@;
my $BUGDBSUPPORT= @BUGDBSUPPORT@;
my $WIKISUPPORT = @WIKISUPPORT@;
my $QUOTA_FSLIST= '@FS_WITH_QUOTAS@';
my $LOGDIR = "$PREFIX/log";
my $ETCDIR = "$PREFIX/etc";
my $LIBDIR = "$PREFIX/lib";
my $SCRATCHDIR = '@FSDIR_SCRATCH@';
......@@ -183,13 +182,11 @@ my $PW = "/usr/sbin/pw";
my $PATCH = "/usr/bin/patch";