#!/usr/bin/perl
#
# $Revision: 1.18 $
# Copyright 2013-2014 Teleflora
#
# tfmkpserver.pl
#
# Script to make a backup server into a production server.
#

use strict;
use warnings;
use POSIX;
use Getopt::Long;
use English qw( -no_match_vars );
use Net::SMTP;
use File::Basename;
use File::Temp qw(tempfile);
use File::stat;
use Sys::Hostname;

use lib '/usr/local/ostools/modules';
use OSTools::Platform;
use OSTools::Hardware;
use OSTools::AppEnv;

our $VERSION = 1.1;
my $CVS_REVISION = '$Revision: 1.18 $';
my $TIMESTAMP = strftime("%Y%m%d%H%M%S", localtime());
my $PROGNAME = basename($PROGRAM_NAME);


#######################################
#########   D E F A U L T S   #########
#######################################

my $PROJ_NAME_DEF       = "tfrsync";

my $RTI_TOPDIR          = "/usr2";
my $RTIDIR              = $RTI_TOPDIR . "/bbx";
my $RTI_BINDIR          = $RTIDIR . '/' . "bin";
my $RTI_CONFIG_DIR      = $RTIDIR . '/' . "config";
my $RTI_TFRSYNC_DIR     = $RTI_TOPDIR . '/' . $PROJ_NAME_DEF;
my $RTI_RSYNC_BU_DIR    = $RTI_TOPDIR . '/' . $PROJ_NAME_DEF;
my $TOOLSDIR_RTI_DEF    = $RTI_TOPDIR . '/' . "ostools";

my $DAISY_TOPDIR        = "/d";
my $DAISYDIR            = $DAISY_TOPDIR . '/' . "daisy";
my $DAISY_BINDIR        = $DAISYDIR . '/' . "bin";
my $DAISY_TFRSYNC_DIR   = $DAISY_TOPDIR . '/' . $PROJ_NAME_DEF;
my $DAISY_RSYNC_BU_DIR  = $DAISY_TOPDIR . '/' . $PROJ_NAME_DEF;
my $TOOLSDIR_DAISY_DEF  = $DAISY_TOPDIR . '/' . "ostools";

my $PRIMARY_SERVER_IP_DEF       = "192.168.1.21";

my $RSYNC_ACCOUNT_DEF           = $PROJ_NAME_DEF;
my $RSYNC_ACCOUNT_NAME_DEF      = $PROJ_NAME_DEF;
my $RSYNC_ACCOUNT_FULL_NAME_DEF = $PROJ_NAME_DEF . " user";

my $TFSUPPORT_ACCOUNT_NAME_DEF  =  "tfsupport";

# name of directory used to hold info to be transferred
# between production server and backup server...
# located in home dir of the "tfsupport" account on the
# production server and the backup server.
my $PSERVER_XFER_DIR  = "pserver_xfer.d";

# name of the file to hold the pserver info
my $PSERVER_INFO_DIR = "pserver_info.d";
my $PSERVER_INFO_FILE = "pserver_info.txt";

# name of dir to hold cloistered files
my $PSERVER_CLOISTER_DIR     = "pserver_cloister.d";

# some components of TCC that must be present
my $TCC_RHEL5_TCC2 = $RTI_BINDIR . '/' . "tcc2_x64";
my $TCC_RHEL5_TCC  = $RTI_BINDIR . '/' . "tcc_x64";

my $TCC_RHEL6_TCC2 = $RTI_BINDIR . '/' . "tcc2_rhel6";
my $TCC_RHEL6_TCC  = $RTI_BINDIR . '/' . "tcc_rhel6";

# generic TCC paths
my $TCC_TCC        = $RTI_BINDIR . '/' . "tcc";
my $TCC_TCC_TWS    = $RTI_BINDIR . '/' . "tcc_tws";


############################################
#########   E X I T  S T A T U S   #########
############################################

my $EXIT_OK = 0;
my $EXIT_COMMAND_LINE = 1;
my $EXIT_MUST_BE_ROOT = 2;

my $EXIT_PREREQS = 10;
my $EXIT_UPDATE_CONFIG = 11;
my $EXIT_START_RTI = 12;
my $EXIT_TCC_CONFIG = 13;
my $EXIT_NETWORK_CONFIG = 14;
my $EXIT_RESTORING_SPECIAL_FILES = 15;
my $EXIT_RESTORING_USERS = 16;
my $EXIT_SAMBA_PW_BACKEND = 17;
my $EXIT_SAMBA_USERS = 18;
my $EXIT_RESTORING_SYSTEM_FILES = 19;

my $EXIT_TEST_USERS_PASSWD = 97;
my $EXIT_TEST_USERS_FILE = 98;
my $EXIT_TEST_USERS_RESTORE = 99;;


#####################################
#########   G L O B A L S   #########
#####################################

my $EMPTY_STR = q{};
my $SPACE_CHAR = q{ };

my $OS = $EMPTY_STR;
my $ALTROOT = ($ENV{'ALTROOT'}) ? "$ENV{'ALTROOT'}" : $EMPTY_STR;
my $ALTOS = ($ENV{'ALTOS'}) ? "$ENV{'ALTOS'}" : $EMPTY_STR;

my $RTI                    = 0;
my $DAISY                  = 0;

my $RSYNC_BU_DIR_RTI       = $RTI_TFRSYNC_DIR;
my $RSYNC_ACCOUNT          = $RSYNC_ACCOUNT_NAME_DEF;
my $TFSUPPORT_ACCOUNT      = $TFSUPPORT_ACCOUNT_NAME_DEF;
my $TOOLSDIR               = "";

my $RTI_DOVE_SERVER_NAME   = "doveserver.pl";

my $PSERVER_INFO_PLATFORM  = "platform";
my $PSERVER_INFO_HOSTNAME  = "hostname";
my $PSERVER_INFO_IPADDR    = "ipaddr";
my $PSERVER_INFO_NETMASK   = "netmask";
my $PSERVER_INFO_GATEWAY   = "gateway";

my $USERS_INFO_BU_DIR        = "users_info.d";
my $NETCONFIGS_BU_DIR        = "netconfigs.d";
my $USERCONFIGS_BU_DIR       = "userconfigs.d";
my $USERFILES_BU_DIR         = "userfiles.d";
my $SPECIALFILES_BU_DIR      = "specialfiles.d";

my $RTI_USERS_LISTING_FILE   = "rti_users_listing.txt";
my $RTI_USERS_SHADOW_FILE    = "rti_users_shadow.txt";
my $DAISY_USERS_LISTING_FILE = "daisy_users_listing.txt";
my $DAISY_USERS_SHADOW_FILE  = "daisy_users_shadow.txt";

my $USER_TYPE_ADMIN          = "admin user";
my $USER_TYPE_NONADMIN       = "non-admin user";

