#
#========================================================================
#
-# Version 2.1.0, released 20 Jun 2004.
+# Version 3.0.0beta3, released 3 Dec 2006.
#
# See http://backuppc.sourceforge.net.
#
sub new
{
my $class = shift;
- my($topDir, $installDir, $noUserCheck) = @_;
+ my($topDir, $installDir, $confDir, $noUserCheck) = @_;
- my $paths = {
- TopDir => $topDir || '/data/BackupPC',
- BinDir => $installDir || '/usr/local/BackupPC',
- LibDir => $installDir || '/usr/local/BackupPC',
- };
- $paths->{BinDir} .= "/bin";
- $paths->{LibDir} .= "/lib";
+ #
+ # Whether to use filesystem hierarchy standard for file layout.
+ # If set, text config files are below /etc/BackupPC.
+ #
+ my $useFHS = 0;
+ my $paths;
- $paths->{storage} = BackupPC::Storage->new($paths);
+ #
+ # Set defaults for $topDir and $installDir.
+ #
+ $topDir = '/tera0/backup/BackupPC' if ( $topDir eq "" );
+ $installDir = '/usr/local/BackupPC' if ( $installDir eq "" );
+
+ #
+ # Pick some initial defaults. For FHS the only critical
+ # path is the ConfDir, since we get everything else out
+ # of the main config file.
+ #
+ if ( $useFHS ) {
+ $paths = {
+ useFHS => $useFHS,
+ TopDir => $topDir,
+ InstallDir => $installDir,
+ ConfDir => $confDir eq "" ? '/etc/BackupPC' : $confDir,
+ LogDir => '/var/log/BackupPC',
+ };
+ } else {
+ $paths = {
+ useFHS => $useFHS,
+ TopDir => $topDir,
+ InstallDir => $installDir,
+ ConfDir => $confDir eq "" ? "$topDir/conf" : $confDir,
+ LogDir => "$topDir/log",
+ };
+ }
my $bpc = bless {
%$paths,
- Version => '2.1.0',
+ Version => '3.0.0beta3',
}, $class;
+ $bpc->{storage} = BackupPC::Storage->new($paths);
+
#
# Clean up %ENV and setup other variables.
#
return;
}
+ #
+ # Update the paths based on the config file
+ #
+ foreach my $dir ( qw(TopDir ConfDir InstallDir LogDir) ) {
+ next if ( $bpc->{Conf}{$dir} eq "" );
+ $paths->{$dir} = $bpc->{$dir} = $bpc->{Conf}{$dir};
+ }
+ $bpc->{storage}->setPaths($paths);
+
#
# Verify we are running as the correct user
#
if ( !$noUserCheck
&& $bpc->{Conf}{BackupPCUserVerify}
&& $> != (my $uid = (getpwnam($bpc->{Conf}{BackupPCUser}))[2]) ) {
- print(STDERR "Wrong user: my userid is $>, instead of $uid"
+ print(STDERR "$0: Wrong user: my userid is $>, instead of $uid"
. " ($bpc->{Conf}{BackupPCUser})\n");
+ print(STDERR "Please su $bpc->{Conf}{BackupPCUser} first\n");
return;
}
return $bpc;
sub BinDir
{
my($bpc) = @_;
- return $bpc->{BinDir};
+ return "$bpc->{InstallDir}/bin";
+}
+
+sub LogDir
+{
+ my($bpc) = @_;
+ return $bpc->{LogDir};
+}
+
+sub ConfDir
+{
+ my($bpc) = @_;
+ return $bpc->{ConfDir};
+}
+
+sub LibDir
+{
+ my($bpc) = @_;
+ return "$bpc->{InstallDir}/lib";
+}
+
+sub InstallDir
+{
+ my($bpc) = @_;
+ return $bpc->{InstallDir};
+}
+
+sub useFHS
+{
+ my($bpc) = @_;
+ return $bpc->{useFHS};
}
sub Version
# Load language file
#
return "No language setting" if ( !defined($bpc->{Conf}{Language}) );
- my $langFile = "$bpc->{LibDir}/BackupPC/Lang/$bpc->{Conf}{Language}.pm";
+ my $langFile = "$bpc->{InstallDir}/lib/BackupPC/Lang/$bpc->{Conf}{Language}.pm";
if ( !defined($ret = do $langFile) && ($! || $@) ) {
$mesg = "Couldn't open language file $langFile: $!" if ( $! );
$mesg = "Couldn't execute language file $langFile: $@" if ( $@ );
return $bpc->{storage}->HostInfoRead($host);
}
+sub HostInfoWrite
+{
+ my($bpc, $host) = @_;
+
+ return $bpc->{storage}->HostInfoWrite($host);
+}
+
#
# Return the mtime of the hosts file
#
#
# First try the unix-domain socket
#
- my $sockFile = "$bpc->{TopDir}/log/BackupPC.sock";
+ my $sockFile = "$bpc->{LogDir}/BackupPC.sock";
socket(*FH, PF_UNIX, SOCK_STREAM, 0) || return "unix socket: $!";
if ( !connect(*FH, sockaddr_un($sockFile)) ) {
my $err = "unix connect: $!";
my($pid, $out, $allOut);
local(*CHILD);
+ $? = 0;
if ( (ref($cmd) eq "ARRAY" ? $cmd->[0] : $cmd) =~ /^\&/ ) {
$cmd = join(" ", $cmd) if ( ref($cmd) eq "ARRAY" );
print(STDERR "cmdSystemOrEval: about to eval perl code $cmd\n")
return $bpc->cmdSystemOrEvalLong($cmd, $stdoutCB, 0, undef, @args);
}
-
#
# Promotes $conf->{BackupFilesOnly}, $conf->{BackupFilesExclude}
-# to hashes and $conf->{$shareName} to an array
+# to hashes and $conf->{$shareName} to an array.
#
sub backupFileConfFix
{
$conf->{$shareName} = [ $conf->{$shareName} ]
if ( ref($conf->{$shareName}) ne "ARRAY" );
foreach my $param qw(BackupFilesOnly BackupFilesExclude) {
- next if ( !defined($conf->{$param}) || ref($conf->{$param}) eq "HASH" );
- $conf->{$param} = [ $conf->{$param} ]
- if ( ref($conf->{$param}) ne "ARRAY" );
- $conf->{$param} = { map { $_ => $conf->{$param} } @{$conf->{$shareName}} };
+ next if ( !defined($conf->{$param}) );
+ if ( ref($conf->{$param}) eq "HASH" ) {
+ #
+ # A "*" entry means wildcard - it is the default for
+ # all shares. Replicate the "*" entry for all shares,
+ # but still allow override of specific entries.
+ #
+ next if ( !defined($conf->{$param}{"*"}) );
+ $conf->{$param} = {
+ map({ $_ => $conf->{$param}{"*"} }
+ @{$conf->{$shareName}}),
+ %{$conf->{$param}}
+ };
+ } else {
+ $conf->{$param} = [ $conf->{$param} ]
+ if ( ref($conf->{$param}) ne "ARRAY" );
+ $conf->{$param} = { map { $_ => $conf->{$param} }
+ @{$conf->{$shareName}} };
+ }
+ }
+}
+
+#
+# This is sort() compare function, used below.
+#
+# New client LOG names are LOG.MMYYYY. Old style names are
+# LOG, LOG.0, LOG.1 etc. Sort them so new names are
+# first, and newest to oldest.
+#
+sub compareLOGName
+{
+ my $na = $1 if ( $a =~ /LOG\.(\d+)(\.z)?$/ );
+ my $nb = $1 if ( $b =~ /LOG\.(\d+)(\.z)?$/ );
+
+ $na = -1 if ( !defined($na) );
+ $nb = -1 if ( !defined($nb) );
+
+ if ( length($na) >= 5 && length($nb) >= 5 ) {
+ #
+ # Both new style: format is MMYYYY. Bigger dates are
+ # more recent.
+ #
+ my $ma = $2 * 12 + $1 if ( $na =~ /(\d+)(\d{4})/ );
+ my $mb = $2 * 12 + $1 if ( $nb =~ /(\d+)(\d{4})/ );
+ return $mb - $ma;
+ } elsif ( length($na) >= 5 && length($nb) < 5 ) {
+ return -1;
+ } elsif ( length($na) < 5 && length($nb) >= 5 ) {
+ return 1;
+ } else {
+ #
+ # Both old style. Smaller numbers are more recent.
+ #
+ return $na - $nb;
+ }
+}
+
+#
+# Returns list of paths to a clients's (or main) LOG files,
+# most recent first.
+#
+sub sortedPCLogFiles
+{
+ my($bpc, $host) = @_;
+
+ my(@files, $dir);
+
+ if ( $host ne "" ) {
+ $dir = "$bpc->{TopDir}/pc/$host";
+ } else {
+ $dir = "$bpc->{LogDir}";
+ }
+ if ( opendir(DIR, $dir) ) {
+ foreach my $file ( readdir(DIR) ) {
+ next if ( !-f "$dir/$file" );
+ next if ( $file ne "LOG" && $file !~ /^LOG\.\d/ );
+ push(@files, "$dir/$file");
+ }
+ closedir(DIR);
}
+ return sort(compareLOGName @files);
}
1;