X-Git-Url: http://git.rot13.org/?p=BackupPC.git;a=blobdiff_plain;f=configure.pl;h=28c4b8661f007dc309e8d3870b6a1144c8e001be;hp=ff910d0578e994d6e9f4f0328f15b4441b311e04;hb=dcde0725fd46cdfe126eb385a1eb356df636bbec;hpb=f6257f558390295c581f4e5af8f084341db05d34 diff --git a/configure.pl b/configure.pl index ff910d0..28c4b86 100755 --- a/configure.pl +++ b/configure.pl @@ -1,4 +1,4 @@ -#!/bin/perl +#!/usr/bin/env perl #============================================================= -*-perl-*- # # configure.pl: Configuration and installation program for BackupPC @@ -9,13 +9,17 @@ # # perl configure.pl # +# To read about the command-line options for this configure script: +# +# perldoc configure.pl +# # The installation steps are described as the script runs. # # AUTHOR # Craig Barratt # # COPYRIGHT -# Copyright (C) 2001-2003 Craig Barratt +# Copyright (C) 2001-2010 Craig Barratt # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -33,23 +37,48 @@ # #======================================================================== # -# Version 2.0.0_CVS, released 18 Jan 2003. +# Version 3.1.0beta0, released 3 Sep 2007. # # See http://backuppc.sourceforge.net. # #======================================================================== use strict; +no utf8; use vars qw(%Conf %OrigConf); use lib "./lib"; +use Encode; -my @Packages = qw(ExtUtils::MakeMaker File::Path File::Spec File::Copy - DirHandle Digest::MD5 Data::Dumper Getopt::Std - BackupPC::Lib BackupPC::FileZIO); +my $EncodeVersion = eval($Encode::VERSION); +if ( $EncodeVersion < 1.99 ) { + print("Error: you need to upgrade perl's Encode package.\n" + . "I found $EncodeVersion and BackupPC needs >= 1.99\n" + . "Please go to www.cpan.org or use the cpan command.\n"); + exit(1); +} + +my @Packages = qw(File::Path File::Spec File::Copy DirHandle Digest::MD5 + Data::Dumper Getopt::Std Getopt::Long Pod::Usage + BackupPC::Lib BackupPC::FileZIO); foreach my $pkg ( @Packages ) { eval "use $pkg"; next if ( !$@ ); + if ( $pkg =~ /BackupPC/ ) { + die < 0, -verbose => 2) if $opts{man}; + +my $DestDir = $opts{"dest-dir"}; +$DestDir = "" if ( $DestDir eq "/" ); + +if ( !$opts{"uid-ignore"} && $< != 0 ) { print < Do you want to continue?", "y") =~ /y/i; + exit(1) if ( prompt("--> Do you want to continue?", + "y") !~ /y/i ); + exit(1) if ( $opts{batch} && !$opts{"uid-ignore"} ); } -print < Full path to existing conf/config.pl", - $ConfigPath); + if ( $ConfigFileOK && -f "/etc/BackupPC/config.pl" ) { + $ConfigPath = "/etc/BackupPC/config.pl"; + $opts{fhs} = 1 if ( !defined($opts{fhs}) ); + print < Full path to existing main config.pl", + $ConfigPath, + "config-path"); + } last if ( $ConfigPath eq "" - || ($ConfigPath =~ /^\// && -r $ConfigPath && -w $ConfigPath) ); + || ($ConfigPath =~ /^\// && -f $ConfigPath && -w $ConfigPath) ); my $problem = "is not an absolute path"; - $problem = "is not writable" if ( !-w $ConfigPath ); - $problem = "is not readable" if ( !-r $ConfigPath ); - $problem = "doesn't exist" if ( !-f $ConfigPath ); + $problem = "is not writable" if ( !-w $ConfigPath ); + $problem = "is not readable" if ( !-r $ConfigPath ); + $problem = "is not a regular file" if ( !-f $ConfigPath ); + $problem = "doesn't exist" if ( !-e $ConfigPath ); print("The file '$ConfigPath' $problem.\n"); + if ( $opts{batch} ) { + print("Need to specify a valid --config-path for upgrade\n"); + exit(1); + } + $ConfigFileOK = 0; } +$opts{fhs} = 1 if ( !defined($opts{fhs}) && $ConfigPath eq "" ); +$opts{fhs} = 0 if ( !defined($opts{fhs}) ); + my $bpc; if ( $ConfigPath ne "" && -r $ConfigPath ) { - (my $topDir = $ConfigPath) =~ s{/[^/]+/[^/]+$}{}; + (my $confDir = $ConfigPath) =~ s{/[^/]+$}{}; die("BackupPC::Lib->new failed\n") - if ( !($bpc = BackupPC::Lib->new($topDir, ".", 1)) ); + if ( !($bpc = BackupPC::Lib->new(".", ".", $confDir, 1)) ); %Conf = $bpc->Conf(); %OrigConf = %Conf; - $Conf{TopDir} = $topDir; - my $err = $bpc->ServerConnect($Conf{ServerHost}, $Conf{ServerPort}, 1); + if ( !$opts{fhs} ) { + ($Conf{TopDir} = $ConfigPath) =~ s{/[^/]+/[^/]+$}{} + if ( $Conf{TopDir} eq '' ); + $bpc->{LogDir} = $Conf{LogDir} = "$Conf{TopDir}/log" + if ( $Conf{LogDir} eq '' ); + } + $bpc->{ConfDir} = $Conf{ConfDir} = $confDir; + my $err = $bpc->ServerConnect($Conf{ServerHost}, $Conf{ServerPort}, 1); if ( $err eq "" ) { print < "PerlPath", - 'gtar/tar' => "TarClientPath", - smbclient => "SmbClientPath", - nmblookup => "NmbLookupPath", - rsync => "RsyncClientPath", - ping => "PingPath", - df => "DfPath", - 'ssh/ssh2' => "SshPath", - sendmail => "SendmailPath", - hostname => "HostnamePath", + perl => "PerlPath", + 'gtar/tar' => "TarClientPath", + smbclient => "SmbClientPath", + nmblookup => "NmbLookupPath", + rsync => "RsyncClientPath", + ping => "PingPath", + df => "DfPath", + 'ssh/ssh2' => "SshPath", + sendmail => "SendmailPath", + hostname => "HostnamePath", + split => "SplitPath", + par2 => "ParPath", + cat => "CatPath", + gzip => "GzipPath", + bzip2 => "Bzip2Path", ); foreach my $prog ( sort(keys(%Programs)) ) { my $path; foreach my $subProg ( split(/\//, $prog) ) { - $path ||= FindProgram("$ENV{PATH}:/bin:/usr/bin:/sbin:/usr/sbin", - $subProg); + $path = FindProgram("$ENV{PATH}:/usr/bin:/bin:/sbin:/usr/sbin", + $subProg) if ( !length($path) ); } - $Conf{$Programs{$prog}} ||= $path; + $Conf{$Programs{$prog}} = $path if ( !length($Conf{$Programs{$prog}}) ); } while ( 1 ) { @@ -148,7 +279,7 @@ I found the following locations for these programs: EOF foreach my $prog ( sort(keys(%Programs)) ) { - printf(" %-11s => %s\n", $prog, $Conf{$Programs{$prog}}); + printf(" %-12s => %s\n", $prog, $Conf{$Programs{$prog}}); } print "\n"; last if (prompt('--> Are these paths correct?', 'y') =~ /^y/i); @@ -158,13 +289,13 @@ EOF } } -my $Perl56 = system($Conf{PerlPath} - . q{ -e 'exit($^V && $^V ge v5.6.0 ? 1 : 0);'}); +my $Perl58 = system($Conf{PerlPath} + . q{ -e 'exit($^V && $^V ge v5.8.0 ? 1 : 0);'}); -if ( !$Perl56 ) { +if ( !$Perl58 ) { print < BackupPC will run on host", $Conf{ServerHost}); +$Conf{ServerHost} = prompt("--> BackupPC will run on host", + $Conf{ServerHost}, + "hostname"); print < BackupPC should run as user", - $Conf{BackupPCUser} || "backuppc"); - ($name, $passwd, $Uid, $Gid) = getpwnam($Conf{BackupPCUser}); - last if ( $name ne "" ); - print < Install directory (full path)", - $Conf{InstallDir}); + $Conf{InstallDir}, + "install-dir"); last if ( $Conf{InstallDir} =~ /^\// ); + if ( $opts{batch} ) { + print("Need to specify --install-dir for new installation\n"); + exit(1); + } } print < Data directory (full path)", $Conf{TopDir}); + $Conf{TopDir} = prompt("--> Data directory (full path)", + $Conf{TopDir}, + "data-dir"); last if ( $Conf{TopDir} =~ /^\// ); + if ( $opts{batch} ) { + print("Need to specify --data-dir for new installation\n"); + exit(1); + } } +$Conf{CompressLevel} = $opts{"compress-level"} + if ( defined($opts{"compress-level"}) ); + if ( !defined($Conf{CompressLevel}) ) { $Conf{CompressLevel} = BackupPC::FileZIO->compOk ? 3 : 0; if ( $ConfigPath eq "" && $Conf{CompressLevel} ) { @@ -255,10 +407,8 @@ BackupPC can compress pool files, but it needs the Compress::Zlib package installed (see www.cpan.org). Compression will provide around a 40% reduction in pool size, at the expense of cpu time. You can leave compression off and run BackupPC without compression, in which case you -should leave the compression level at 0 (which means off). You could -install Compress::Zlib and turn compression on later, but read the -documentation first about how to do this. Or the better choice is -to quit, install Compress::Zlib, and re-run configure.pl. +should leave the compression level at 0 (which means off). Or the better +choice is to quit, install Compress::Zlib, and re-run configure.pl. EOF } elsif ( $Conf{CompressLevel} ) { @@ -266,14 +416,12 @@ EOF print < CGI bin directory (full path)", $Conf{CgiDir}); + $Conf{CgiDir} = prompt("--> CGI bin directory (full path)", + $Conf{CgiDir}, + "cgi-dir"); last if ( $Conf{CgiDir} =~ /^\// || $Conf{CgiDir} eq "" ); + if ( $opts{batch} ) { + print("Need to specify --cgi-dir for new installation\n"); + exit(1); + } } if ( $Conf{CgiDir} ne "" ) { print < Apache image directory (full path)", - $Conf{CgiImageDir}); + $Conf{CgiImageDir}, + "html-dir"); last if ( $Conf{CgiImageDir} =~ /^\// ); + if ( $opts{batch} ) { + print("Need to specify --html-dir for new installation\n"); + exit(1); + } } while ( 1 ) { $Conf{CgiImageDirURL} = prompt("--> URL for image directory (omit http://host; starts with '/')", - $Conf{CgiImageDirURL}); + $Conf{CgiImageDirURL}, + "html-dir-url"); last if ( $Conf{CgiImageDirURL} =~ /^\// ); + if ( $opts{batch} ) { + print("Need to specify --html-dir-url for new installation\n"); + exit(1); + } } } @@ -349,7 +511,7 @@ Ok, we're about to: - install the binaries, lib and docs in $Conf{InstallDir}, - create the data directory $Conf{TopDir}, - - create/update the config.pl file $Conf{TopDir}/conf, + - create/update the config.pl file $Conf{ConfDir}/config.pl, - optionally install the cgi-bin interface. EOF @@ -359,15 +521,22 @@ exit unless prompt("--> Do you want to continue?", "y") =~ /y/i; # # Create install directories # -foreach my $dir ( qw(bin lib/BackupPC/Xfer lib/BackupPC/Zip - lib/BackupPC/Lang doc) ) { - next if ( -d "$Conf{InstallDir}/$dir" ); - mkpath("$Conf{InstallDir}/$dir", 0, 0775); - if ( !-d "$Conf{InstallDir}/$dir" - || !chown($Uid, $Gid, "$Conf{InstallDir}/$dir") ) { - die("Failed to create or chown $Conf{InstallDir}/$dir\n"); +foreach my $dir ( qw(bin doc + lib/BackupPC/CGI + lib/BackupPC/Config + lib/BackupPC/Lang + lib/BackupPC/Storage + lib/BackupPC/Xfer + lib/BackupPC/Zip + lib/Net/FTP + ) ) { + next if ( -d "$DestDir$Conf{InstallDir}/$dir" ); + mkpath("$DestDir$Conf{InstallDir}/$dir", 0, 0755); + if ( !-d "$DestDir$Conf{InstallDir}/$dir" + || !my_chown($Uid, $Gid, "$DestDir$Conf{InstallDir}/$dir") ) { + die("Failed to create or chown $DestDir$Conf{InstallDir}/$dir\n"); } else { - print("Created $Conf{InstallDir}/$dir\n"); + print("Created $DestDir$Conf{InstallDir}/$dir\n"); } } @@ -375,93 +544,111 @@ foreach my $dir ( qw(bin lib/BackupPC/Xfer lib/BackupPC/Zip # Create CGI image directory # foreach my $dir ( ($Conf{CgiImageDir}) ) { - next if ( $dir eq "" || -d $dir ); - mkpath($dir, 0, 0775); - if ( !-d $dir || !chown($Uid, $Gid, $dir) ) { - die("Failed to create or chown $dir"); + next if ( $dir eq "" || -d "$DestDir$dir" ); + mkpath("$DestDir$dir", 0, 0755); + if ( !-d "$DestDir$dir" || !my_chown($Uid, $Gid, "$DestDir$dir") ) { + die("Failed to create or chown $DestDir$dir"); } else { - print("Created $dir\n"); + print("Created $DestDir$dir\n"); } } # -# Create $TopDir's top-level directories +# Create other directories # -foreach my $dir ( qw(. conf pool cpool pc trash log) ) { - mkpath("$Conf{TopDir}/$dir", 0, 0750) if ( !-d "$Conf{TopDir}/$dir" ); - if ( !-d "$Conf{TopDir}/$dir" - || !chown($Uid, $Gid, "$Conf{TopDir}/$dir") ) { - die("Failed to create or chown $Conf{TopDir}/$dir\n"); +foreach my $dir ( ( + "$Conf{TopDir}", + "$Conf{TopDir}/pool", + "$Conf{TopDir}/cpool", + "$Conf{TopDir}/pc", + "$Conf{TopDir}/trash", + "$Conf{ConfDir}", + "$Conf{LogDir}", + ) ) { + mkpath("$DestDir$dir", 0, 0750) if ( !-d "$DestDir$dir" ); + if ( !-d "$DestDir$dir" + || !my_chown($Uid, $Gid, "$DestDir$dir") ) { + die("Failed to create or chown $DestDir$dir\n"); } else { - print("Created $Conf{TopDir}/$dir\n"); + print("Created $DestDir$dir\n"); } } -printf("Installing binaries in $Conf{InstallDir}/bin\n"); -foreach my $prog ( qw(BackupPC BackupPC_dump BackupPC_link BackupPC_nightly - BackupPC_sendEmail BackupPC_tarCreate BackupPC_trashClean - BackupPC_tarExtract BackupPC_compressPool BackupPC_zcat - BackupPC_restore BackupPC_serverMesg BackupPC_zipCreate ) ) { - InstallFile("bin/$prog", "$Conf{InstallDir}/bin/$prog", 0555); +printf("Installing binaries in $DestDir$Conf{InstallDir}/bin\n"); +foreach my $prog ( qw( + __CONFIGURE_BIN_LIST__ + ) ) { + InstallFile($prog, "$DestDir$Conf{InstallDir}/$prog", 0555); } -# -# Remove unused binaries from older versions -# -unlink("$Conf{InstallDir}/bin/BackupPC_queueAll"); - -printf("Installing library in $Conf{InstallDir}/lib\n"); -foreach my $lib ( qw(BackupPC/Lib.pm BackupPC/FileZIO.pm BackupPC/Attrib.pm - BackupPC/PoolWrite.pm BackupPC/View.pm BackupPC/Xfer/Tar.pm - BackupPC/Xfer/Smb.pm BackupPC/Xfer/Rsync.pm - BackupPC/Xfer/RsyncFileIO.pm BackupPC/Zip/FileMember.pm - BackupPC/Lang/en.pm BackupPC/Lang/fr.pm BackupPC/Lang/es.pm - BackupPC/Lang/de.pm +printf("Installing library in $DestDir$Conf{InstallDir}/lib\n"); +foreach my $lib ( qw( + __CONFIGURE_LIB_LIST__ ) ) { - InstallFile("lib/$lib", "$Conf{InstallDir}/lib/$lib", 0444); + InstallFile($lib, "$DestDir$Conf{InstallDir}/$lib", 0444); } if ( $Conf{CgiImageDir} ne "" ) { - printf("Installing images in $Conf{CgiImageDir}\n"); + printf("Installing images in $DestDir$Conf{CgiImageDir}\n"); foreach my $img ( ) { (my $destImg = $img) =~ s{^images/}{}; - InstallFile($img, "$Conf{CgiImageDir}/$destImg", 0444, 1); + InstallFile($img, "$DestDir$Conf{CgiImageDir}/$destImg", 0444, 1); + } + + # + # Install new CSS file, making a backup copy if necessary + # + my $cssBackup = "$DestDir$Conf{CgiImageDir}/BackupPC_stnd.css.pre-__VERSION__"; + if ( -f "$DestDir$Conf{CgiImageDir}/BackupPC_stnd.css" && !-f $cssBackup ) { + rename("$DestDir$Conf{CgiImageDir}/BackupPC_stnd.css", $cssBackup); } + InstallFile("conf/BackupPC_stnd.css", + "$DestDir$Conf{CgiImageDir}/BackupPC_stnd.css", 0444, 0); + InstallFile("conf/BackupPC_stnd_orig.css", + "$DestDir$Conf{CgiImageDir}/BackupPC_stnd_orig.css", 0444, 0); + InstallFile("conf/sorttable.js", + "$DestDir$Conf{CgiImageDir}/sorttable.js", 0444, 0); } printf("Making init.d scripts\n"); foreach my $init ( qw(gentoo-backuppc gentoo-backuppc.conf linux-backuppc - solaris-backuppc debian-backuppc suse-backuppc) ) { + solaris-backuppc debian-backuppc freebsd-backuppc + freebsd-backuppc2 suse-backuppc slackware-backuppc ) ) { InstallFile("init.d/src/$init", "init.d/$init", 0444); } -printf("Installing docs in $Conf{InstallDir}/doc\n"); +printf("Making Apache configuration file for suid-perl\n"); +InstallFile("httpd/src/BackupPC.conf", "httpd/BackupPC.conf", 0644); + +printf("Installing docs in $DestDir$Conf{InstallDir}/doc\n"); foreach my $doc ( qw(BackupPC.pod BackupPC.html) ) { - InstallFile("doc/$doc", "$Conf{InstallDir}/doc/$doc", 0444); + InstallFile("doc/$doc", "$DestDir$Conf{InstallDir}/doc/$doc", 0444); } -printf("Installing config.pl and hosts in $Conf{TopDir}/conf\n"); -InstallFile("conf/hosts", "$Conf{TopDir}/conf/hosts", 0644) - if ( !-f "$Conf{TopDir}/conf/hosts" ); +printf("Installing config.pl and hosts in $DestDir$Conf{ConfDir}\n"); +InstallFile("conf/hosts", "$DestDir$Conf{ConfDir}/hosts", 0644) + if ( !-f "$DestDir$Conf{ConfDir}/hosts" ); # # Now do the config file. If there is an existing config file we # merge in the new config file, adding any new configuration # parameters and deleting ones that are no longer needed. # -my $dest = "$Conf{TopDir}/conf/config.pl"; -my ($newConf, $newVars) = ConfigParse("conf/config.pl"); +my $dest = "$DestDir$Conf{ConfDir}/config.pl"; +my ($distConf, $distVars) = ConfigParse("conf/config.pl"); my ($oldConf, $oldVars); +my ($newConf, $newVars) = ($distConf, $distVars); if ( -f $dest ) { ($oldConf, $oldVars) = ConfigParse($dest); - $newConf = ConfigMerge($oldConf, $oldVars, $newConf, $newVars); + ($newConf, $newVars) = ConfigMerge($oldConf, $oldVars, $distConf, $distVars); } -$Conf{EMailFromUserName} ||= $Conf{BackupPCUser}; -$Conf{EMailAdminUserName} ||= $Conf{BackupPCUser}; # -# Update various config parameters +# Update various config parameters. The old config is in Conf{} +# and the new config is an array in text form in $newConf->[]. # +$Conf{EMailFromUserName} ||= $Conf{BackupPCUser}; +$Conf{EMailAdminUserName} ||= $Conf{BackupPCUser}; # # Guess $Conf{CgiURL} @@ -490,11 +677,53 @@ if ( defined($Conf{SmbClientArgs}) ) { delete($Conf{SmbClientArgs}); } +# +# CSS is now stored in a file rather than a big config variable. +# +delete($Conf{CSSstylesheet}); + +# +# The blackout timing settings are now stored in a list of hashes, rather +# than three scalar parameters. +# +if ( defined($Conf{BlackoutHourBegin}) ) { + $Conf{BlackoutPeriods} = [ + { + hourBegin => $Conf{BlackoutHourBegin}, + hourEnd => $Conf{BlackoutHourEnd}, + weekDays => $Conf{BlackoutWeekDays}, + } + ]; + delete($Conf{BlackoutHourBegin}); + delete($Conf{BlackoutHourEnd}); + delete($Conf{BlackoutWeekDays}); +} + +# +# $Conf{RsyncLogLevel} has been replaced by $Conf{XferLogLevel} +# +if ( defined($Conf{RsyncLogLevel}) ) { + $Conf{XferLogLevel} = $Conf{RsyncLogLevel}; + delete($Conf{RsyncLogLevel}); +} + +# +# In 2.1.0 the default for $Conf{CgiNavBarAdminAllHosts} is now 1 +# +$Conf{CgiNavBarAdminAllHosts} = 1; + # # IncrFill should now be off # $Conf{IncrFill} = 0; +# +# Empty $Conf{ParPath} if it isn't a valid executable +# (pre-3.0.0 configure.pl incorrectly set it to a +# hardcoded value). +# +$Conf{ParPath} = '' if ( $Conf{ParPath} ne '' && !-x $Conf{ParPath} ); + # # Figure out sensible arguments for the ping command # @@ -504,7 +733,7 @@ if ( defined($Conf{PingArgs}) ) { if ( $^O eq "solaris" || $^O eq "sunos" ) { $Conf{PingCmd} = '$pingPath -s $host 56 1'; } elsif ( ($^O eq "linux" || $^O eq "openbsd" || $^O eq "netbsd") - && !system("$Conf{PingClientPath} -c 1 -w 3 localhost") ) { + && !system("$Conf{PingPath} -c 1 -w 3 localhost") ) { $Conf{PingCmd} = '$pingPath -c 1 -w 3 $host'; } else { $Conf{PingCmd} = '$pingPath -c 1 $host'; @@ -529,6 +758,64 @@ if ( defined($Conf{SmbClientTimeout}) ) { delete($Conf{SmbClientTimeout}); } +# +# Replace --devices with -D in RsyncArgs and RsyncRestoreArgs +# +foreach my $param ( qw(RsyncArgs RsyncRestoreArgs) ) { + next if ( !defined($newVars->{$param}) ); + $newConf->[$newVars->{$param}]{text} =~ s/--devices/-D/g; +} + +# +# Merge any new user-editable parameters into CgiUserConfigEdit +# by copying the old settings forward. +# +if ( defined($Conf{CgiUserConfigEdit}) ) { + # + # This is a real hack. The config file merging is done in text + # form without actually instantiating the new conf structure. + # So we need to extract the new hash of settings, update it, + # and merge the text. Ugh... + # + my $new; + my $str = $distConf->[$distVars->{CgiUserConfigEdit}]{text}; + + $str =~ s/^\s*\$Conf\{.*?\}\s*=\s*/\$new = /m; + eval($str); + foreach my $p ( keys(%$new) ) { + $new->{$p} = $Conf{CgiUserConfigEdit}{$p} + if ( defined($Conf{CgiUserConfigEdit}{$p}) ); + } + $Conf{CgiUserConfigEdit} = $new; + my $d = Data::Dumper->new([$new], [*value]); + $d->Indent(1); + $d->Terse(1); + my $value = $d->Dump; + $value =~ s/(.*)\n/$1;\n/s; + $newConf->[$newVars->{CgiUserConfigEdit}]{text} + =~ s/(\s*\$Conf\{.*?\}\s*=\s*).*/$1$value/s; +} + +# +# Apply any command-line configuration parameter settings +# +foreach my $param ( keys(%{$opts{"config-override"}}) ) { + my $val = eval { $opts{"config-override"}{$param} }; + if ( @$ ) { + printf("Can't eval --config-override setting %s=%s\n", + $param, $opts{"config-override"}{$param}); + exit(1); + } + if ( !defined($newVars->{$param}) ) { + printf("Unkown config parameter %s in --config-override\n", $param); + exit(1); + } + $newConf->[$newVars->{$param}]{text} = $opts{"config-override"}{$param}; +} + +# +# Now backup and write the config file +# my $confCopy = "$dest.pre-__VERSION__"; if ( -f $dest && !-f $confCopy ) { # @@ -539,12 +826,15 @@ if ( -f $dest && !-f $confCopy ) { my $mode = $stat[2]; my $uid = $stat[4]; my $gid = $stat[5]; - die("can't copy($dest, $confCopy)\n") unless copy($dest, $confCopy); + die("can't copy($dest, $confCopy)\n") + unless copy($dest, $confCopy); die("can't chown $uid, $gid $confCopy\n") - unless chown($uid, $gid, $confCopy); - die("can't chmod $mode $confCopy\n") unless chmod($mode, $confCopy); + unless my_chown($uid, $gid, $confCopy); + die("can't chmod $mode $confCopy\n") + unless my_chmod($mode, $confCopy); } -open(OUT, ">$dest") || die("can't open $dest for writing\n"); +open(OUT, ">", $dest) || die("can't open $dest for writing\n"); +binmode(OUT); my $blockComment; foreach my $var ( @$newConf ) { if ( length($blockComment) @@ -562,14 +852,14 @@ foreach my $var ( @$newConf ) { } close(OUT); if ( !defined($oldConf) ) { - die("can't chmod 0640 mode $dest\n") unless chmod(0640, $dest); - die("can't chown $Uid, $Gid $dest\n") unless chown($Uid, $Gid, $dest); + die("can't chmod 0640 mode $dest\n") unless my_chmod(0640, $dest); + die("can't chown $Uid, $Gid $dest\n") unless my_chown($Uid, $Gid, $dest); } if ( $Conf{CgiDir} ne "" ) { - printf("Installing cgi script BackupPC_Admin in $Conf{CgiDir}\n"); - mkpath("$Conf{CgiDir}", 0, 0755); - InstallFile("cgi-bin/BackupPC_Admin", "$Conf{CgiDir}/BackupPC_Admin", + printf("Installing cgi script BackupPC_Admin in $DestDir$Conf{CgiDir}\n"); + mkpath("$DestDir$Conf{CgiDir}", 0, 0755); + InstallFile("cgi-bin/BackupPC_Admin", "$DestDir$Conf{CgiDir}/BackupPC_Admin", 04554); } @@ -578,27 +868,53 @@ print <$dest") || die("can't open $dest for writing\n"); + open(PROG, $prog) || die("can't open $prog for reading\n"); + open(OUT, ">", $dest) || die("can't open $dest for writing\n"); + binmode(PROG); + binmode(OUT); while ( ) { s/__INSTALLDIR__/$Conf{InstallDir}/g; + s/__LOGDIR__/$Conf{LogDir}/g; + s/__CONFDIR__/$Conf{ConfDir}/g; s/__TOPDIR__/$Conf{TopDir}/g; + s/^(\s*my \$useFHS\s*=\s*)\d;/${1}$opts{fhs};/ + if ( $prog =~ /Lib.pm/ ); s/__BACKUPPCUSER__/$Conf{BackupPCUser}/g; s/__CGIDIR__/$Conf{CgiDir}/g; + s/__IMAGEDIR__/$Conf{CgiImageDir}/g; + s/__IMAGEDIRURL__/$Conf{CgiImageDirURL}/g; if ( $first && /^#.*bin\/perl/ ) { - if ( $Perl56 ) { - # - # perl56 and later is taint ok - # - print OUT "#!$Conf{PerlPath} -T\n"; - } else { - # - # prior to perl56, File::Find fails taint checks, - # so we run without -T. It's still safe. - # - print OUT "#!$Conf{PerlPath}\n"; - } + # + # Fill in correct path to perl (no taint for >= 2.0.1). + # + print OUT "#!$Conf{PerlPath}\n"; } else { print OUT; } @@ -650,28 +966,35 @@ sub InstallFile close(PROG); close(OUT); } - die("can't chown $uid, $gid $dest") unless chown($uid, $gid, $dest); - die("can't chmod $mode $dest") unless chmod($mode, $dest); + die("can't chown $uid, $gid $dest") unless my_chown($uid, $gid, $dest); + die("can't chmod $mode $dest") unless my_chmod($mode, $dest); } sub FindProgram { my($path, $prog) = @_; + + if ( defined($opts{"bin-path"}{$prog}) ) { + return $opts{"bin-path"}{$prog}; + } foreach my $dir ( split(/:/, $path) ) { my $file = File::Spec->catfile($dir, $prog); return $file if ( -x $file ); } + return; } sub ConfigParse { my($file) = @_; open(C, $file) || die("can't open $file"); + binmode(C); my($out, @conf, $var); my $comment = 1; my $allVars = {}; + my $endLine = undef; while ( ) { - if ( /^#/ ) { + if ( /^#/ && !defined($endLine) ) { if ( $comment ) { $out .= $_; } else { @@ -699,7 +1022,10 @@ sub ConfigParse $out .= $_; } $var = $1; + $endLine = $1 if ( /^\s*\$Conf\{[^}]*} *= *<<(.*);/ ); + $endLine = $1 if ( /^\s*\$Conf\{[^}]*} *= *<<'(.*)';/ ); } else { + $endLine = undef if ( defined($endLine) && /^\Q$endLine[\n\r]*$/ ); $out .= $_; } } @@ -718,7 +1044,7 @@ sub ConfigMerge { my($old, $oldVars, $new, $newVars) = @_; my $posn = 0; - my $res; + my($res, $resVars); # # Find which config parameters are not needed any longer @@ -750,5 +1076,244 @@ sub ConfigMerge push(@$res, $new); } } - return $res; + for ( my $i = 0 ; $i < @$res ; $i++ ) { + $resVars->{$res->[$i]{var}} = $i; + } + return ($res, $resVars); +} + +sub my_chown +{ + my($uid, $gid, $file) = @_; + + return 1 if ( !$opts{"set-perms"} ); + return chown($uid, $gid, $file); +} + +sub my_chmod +{ + my ($mode, $file) = @_; + + return 1 if ( !$opts{"set-perms"} ); + return chmod($mode, $file); +} + +sub prompt +{ + my($question, $default, $option) = @_; + + $default = $opts{$option} if ( defined($opts{$option}) ); + if ( $opts{batch} ) { + print("$question [$default]\n"); + return $default; + } + print("$question [$default]? "); + my $reply = ; + $reply =~ s/[\n\r]*//g; + return $reply if ( $reply !~ /^$/ ); + return $default; } + +__END__ + +=head1 SYNOPSIS + +configure.pl [options] + +=head1 DESCRIPTION + +configure.pl is a script that is used to install or upgrade a BackupPC +installation. It is usually run interactively without arguments. It +also supports a batch mode where all the options can be specified +via the command-line. + +For upgrading BackupPC you need to make sure that BackupPC is not +running prior to running BackupPC. + +Typically configure.pl needs to run as the super user (root). + +=head1 OPTIONS + +=over 8 + +=item B<--batch> + +Run configure.pl in batch mode. configure.pl will run without +prompting the user. The other command-line options are used +to specify the settings that the user is usually prompted for. + +=item B<--backuppc-user=USER> + +Specify the BackupPC user name that owns all the BackupPC +files and runs the BackupPC programs. Default is backuppc. + +=item B<--bin-path PROG=PATH> + +Specify the path for various external programs that BackupPC +uses. Several --bin-path options may be specified. configure.pl +usually finds sensible defaults based on searching the PATH. +The format is: + + --bin-path PROG=PATH + +where PROG is one of perl, tar, smbclient, nmblookup, rsync, ping, +df, ssh, sendmail, hostname, split, par2, cat, gzip, bzip2 and +PATH is that full path to that program. + +Examples + + --bin-path cat=/bin/cat --bin-path bzip2=/home/user/bzip2 + +=item B<--compress-level=N> + +Set the configuration compression level to N. Default is 3 +if Compress::Zlib is installed. + +=item B<--config-dir CONFIG_DIR> + +Configuration directory for new installations. Defaults +to /etc/BackupPC with FHS. Automatically extracted +from --config-path for existing installations. + +=item B<--config-path CONFIG_PATH> + +Path to the existing config.pl configuration file for BackupPC. +This option should be specified for batch upgrades to an +existing installation. The option should be omitted when +doing a batch new install. + +=item B<--cgi-dir CGI_DIR> + +Path to Apache's cgi-bin directory where the BackupPC_Admin +script will be installed. This option only needs to be +specified for a batch new install. + +=item B<--data-dir DATA_DIR> + +Path to the BackupPC data directory. This is where all the backup +data is stored, and it should be on a large file system. This option +only needs to be specified for a batch new install. + +Example: + + --data-dir /data/BackupPC + +=item B<--dest-dir DEST_DIR> + +An optional prefix to apply to all installation directories. +Usually this is not needed, but certain auto-installers like +to stage an install in a temporary directory, and then copy +the files to their real destination. This option can be used +to specify the temporary directory prefix. Note that if you +specify this option, BackupPC won't run correctly if you try +to run it from below the --dest-dir directory, since all the +paths are set assuming BackupPC is installed in the intended +final locations. + +=item B<--fhs> + +Use locations specified by the Filesystem Hierarchy Standard +for installing BackupPC. This is enabled by default for new +installations. To use the pre-3.0 installation locations, +specify --no-fhs. + +=item B<--help|?> + +Print a brief help message and exits. + +=item B<--hostname HOSTNAME> + +Host name (this machine's name) on which BackupPC is being installed. +This option only needs to be specified for a batch new install. + +=item B<--html-dir HTML_DIR> + +Path to an Apache html directory where various BackupPC image files +and the CSS files will be installed. This is typically a directory +below Apache's DocumentRoot directory. This option only needs to be +specified for a batch new install. + +Example: + + --html-dir /var/www/htdocs/BackupPC + +=item B<--html-dir-url URL> + +The URL (without http://hostname) required to access the BackupPC html +directory specified with the --html-dir option. This option only needs +to be specified for a batch new install. + +Example: + + --html-dir-url /BackupPC + +=item B<--install-dir INSTALL_DIR> + +Installation directory for BackupPC scripts, libraries, and +documentation. This option only needs to be specified for a +batch new install. + +Example: + + --install-dir /usr/local/BackupPC + +=item B<--log-dir LOG_DIR> + +Log directory. Defaults to /var/log/BackupPC with FHS. + +=item B<--man> + +Prints the manual page and exits. + +=item B<--set-perms> + +When installing files and creating directories, chown them to +the BackupPC user and chmod them too. This is enabled by default. +To disable (for example, if staging a destination directory) +then specify --no-set-perms. + +=item B<--uid-ignore> + +configure.pl verifies that the script is being run as the super user +(root). Without the --uid-ignore option, in batch mode the script will +exit with an error if not run as the super user, and in interactive mode +the user will be prompted. Specifying this option will cause the script +to continue even if the user id is not root. + +=head1 EXAMPLES + +For a standard interactive install, run without arguments: + + configure.pl + +For a batch new install you need to specify answers to all the +questions that are normally prompted: + + configure.pl \ + --batch \ + --cgi-dir /var/www/cgi-bin/BackupPC \ + --data-dir /data/BackupPC \ + --hostname myHost \ + --html-dir /var/www/html/BackupPC \ + --html-dir-url /BackupPC \ + --install-dir /usr/local/BackupPC + +For a batch upgrade, you only need to specify the path to the +configuration file: + + configure.pl --batch --config-path /data/BackupPC/conf/config.pl + +=head1 AUTHOR + +Craig Barratt + +=head1 COPYRIGHT + +Copyright (C) 2001-2010 Craig Barratt. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +=cut