##############################################
#########   C O M M A N D  L I N E   #########
##############################################

#
# The command line must be recorded before the GetOptions modules
# is called or any options will be removed.
#
my $COMMAND_LINE = get_command_line();

# command line options
my $HELP = 0;
my $CVS_VERSION = 0;
my $VERBOSE = 0;
my $REPORT = 0;
my $LOGFILE_PATH = $EMPTY_STR;
my $DRY_RUN = 0;
my $TEST_CONF_FILE = $EMPTY_STR;
my $TEST_PW_FILE = $EMPTY_STR;
my $TEST_ADD_USERS = 0;
my $TEST_RESTORE_PASSWDS = 0;
my $TEST_SAMBA_GET_PASSWORD_BACKEND = 0;
my $TEST_SAMBA_SET_PASSWORD_BACKEND = 0;
my $TEST_SAMBA_GET_UIDS = 0;
my $TEST_SAMBA_SYNC_PASSWORD_UIDS = 0;
my $DEBUGMODE = 0;

GetOptions(
    "help" => \$HELP,
    "version" => \$CVS_VERSION,
    "verbose" => \$VERBOSE,
    "report" => \$REPORT,
    "logfile=s" => \$LOGFILE_PATH,
    "dry-run" => \$DRY_RUN,
    "test-conf-file=s" => \$TEST_CONF_FILE,
    "test-pw-file=s" => \$TEST_PW_FILE,
    "test-add-users" => \$TEST_ADD_USERS,
    "test-restore-passwds" => \$TEST_RESTORE_PASSWDS,
    "test-samba-get-passwd-backend" => \$TEST_SAMBA_GET_PASSWORD_BACKEND,
    "test-samba-set-passwd-backend" => \$TEST_SAMBA_SET_PASSWORD_BACKEND,
    "test-samba-get-uids" => \$TEST_SAMBA_GET_UIDS,
    "test-samba-sync-passwd-uids" => \$TEST_SAMBA_SYNC_PASSWORD_UIDS,
    "debugmode" => \$DEBUGMODE,
) || die "Error: invalid command line option, exiting...\n";


# --version
if ($CVS_VERSION) {
    print "OSTools Version: __OSTOOLS_VERSION__\n";
    print "$CVS_REVISION\n";
    exit($EXIT_OK);
}

# --help
if ($HELP) {
    usage();
    exit($EXIT_OK);
}

# which OS?
$OS = plat_os_version();

# which POS?
$RTI = (appenv_pos_name()) eq "RTI" ? 1 : 0;
$DAISY = (appenv_pos_name()) eq "Daisy" ? 1 : 0;

# which ostools?
$TOOLSDIR = (appenv_ostools_dir()) ? $TOOLSDIR_RTI_DEF : $TOOLSDIR_DAISY_DEF;

# make the default logfile name from the program name
#
# remove the extension from the name of the script and
# then append the new extension.
my $LOGFILE_NAME_DEF = $PROGNAME;
$LOGFILE_NAME_DEF =~ s{\.[^.]+$}{}; 
$LOGFILE_NAME_DEF = $LOGFILE_NAME_DEF . ".log";

# --logfile=path
#
# There are several possibilities:
#   1) the default location and name
#   2) path to the logfile was specified on the command line
#   3) if $RTIDIR/log does not exist use "/tmp" for location
#
#my $ISO8601 = strftime("%Y%m%d", localtime());
#my $LOGFILE_NAME = sprintf($LOGFILE_NAME_DEF, $ISO8601);
my $LOGFILE_NAME = $LOGFILE_NAME_DEF;
if ($LOGFILE_PATH) {
    if (is_input_insecure($LOGFILE_PATH)) {
	print "insecure value for \$LOGFILE: $LOGFILE_PATH\n";
	exit($EXIT_COMMAND_LINE);
    }
}
else {
    my $logfiledir = "/tmp";

    if (-d "$RTIDIR/log") {
	$logfiledir= "$RTIDIR/log";
    }
    if (-d "$DAISYDIR/log") {
	$logfiledir= "$DAISYDIR/log";
    }

    $LOGFILE_PATH = "$logfiledir/$LOGFILE_NAME";
}

# should never get here with $LOGFILE undefined, but...
if ($LOGFILE_PATH eq $EMPTY_STR) {
    $LOGFILE_PATH = "/tmp/$LOGFILE_NAME";
}
touch($LOGFILE_PATH);

####################################
######### TEST ROUTINES  ###########
####################################
if ($TEST_ADD_USERS) {
    exit(tfmp_test_restore_users($TEST_CONF_FILE));
}

if ($TEST_RESTORE_PASSWDS) {
    exit(tfmp_test_restore_passwords($TEST_CONF_FILE));
}

if ($TEST_SAMBA_GET_PASSWORD_BACKEND) {
    exit(tfmp_test_get_samba_passwd_backend($TEST_CONF_FILE));
}

if ($TEST_SAMBA_SET_PASSWORD_BACKEND) {
    exit(tfmp_test_set_samba_passwd_backend($TEST_CONF_FILE));
}

if ($TEST_SAMBA_GET_UIDS) {
    exit(tfmp_test_get_uids($TEST_CONF_FILE));
}

if ($TEST_SAMBA_SYNC_PASSWORD_UIDS) {
    exit(tfmp_test_samba_sync_password_uids($TEST_CONF_FILE, $TEST_PW_FILE));
}


#
# A journey of a 1000 instructions begins with a single clock cycle.
#
my $exit_status = main();


#
# Done - inform system what happened.
#
exit($exit_status);


###############################
#########   M A I N   #########
###############################

sub main
{
    loginfo("$PROGNAME $CVS_REVISION");

    my $rc = tf_make_pserver();
    if ($rc == $EXIT_OK) {
	loginfo("backup server converted to production server successfully");
    }
    else {
	logerror("conversion of backup server to production server failed: $rc");
    }

    return($rc);
}


########################################
#########   F U N C T I O N S  #########
########################################

sub usage
{
    print "$PROGNAME $CVS_REVISION\n";
    print "SYNOPSIS\n";
    print "$PROGNAME --help\n";
    print "$PROGNAME --version\n";
    print "$PROGNAME [options]\n";
    print "OPTIONS\n";
    print "$PROGNAME --verbose\n";          # include more output than normal
    print "$PROGNAME --report\n";           # report state of the backup server
    print "$PROGNAME --logfile=path\n";     # specify logfile path
    print "$PROGNAME --dry-run\n";          # reveal operation but don't execute it
    print "$PROGNAME --debugmode\n";        # run in debug mode

    return(1);
}


sub get_command_line
{
    my $cmd_line = $PROGRAM_NAME;

    foreach my $i (@ARGV) {
	$cmd_line .= $SPACE_CHAR;
	if ($i =~ /\s/x) {
	    if ($i =~ /(--[[:print:]]+)(=)(.+)$/x) {
		$cmd_line .= "$1$2\"$3\"";
	    }
	    else {
		$cmd_line .= "\"$i\"";
	    }
	}
	else {
	    $cmd_line .= "$i";
	}
    }

    return($cmd_line);
}


