#! /usr/bin/perl
#
#	bup_db - clx db backup
#
# Last Change: Sat Feb 27 09:15:17 GMT 1999

$| = 1;					# Kein gepufferter Output

$db_name = "clx_db";			# db name
$boxdir = "~clx_us/box";
$psql = "psql -d $db_name -Aqtc";

($home) = (getpwnam('clx_us'))[7];
$bu_dir = "$home/backup";		# back-up dir

$dir = "unknown";
if ($ARGV[0] eq "-s") { $dir = "to"; shift; }
if ($ARGV[0] eq "-r") { $dir = "from"; shift; }
if ( $dir eq "unknown" ) {
	printf "usage: bup_db -s [table]	# backup\n";
	printf "       bup_db -r [table]	# restore\n";
	exit(1);
}

if ($dir eq "to") {			# start backup
    unless (open(X, $bu_dir)) { # dir vorhanden ?
	mkdir($bu_dir, oct(775)); 	# dir einrichten
    }
    chmod(oct(775),$bu_dir);

    if ( $#ARGV == -1 ) {
	#
	# Liste der in Postgres verzeichneten Tabellen
	#
	$qry = "select relname from pg_class where \
	not relname ~ 'pg_*' and relkind = 'r';";
	open(LIST, "$psql \"$qry\" |");
	@list = <LIST>;
	close(LIST);
	chop(@list);
	foreach (@list) { tr/ //d; }
    } 
    else {
    	@list = @ARGV;
    }

    print "CLX database backup started.\n";
}
else {
    unless (open(X, $bu_dir)) { # dir vorhanden ?
	print "Can't restore. need backups in $bu_dir";
	exit(1);
    }
    $udt_tmpl = `/bin/cat $home/db/udt_tbl.tmpl`;

    if ( $#ARGV == -1 ) {
	#
	# Liste der im Backup-Directory vorhandenen Tabellen
	#
	open(LIST, "cd $bu_dir ; ls *_* |");
	@list = grep(!/\./,grep(!/~/,<LIST>));
	close(LIST);
	chop(@list);
    }
    else {
    	@list = @ARGV;
    }

    print "CLX database restore started.\n";
}

foreach $tab (@list) {			# tabellen bearbeiten

    next if ( $tab eq "sys_dat" );	# no backup for sys_dat
    next if ( $tab eq "ar_band" );	# no backup for ar_band

    #
    # Udt-Tabellen selbst erzeugen
    #
    $fnam = join("/", $bu_dir, $tab);
    $short_fnam = "backup/$tab";
    $qry = sprintf("copy %s %s '%s'\;", $tab, $dir, $fnam);
    if ($dir eq "to") {			# falls retten
	if (-e $fnam) {
	    $mv = sprintf("mv -f %s %s~", $fnam, $fnam);
	    system "$mv";
	}
    }
    else {
        #
        # Udt-Tabelle selbst erzeugen
        #
        if ($tab =~ /udt_*/) {
	    $cmd = sprintf($udt_tmpl,$tab);
            system "$psql \"$cmd\"";
        }
	if (!(-e $fnam)) {
	    next;			# kein back-up vorhanden
	}
    }

    print "-- class $tab";

    if ($dir eq "from") {
        $count = (split(/ +/,`wc -l $fnam`))[1];
	$cmd = "select relnatts from pg_class where relname='$tab';";
	$col1 = `$psql \"$cmd\"`;		# get number of attributes
 	chop($col1);
	$col2 = split(/\t/,`head -1 $fnam`);	# count tabs in $fnam
	print " ($count records, $col1 cols in table, $col2 cols in $short_fnam)\n";
	$diff = $col1-$col2;
        if ( $diff > 0 && $col2 > 2) {
		&repair($fnam,$diff);
	}

        if ( $diff < 0 ) {
		print "!! More columns in backup file $fnam than in\n";
		print "!! database table $tab - you must fix this manually.\n";
		next;
	}

        if ( $tab eq "ml_file" ) {
    		print "-- directory $boxdir\n";
    		system "gunzip -c $bu_dir/box.tgz | tar xf - -C $boxdir --exclude=info/help*";
	}
    }

    system "$psql \"$qry\"";

    if ($dir eq "to") {
        $count = (split(/ +/,`wc -l $fnam`))[1];
	$cmd = "select relnatts from pg_class where relname='$tab';";
	$col1 = `$psql \"$cmd\"`;
 	chop($col1);
	$col2 = split(/\t/,`head -1 $fnam`);
	print " ($count records, $col1 cols in table)\n";
        if ( $tab eq "ml_file" ) {
		if ( -e "$bu_dir/box.tgz" ) {
			system "mv -f $bu_dir/box.tgz $bu_dir/box.tgz~";
    		}
		system "tar cf - -C $boxdir --exclude=info/help* . | gzip -c > $bu_dir/box.tgz";
		print "-- directory $boxdir\n";
	}
    }
}

if ($dir eq "to") {
    print "CLX database backup finished.\n";
}
else {
    print "CLX database restore finished.\n";
}

sub repair() {

	($fnam,$diff) = @_;
	print "!! Formats don't match, adding $diff emtpy field(s)\n";
	print "!! to every line in $fnam.\n";
	print "!! The original file $fnam will be renamed to\n";
	print "!! $fnam.$$\n";

	$new = $fnam . ".new";
	open(IN,"< $fnam");
	open(OUT,"> $new");
	while(<IN>) {
		chop;
		print OUT $_;
		print OUT "\t\\N" x $diff;
		print OUT "\n";
	}
	close(IN);
	close(OUT);

	rename($fnam,"$fnam.$$") || die "Could not rename $fnam to $fnam.$$\n";
	rename($new,$fnam) || die "Could not rename $new to $fnam\n";;

	return;
}
