home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.sberbank.sumy.ua
/
2014.11.ftp.sberbank.sumy.ua.tar
/
ftp.sberbank.sumy.ua
/
incoming
/
sxtech
/
upgrade.pl
< prev
next >
Wrap
Perl Script
|
2014-08-29
|
60KB
|
2,904 lines
#!/usr/bin/perl -w
#
# $Revision: #18 $
#
# upgrade - perform upgrade to latest firmware revision
#
use Carp;
use IO::Handle;
use File::Basename;
require "getopts.pl";
require "stat.pl";
$pres_eq_conf = 1;
$pres_en_conf = 1;
$pres_sw_conf = 1;
$no_preserve = 0;
$set_use_ssl = 0;
$logfile = "./upgrade.log";
$dbgfile = "./upgrade.dbg";
$inputfile = "/var/tmp/eq_upgrade.in";
$outputfile = "/var/log/eq_upgrade.log";
$vers = "8.6.0"; # product version #
$oslevel = 0;
$disk = "";
$slice_old = 1;
$slice_new = 2;
$slice_xtra = 0; # extra slice always allocated
#
# We will now try to make this the same as the layout used in the
# PXE installs:
# All sizes are expressed in 512 byte blocks!
#
# {DISK}s1-1=ufs 503808 / 0
#
#
$root_size = 503808; # 512 byte sectors
$swap_size = 10240; # vestigeal
$usr_size = 0; # 512 byte sectors
$tmp_size = 0; # 512 byte sectors
$var_size = 0; # 512 byte sectors (at least)
$size = $root_size + $swap_size + $var_size + $tmp_size + $usr_size;
$opt_R = 0; # reset after botched attempt
$opt_r = 0; # Auto reboot if set (don't ask).
$opt_b = 0; # batch mode
$opt_k = 0; # load test4QA key
$opt_e = 0; # preserve /eqsupport/.ssh/
$opt_l = 0; # preserve license files only with -C option.
$opt_S = 0; # install SNMP?
$opt_G = 0; # GUI mode
local *DBG;
@mp = ("/"); # mount points
%slice_map = ();
@mp_x = (); # extra mount points
%slice_map_x = ();
%bits_map = (
'/' => "./root.tgz",
);
%fdisk = ();
%label = ();
#
# Preserving old version information
#
sub previous {
system "rm -rf /.master/var/eq/eq.previous";
system "cp /.master/var/eq/eq.conf /.master/var/eq/eq.previous";
system "rm -rf /version/eq.previous";
system "cp /.version/eq /.version/eq.previous";
}
%xlate = (
'/etc/hosts' => '/var/etc/hosts',
'/etc/group' => '/var/etc/group',
'/etc/resolv.conf' => '/var/etc/resolv.conf',
'/etc/ntp.conf' => '/var/etc/ntp.conf',
'/etc/syslog.conf' => '/var/etc/syslog.conf',
'/etc/ntp.drift' => '/var/etc/ntp.drift',
'/etc/localtime' => '/var/etc/localtime',
'/etc/ipfw.conf' => '/var/eq/ipfw.conf',
'/etc/eq.conf' => '/.master/var/eq/eq.conf',
'/etc/tac_client.conf'=> '/.master/var/eq/tac_client.conf',
'/etc/eq.previous' => '/.master/var/eq/eq.previous',
'/etc/switch.conf' => '/var/eq/switch.conf',
'/etc/envoy.conf' => '/var/eq/envoy.conf',
'/etc/natd.conf' => '/var/eq/natd.conf',
'/eq.previous' => '/.version/eq.previous',
'/usr/local/www/cgi-bin/users'
=> '/var/eq/users',
);
#
# Determine whether to get our answer from STDIN, or from our
# file
sub get_answer {
my $ans = "x";
if ($opt_G) {
while($ans eq "x") {
open (EQ_IN_FILE, $inputfile);
chop($ans = <EQ_IN_FILE>);
close EQ_IN_FILE;
sleep 1;
}
open (EQ_IN_FILE, ">" . $inputfile);
print EQ_IN_FILE "x\n";
close EQ_IN_FILE;
}
else {
chop($ans = <STDIN>);
}
return($ans);
}
sub curr_vers {
my $vers;
if (-f "/.version/eq") {
open IN, "< /.version/eq" or die;
while (<IN>) {
chop;
if (/^EQVERS=(\d.*)$/) {
$vers = $1;
}
}
} else {
$vers = "0";
}
return $vers;
}
#
# dummy - ensure we don't get warning messages
#
sub dummy {
print $disk . $slice_old . $slice_new;
print $opt_R;
print $size;
print $ST_MODE + $ST_GID + $ST_UID;
}
#
# usage - print usage info
#
sub usage {
print "usage: upgrade [-R]\n";
exit 1;
}
#
# dbg - print an informational message
#
sub dbg {
my $arg = shift;
print DBG "$arg\n";
}
#
# dbg_save - save the debug file
#
sub dbg_save {
my $now = time();
&sis("gzip --best < $dbgfile > /.version/upgrade.dbg.$now.gz");
}
#
# note - print an informational message
#
sub note {
my $arg = shift;
&dbg("$arg");
print "$arg\n";
}
#
# cark - cark it
#
sub cark {
my $arg = shift;
&dbg("cark: $arg");
&dbg_save;
¬e("**** Fatal error.");
¬e("**** Please contact Coyote Point customer support.");
¬e("**** Please provide the contents of $dbgfile.");
if ($opt_r) {
print "NOTE: This system is currently in an intermediate state.";
print "It must be rebooted to return it to a stable state.";
print "Because the upgrade did *NOT* succeed, the current version";
print "will start when the system is rebooted.";
}
die "$arg";
}
#
# dbg_hash - print an informational message
#
sub dbg_hash {
my $ref = shift;
return unless defined %$ref;
foreach $k (sort keys %$ref) {
print DBG "$k $ref->{$k}\n";
}
}
#
# dbg_array - print an informational message
#
sub dbg_array {
my $ref = shift;
my $siz = @$ref;
for ($i = 0; $i < $siz; ++$i) {
print DBG "$ref->[$i]\n";
}
}
#
# sis - perform `system' function and croak if non-zero result.
#
sub sis {
my $arg = shift or &cark("");
&dbg("sis: $arg");
#
# This is perl-ass-backwards, if you can imagine what that is.
#
system $arg and sleep 1 and &cark("\n");
}
#
# vsis - verbosely perform system function (sort of)
#
sub vsis {
local *FH;
local *TTY;
my $success = 0;
my $last = '';
my $arg = shift or &cark("");
my @rot = ('/', '-', '\\', '|');
my @rat = ('o', '.', 'o', '0');
my @spc = (' ', '- ', ' - ', ' - ', ' -');
my $i = 0;
my $j = 0;
my $k = 0;
my $s = 0;
return &sis($arg) unless !$opt_b;
if (!$opt_G) {
open TTY, ">/dev/tty" or die;
select((select(TTY), $| = 1)[0]);
}
open FH, "sh -c '". $arg ."' && echo '>>>success<<<' 2>&1 |" or die;
select((select(FH), $| = 1)[0]);
my $rin = '';
my $ein = '';
my $rout;
my $eout;
vec($rin, fileno(FH), 1) = 1;
$ein = $rin;
my $eof = 0;
my $off = 0;
my $toss = '';
while (!$eof && !$success) {
my ($n, $t) = select($rout=$rin, undef, $eout=$ein, 0.05);
$eof = vec($eout, fileno(FH), 1);
if (!$eof && vec($rout, fileno(FH), 1)) {
if (length($toss) > 128) {
$off = 128;
$toss = substr($toss, -$off);
}
my $cc = sysread(FH, $toss, 1024, $off);
if ($cc) {
$last = $toss;
} else {
$eof = 1;
}
}
if (!$opt_G) {
print TTY "\rW$rat[$i]rking$spc[$j]$rot[$k]";
}
if ($s == 0) {
($i = 0, $s = 1) unless ++$i <= $#rat;
}
if ($s == 1) {
($j = 0, $s = 2) unless ++$j <= $#spc;
}
if ($s == 2) {
($k = 0) unless ++$k <= $#rot;
$s = 0;
}
if ($toss =~ />>>success<<</) {
$success = 1;
print "\rsuccess! \n";
}
}
print "\r \r$last" unless $success;
close FH;
if (!$opt_G) {
close TTY;
select(STDOUT); $| = 1;
}
print "\n";
}
sub do_mounts {
foreach $mp (@mp) {
sis "mount $slice_map{$mp} /mnt/$mp";
}
foreach $mp (@mp_x) {
sis "mount $slice_map_x{$mp} /mnt/$mp";
}
}
sub undo_mounts {
foreach $mp (reverse @mp_x) {
my $mnt = "$slice_map_x{$mp}";
foreach (`mount`) {
if (/^$mnt/) {
sis "umount $mnt";
}
}
}
foreach $mp (reverse @mp) {
my $mnt = "$slice_map{$mp}";
foreach (`mount`) {
if (/^$mnt/) {
sis "umount $mnt";
}
}
}
}
#
# root_disk - determine the disk to root with
#
sub root_disk {
foreach (`df /`) {
if (m:^/dev/(\D+\d)s(\d)[a-f]\s:) {
&dbg("root disk: $1:$2");
$disk = $1;
$slice_old = $2;
return;
}
}
&cark("Cannot determine disk type.\n");
}
#
# sync_disk - sync the in-core view of the slices with the on-disk.
#
sub sync_disk {
local *FH;
open FH, "./disk $disk 2>&1 |" or die;
while (<FH>) {
chop;
&dbg("pre: $_");
}
close FH;
open FH, "./disk -S $disk 2>&1 |" or die;
while (<FH>) {
chop;
&dbg("post: $_");
&cark("$_\n") if (/ioctl/);
}
close FH;
}
#
# fdisk_reset - reset the %fdisk cache
#
sub fdisk_reset {
local $d = shift || die;
local *FH;
&dbg("fdisk_reset $d");
%fdisk = ();
open FH, "fdisk -s $d |";
$_ = <FH>;
chop;
my @zot = split;
@fdisk{'cyl', 'hd', 'sec'} = @zot[1, 3, 5];
$_ = <FH>;
while (<FH>) {
chop;
@zot = split;
&cark("invalid input: $_") unless m/^\s+(\d+):/;
$fdisk{$1} = ();
@{$fdisk{$1}}{'start', 'size', 'type', 'flags'} = @zot[1..4];
}
close FH;
#
# debug
#
foreach $p (1..4) {
next unless defined $fdisk{$p};
foreach $k (keys %{$fdisk{$p}}) {
&dbg("$p: $k $fdisk{$p}->{$k}");
}
}
}
#
# disklabel_reset - reset the %label cache
#
sub disklabel_reset {
local $d = shift || die;
local $s = shift || die
local *FH;
&dbg("disklabel_reset $d $s");
%label = ();
open FH, "disklabel ${d}s${s} |";
while (<FH>) {
@zot = split;
if ($#zot >= 4 && $zot[0] =~ /^([abcdefgh]):/) {
$label{$1}->{'size'} = $zot[1];
$label{$1}->{'fstype'} = $zot[3];
}
}
close FH;
}
#
# slice_4_inuse - predicate
#
sub slice_4_inuse {
local *FH;
open FH, "swapinfo|";
while (<FH>) {
if (m:^/dev/r${disk}s4:) {
close FH;
return 1;
}
}
close FH;
open FH, "mount|";
while (<FH>) {
if (m:^/dev/${disk}s4:) {
close FH;
return 1;
}
}
close FH;
open FH, "</etc/rc.conf";
while (<FH>) {
if (m:^dumpdev=.*/dev/${disk}s4:) {
close FH;
return 1;
}
}
return 0;
}
#
# reclaim_space - reclaim space on $disk
#
sub reclaim_space {
local $d = shift;
local $p = shift;
local *FH;
&dbg("reclaim($d, $p)");
if ($p == 4 && &slice_4_inuse()) {
&cark("**** Cannot delete slice 4.\n");
}
open FH, "| fdisk -f - $d" or die;
print FH "p $p 0 0 0\n";
close FH;
&sync_disk($d);
&fdisk_reset($d);
}
#
# current_slice - return current slice used
#
sub current_slice {
#
# XXX: this is bogus as the 0x80 has been seen to be set
# XXX: on more than one partition at a time.
#
foreach (1..3) {
next unless defined $fdisk{$_};
next unless oct($fdisk{$_}->{'type'}) == 165;
next unless oct($fdisk{$_}->{'flags'}) & 0x80;
&dbg("current slice = $_");
return $_;
}
&cark("no current slice\n");
}
#
# free_space - return the amount of free space for a given FDISK slice
#
sub free_space {
my $p = shift || die;
my $start = 0;
my $end = $fdisk{'cyl'} * $fdisk{'hd'} * $fdisk{'sec'};
&dbg("free_space $p - start=$start end=$end");
return 0 unless !defined($fdisk{$p});
foreach $i (1..4) {
next unless defined $fdisk{$i};
if ($i < $p) {
#
# allocated partition prior to the one of interest.
#
$start = $fdisk{$i}->{'start'} + $fdisk{$i}->{'size'};
&dbg("free_space $i start=$start");
} elsif ($p < $i) {
#
# allocated partition past the one of interest.
#
$start = $fdisk{$i}->{'start'} - $start;
&dbg("free_space $i start=$start");
return $start;
} else {
#
# allocated partition is the one of interest.
#
&cark("not reached\n");
}
}
my $space = $end - $start;
&dbg("free_space $space");
return $space;
}
#
# next_slice - return a slice to use for the next install
#
sub next_slice {
my $need = shift || die;
my $blk = 0;
foreach $i (1..3) {
next unless $slice_old != $i;
&dbg("next_slice $need = $i") unless free_space($i) < $need;
return $i unless free_space($i) < $need;
}
&dbg("no next slice");
return 0;
}
#
# lm_check - check with license manager
#
sub lm_check {
my $once = shift;
my $prod = "";
local *LM;
my %opts = ();
my %lic = ();
open LM, "./lm -? 2>&1 |" or &cark("$!\n");
while (<LM>) {
foreach $c (['V', 'I', 'S', 'p', 'f', 'r', 'v']) {
$opts{$c} = $c if /^\s+-$c/;
}
}
close LM;
open LM, "./lm -p 2>&1 |" or &cark("$!\n");
while (<LM>) {
if (/^(e[23456789]50)/) {
$prod = $1;
}
}
close LM;
if ($prod) {
open LM, "./lm -Z 2>&1 |" or &cark("$!\n");
#
# If we are licensed, we abuse the fact that the last license
# spat out by the debug (-Z) reflects the licensed capability.
#
# In the future, we will use the new '-E' option which spits out perl
#
my $state = 0;
while (<LM>) {
if ($state == 0 && /^license {/) {
$state = 1;
}
if ($state == 1 && /^}$/) {
$state = 2;
}
if ($state == 2 && /^license {/) {
$state = 1;
%lic = ();
}
if ($state == 1) {
next unless /\s+(\S+)\s+=\s+(.*)$/;
$lic{$1} = $2;
$lic{$1} =~ s/["';'"]//g;
}
}
close LM;
&cark("") unless $state == 2;
#
# Ensure version locked. If not, that is the same as failure.
#
if (!defined $lic{'eq_vers'}) {
note "**** Cannot upgrade with non-version locked license.";
if (!$once) {
note "**** Attempting to get new license.";
sis "./lm -f -r -U";
&lm_check(1);
return;
} else {
&cark("**** Licensing problems.\n");
}
}
# The license is valid if:
# either the major number is equal and the
# minor number of the "allowed" is greater than
# or equal to the "actual"
# or
# the major number of the "allowed" is greater
# than the major number of the actual
my ($maj1, $min1, $junk1) = split(/\./,$lic{'eq_vers'},3);
my ($maj2, $min2, $junk2) = split(/\./,$vers,3);
if (($maj1 eq $maj2 && $min1 ge $min2) ||
($maj1 gt $maj2)) {
return;
}
note "**** Need new license for version $vers.";
} else {
note "**** Need license for version $vers.";
}
if (-f "/var/eq/licenses/recent") {
sis "cd /var/eq/licenses"
. " && mv recent recent.$lic{'eq_vers'}";
}
open LM, "./lm -f -r -U 2>&1 |" or die;
while (<LM>) {
#
# expecting nothing output, so anything must be error message.
#
chop;
&cark("$_\n");
}
close LM;
open LM, "./lm -p 2>&1 |" or die;
while (<LM>) {
&cark("Not licensed.\n") unless /^e[23456789]50/;
}
close LM;
}
#
# zoneupdate - update zoneinfo
#
sub zoneupdate {
my $vers;
my %md5hash;
my $md5;
my $file;
my $localmd5;
local *IN;
if (-f "/.version/eq") {
open IN, "< /.version/eq" or die;
while (<IN>) {
chop;
if (/^EQVERS=(\d.*)$/) {
$vers = $1;
}
}
} else {
$vers = "0";
}
close IN;
open IN, "< ./zonehash";
while (<IN>) {
chop;
/^(.*?) (.*?)$/;
$md5hash{$2} = $1;
}
close IN;
$localmd5 = 0;
if ($vers lt "7.2.3g") {
$localmd5 = `md5 -q /.master/var/etc/localtime`;
chop($localmd5);
if ($md5hash{$localmd5}) {
print "Your localtime has been changed. If your timezone is ";
print "within the United States,\nyou will notice that your ";
print "system is updated for the new Daylight Savings time\n";
print "rules.\n";
$file = $md5hash{$localmd5};
system("cp /mnt/$file /mnt/.master/var/etc/localtime");
}
}
}
sub verscheck {
my $vers;
my $live;
$live = 0;
if (-f "/.version/eq") {
open IN, "< /.version/eq" or die;
while (<IN>) {
chop;
if (/^EQVERS=(\d.*)$/) {
$vers = $1;
}
}
} else {
$vers = "0";
}
if ($vers lt "8.5.1") {
die("You must be running Version 8.5.1 to upgrade to Version 8.6.\n".
"Please upgrade your system to the latest 8.5.1 image and try again.");
}
close IN;
open IN, "./lm -h -U 2>&1 |" or &cark("$!\n");
while (<IN>) {
if (/^(e[2346]50)gx-?|(e[23456]50)si-?|(ex1[78]50)-?|(vmware)-?/) {
$live = 1;
}
}
&cark("This upgrade is not valid on your hardware platform. Please contact Coyote Point Support.") unless $live == 1;
}
#
# setup - perform necessary setup.
#
sub setup {
#
# cleanup any old unsaved kernel dump info
#
system "/sbin/savecore -c >/dev/null 2>&1";
open DBG, ">> $dbgfile";
&root_disk;
&fdisk_reset($disk);
my $tot = $fdisk{'cyl'} * $fdisk{'hd'} * $fdisk{'sec'};
note "root disk: $disk, root slice $slice_old, capacity $tot sectors";
$slice_xtra = 4 unless $tot < 15625000; # 8Gig in sectors.
#
# Determine if we are upgrading from 2.2.8 or newer.
#
chop($oslevel = `uname -r`);
chop($opsys = `uname -s`);
if ($oslevel =~ /^[23][.]/) {
#
# Ancient.
#
&cark("Cannot upgrade from 2.2.8 to 7.1.0");
} elsif ($oslevel =~ /^4[.][789]/) {
#
# Slightly newer.
#
$oslevel = 4;
&kluges;
} elsif ($oslevel =~ /^4[.]1[01]/) {
$oslevel = 4;
} elsif ($opsys =~ /^EQ\/OS/) {
$oslevel = 4;
} else {
&cark("Unsupported OS level: $oslevel\n");
}
chdir "/usr/l7up" or &cark("$!\n");
if ($opt_G) {
open(STDOUT, '>>'.$outputfile ) or die $!;
open(STDERR, '>>'.$outputfile ) or die $!;
}
else {
open(STDOUT, "| tee -a $logfile") or &cark("$!\n");
open(STDERR, ">&STDOUT") or &cark("$!\n");
}
select(STDOUT); $| = 1;
select(STDERR); $| = 1;
#
# show current level (debug assist)
#
open IN, "./lm -v |" or die;
map { ¬e("lm: $_") } <IN>;
close IN;
#
# show current mounts in debug log
#
open IN, "/sbin/mount |" or die;
map { &dbg($_) } <IN>;
close IN;
open IN, "/sbin/fdisk -s $disk |" or die;
map { &dbg($_) } <IN>;
close IN;
#
# Give up if there is more than one active partition.
#
my $count = 0;
foreach $s (1..4) {
next unless defined($fdisk{$s});
next unless (oct($fdisk{$s}->{'flags'}) & 0x80);
$count++;
}
&cark("No active partition.\n") unless $count > 0;
# &cark("Too many active partitions: $count.\n") unless $count == 1;
}
#
# lsmash - smash out sym links
#
sub lsmash {
local $f = shift;
local $m = "";
foreach $c (split('/', $f)) {
$m .= "/$c";
if (-l "/mnt/$m") {
$m = readlink "/mnt/$m";
}
}
&dbg("lsmash: $f -> $m");
return $m;
}
#
# unshad - unshadow
#
sub __unshad {
local $f = shift;
local $m = "/.master$f";
return $m unless !-f "/mnt$m";
return $m unless !-d dirname("/mnt$m");
return $f
}
sub unshad {
local $f = shift;
local $s = &__unshad($f);
&dbg("unshad: $f -> $s");
return $s;
}
sub xlate {
local $f = shift;
&dbg("xlate: $f -> $xlate{$f}") unless !defined($xlate{$f});
return $xlate{$f} unless !defined($xlate{$f});
return $f;
}
#
# preserve - preserve old version of file
#
sub preserve {
local $f = shift;
local $m = "/mnt" . &unshad(&lsmash(&xlate($f)));
local @inode;
$f = readlink $f unless ! -l $f;
$f = &xlate($f) unless -f $f;
note " ** preserve $f";
if (-f "$f") {
if (-f "$m") {
@inode = stat("$m");
rename "$m", "${m}.dist";
} else {
@inode = stat("$f");
}
if ($f ne $m) {
sis "cp $f $m";
}
chown $inode[$ST_UID], $inode[$ST_GID], "$m";
chmod $inode[$ST_MODE], "$m";
}
}
#
# d_preserve - preserve old contents of directory (not recursive)
#
sub d_preserve {
local $d = shift;
local $f;
local @inode;
if (-d "$d") {
local *DP;
sis "mkdir -p /mnt/$d";
note " ** preserve $d/";
opendir(DP, $d) || &cark("$!\n");
foreach $f (grep { -f "$d/$_" } readdir(DP)) {
preserve "$d/$f";
}
closedir DP;
}
}
sub new_fstab {
local *OUT;
my $slice = $slice_map{'/'};
note "**** new fstab";
unlink "/mnt/etc/fstab";
open OUT, ">/mnt/etc/fstab" or &cark("$!\n");
if ($slice_xtra) {
local $xx = "b none swap sw 0 0";
print OUT "/dev/${disk}s$slice_xtra" . "${xx}\n";
&dbg( "/dev/${disk}s$slice_xtra" . "${xx}");
&disklabel_reset($disk, $slice_xtra);
}
if ($slice_xtra && $label{'a'}->{'size'} > 4000000
&& $label{'a'}->{'fstype'} =~ "4.2BSD") {
#
# If there is an 'a' partition, we will attempt to use this as
# /var/crash
#
local $xx = "a /var/crash ufs rw 2 2";
print OUT "/dev/${disk}s$slice_xtra" . "${xx}\n";
&dbg( "/dev/${disk}s$slice_xtra" . "${xx}");
}
if ($slice_xtra && $label{'b'}->{'size'} > 4000000
&& $label{'b'}->{'fstype'} =~ "swap") {
#
# If there is a 'b' partition, we will attempt to use this as
# dump device
#
sis 'echo dumpdev="/dev/${disk}s${slice_xtra}b"'
. '>> /mnt/.master/var/etc/rc.conf';
}
print OUT "$slice / ufs ro 1 1\n";
&dbg( "$slice / ufs ro 1 1");
close OUT;
}
sub check_gx {
my $rc;
open IN, "./lm -h -U 2>&1 |" or &cark("$!\n");
while (<IN>) {
if (/^(e[346]50)gx-?/) {
$rc = 1;
}
else {
$rc = 0;
}
}
close IN;
return $rc;
}
sub munge_rc_conf {
local *IN;
local *OT;
my %conf = ();
my @lval = ();
#
# Determine {DISK} and {NET0} and {NET1} from existing rc.conf
#
my $net0 = "fxp0";
my $net1 = "fxp1";
my $vlan1 = "";
my $agr0 = "";
my $agrport0 = "";
my $agrport1 = "";
my $nix = 0;
my $dump = '';
my $vlanif1 = 0;
#
# As part of NTP modification we will need two more extra
# variable which are not part of earlier rc.conf into new
#
my $ntpd = "xntpd_enable";
my $ntpf = "xntpd_flags";
my $routes = "static_routes";
open IN, "< /etc/rc.conf" or &cark("$!\n");
while (<IN>) {
if (/^EQ_IF_0=(.*)$/) {
$net0 = $1;
$net0 =~ s/^(["''"])(.*)\1/$2/;
&dbg("net0 = $net0");
$nix |= 1;
} elsif (/^EQ_IF_1=(.*)$/) {
$net1 = $1;
$net1 =~ s/^(["''"])(.*)\1/$2/;
&dbg("net1 = $net1");
$nix |= 2;
} elsif (/^EQ_VLIF_0=(.*)$/) {
$vlan1 = $1;
$vlan1 =~ s/^(["''"])(.*)\1/$2/;
&dbg("vlan1 = $vlan1");
$nix |= 2;
} elsif (/^EQ_AGRIF_0=(.*)$/) {
$agr0 = $1;
$agr0 =~ s/^(["''"])(.*)\1/$2/;
&dbg("agr0 = $agr0");
$nix |= 2;
} elsif (/^EQ_AGRPORT_0=(.*)$/) {
$agrport0 = $1;
$agrport0 =~ s/^(["''"])(.*)\1/$2/;
&dbg("agrport0 = $agrport0");
$nix |= 2;
} elsif (/^EQ_AGRPORT_1=(.*)$/) {
$agrport1 = $1;
$agrport1 =~ s/^(["''"])(.*)\1/$2/;
&dbg("agrport1 = $agrport1");
$nix |= 2;
} elsif (/-r ([^ ]*) .* [.] \1/) {
&dbg("source $1");
close IN;
open IN, "<$1";
}
}
close IN;
my $rc = check_gx();
if (($rc == 1) && ($agr0 eq '')) {
$vlan1 = "vlan1";
$agr0 = "agr0";
$agrport0 = "em0";
$agrport1 = "em1";
}
if ($nix != 3) {
#
# not the newer format. Look for old style.
#
$nix = 0;
open IN, "</etc/rc.conf" or &cark("$!\n");
while (<IN>) {
if (/^ifconfig_lo0=/) {
;
} elsif (/^ifconfig_([^_=0-9]*0)=(.*)$/) {
$net0 = $1;
&dbg("net0 = $net0");
$nix |= 1;
} elsif (/^ifconfig_([^_=0-9]*1)=(.*)$/) {
$net1 = $1;
&dbg("net1 = $net1");
$nix |= 2;
} elsif (/^dumpdev=(.*)$/) {
if ($1 eq '"/dev/da0s4b"') {
$dump = $1;
}
}
}
close IN;
}
&cark("Cannot determine {NET0} and {NET1}\n") unless $nix == 3;
#
# Expand the template out
#
open IN, "< ./etc.rc.conf.tmpl" || &cark("$!");
open OT, "> /mnt/etc/rc.conf" || &cark("$!");
while (<IN>) {
next if /^{DUMPDEV}/;
if ($dump eq '' && (/^dumpdev/ || /^savecore_flags/)) {
next;
}
s/{DISK}/$disk/g;
s/{NET0}/$net0/g;
s/{NET1}/$net1/g;
s/{VLAN1}/$vlan1/g;
s/{AGR0}/$agr0/g;
s/{AGRPORT0}/$agrport0/g;
s/{AGRPORT1}/$agrport1/g;
if (/^(\S+)=(.*)/) {
push @lval, $1;
}
print OT;
}
close OT;
close IN;
#
# Everything below this point preserves existing pieces of the
# configuration, which we don't want sometimes.
#
if ($no_preserve == 0) {
#
# Push NTPD variable into lval
#
push @lval, $ntpd;
push @lval, $ntpf;
push @lval, $routes;
#
# Now that that has been accomplished, we need to determine what
# modifications to the old need to be migrated to the new.
#
open IN, "< /etc/rc.conf" or &cark("$!\n");
#
# Look for entries we wish to preserve and add them to %conf
#
while (<IN>) {
if (/-r ([^ ]*) .* [.] \1/) {
&dbg("source $1");
close IN;
open IN, "< $1";
} elsif (/^(\S+)=(.*)/) {
if (grep(/$1/, @lval)) {
next if $1 =~ "network_interfaces";
#
# It is in the new conf (@lval) so we
# snarf a copy.
#
$conf{$1} = $2;
&dbg("conf[$1] = $2");
} elsif (/(ifconfig_[^=]+)=(.*)/) {
next if $1 =~ "ifconfig_lo0";
#
# Try to preserve non-conflicting ifconfigs.
# These might be aliases.
#
$conf{$1} = $2;
&dbg("conf[$1] = $conf{$1}");
if ($1 eq "ifconfig_vlan1") {
$vlanif1 = 1;
}
} elsif (/(route_[^=]+)=(.*)/) {
#
# Preserve static routes list
#
$conf{$1} = $2;
} else {
&dbg("old conf: $_");
}
}
}
close IN;
if ($vlanif1 == 0) {
$ifconfig1 = "ifconfig_" . $net0;
$ifconfig2 = "ifconfig_" . $vlan1;
&dbg("Adding $ifconfig2");
$conf{$ifconfig2} = $conf{$ifconfig1};
}
&dbg("lval");
&dbg_array(\@lval);
&dbg("conf");
&dbg_hash(\%conf);
#
# Add to %fnoc some potentially new entries
#
my %fnoc = ();
if ($slice_xtra) {
$fnoc{'dumpdev'} = '"/dev/' . "${disk}s${slice_xtra}" . 'e"';
sis "cd /mnt/.master/dev && ./MAKEDEV ${disk}s${slice_xtra}e";
}
#
# Run thru the new rc.conf, preserving those entries we wish to preserve.
#
my $new_conf = "/mnt/.master/var/etc/rc.conf-eq";
open IN, "< /mnt/etc/rc.conf" or &cark("$!\n");
open OT, "> ${new_conf}.new" or &cark("$!\n");
my $discard = 1;
my %seen = ();
line:
while (<IN>) {
my $hash = '#';
next line if ($discard and /^$hash/);
&dbg("_ = $_");
if (/-r ([^ ]*) .* [.] \1/) {
&dbg("source $1");
close IN;
open IN, "< /mnt/.master/$1" or &cark("$!\n");
$discard = 0;
next line;
}
foreach $k (keys %conf) {
if (/^($k)=(.*)/) {
&dbg("conf: $k '$2' :: '$conf{$k}'");
if ($2 ne $conf{$k}) {
note " ** updating rc.conf entry:\n\t$k=$conf{$k}";
print OT "$k=$conf{$k}\n";
}
delete $conf{$k};
next line;
}
}
foreach $k (keys %fnoc) {
if (/^($k)=(.*)/) {
if ($2 ne $fnoc{$k}) {
note " ** updating rc.conf entry:\n\t$k=$fnoc{$k}";
print OT "$k=$fnoc{$k}\n";
}
delete $fnoc{$k};
next line;
}
}
#
# Not overridden.
#
print OT $_;
}
&dbg("conf remains");
&dbg_hash(\%conf);
&dbg("fnoc remains");
&dbg_hash(\%fnoc);
#
# Anything remaining will be new entries which we append.
#
my $once = 0;
foreach $k (keys %conf) {
if (!$once++) {
note " ** preserving rc.conf entry:";
}
note "\t$k=$conf{$k}";
print OT "$k=$conf{$k}\n";
}
foreach $k (keys %fnoc) {
if (!$once++) {
note " ** preserving /etc/rc.conf entry:";
}
note "\t$k=$fnoc{$k}";
print OT "$k=$fnoc{$k}\n";
}
close OT;
close IN;
#
# Commit to the new one.
#
sis "cp ${new_conf}.new .";
sis "mv ${new_conf}.new ${new_conf}";
} #if no)preserve is 0
}
#
# support_hacks - hacks for support
#
sub support_hacks {
local *DIR;
my $dir = "/usr/local/etc/rc.d";
opendir DIR, $dir or return;
my @contents =
map "$dir/$_",
sort grep /_eq_support\.sh$/,
readdir DIR;
closedir DIR;
foreach (@contents) {
preserve $_;
chmod '0644', "/mnt/$_";
note "**** disabling execute on $_";
}
}
sub chg_snmpd {
local *PWE;
local *PWD;
my $OLD = "/var/eq/snmpd.cnf";
my $NEW = "/var/eq/snmpd.cnf.new";
my $need_change = 0;
if (!-f "$OLD") {
note "No snmpd.cnf\n";
return;
}
open PWD, "<$OLD";
# Checking if we need to rewrite the file
while (<PWD>) {
if (/^\s*sysObjectID/) {
my $new = $_;
my @all = split(" ", $new);
if ($all[1] eq "0.0") {
$need_change = 1;
}
}
}
close PWD;
if ($need_change != 1) {
return;
}
open PWE, ">$NEW";
open PWD, "<$OLD";
while (<PWD>) {
if (/^\s*sysObjectID/) {
my $correct_line = "sysObjectID 1.3.6.1.4.1.24427.2.2.2.1\n";
print PWE "$correct_line";
} else {
print PWE;
}
}
close PWD;
close PWE;
#saving old file in /var/eq/snmpd.cnf.OLD
rename "$OLD", "$OLD.OLD";
rename "$NEW", "$OLD";
}
sub munge_users {
local *PWD;
local *PWE;
my %users = ();
my $mve = "/mnt/.master/var/eq";
open PWD, "</var/eq/users";
while (<PWD>) {
if (/^\#/) {
} elsif (/^(touch|look):/) {
my $posterity = $_;
my ($user, $p) = split(/:/);
$users{$user} = $posterity;
}
}
close PWD;
open PWD, "<$mve/eq.conf";
open PWE, ">$mve/eq.conf.new";
while (<PWD>) {
print PWE;
}
close PWD;
foreach $user (keys %users) {
my ($_user, $_p) = split(/[:\n]/, $users{$user});
print PWE "\nuser $_user {\n";
print PWE " desc = \"user $_user\";\n";
print PWE " password = \"$_p\";\n";
if ($_user eq "touch") {
print PWE " change = \"all, global\";\n}\n";
} else {
print PWE " read = \"all, global\";\n}\n";
}
}
close PWE;
rename "$mve/eq.conf", "$mve/eq.conf.OLD";
rename "$mve/eq.conf.new", "$mve/eq.conf";
}
sub ask_migrate_failover {
if ($opt_G) {
print "\nDo you wish to preserve failover configuration? [y/n]\n";
}
while (1) {
my $ans;
if (!$opt_G) {
print "\nDo you wish to preserve failover configuration? [y/n]";
}
if ($opt_b) {
print "Y\n";
return 1;
}
$ans = &get_answer;
return 1 if ($ans =~ /^[Yy]/);
return 0 if ($ans =~ /^[Nn]/);
}
}
sub munge_master_passwd {
local *PWD;
local *PWE;
my %users = ();
my $mve = "/mnt/.master/var/etc";
open PWD, "</var/etc/master.passwd";
while (<PWD>) {
if (/^\#/) {
} elsif (/^(toor|daemon|operator|bin|games|news|man):/) {
} elsif (/^(uucp|xten|pop|nobody|l7up|cpsup):/) {
} else {
my $posterity = $_;
my ($user, $p, $u, $g, $x, $y, $z, $n, $d, $s) = split(/:/);
$users{$user} = $posterity;
}
}
close PWD;
open PWD, "<$mve/master.passwd";
open PWE, ">$mve/master.passwd.new";
while (<PWD>) {
my ($user, $p, $u, $g, $x, $y, $z, $n, $d, $s) = split(/:/);
if (/^\#/) {
print PWE;
} elsif (defined($users{$user})) {
my ($_user, $_p, $_u, $_g, $_x, $_y, $_z, $_d, $_s)
= split(/:/, $users{$user});
#
# user exists in new system -- migrate passwd.
#
print PWE "$user:$_p:$u:$g:$x:$y:$z:$n:$d:$s";
delete $users{$user};
} else {
print PWE;
}
}
close PWD;
foreach $user (keys %users) {
my ($_user, $p, $u, $g, $x, $y, $z, $n, $d, $s)
= split(/:/, $users{$user});
note "*=*=*=* NOT migrating user $user.";
}
close PWE;
rename "$mve/master.passwd" , "$mve/master.passwd.OLD";
sis "pwd_mkdb -p -d $mve $mve/master.passwd.new";
}
sub keep_loghosts {
my @oldfile;
my $line;
my $loghost = 0;
my $OSC;
my $NSC;
my @tmpsc = ();
my $already = 0;
open OSC, "< /etc/syslog.conf";
@oldfile = <OSC>;
open NSC, "< /mnt/.master/var/etc/syslog.conf";
foreach $line (@oldfile) {
chomp($line);
if ($line =~ /^\*\.\*.*@.*/) {
$loghost = $line;
last;
}
}
while ($line = <NSC>) {
chomp($line);
# match only the commented-out example!
if (!$already && ($line =~ /^#\*\.\*.*@/) && $loghost) {
push @tmpsc, $loghost;
$already = 1;
} else {
push @tmpsc, $line;
}
}
close OSC;
close NSC;
open NSC, "> /mnt/.master/var/etc/syslog.conf";
foreach $line (@tmpsc) {
print NSC "$line\n";
}
close NSC;
}
#
# phase3 -
#
sub phase3 {
#
# cleanup /var/crash and clear savecore flag.
#
system "rm -f /var/crash/*.core";
system "rm -f /var/crash/kernel.*";
system "rm -f /var/crash/vmcore.*";
system "/sbin/savecore -c 2>/dev/null";
&new_fstab;
# We have to be careful with rc_conf since
# it contains hardware-specific information that can't be
# fixed during an upgrade.
# We go and pull in the hardware-specific information in munge_rc_conf,
# and then
# skip the rest of the function if we're returning the system to defaults.
&munge_rc_conf;
if ($no_preserve == 0) {
&munge_master_passwd;
&keep_loghosts;
#
# Preserve the newer machine's SSH host key(s) if present.
# Old machines will get a new one automatically on first boot
# of new system.
#
my @ssh = (
'ssh_host_dsa_key',
'ssh_host_dsa_key.pub',
'ssh_host_key',
'ssh_host_key.pub',
'ssh_host_rsa_key',
'ssh_host_rsa_key.pub',);
foreach $f (@ssh) {
preserve "/etc/ssh/$f";
}
if ($opt_k) {
preserve "/usr/home/cpsup/.ssh/authorized_keys";
}
if ($opt_e) {
preserve "/usr/home/eqsupport/.ssh/authorized_keys";
}
if ($pres_eq_conf == 1) {
preserve "/etc/eq.conf";
if ($set_use_ssl == 1) {
system "/usr/l7up/convert_default -i/mnt/.master/var/eq/eq.conf -v ".
"use_ssl_only -d \!use_ssl_only -o /mnt/.master/var/eq/eq.conf";
}
my $running_vers = &curr_vers();
#
# The translate_85_86 program takes the contents of the running system's
# eq.conf, rc.conf-eq and switch.conf and creates a new eq.conf that is
# compatible with 8.6
#
print "migrating network configurations.\n";
sis "/usr/l7up/./translate_85_86 -i /mnt/.master/var/eq/eq.conf -p /mnt/.master/var/eq/eq.conf";
} else {
system "rm -rf /mnt/.master/var/eq/eq.conf";
system "touch /mnt/.master/var/eq/eq.conf";
print "eq.conf not preserved.\n";
}
if ($pres_en_conf == 1) {
preserve "/etc/envoy.conf";
} else {
system "rm -rf /mnt/.master/var/eq/envoy.conf";
system "touch /mnt/.master/var/eq/envoy.conf";
print "envoy.conf not preserved.\n";
}
if ($pres_sw_conf == 1) {
preserve "/etc/switch.conf";
} else {
system "rm -rf /mnt/.master/var/eq/switch.conf";
system "touch /mnt/.master/var/eq/switch.conf";
print "switch.conf not preserved.\n";
}
preserve "/etc/natd.conf";
preserve "/etc/resolv.conf";
preserve "/etc/ntp.conf";
#preserve "/etc/syslog.conf"; # Now we preserve only lines with @.
preserve "/etc/ntp.drift";
preserve "/etc/hosts";
preserve "/etc/ipfw.conf";
preserve "/etc/localtime";
preserve "/etc/eq.previous";
preserve "/eq.previous";
preserve "/etc/tac_client.conf";
#
# Need to preserve the cluster certificates.
#
if (-d "/var/eq/ssl") {
sis "find /var/eq/ssl -print | cpio -pdumL /mnt/.master/";
}
#
# Need to preserve the certificate and the key for equalizer if we
# have one else create it
#
if (-d "/var/eq/eqssl") {
sis "find /var/eq/eqssl -print | cpio -pdumL /mnt/.master/";
} else {
sis "mkdir -p /mnt/.master/var/eq/eqssl";
}
#
# Need to preserve the SKS
#
if (-d "/var/eq/sks") {
sis "find /var/eq/sks -print | cpio -pdumL /mnt/.master/";
}
#
# Need to preserve any licenses
#
d_preserve "/var/eq/licenses";
#
# Need to preserve any responders.
#
if (-d "/var/eq/responder") {
sis "find /var/eq/responder -print | cpio -pdumL /mnt/.master/";
}
}
#
# Preserve license files only while upgrade with default configuration.
#
if ($opt_C && $opt_l) {
d_preserve "/var/eq/licenses";
}
if ($opt_S) {
note " ** install SNMP ";
sis "tar zxf ./snmp.tgz -C /mnt 2>/usr/l7up/tar.out";
if ($no_preserve == 0) {
&chg_snmpd;
preserve "/var/eq/snmpd.cnf";
preserve "/var/eq/traps.cnf";
}
}
#
# Execute any additional version-specific upgrade script
#
sis "./upgrade.$vers.pl -p 2" if -x "./upgrade.$vers.pl";
#
# If desired, attempt to migrate failover config
# fo_migrate will leave the interface disable flag
# set, so we use perl to yank it out.
#
if ($no_preserve == 0) {
if((-f "/etc/eq.static") && (-f "/etc/eq.conf")) {
if (ask_migrate_failover()) {
sis "./fo_migrate -i/etc/eq.static"
. " -o/mnt/.master/var/eq/eq.conf -c/etc/eq.conf";
sis "perl -pi -e 's/^.*if_flag.*//' /mnt/.master/var/eq/eq.conf";
}
}
#
# If desired, attempt to migrate user config
#
if((-f "/var/eq/users")) {
&munge_users;
}
}
#
# Last step here is to check for any EQ support hacks and
# copy them and disable the execue bits on them
#
&support_hacks();
#
# save copies of debug and log to new filesystem.
#
if (-f $logfile && -f $dbgfile && -d "/mnt/usr/home/cpsup") {
select((select(DBG), $| = 1)[0]);
sis "cp $logfile $dbgfile /mnt/usr/home/cpsup";
sis "cd /mnt/usr/home/cpsup && tar zcvf upginfo.tgz upgrade.???";
sis "cd /mnt/usr/home/cpsup && rm upgrade.???";
}
sis "sync";
sis "sync";
sis "sync";
sis "sync";
sis "sync";
}
#
# slice_new - perform the DOS type disk partitioning
#
sub slice_new {
local *FH;
&cark("Partition $slice_new is in use.\n")
unless !defined($fdisk{$slice_new});
#
# create new slice
#
note "**** Create $size sized FreeBSD partition.";
&dbg("slice_new slice=$slice_new size=$size");
&dbg("fdisk -f -");
open FH, "|fdisk -f -";
if ($slice_new == 1) {
$size -= 63;
print FH "p 1 165 63 $size\n";
} else {
my $prev = $slice_new - 1;
my $start;
if ($slice_xtra) {
#
# Adjust this so that it nestles up against slice 4.
#
$start = $fdisk{4}->{'start'} - $size;
} else {
$start = $fdisk{'cyl'} * $fdisk{'hd'} * $fdisk{'sec'} - $size;
}
#
# Except that it needs to be bootable with all the
# crufty BIOSes out there.
#
my $spc = $fdisk{'hd'} * $fdisk{'sec'}; # sectors per cylinder
my $low = $fdisk{$prev}->{'start'} + $fdisk{$prev}->{'size'};
$low = $spc * (int(($low - 1) / $spc) + 1); # round up
while ($start > $low && int($start / $spc) > 1023) {
#
# This is silly, but we are seeking back by cylinders
# until we get to a bootable one or we overlap the
# $prev.
#
$start -= $spc;
}
if ($start / $spc >= 1024) {
&cark("******** MAY NOT BE BOOTABLE");
}
&dbg( "p $slice_new 165 $start $size");
print FH "p $slice_new 165 $start $size\n";
}
close FH;
&sync_disk($disk);
#
# Verify that slice was created, and record the actual size
#
&fdisk_reset($disk);
note "Created FDISK partition $slice_new of size"
. " $fdisk{$slice_new}->{'size'}.";
#
# fdisk tends to make them smaller at times. The root size is now the
# entire size, so adjust.
#
$root_size = $fdisk{$slice_new}->{'size'};
note "Created FDISK partition $slice_new of size"
. " $fdisk{$slice_new}->{'size'}.";
}
sub disklabel {
local *FH;
local *OUT;
my %label = ();
my $resid = 0;
$label{'c:size'} = $fdisk{$slice_new}->{'size'};
my $bpc = $fdisk{'hd'} * $fdisk{'sec'};
unlink "/tmp/l7upd";
open OUT, ">/tmp/l7upd";
print OUT "type: ESDI\n";
print OUT "disk: ${disk}s$slice_new\n";
print OUT "label: l7upgrade\n";
print OUT "flags:\n";
print OUT "bytes/sector: 512\n";
print OUT "sectors/track: $fdisk{'sec'}\n";
print OUT "tracks/cylinder: $fdisk{'hd'}\n";
print OUT "sectors/cylinder: $bpc\n";
print OUT "cylinders: $fdisk{'hd'}\n";
print OUT "sectors/unit: $fdisk{$slice_new}->{'size'}\n";
print OUT "rpm: 3600\n";
print OUT "interleave: 1\n";
print OUT "trackskew: 0\n";
print OUT "cylinderskew: 0\n";
print OUT "headswitch: 0\n";
print OUT "track-to-track seek: 0\n";
print OUT "drivedata: 0 \n";
print OUT "3 partitions:\n";
#
# layout the space
#
$resid = $label{'c:size'};
$label{'a:size'} = $root_size;
$label{'a:offs'} = 0;
$resid -= $label{'a:size'};
$label{'b:size'} = $swap_size; # vestigeal
$label{'b:offs'} = $label{'a:size'} + $label{'a:offs'};
$resid -= $label{'b:size'};
&dbg("disklabel: %label");
&dbg_hash(\%label);
print OUT "a: $label{'a:size'} $label{'a:offs'} 4.2BSD 0 0 0\n";
print OUT "c: $label{'c:size'} 0 unused 0 0\n";
close OUT;
#
# Install this disklabel
#
note "**** installing new disk label on ${disk}s$slice_new";
sis "dd if=/dev/zero of=/dev/${disk}s$slice_new bs=1b count=1";
sis "disklabel -R -r ${disk}s$slice_new /tmp/l7upd";
#
# create filesystems
#
sis "cd /dev; ./MAKEDEV ${disk}s${slice_new}a";
foreach $mp (@mp) {
my $newfs_opts = "";
my $rdev = $slice_map{$mp};
$rdev =~ s:/dev/:/dev/r:;
# $newfs_opts = "-O " if $mp eq "/";
sis "rm -f /tmp/rstmode*";
sis "rm -f /tmp/rstdir*";
note "****";
note "**** create filesystem for $mp";
note "****";
sis "newfs $newfs_opts $rdev";
sis "mkdir -p /mnt/$mp";
sis "touch /mnt/$mp/failed";
}
}
sub restore {
note "****";
#
# it is much easier now.
#
system "fsck $slice_map{'/'}";
sis "mount -o async $slice_map{'/'} /mnt/";
&cark("failed to mount '/'\n") if -f "/mnt/failed";
note "**** extract bits for '/'";
vsis "gzcat $bits_map{'/'} | (cd /mnt/ && tar xvSpf -) 2>/usr/l7up/tar.out";
sis "sync; sync; sync or swim;";
#
# Ensure we have correct /dev entries.
#
sis "cd /mnt/dev; ./MAKEDEV ${disk}s${slice_new}a";
sis "cd /mnt/dev; ./MAKEDEV ${disk}s${slice_xtra}a" unless !$slice_xtra;
#
# Install boot blocks
#
note "**** install boot blocks";
if (-x "/usr/sbin/chroot") {
sis "chroot /mnt boot0cfg -B $disk";
sis "chroot /mnt disklabel -B ${disk}s$slice_new";
} else {
sis "boot0cfg -B $disk";
sis "disklabel -B ${disk}s$slice_new";
}
}
#
# md5_check - check md5 checksum
#
sub md5_check {
my $what = shift or &cark("");
my $desired = shift or &cark("");
my $sum;
chop($sum = `md5 $what`);
$sum =~ s/.* = //;
$sum eq $desired;
}
#
# md5_verify - verify md5 checksum
#
sub md5_verify {
my $what = shift or &cark("");
my $desired = shift or &cark("");
&cark("$what: md5 mismatch.\n") unless md5_check($what, $desired);
}
#
# bom_check - verify files match the BoM
#
sub bom_check {
my $bom = shift;
local *BOM;
open BOM, "<$bom" or &cark("$!: $bom\n");
while (<BOM>) {
chop;
if (/^\# EQVERS=([^:]+)/) {
my $v = $1;
&cark("Version mismatch: $vers != $v\n") unless $v eq $vers;
next;
}
if (/^md5 /) {
my ($ign, $md5, $uid, $gid, $mode, $path) = split;
# note "verifying file $path";
&cark("missing $path\n") unless -f $path;
md5_verify($path, $md5);
} elsif (/^exe (.*)$/) {
my $todo = $1;
} else {
warn "unexpected BoM entry: $_\n";
}
}
close BOM;
}
sub badger {
print "System reboot is required.";
if ($opt_G) {
print "\nReboot now? [y/n]\n";
}
while (1) {
my $ans;
if (!$opt_G) {
print "\nReboot now? [y/n]";
}
if ($opt_b) {
print "YES\n";
return 1;
}
$ans = &get_answer;
return if ($ans =~ /^[Yy]/);
if ($ans =~ /^[Nn]/) {
printf "Aborting reboot.\n";
exit(0);
}
}
}
#
# Check the version level to see if we have the version of switchd
# (8.5.0g or later) that supports quiesce
#
sub switchd_verscheck {
my $vers;
my $rc;
if (-f "/.version/eq") {
open IN, "< /.version/eq" or die;
while (<IN>) {
chop;
if (/^EQVERS=(\d.*)$/) {
$vers = $1;
}
}
} else {
$vers = "0";
}
if ($vers lt "8.5.0g") {
$rc = 1;
}
else {
$rc = 0;
}
close IN;
return $rc;
}
#
# switch_firmware
#
sub switch_firmware {
my $reboot = 0;
my $ans=0;
if ($opt_F) {
sleep 1;
print "WARNING: THIS MAY TAKE UP TO 5 MINUTES. YOU\n";
print "MUST NOT POWER CYCLE THE SYSTEM DURING THIS\n";
print "TIME, OR INTERRUPT THIS PROCESS IN ANY\n";
print "OTHER WAY!\n";
print "[If you are using the GUI, click 'Show Details'\n";
print "to follow the progress of the upgrade.]\n";
print "\n";
print "Do you acknowledge this warning? [y/y]\n";
$ans = &get_answer;
system "/usr/local/sbin/switchd -Q";
sleep 5;
select(STDOUT); $| = 1;
system("/usr/l7up/swconfig -S -N -X 'fw guiflash ./cp301.bin '");
if (($? == 0)) {
$reboot = 1;
}
else {
print "Firmware remains at previous version.\n";
print "Software upgrade will continue.\n";
$reboot = 0;
}
}
return $reboot;
}
#
# cert_check - checking for sibd & GUI certificate file.
#
sub cert_check {
if ($opt_G) {
system "/bin/sh /usr/l7up/regen_sslkeys -G /var/tmp/eq_upgrade.in";
} else {
system "/bin/sh /usr/l7up/regen_sslkeys";
}
if (($?)) {
print "********************************************************\n";
¬e("**Certificate check failed\n");
¬e("**** Please contact Coyote Point customer support.");
die ("Aborting upgrade");
}
}
#
# If this is a system running version < 8.6, check for
# network misconfiguration. See bug #3275
# Subroutine returns zero if everything is cool and
# no corrective action is required. Returns 1 if we need
# to do a "-C" upgrade
#
sub check_for_invalid_net_config {
my $trouble = 0;
#
# Find the value of EQ_IF_0 & EQ_IF_1 in /etc/rc.conf
#
open IN, "< /etc/rc.conf" or &cark("$!\n");
while (<IN>) {
if (/^EQ_IF_0=(.*)$/) {
$net0 = $1;
$net0 =~ s/^(["''"])(.*)\1/$2/;
&dbg("net0 = $net0");
} elsif (/^EQ_IF_1=(.*)$/) {
$net1 = $1;
$net1 =~ s/^(["''"])(.*)\1/$2/;
&dbg("net1 = $net1");
}
}
#
# Check to see if ifconfig_$net0 is populated
# but ifconfig_$net1 is blank
#
open IN, "< /var/etc/rc.conf-eq" or &cark("$!\n");
$ifcfg0 = " ";
$ifcfg1 = " ";
while (<IN>) {
if (/^ifconfig_$net0=(.*)$/) {
$ifcfg0 = $1;
$ifcfg0 =~ s/^(["''"])(.*)\1/$2/;
&dbg("ifcfg0 = $ifcfg0");
} elsif (/^ifconfig_$net1=(.*)$/) {
$ifcfg1 = $1;
$ifcfg1 =~ s/^(["''"])(.*)\1/$2/;
&dbg("ifcfg1 = $ifcfg1");
}
}
#
# It is possible to see ifconfig_xx0='' or ifconfig_xx0='inet netmask '
# we only want ifconfig_xx0='inet ###.###.###.### netmask ###.###.###.###'
#
if ($ifcfg0 =~ m/^\s*inet\s*[\d\.]+\s*netmask\s*[\d\.]/) {
&dbg("ifcfg0 was true\n");
} else {
$ifcfg0 = 0;
}
if ($ifcfg1 =~ m/^\s*inet\s*[\d\.]+\s*netmask\s*[\d\.]/) {
&dbg("ifcfg1 was true\n");
} else {
$ifcfg1 = 0;
}
my $running_vers = &curr_vers();
if (($running_vers lt "8.6.0") && ($ifcfg0 && !$ifcfg1)) {
$trouble = 1;
print "\n\n";
print "*****************************************************************************\n";
print "* You are upgrading this system to Version 8.6.\n";
print "* The upgrade process has determined that you have an IP address configured\n";
print "* on the Equalizer external interface, but none on the internal interface.\n";
if ($opt_G) {
print "* This is not a supported configuration. You will need to correct\n";
print "* the network misconfiguration and retry the upgrade.\n";
print "*****************************************************************************\n";
die ("Upgrade terminated\n");
}
print "* This is not a supported configuration. You may either exit the upgrade and\n";
print "* correct the network misconfiguration, or you may delete the entire existing\n";
print "* configuration.\n";
print "*****************************************************************************\n\n";
$valid_ans = 0;
while ($valid_ans == 0) {
print "Do you wish to abort(a) the upgrade or\n";
print "delete(d) the existing configuration? [a/d]: ";
my $ans;
$ans = &get_answer;
if ($ans =~ /^[Aa]/) {
die ("Upgrade terminated");
} elsif ($ans =~ /^[Dd]/) {
print "Continuing upgrade.\n";
$valid_ans++;
} else {
print "ERROR: You did not enter a valid response.\n\n";
}
}
}
return $trouble;
}
#
# main
#
sub main {
my $reboot = 0;
&Getopts('RbkeSCrGFl');
if ($opt_C) {
my $rusure;
print "**************************************************************\n";
print "WARNING: You have specified for the upgrade script\n";
print "to clear the system configuration and revert to defaults\n";
print "Are you absolutely SURE that you would like to continue? [y/n]\n";
$rusure = &get_answer;
if ($rusure =~ /^[Nn]/) {
die("Aborting upgrade.");
} else {
print "****************************************************************\n";
print "WARNING: Please re-confirm: your Equalizer will not be\n";
print "accessible except by serial, and any configuration will be lost.\n";
print "Are you sure you want to continue? [y/n]\n";
if ($opt_G) {
print "\n";
}
$rusure = &get_answer;
if ($rusure =~ /^[Yy]/) {
$no_preserve = $opt_C;
} else {
die("You did not type \"y\". Aborting upgrade.");
}
}
}
#
# Save STDOUT and STDERR before we "tee" up so we can restore
# console output for the switch firmware update
#
open(OLDOUT, ">&STDOUT");
open(OLDERR, ">&STDERR");
#
# This is just so we don't get any annoying "used only once"
# messages...
#
stat OLDOUT;
stat OLDERR;
&previous;
&setup;
&verscheck;
&bom_check("./BoM");
&lm_check(0);
# sibd & gui Certificate checks
&cert_check;
# See comments at head if called function
# no need to perform this check if -C was specified
if ($no_preserve || &check_for_invalid_net_config) {
$no_preserve = 1;
}
#
# Check whether the OLD configuration can be parsed with the
# NEW parser.
#
if ($no_preserve == 0) {
if((-f "/.master/var/eq/eq.conf")) {
my $running_vers = &curr_vers();
if ($running_vers lt "8.6.0") {
#
# convert use_ssl_only flag for failover
#
print "\n\nYou are upgrading this system to Version 8.6. If you will be using this\n";
print "system in a failover configuration with an Equalizer that is running\n";
print "Version 8.5, then you must disable the \"use ssl only\" flag on the 8.6\n";
print "system.\n";
print "Would you like the upgrade script to disable this option for you now? [y/n]\n";
my $ans;
$ans = &get_answer;
if ($ans =~ /^[Yy]/) {
$set_use_ssl = 1;
}
}
print "\n\nConverting default for once_only...\n";
system "/usr/l7up/convert_default -i/.master/var/eq/eq.conf -v ".
"once_only -d once_only -o /.master/var/eq/eq.conf";
if (($? == 0)) {
print "\nConversion done.\n";
}
print "\n\nChecking configuration with new version's parser...\n";
system "/usr/l7up/parse_config -i/.master/var/eq/eq.conf -U";
if (($? == 512)) {
$cfgcount = 0;
while ($cfgcount == 0) {
print "Do you wish to continue(c) or abort(a) the upgrade? [c/a]:";
my $ans;
$ans = &get_answer;
if ($ans =~ /^[Aa]/) {
die ("Aborting upgrade");
} elsif ($ans =~ /^[Cc]/) {
print "Continue upgrade.\n";
$cfgcount++;
} else {
print "ERROR: You did not enter a valid response. Please try again. \n";
}
}
}
elsif (($?)) {
print "***********************************************************************\n";
print "Configuration parse FAILED\n\n";
print "You have the following options:\n".
" (k)eep the current configuration file\n".
" - Continue the upgrade using the current configuration file.\n".
" - Edit the file after the system boots to fix the above errors.\n".
" (d)elete the current configuration\n".
" - Delete all clusters, servers, VLANs, user logins, etc.\n".
" - After reboot, you must log in using the serial console and\n".
" - use the eqadmin utility to configure the network and logins.\n".
" (a)bort the upgrade\n".
" - Exit to the command line now to edit the configuration file\n".
" and restart the upgrade.\n\n".
"If you need assistance editing your configuration file, please note the\n".
"errors above and contact support\@coyotepoint.com.\n";
print "***********************************************************************\n";
$cfgcount = 0;
while ($cfgcount == 0) {
print "\nDo you wish to keep(k) or delete(d) your configuration, or abort(a)\n".
"the upgrade? [k/d/a]\n";
if ($opt_G) {
print "\n";
}
my $ans;
if ($opt_b) {
print "k\n";
return 1;
}
$ans = &get_answer;
if ($ans =~ /^[Dd]/) {
print "Are you sure you would like to delete the configuration file? [y/n] \n";
if ($opt_G) {
print "\n";
}
$ans = &get_answer;
if ($ans =~ /^[Yy]/) {
$pres_eq_conf = 0;
$cfgcount++;
} else {
print "ERROR: You did not Enter \"y\". Try again.\n";
}
} elsif ($ans =~ /^[Kk]/) {
print "Keeping configuration.\n";
$cfgcount++;
} elsif ($ans =~ /^[Aa]/) {
die ("Aborting upgrade");
} else {
print "ERROR: You did not enter a valid response. Please try again. \n";
}
}
} else {
print " SUCCESS\n\n";
}
} else {
print "Configuration file not found -- not checking configuration.\n";
}
if((-f "/.master/var/eq/envoy.conf")) {
print "\n\nChecking envoy configuration with new version's parser...\n";
system "/usr/l7up/envoy_parse_config -i /.master/var/eq/envoy.conf";
if (($?)) {
print "***********************************************************************\n";
print "Envoy configuration parse FAILED\n\n";
print "You have the following options:\n".
" (k)eep the current configuration file\n".
" - Continue the upgrade using the current configuration file.\n".
" - Edit the file after the system boots to fix the above errors.\n".
" (d)elete the current Envoy configuration\n".
" - All geo clusters, sites, and Envoy parameters are deleted.\n".
" - The cluster, server and networking configuration is unchanged.\n".
" (a)bort the upgrade\n".
" - Exit to the command line now to edit the configuration file\n".
" and restart the upgrade.\n\n".
"If you need assistance editing your configuration file, please note the\n".
"errors above and contact support\@coyotepoint.com\n";
print "***********************************************************************\n";
$cfgcount = 0;
while ($cfgcount == 0) {
print "\nDo you wish to keep(k) or delete(d) your Envoy configuration, or\n".
"abort(a) the upgrade? [k/d/a]\n";
if ($opt_G) {
print "\n";
}
my $ans;
if ($opt_b) {
print "k\n";
return 1;
}
$ans = &get_answer;
if ($ans =~ /^[Dd]/) {
print "Are you sure you would like to delete the configuration file? [y/n] \n";
if ($opt_G) {
print "\n";
}
$ans = &get_answer;
if ($ans =~ /^[Yy]/) {
$pres_en_conf = 0;
$cfgcount++;
} else {
print "ERROR: You did not Enter \"y\". Try again.\n";
}
} elsif ($ans =~ /^[Kk]/) {
print "Keeping configuration.\n";
$cfgcount++;
} elsif ($ans =~ /^[Aa]/) {
die ("Aborting upgrade");
} else {
print "ERROR: You did not enter a valid response. Please try again. \n";
}
}
} else {
print " SUCCESS\n\n";
}
} else {
print "Envoy configuration file not found -- not checking configuration.\n";
}
#
# In Version 8.6 and above, we no longer use switch.conf.
# And, in that case, there is no reason to parse_config it
#
}
#
# Ruthlessly delete non-active slices.
#
foreach $s (1..3) {
next unless ($s != $slice_old);
next unless defined($fdisk{$s});
&reclaim_space($disk, $s);
}
my $spc = $fdisk{'hd'} * $fdisk{'sec'}; # sectors per cylinder
my $i = 0;
my ($r, $v, $u) = ($root_size, $var_size, $usr_size);
$slice_new = 0;
while (!$slice_new) {
#
# Try hard to fit in. Various buggy prior upgrades
# left strange partitions which are slightly "too small".
# Try reducing our demands.
#
$root_size = $spc * int($r / $spc) - $i * $spc;
$var_size = 0;
$usr_size = 0;
$swap_size = 0;
$tmp_size = 0;
$size = ($root_size + $swap_size + $var_size
+ $tmp_size + $usr_size);
if ($root_size < (3 * $r) / 4) {
&cark("Insufficient space.\n");
}
note "**** trying root $root_size";
$slice_new = next_slice($size);
++$i; # sic.
}
%slice_map = (
'/' => "/dev/${disk}s$slice_new" . "a",
);
#
# Ensure that there are /dev entries
#
sis "cd /dev; ./MAKEDEV ${disk}s$slice_new";
sis "cd /dev; ./MAKEDEV ${disk}s$slice_new" . "c";
# creating ntp.drift file
sis "touch /var/etc/ntp.drift";
&slice_new;
&disklabel;
&restore;
&phase3;
# if this is a kontron box, create a kernel configuration file
# disabling syscons
chop($systype = `./lm -h -U`);
if ($systype =~ /^classic-1U/) {
note "disabling syscons device";
open FH, "| cat > /mnt/boot/kernel.conf" or die;
print FH "disable sc0\n";
print FH "quit\n";
close FH;
}
# Fix up timezone stuff.
&zoneupdate;
# Fix up boot time tunables
system "/bin/sh /usr/l7up/tune.sh /mnt";
&undo_mounts;
note "";
#
# Assuming this all worked, arrange to boot to new partition
#
sis "boot0cfg -o packet -s$slice_new $disk";
&dbg_save;
if (!$opt_G) {
#
# Restore output to console because we want to see the progress
# of the switch firmware update
#
close(STDERR);
close(STDOUT);
open(STDOUT, ">&OLDOUT");
open(STDERR, ">&OLDERR");
select(STDOUT); $| = 1;
select(STDERR); $| = 1;
}
#
# Check switch firmware level and update if necessary
#
if ($opt_F) {
$reboot = &switch_firmware;
}
if (($opt_r) or ($reboot)) {
print "Performing automatic reboot.\n";
print "System will reboot with new version.\n";
sleep 1;
} else {
&badger;
}
#
# Now redo what we undid
#
if ($opt_G) {
open(STDOUT, '>>'.$outputfile ) or die $!;
open(STDERR, '>>'.$outputfile ) or die $!;
}
else {
open(STDOUT, "| tee -a $logfile") or &cark("$!\n");
open(STDERR, ">&STDOUT") or &cark("$!\n");
}
select(STDOUT); $| = 1;
select(STDERR); $| = 1;
sis "shutdown -r now";
1;
if ($opt_G) {
close STDOUT;
}
}
#
# kluges for migration from 7.1.0 f/s layout to 7.2.0 f/s layout.
#
sub kluges {
sis "mkdir -p /.master/var/eq/licenses";
sis "touch /.master/.LOCK";
}
&main;