# PCI 6.5.6
#
# Look for a list of patterns in an input string that might
# indicate that some insecure value was passed into the script.
# Example, no input scring should have the BACKQUOTE chars as
# part of the string... if there were, it could mean that
# someone was trying to get the script to run another unknown
# script as "root".
#
# Returns
#   1 if input is insecure
#   0 if input is OK
#
sub is_input_insecure
{
    my ($cmd) = @_;

    return(1) if ($cmd eq $EMPTY_STR);

    my $rc = 0;

    my @insecure_patterns = (
	'\`',               # `bad command`
	'(\$\()(.*.)(\))',  # $(bad command)
	'\;',               # stuff ; bad command
	'\&',               # stuff && bad command
	'\|',               # stuff | bad command
	'\>',               # stuff > bad command
	'\<',               # stuff < bad command
	'[[:cntrl:]]',      # non printables
    );

    foreach my $re (@insecure_patterns) {
	if ($cmd =~ /$re/x) {
	    $rc = 1;
	    last;
	}
    }

    return($rc);
}


#
# Same as Linux shell command "touch".  Mostly taken from
# ExtUtils::Command but operates on input argument and
# does not call the die() function on error.
#
# Returns
#   1 on success
#   0 of failure
#
sub touch {
    my (@files) = @_;

    my $atime = time;
    my $mtime = $atime;
    my $rc = 0;

    foreach my $file (@files) {
        if (open(my $tfh, '>>', $file)) {
	    unless (close($tfh)) {
		warn "error: closing touched file: $file";
	    }
	    utime($atime, $mtime, $file);
	    $rc = 1;
	}
    }

    return($rc);
}


sub is_service_configured
{
    my ($service_name) = @_;

    my $rc = 0;

    my $cmd = "/sbin/chkconfig --list";
    if (open(my $pipe, '-|', $cmd)) {
	while (<$pipe>) {
	    if (/^${service_name}\s+/) {
		$rc = 1;
	    }
	}
	close($pipe);
    }
    else {
	logerror("error opening pipe to command: $cmd");
    }

    return($rc);
}


# Output to screen, and write info to logfile.
sub showinfo
{
    my ($message) = @_;

    chomp $message;
    print "$message\n";

    return(loginfo($message));
}


# Output to screen, and write error to logfile.
sub showerror
{
    my ($message) = @_;

    chomp $message ;
    print "error: $message\n" ;

    return(logerror($message));
}


sub loginfo
{
    my ($message) = @_;

    chomp $message;

    return(logit("<I>  $message"));
}


sub logerror
{
    my ($message) = @_;

    chomp $message;

    return(logit("<E>  error: $message"));
}


sub logit
{
    my ($message) = @_;

    my $logtime = strftime('%Y-%m-%d %H:%M:%S', localtime());

    chomp($message);
    if (open(my $logfh, '>>', $LOGFILE_PATH)) {
	print {$logfh} "$logtime ($PROGNAME-$PID) $message\n";
	unless (close($logfh)) {
	    warn "error: closing log file: $LOGFILE_PATH";
	}
    }
    else {
	print "$logtime ($PROGNAME-$PID) $message\n";
    }

    if ($VERBOSE) {
	print "$message\n";
    }

    return(1);
}


###################################
####### TFRSYNC MODULE SUBS #######
###################################

#
# search file for regular expression.
#
# Returns
#   0 found regular expression
#   1 did not find regular expression
#
sub tfrm_fgrep
{
    my ($file, $re) = @_;

    my $rc = 1;
    if (open(my $fp, '<', $file)) {
	while (<$fp>) {
	    chomp;
	    if (/$re/) {
		$rc = 0;
		last;
	    }
        }
	close($fp);
    }

    return($rc);
}


#
# Given an account name, return path to home directory.
#
# Returns
#   path to home dir if account exists
#   empty string if account does NOT exist
#
sub tfrm_accounts_homedir
{
    my ($account_name) = @_;

    my $homedir_path = (getpwnam($account_name))[7];
    if (!defined($homedir_path)) {
	$homedir_path = "";
    }

    return($homedir_path);
}


############################################
##                                        ##
## subsection: "pathto" and "nameof" subs ##
##                                        ##
############################################

sub tfrm_pathto_project_bu_dir
{
    return($RTI_RSYNC_BU_DIR) if ($RTI);
    return($DAISY_RSYNC_BU_DIR) if ($DAISY);
    return($EMPTY_STR);
}


sub tfrm_pathto_users_info_bu_dir
{
    my $bu_dir = tfrm_pathto_project_bu_dir();
    return($bu_dir . '/' . $USERS_INFO_BU_DIR) if ($bu_dir);
    return($EMPTY_STR);
}


#
# Given an account name, return the path to production server
# transfer dir.
#
# Returns
#   path to xfer dir on success
#   empty string on error
#
sub tfrm_pathto_pserver_xferdir
{
    my ($account_name) = @_;

    my $rc = $EMPTY_STR;

    my $homedir_path = tfrm_accounts_homedir($account_name);
    if ($homedir_path) {
	$rc = $homedir_path . '/' . $PSERVER_XFER_DIR;
    }

    return($rc);
}


sub tfrm_pathto_pserver_info_dir
{
    return(tfrm_pathto_project_bu_dir() . '/' . $PSERVER_INFO_DIR);
}


sub tfrm_pathto_pserver_info_file
{
    return(tfrm_pathto_pserver_info_dir() . '/' . $PSERVER_INFO_FILE);
}

sub tfrm_pathto_pserver_cloister_dir
{
    return(tfrm_pathto_project_bu_dir() . '/' . $PSERVER_CLOISTER_DIR);
}

sub tfrm_pathto_dove_server
{
    return($RTI_BINDIR . '/' . $RTI_DOVE_SERVER_NAME);
}

sub tfrm_pathto_saved_dove_server
{
    return(tfrm_pathto_pserver_cloister_dir() . tfrm_pathto_dove_server());
}

sub tfrm_pathto_users_listing_file
{
    return(tfrm_pathto_users_info_bu_dir() . '/' . $RTI_USERS_LISTING_FILE) if ($RTI);
    return(tfrm_pathto_users_info_bu_dir() . '/' . $DAISY_USERS_LISTING_FILE) if ($DAISY);
    return($EMPTY_STR);
}


sub tfrm_pathto_users_shadow_file
{
    return(tfrm_pathto_users_info_bu_dir() . '/' . $RTI_USERS_SHADOW_FILE) if ($RTI);
    return(tfrm_pathto_users_info_bu_dir() . '/' . $DAISY_USERS_SHADOW_FILE) if ($DAISY);
    return($EMPTY_STR);
}


sub tfrm_pathto_pos_users_script
{
    return("$RTI_BINDIR/rtiuser.pl") if ($RTI);
    return("$DAISY_BINDIR/dsyuser.pl") if ($DAISY);
    return($EMPTY_STR);
}


#
# search the Samba conf file for the statement:
#   smb passwd file = <path>
# and return <path>.
#
# Returns
#   non-empty <path> if successful
#   empty string if not
#
sub tfrm_pathto_samba_passwd_file
{
    my ($conf_file) = @_;

    my $samba_pw_file_path = $EMPTY_STR;

    if (open(my $cfh, '<', $conf_file)) {
	while (<$cfh>) {
	    if (/^\s*smb\s+passwd\s+file\s*=\s*(\S*)\s*$/) {
		$samba_pw_file_path = $1;
	    }
	}
	close($cfh);
    }

    return($samba_pw_file_path);
}


sub tfmp_pserver_read_info_file
{
    my ($pserver_info_ref) = @_;

    my $rc = 0;

    my $pserver_info_file_path = tfrm_pathto_pserver_info_file();
    if ($pserver_info_file_path) {
	if (open(my $fh, '<', $pserver_info_file_path)) {
	    while (<$fh>) {
		if (/^PLATFORM=(.+)$/) {
		    $pserver_info_ref->{$PSERVER_INFO_PLATFORM} = $1;
		}
		if (/^HOSTNAME=(.+)$/) {
		    $pserver_info_ref->{$PSERVER_INFO_HOSTNAME} = $1;
		}
		elsif (/^IPADDR=(.+)$/) {
		    $pserver_info_ref->{$PSERVER_INFO_IPADDR} = $1;
		}
		elsif (/^NETMASK=(.+)$/) {
		    $pserver_info_ref->{$PSERVER_INFO_NETMASK} = $1;
		}
		elsif (/^GATEWAY=(.+)$/) {
		    $pserver_info_ref->{$PSERVER_INFO_GATEWAY} = $1;
		}
	    }
	    close($fh);
	    $rc = 1;
	}
	else {
	    logerror("could not open pserver info file: $pserver_info_file_path");
	}
    }
    else {
	logerror("could not get path to pserver info file");
    }

    return($rc);
}


###################################
####### TOP LEVEL TEST SUBS #######
###################################

sub tfmp_test_restore_users
{
    my ($users_file) = @_;

    my $rc = $EXIT_OK;

    if ($users_file) {
	if (tfmp_restore_pos_users($users_file)) {
	    print "normal users added from: $users_file\n";
	}
	else {
	    print "error: could not restore POS users from: $users_file\n";
	    $rc = $EXIT_TEST_USERS_RESTORE;
	}
    }
    else {
	print "error: specify path to users file: --test-users-file=path\n";
	$rc = $EXIT_TEST_USERS_FILE;
    }

    return($rc);
}


sub tfmp_test_restore_passwords
{
    my ($shadow_file) = @_;

    my $rc = $EXIT_OK;

    if ($shadow_file) {
	if (tfmp_restore_passwords($shadow_file)) {
	    print "passwords for POS users restored from: $shadow_file\n";
	}
	else {
	    print "error: could not restore passwords for POS users in: $shadow_file\n";
	    $rc = $EXIT_TEST_USERS_RESTORE;
	}
    }
    else {
	print "error: could not get path to POS users shadow file\n";
	    $rc = $EXIT_TEST_USERS_FILE;
    }

    return($rc);
}


sub tfmp_test_get_samba_passwd_backend
{
    my ($conf_file) = @_;

    my $samba_passwd_backend = tfrm_get_samba_passwd_backend($conf_file);
    if ($samba_passwd_backend) {
	print "Samba passwd backend configured for: <$samba_passwd_backend>\n";
    }
    else {
	print "Samba passwd backend unconfigured\n";
    }

    return($EXIT_OK);
}


sub tfmp_test_set_samba_passwd_backend
{
    my ($conf_file) = @_;

    my $new_conf_file = $conf_file . '_' . "$$";
    if (tfmp_set_samba_passwd_backend($conf_file, $new_conf_file)) {
	print "Samba password backend config changed to: smbpasswd\n";
    }
    else {
	print "Samba password backend config unchanged\n";
    }

    return($EXIT_OK);
}


sub tfmp_test_get_uids
{
    my ($conf_file) = @_;

    my %uids = ();
    if (tfrm_get_uids($conf_file, \%uids)) {
	foreach my $key (keys(%uids)) {
	    print "account $key has uid: $uids{$key}\n";
	}
    }
    else {
	print "error: could not get system uids from: $conf_file\n";
    }
}


sub tfmp_test_samba_sync_password_uids
{
    my ($conf_file, $pw_file) = @_;

    my %uids = ();
    if (tfrm_get_uids($pw_file, \%uids)) {
	my $samba_pw_file = tfrm_pathto_samba_passwd_file($conf_file);
	if ($samba_pw_file) {
	    my $new_samba_pw_file = $samba_pw_file . '_' . "$$";
	    if (tfmp_samba_rebuild_passdb($samba_pw_file, $new_samba_pw_file, \%uids)) {
	    }
	    else {
		print "error: could not sync uids in samba passwd file: $samba_pw_file\n";
	    }
	}
	else {
	    print "error: could not get path to samba passwd file from: $conf_file\n";
	}
    }
    else {
	print "error: could not get system uids from: $pw_file\n";
    }

    return($EXIT_OK);
}


#
# read file of users, fill in supplied hash.
# keys of hash are user names, value of hash
# refects normal user or admin user.
#
# Returns
#   1 if successful
#   0 on error
#
sub tfrm_read_users_listing_file
{
    my ($users_file, $users_ref) = @_;

    my $rc = 1;

    my $admin_re = ($RTI) ? "RTI Admin" : "Daisy Admin";

    if (open(my $uf_fh, '<', $users_file)) {
	while (my $line = <$uf_fh>) {
	    if ($line =~ /^(\S+)\s.*$admin_re/) {
		$users_ref->{$1} = $USER_TYPE_ADMIN;
	    }
	    elsif ($line =~ /^(\S+)\s/) {
		$users_ref->{$1} = $USER_TYPE_NONADMIN;
	    }
	}
	close($uf_fh);

	unless (keys(%{$users_ref})) {
	    logerror("users file empty: $users_file");
	    $rc = 0;
	}

    }
    else {
	logerror("could not open users file: $users_file");
	$rc = 0;
    }

    return($rc);
}


#
# Read the "usersinfo.txt" file from a backup which
# consists of the lines from the shadow file for each
# user on the system at the time of the backup.
#
# This sub reads the user info file and
# returns a hash with the username as the key and
# the line as the value.
#
sub tfrm_read_users_shadow_file
{
    my ($shadow_file, $shadow_ref) = @_;

    my $rc = 1;

    my $line;

    if (open(my $ui_fh, '<', $shadow_file)) {
	while ($line = <$ui_fh>) {
	    my $i = index($line, ":");
	    my $username = substr($line, 0, $i);
	    $shadow_ref->{$username} = $line;
	}
	close($ui_fh);
    }
    else {
	logerror("could not open users shadow file: $shadow_file");
    }

    return($rc);
}


#
# replace an existing conf file with a new one.
#
# if the new conf file exists and is non-zero sized, call
# it good and replace the existing one with the new one.
#
# Returns
#   1 if successful
#   0 on error
#
sub tfrm_replace_conf_file
{
    my ($conf_file, $new_conf_file) = @_;

    my $rc = 1;

    if (-s $new_conf_file) {
	system("chmod --reference=$conf_file $new_conf_file");
	system("chown --reference=$conf_file $new_conf_file");
	system("cp $new_conf_file $conf_file");
    }
    else {
	unlink($new_conf_file) if (-e $new_conf_file);
	$rc = 0;
    }

    return($rc);
}


sub tfrm_get_uids
{
    my ($passwd_file, $system_uids) = @_;

    my $rc = 0;

    if (open(my $pdfh, '<', $passwd_file)) {
	while (<$pdfh>){
	    my ($name,$passwd,$uid,$gid,$gcos,$dir,$shell) = split(/:/);
	    $system_uids->{$name} = $uid;
	}
	close($pdfh);
	$rc = 1;
    }

    return($rc);
}


#
# parse Samba conf file looking for this statement:
#
#	passdb backend = <backend_type>
#
sub tfrm_get_samba_passwd_backend
{
    my ($conf_file) = @_;

    my $samba_passwd_backend = $EMPTY_STR;

    if (open(my $cfh, '<', $conf_file)) {
	while (<$cfh>) {
	    if (/^\s*passdb\s+backend\s*=\s*([[:alpha:]]+)/) {
		$samba_passwd_backend = $1;
	    }
	}
	close($cfh);
    }
    return($samba_passwd_backend);
}


#
# restore POS uses from users listing file.
#
sub tfmp_restore_pos_users
{
    my ($users_file) = @_;

    my $rc = 1;
    my %users = ();

    if (tfrm_read_users_listing_file($users_file, \%users)) {
	my $users_cmd = tfrm_pathto_pos_users_script();

	foreach my $key (keys(%users)) {
	    system("$users_cmd --add $key 2>> $LOGFILE_PATH");
	    if ($? == 0) {
		loginfo("POS user added: $key");
		if ($users{$key} eq $USER_TYPE_ADMIN) {
		    system("$users_cmd --enable-admin $key password 2>> $LOGFILE_PATH");
		    if ($? == 0) {
			loginfo("admin mode enabled for POS user: $key");
		    }
		    else {
			logerror("could not enable admin mode for: $key");
			$rc = 0;
			last;
		    }
		}
	    }
	    else {
		logerror("could not add POS user: $key");
		$rc = 0;
		last;
	    }
	}
    }
    else {
	logerror("could not read users listing file: $users_file");
	$rc = 0;
    }

    return($rc);
}


sub tfmp_restore_passwords
{
    my ($shadow_file) = @_;

    my $rc = 0;

    my %users_shadow = ();
    if (tfrm_read_users_shadow_file($shadow_file, \%users_shadow)) {

	my $conf_file = "/etc/shadow";
	my $new_conf_file = "$conf_file.$$";

	if (open(my $old_fh, '<', $conf_file)) {
	    if (open(my $new_fh, '>', $new_conf_file)) {
		while (my $line = <$old_fh>) {
		    my $i = index($line, ":");
		    my $username = substr($line, 0, $i);
		    if (defined($users_shadow{$username})) {
			print $new_fh "$users_shadow{$username}";
		    }
		    else {
			print $new_fh "$line";
		    }
		}
		close($new_fh);
	    }
	    else {
		logerror("could not open new shadow file: $new_conf_file");
	    }
	    close($old_fh);

	    if (-s $new_conf_file) {
		system("chmod --reference=$conf_file $new_conf_file");
		system("chown --reference=$conf_file $new_conf_file");
		system("mv $new_conf_file $conf_file");
		$rc = 1;
	    }
	    else {
		unlink $new_conf_file;
		logerror("could not update shadow file: $new_conf_file");
	    }
	}
	else {
	    logerror("could not open shadow file: $conf_file");
	}
    }

    return($rc);
}


#
# set the "passdb backend"  parameter to a value of "smbpasswd".
# in the "global" section.
#
# this must be done for RHEL6 systems to be backwards compatabile
# with the way the pre-RHEL6 systems were configured.
#
sub tfmp_set_samba_passwd_backend
{
    my ($conf_file, $new_conf_file) = @_;

    my $parameter = "passdb backend = smbpasswd";
    my $parameter2 = "smb passwd file = /etc/samba/smbpasswd";

    my $rc = 1;

    #
    # Copy all lines from old to new, but immediately after the
    # global section declaraion, write the new parameter(s) into
    # the new conf file.
    #
    if (open(my $old_fh, '<', $conf_file)) {
	if (open(my $new_fh, '>', $new_conf_file)) {
	    while (<$old_fh>) {
		if (/^\s*\[global\]/) {
		    print($new_fh $_);
		    print($new_fh "#Following lines added by $PROGNAME, $CVS_REVISION, $TIMESTAMP\n");
		    print($new_fh "$parameter\n");
		    print($new_fh "$parameter2\n");
		    next;
		}
		else {
		    print($new_fh $_);
		}
	    }
	    close($new_fh);

	}
	else {
	    showerror("could not open new Samba config file: $new_conf_file");
	    $rc = 0;
	}
	close($old_fh);
    }
    else {
	showerror("could not open existing Samba config file: $conf_file");
	$rc = 0;
    }

    return($rc);
}


#
# Make the UIDs in the "smbpasswd" file match those in /etc/passwd.
#
# Copy all lines from old to new, but adjust the UID field if necessary.
#
# The structure of an smbpasswd entry is:
#
# username:uid:lanman_hash:nt_hash:flags:pw_lct
#
# username    - the user's login name.
# uid         - the user's UID
# lanman_hash - Windows stuff
# nt_hash     - Windows stuff
# flags       - Various single-character flags representing the type and
#               state of the user's account.
# pw_lct      - the timestamp of the user's last successful password change
#
sub tfmp_samba_rebuild_passdb
{
    my ($conf_file, $new_conf_file, $system_uids) = @_;

    my $rc = 1;

    my $file_modified = 0;
    if (open(my $old_fh, '<', $conf_file)) {
	if (open(my $new_fh, '>', $new_conf_file)) {
	    while (<$old_fh>) {
		my $line = $_;
		if ($line =~ /^(\S+):(\d+):(.*)$/) {
		    my $samba_username = $1;
		    my $samba_uid = $2;
		    my $remainder = $3;

		    my $system_uid = $system_uids->{$samba_username};
		    if (defined($system_uid)) {
			if ($samba_uid ne $system_uid) {
			    $line = $samba_username . ':' . $system_uid . ':' . $remainder . "\n";
			    $file_modified = 1;
			}
		    }
		}
		print($new_fh $line);
	    }

	    close($old_fh);
	    close($new_fh);
	}
	else {
	    close($old_fh);
	    showerror("error opening new Samba config file: $new_conf_file");
	    $rc = 0;
	}
    }
    else {
	showerror("error opening existing Samba config file: $conf_file");
	$rc = 0;
    }

    return($rc);
}


sub tfmp_get_pserver_platform
{
    my %pserver_info = ();
    my $pserver_platform = $EMPTY_STR;

    if (tfmp_pserver_read_info_file(\%pserver_info)) {
	$pserver_platform = $pserver_info{$PSERVER_INFO_PLATFORM};
    }

    return($pserver_platform);
}


sub tfmp_copy_system_file
{
    my ($file) = @_;

    my $rc = 0;

    my $src_dir = tfrm_pathto_project_bu_dir();
    my $src_path = $src_dir . $file;
    if (-e $src_path) {
	if (-d $src_path) {
	    $rc = system("cp -pr $src_path/* $file");
	}
	else {
	    $rc = system("cp -p $src_path $file");
	}
	$rc = 1 if ($rc == 0);
    }
    else {
	logerror("could not restore system file since it does not exist: $src_path ");
    }

    return($rc);
}


sub tfmp_restore_select_system_files
{
    my $rc = 1;

    my @system_files = qw(
	/etc/samba/smb.conf
	/etc/samba/smbpasswd
	/etc/inittab
	/etc/hosts
	/etc/hosts.allow
	/etc/hosts.deny
	/etc/resolv.conf
	/etc/sysconfig/iptables
	/var/spool/cron
	/etc/cron.d
	/etc/mail
	/home
    );

    my $pserver_platform = tfmp_get_pserver_platform();
    if ($pserver_platform) {
	foreach my $file (@system_files) {
	    if (($file eq "/etc/inittab") && ($pserver_platform ne $OS)) {
		loginfo("file restore not required: $file");
		next;
	    }

	    if (tfmp_copy_system_file($file)) {
		loginfo("system file restored: $file");
	    }
	    else {
		logerror("could not restore file: $file");
		$rc = 0;
		last;
	    }
	}
    }
    else {
	logerror("could not determine production server platform");
	$rc = 0;
    }

    return($rc);
}



#############################################
#########   A P P L I C A T I O N   #########
#############################################

#
# Convert a backup server back into a production server
#
# 1) verify pre-requisites
# 2) restore special files
# 3) configure tcc
# 4) set the ip addr and hostname
# 5) chkconfig on: http, bbj, blm, rti
# 6) service start: http, bbj, blm, rti
#

sub tf_make_pserver
{
    if (tfmp_verify_prereqs()) {
	loginfo("pre-requisites verified");
    }
    else {
	showerror("could not verify pre-requisites");
	return($EXIT_PREREQS);
    }

    if (tfmp_restore_special_files()) {
	loginfo("special files restored");
    }
    else {
	showerror("could not restore special files");
	return($EXIT_RESTORING_SPECIAL_FILES);
    }

    if (tfmp_restore_system_files()) {
	loginfo("special backups restored");
    }
    else {
	showerror("could not restore special backups");
	return($EXIT_RESTORING_SYSTEM_FILES);
    }

    if (tfmp_configure_tcc()) {
	loginfo("tcc configured");
    }
    else {
	showerror("could not configure TCC");
	return($EXIT_TCC_CONFIG);
    }

    if (tfmp_configure_network()) {
	loginfo("network configured");
    }
    else {
	showerror("could not change network configuration");
	return($EXIT_NETWORK_CONFIG);
    }

    if (tfmp_restore_users_info()) {
	loginfo("POS users restored");
    }
    else {
	showerror("could not restore POS users");
	return($EXIT_RESTORING_USERS);
    }

    if (tfmp_change_samba_passwd_backend()) {
	if (tfmp_update_samba_passwd_file()) {
	    loginfo("Samba config updated");
	}
	else {
	    showerror("could not change Samba password file");
	    return($EXIT_SAMBA_USERS);
	}

    }
    else {
	showerror("could not change Samba password backend");
	return($EXIT_SAMBA_PW_BACKEND);
    }

    if (tfmp_start_rti()) {
	loginfo("RTI started");
    }
    else {
	showerror("could not start RTI");
	return($EXIT_START_RTI);
    }

    return($EXIT_OK);
}


#
# verify pre-requisites
#
# -> supported platform?
# -> does production server info file exist?
# -> does /usr2/ostools exist? /d/ostools?
# -> does /usr2/bbx exist? /d/daisy?
# -> does /etc/init.d/rti exist?
# -> does /etc/init.d/bbj exist?
# -> does /etc/init.d/blm exist?
# -> do TCC components exist?
#
# Returns
#   1 on success
#   0 if error
#
sub tfmp_verify_prereqs
{
    my $rc = 1;

    if ($OS ne "RHEL5" && $OS ne "RHEL6") {
	showerror("unsupported platform: $OS");
	return($rc);
    }

    my $pserver_info_file_path = tfrm_pathto_pserver_info_file();
    if (-s $pserver_info_file_path) {
	my %pserver_info = ();
	if (tfmp_pserver_read_info_file(\%pserver_info)) {
	    my @pserver_info_file_stmts = (
		$PSERVER_INFO_PLATFORM,
		$PSERVER_INFO_HOSTNAME,
		$PSERVER_INFO_IPADDR,
		$PSERVER_INFO_NETMASK,
		$PSERVER_INFO_GATEWAY,
	    );
	    foreach (@pserver_info_file_stmts) {
		unless (defined($pserver_info{$_})) {
		    showerror("missing pserver info file stmt: $_");
		    $rc = 0;
		    last;
		}
	    }
	}
	else {
	    showerror("reading pserver info file: $pserver_info_file_path");
	    $rc = 0;
	}
    }
    else {
	showerror("pserver info file empty: $pserver_info_file_path");
	$rc = 0;
    }

    unless (-e $TOOLSDIR) {
	showerror("ostools dir does not exist: $TOOLSDIR");
	$rc = 0;
    }

    if ($RTI) {
	if (-e $RTIDIR) {
	    my @required_files = (
		# platform       file path          type
		[ "any",         "/etc/init.d/rti", "init script" ],
		[ "any",         "/etc/init.d/bbj", "init script" ],
		[ "any",         "/etc/init.d/blm", "init script" ],
		[ "RHEL5",       $TCC_RHEL5_TCC2,   "TCC component" ],
		[ "RHEL5",       $TCC_RHEL5_TCC,    "TCC component" ],
		[ "RHEL6",       $TCC_RHEL6_TCC2,   "TCC component" ],
		[ "RHEL6",       $TCC_RHEL6_TCC,    "TCC component" ],
	    );
	    foreach my $idx (0 .. $#required_files) {

		next if ($required_files[$idx][0] ne "any" && $required_files[$idx][0] ne $OS);

		unless (-e $required_files[$idx][1]) {
		    showerror("missing $required_files[$idx][2]: $required_files[$idx][1]");
		    $rc = 0;
		}
	    }
	}
	else {
	    showerror("RTI directory does not exist: $RTIDIR");
	    $rc = 0;
	}
    }
    if ($DAISY) {
	unless (-e $DAISYDIR) {
	    showerror("Daisy directory does not exist: $DAISYDIR");
	    $rc = 0;
	}
    }

    return($rc);
}


#
# restore special files, ie those that could not be
# backed up in place.
#
# 1) for rti, doveserver.pl
#
# Returns
#   1 on success
#   0 if error
#
sub tfmp_restore_special_files
{
    my $rc = 0;

    if ($RTI) {
	my $dove_server_path = tfrm_pathto_dove_server();
	if (-e $dove_server_path) {
	    showerror("Dove server script already exists: $dove_server_path");
	}
	else {
	    my $saved_dove_server_path = tfrm_pathto_saved_dove_script();
	    if (-e $saved_dove_server_path) {
		system("cp -p $saved_dove_server_path $dove_server_path");
		if ($? == 0) {
		    loginfo("Dove server script restored: $dove_server_path");
		    $rc = 1;
		}
		else {
		    showerror("restoration of Dove server script failed: $dove_server_path");
		}
	    }
	    else {
		showerror("saved Dove server script does not exist: $saved_dove_server_path");
	    }
	}
    }

    return($rc);
}


#
# restore appropriate system files and directories.
#
# Returns
#   1 on success
#   0 if error
#
sub tfmp_restore_system_files
{
    my $rc = 1;

    if (tfmp_restore_select_system_files()) {
	loginfo("system files restored");
    }
    else {
	showerror("could not restore system files");
	$rc = 0;
    }

    return($rc);
}

#
# configure tcc
#
# Returns
#   1 on success
#   0 if error
#
sub tfmp_configure_tcc
{
    my $rc = 1;

    if ($OS eq "RHEL5") {
	system("ln -sf $TCC_RHEL5_TCC2 $TCC_TCC");
	system("ln -sf $TCC_RHEL5_TCC  $TCC_TCC_TWS");
    }

    elsif ($OS eq "RHEL6") {
	system("ln -sf $TCC_RHEL6_TCC2 $TCC_TCC");
	system("ln -sf $TCC_RHEL6_TCC  $TCC_TCC_TWS");
    }

    if (-e $TCC_TCC && -e $TCC_TCC_TWS) {
	loginfo("TCC symlinks configured: $TCC_TCC, $TCC_TCC_TWS");
    }
    else {
	showerror("TCC symlink configuration: $TCC_TCC, $TCC_TCC_TWS");
    }

    return($rc);
}


#
# configure the network to match the production server.
#
# take network down before making changes.
#
# Returns
#   1 on success
#   0 if error
#
sub tfmp_configure_network
{
    my %pserver_info = ();

    my $rc = 1;

    if (tfmp_pserver_read_info_file(\%pserver_info)) {

	my $cmd = $TOOLSDIR . "/bin/updateos.pl";
	my $cmd_opts = " --ipaddr=$pserver_info{$PSERVER_INFO_IPADDR}";
	$cmd_opts .=   " --netmask=$pserver_info{$PSERVER_INFO_NETMASK}";
	$cmd_opts .=   " --gateway=$pserver_info{$PSERVER_INFO_GATEWAY}";
	system("perl $cmd $cmd_opts");
	if ($? == 0) {
	    loginfo("successful exit status for cmd: $cmd $cmd_opts");
	}
	else {
	    showerror("exit status non-zero ($?) for: $cmd $cmd_opts");
	    $rc = 0
	}

	$cmd_opts = " --hostname=$pserver_info{$PSERVER_INFO_HOSTNAME}";
	system("perl $cmd $cmd_opts");
	if ($? == 0) {
	    loginfo("successful exit status for cmd: $cmd $cmd_opts");
	}
	else {
	    showerror("exit status non-zero ($?) for: $cmd $cmd_opts");
	    $rc = 0
	}

	system("/sbin/service network restart");
    }
    else {
	showerror("could not read pserver info file");
	$rc = 0;
    }

    return($rc);
}


#
# add any POS user accounts from users listing file
# if the accounts do not already exists, and update
# of they do.
#
# enable any admin accounts.
#
# sync up the passwords.
#
# Returns
#   1 if successful
#   0 on error
#
sub tfmp_restore_users_info
{
    my $rc = 0;

    my %users = ();
    my $users_file = tfrm_pathto_users_listing_file();
    if ($users_file) {
	if (tfmp_restore_pos_users($users_file, \%users)) {
	    loginfo("POS normal and admin users restored from: $users_file");
	    $rc = 1;
	}
	else {
	    showerror("could not restore POS users from: $users_file");
	}
    }
    else {
	showerror("could not get path to POS users listing file");
    }

    if ($rc) {
	my $shadow_file = tfrm_pathto_users_shadow_file();
	if ($shadow_file) {
	    if (tfmp_restore_passwords($shadow_file)) {
		loginfo("passwords for POS users restored: $shadow_file");
		$rc = 1;
	    }
	    else {
		showerror("could not restore passwords for POS users in: $shadow_file");
	    }
	}
	else {
	    showerror("could not get path to POS users shadow file");
	}
    }

    return($rc);
}


sub tfmp_change_samba_passwd_backend
{
    my $rc = 1;

    my $conf_file = "/etc/samba/smb.conf";

    if ($OS eq "RHEL6") {
	my $samba_passwd_backend = tfrm_get_samba_passwd_backend($conf_file);
	if ($samba_passwd_backend eq "smbpasswd") {
	    loginfo("Samba already configured for smbpasswd");
	}
	else {
	    my $new_conf_file = $conf_file . '_' . "$$";
	    if (tfmp_set_samba_passwd_backend($conf_file, $new_conf_file)) {
		if (tfrm_replace_conf_file($conf_file, $new_conf_file)) {
		    loginfo("Samba password backend config changed to: smbpasswd");
		}
		else {
		    showerror("could not replace conf file: $conf_file");
		    $rc = 0;
		}
	    }
	    else {
		showerror("could not change Samba password backend config to: smbpasswd");
		$rc = 0;
	    }
	}
    }

    return($rc);
}


sub tfmp_update_samba_passwd_file
{
    my $conf_file = "/etc/samba/smb.conf";
    my $rc = 0;

    my %uids = ();
    if (tfrm_get_uids("/etc/passwd", \%uids)) {
	my $samba_pw_file = tfrm_pathto_samba_passwd_file($conf_file);
	if ($samba_pw_file) {
	    my $new_samba_pw_file = $samba_pw_file . '_' . "$$";
	    if (tfmp_samba_rebuild_passdb($samba_pw_file, $new_samba_pw_file, \%uids)) {
		if (tfrm_replace_conf_file($samba_pw_file, $new_samba_pw_file)) {
		    loginfo("Samba password file rebuilt: $samba_pw_file");
		    $rc = 1;
		}
		else {
		    showerror("could not replace conf file: $samba_pw_file");
		}
	    }
	    else {
		showerror("could not rebuild samba password database: $samba_pw_file");
	    }
	}
	else {
	    showerror("could not get path to samba password file: $conf_file");
	}
    }
    else {
	showerror("could not read passwd file");
    }

    return($rc);
}


#
# Start the RTI POS and it's dependencies.
#
# 0) start web server
# 1) start blm service
# 2) start bbj service
# 3) start rti service
#
# Returns
#   1 on success
#   0 if error
#
sub tfmp_start_rti
{
    my $rc = 1;

    my @rti_services = (
	"blm",
	"bbj",
	"rti",
    );

    if (is_service_configured("httpd")) {
	system("/sbin/service httpd start 2>> $LOGFILE_PATH");

	foreach my $service (@rti_services) {
	    unless (is_service_configured($service)) {
		system("/sbin/chkconfig --add $service 2>> $LOGFILE_PATH");
	    }
	    system("/sbin/chkconfig $service on 2>> $LOGFILE_PATH");
	    system("/sbin/service $service start");
	}
    }
    else {
	showerror("http service is not configured");
	$rc = 0;
    }

    return($rc);
}


__END__


#################################################
#########   D O C U M E N T A T I O N   #########
#################################################

=pod


=head1 NAME

I<tfmkpserver.pl> - Script to make a backup server into a production server.


=head1 VERSION

This documentation refers to version: $Revision: 1.18 $


=head1 SYNOPSIS

tfmkpserver.pl B<--help>

tkmkpserver.pl B<--version>

tkmkpserver.pl [B<--verbose>] [B<--dry-run>] [B<--logfile=path>]

tkmkpserver.pl [B<--verbose>] [B<--dry-run>] [B<--logfile=path>] --report


=head1 DESCRIPTION

=head2 Overview

The F<tkmkpserver.pl> script is used to convert a backup server into
a production server.

=head2 Details

Here is a detailed outline of how F<tfmkpserver.pl>
converts the backup server to a production serverby performing

=over 4

=item 1.

The script verifies the following list of pre-requesites are fulfilled:

=over 4

=item a.

verify the platform is "RHEL5" or "RHEL6".

=item b.

verify that the "production server info file" is present and
contains values for each of the possible fields allowed.

=item c.

verify that the B<OSTools> package is installed.

=item d.

if RTI, verify that F</usr2> exists and is a directory.

=item e.

if RTI, verify that the RTI F</etc/init.d> scripts exist.

=item f.

if RTI, verify that the TCC package is installed.

=item g.

if Daisy, verify that F</d> exists and is a directory.

=back

=item 2.

restore special files like F</usr2/bbx/bin/doveserver.pl>.
The restoration involves renaming the file to it's actual name, and
setting the perms, owner, and group to there proper values.

=item 3.

restore a select set of system files from the production server,
for example, F</etc/samba/smb.conf>.

=item 4.

configure the TCC package as appropriate for the platform.

=item 5.

configure the network by setting the hostname, the ip addr,
the netmask, and the gateway ipaddr of the backup server
to that of the production server.

=item 6.

add any POS users from the production server to the backup server.

=item 7.

reconcile the UIDs in the Samba password file from the
production server with those in the password file of the
backup server.

=item 8.

Configure and start the RTI system services: http, bbj, blm, and rti.

The script exits with the exit status returned by F<tf_make_pserver()>.
See section on "EXIT STATUS" below for actual exit status values and
the the reason why each status would be reported.

=back

=head2 Command Line Options

=over 4

=item B<--version>

Output the version number of the script and exit.

=item B<--help>

Output a short help message and exit.

=item B<--verbose>

Modifier: report extra information.

=item B<--report>

Output a report of state of backup server.

=item B<--logfile=path>

Specify path to log file.

=item B<--dry-run>

Report what an operation would do but don't actually do it.

=item B<--debugmode>

If specified, run in debug mode.

=back


=head1 EXAMPLES


=head1 FILES

=over 4

=item F</usr2>

The top of the RTI filesystem.

=item F</usr2/tfrsync>

This directory contains files from the production system.

=item F</usr2/bbx>

The default RTI directory - this directory must exist and
contain a standard RTI POS installation.

=item F</usr2/bbx/log/tfmkpserver.log>

The log file produced by this script.

=back


=head1 EXIT STATUS

=over 4

=item Exit status 0 ($EXIT_OK)

Successful completion.

=item Exit status 1 ($EXIT_COMMAND_LINE)

In general, there was an issue with the syntax of the command line.

=item Exit status 2 ($EXIT_MUST_BE_ROOT)

The script must run as root or with sudo(1).

=item Exit status 10 ($EXIT_PREREQS)

One or more of the prerequisites could not be verified.
These "prereqs" include conditions like the platform the
script is running on, the installation of the OSTools package,
the existence of specific files, directories, and scripts, and
the existence of an installed POS, either RTI or Daisy.

=item Exit status 12 ($EXIT_START_RTI)

The RTI point of sales application could not be started.

=item Exit status 13 ($EXIT_TCC_CONFIG)

The TCC symlinks for RTI could not be configured.

=item Exit status 14 ($EXIT_NETWORK_CONFIG)

The network configuration of the backup server could not
be changed to that of the production server.

=item Exit status 15 ($EXIT_RESTORING_SPECIAL_FILES)

The set of files requiring special handling could not be restored.
Examples include F<doveserver.pl>.

=item Exit status 16 ($EXIT_RESTORING_USERS)

The set of POS users from the production server and their info
such as passwords, could not be restored on the backup server.

=item Exit status 17 ($EXIT_SAMBA_PW_BACKEND)

The Samba password backend configuration could not be updated
on a RHEL6 system.

=item Exit status 18 ($EXIT_SAMBA_USERS)

The Samba B<uid> values in the Samba password file could not be updated.

=item Exit status 19 ($EXIT_RESTORING_SYSTEM_FILES)

The backup sets that could not be stored "in place" could
not be copied into place.

=back


=head2 SEE ALSO

I<tfrsync.pl>


=cut
