#! @PERL@
# Copyright (c) 2008-2012 Zmanda, Inc. All Rights Reserved.
# Copyright (c) 2013-2016 Carbonite, Inc. All Rights Reserved.
#
# 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.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Contact information: Carbonite Inc., 756 N Pastoria Ave
# Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
use lib '@amperldir@';
use strict;
use warnings;
use Amanda::Config qw( :getconf :init );
use Amanda::Debug qw( :logging );
use Amanda::Util qw( :constants );
use Amanda::Paths;
use Amanda::Constants;
eval 'use Amanda::Disklist;'; # can fail if compiled for client only
use Getopt::Long;
# Implementation note: this application is a bit funny, because it does not
# set up Amanda fully until some time into processing. This lets it respond
# with build configuration information without a config file, and lets it set
# up debugging for the caller.
#
# The most obvious consequence is that, rather than calling die (which interfaces
# with Amanda::Debug), this file uses a locally defined 'fail' to print error
# messages.
sub usage {
print <<EOF;
Usage: amgetconf [--platform] [--distro] [--client] [--execute-where client|server] [-l|--list] [-o configoption]* <config> <paramname>
(any ordering of options and arguments is acceptable)
--client is equivalent to --execute-where client
--execute-where tells amgetconf whether to operate on the client or the
server; the server is the default.
paramname can be one of
dbopen.APPNAME -- open a debug file
dbclose.APPNAME:FILENAME -- close debug file FILENAME
build.PARAM -- get a build parameter
PARAM -- get an Amanda configuration parameter
For all but Amanda configuration parameters, the <config> option is
ignored, but must be present. For Amanda configuration parameters,
values in subsections are specified in the form TYPE:NAME:PARAMETER.
With --list, PARAM can be one of
EOF
for my $name (sort keys %Amanda::Config::subsection_names) {
print " $name\n"
if $Amanda::Config::subsection_names{$name};
}
exit(1);
}
sub fail {
print STDERR @_, "\n";
exit(1);
}
sub no_such_param {
my ($parameter) = @_;
fail("amgetconf: no such parameter \"$parameter\"");
}
## build parameters
my %build_info = (
# NOTE TO MAINTAINERS:
# If you add to this list, be sure to also add the new parameter
# amgetconf(8) manual page. Note that all keys are lower-case.
## directories from Amanda::Paths
'bindir' => $bindir,
'sbindir' => $sbindir,
'libdir' => $libdir,
'amlibdir' => $amlibdir,
'libexecdir' => $libexecdir,
'amlibexecdir' => $amlibexecdir,
'amdatadir' => $amdatadir,
'amperldir' => $amperldir,
'mandir' => $mandir,
'amanda_tmpdir' => $AMANDA_TMPDIR,
'config_dir' => $CONFIG_DIR,
'amanda_dbgdir' => $AMANDA_DBGDIR,
'application_dir' => $APPLICATION_DIR,
'gnutar_listed_incremental_dir' => $GNUTAR_LISTED_INCREMENTAL_DIR,
'listed_inc_dir' => $GNUTAR_LISTED_INCREMENTAL_DIR, # (historical alias)
'security_file' => $SECURITY_FILE,
'amandates_file' => $AMANDATES_FILE,
## constants from Amanda::Constants
# build environment info
'cc' => $Amanda::Constants::CC,
'version' => $Amanda::Constants::VERSION,
'assertions' => $Amanda::Constants::ASSERTIONS,
'use_version_suffixes' => 'no', # for backward compatibility
'locking' => $Amanda::Constants::LOCKING,
# executable paths
'dump' => $Amanda::Constants::DUMP,
'restore' => $Amanda::Constants::RESTORE,
'vdump' => $Amanda::Constants::VDUMP,
'vrestore' => $Amanda::Constants::VRESTORE,
'xfsdump' => $Amanda::Constants::XFSDUMP,
'xfsrestore' => $Amanda::Constants::XFSRESTORE,
'vxdump' => $Amanda::Constants::VXDUMP,
'vxrestore' => $Amanda::Constants::VXRESTORE,
'samba_client' => $Amanda::Constants::SAMBA_CLIENT,
'bsdtar' => $Amanda::Constants::BSDTAR,
'gnutar' => $Amanda::Constants::GNUTAR,
'star' => $Amanda::Constants::STAR,
'bsdtar_path' => $Amanda::Constants::BSDTAR,
'gnutar_path' => $Amanda::Constants::GNUTAR,
'star_path' => $Amanda::Constants::STAR,
'compress_path' => $Amanda::Constants::COMPRESS_PATH,
'uncompress_path' => $Amanda::Constants::UNCOMPRESS_PATH,
'aix_backup' => $Amanda::Constants::AIX_BACKUP,
'dump_returns_1' => $Amanda::Constants::DUMP_RETURNS_1,
# amanda modules
'bsd_security' => $Amanda::Constants::BSD_SECURITY,
'bsdudp_security' => $Amanda::Constants::BSDUDP_SECURITY,
'bsdtcp_security' => $Amanda::Constants::BSDTCP_SECURITY,
'krb5_security' => $Amanda::Constants::KRB5_SECURITY,
'ssh_security' => $Amanda::Constants::SSH_SECURITY,
'rsh_security' => $Amanda::Constants::RSH_SECURITY,
'use_amandahosts' => $Amanda::Constants::USE_AMANDAHOSTS,
# build-time constants
'amanda_debug_days' => $Amanda::Constants::AMANDA_DEBUG_DAYS,
'default_server' => $Amanda::Constants::DEFAULT_SERVER,
'default_amandates_file' => $Amanda::Constants::DEFAULT_AMANDATES_FILE,
'default_config' => $Amanda::Constants::DEFAULT_CONFIG,
'default_tape_server' => $Amanda::Constants::DEFAULT_TAPE_SERVER,
'default_tape_device' => $Amanda::Constants::DEFAULT_TAPE_DEVICE,
'client_login' => $Amanda::Constants::CLIENT_LOGIN,
'use_rundump' => $Amanda::Constants::USE_RUNDUMP,
'check_userid' => $Amanda::Constants::CHECK_USERID,
# compression information
'compress_suffix' => $Amanda::Constants::COMPRESS_SUFFIX,
'compress_fast_opt' => $Amanda::Constants::COMPRESS_FAST_OPT,
'compress_best_opt' => $Amanda::Constants::COMPRESS_BEST_OPT,
'uncompress_opt' => $Amanda::Constants::UNCOMPRESS_OPT,
# (for testing purposes)
'__empty' => '',
);
sub build_param {
my ($parameter, $opt_list) = @_;
if ($opt_list) {
usage() unless ($parameter eq "build");
for my $pname (sort keys %build_info) {
print "$pname\n";
}
} else {
my ($pname) = $parameter =~ /^build\.(.*)/;
no_such_param($parameter) unless exists $build_info{lc $pname};
my $val = $build_info{lc $pname};
print "$val\n";
}
}
## dbopen or dbclose
sub db_param {
my ($parameter, $opt_list) = @_;
my ($appname, $filename);
# copy amgetconf pname and pcontext
my $pname = Amanda::Util::get_pname();
my $pcontext = Amanda::Util::get_pcontext();
if (($appname) = $parameter =~ /^dbopen\.(.*)/) {
$appname =~ s/[^[:alnum:]]/_/g;
# set pname and pcontext for the application
Amanda::Util::set_pname($appname);
Amanda::Util::set_pcontext($CONTEXT_CMDLINE);
Amanda::Debug::dbopen("server");
print Amanda::Debug::dbfn(), "\n";
} elsif (($appname, $filename) = $parameter =~ /^dbclose\.([^:]*):(.*)/) {
fail("debug file $filename does not exist") unless (-f $filename);
# set pname and pcontext for the application
Amanda::Util::set_pname($appname);
Amanda::Util::set_pcontext($CONTEXT_CMDLINE);
Amanda::Debug::dbreopen($filename, '');
Amanda::Debug::dbclose();
print "$filename\n";
} else {
fail("cannot parse $parameter");
}
# reset pname and pcontext for amgetconf
Amanda::Util::set_pcontext($pcontext);
Amanda::Util::set_pname($pname);
}
## regular configuration parameters
sub conf_param {
my ($parameter, $opt_list) = @_;
if ($opt_list) {
# getconf_list will return an empty list for any unrecognized name,
# so first check that the user has supplied a real subsection
no_such_param($parameter)
unless defined($Amanda::Config::subsection_names{$parameter});
my @list = getconf_list($parameter);
for my $subsec (@list) {
print "$subsec\n";
}
} elsif ($parameter =~ /^property:/i) {
my %properties = %{ getconf($CNF_PROPERTY)};
my $propname = $parameter;
$propname =~ s/^property://i;
$propname = lc($propname);
if (exists $properties{$propname}) {
print $properties{$propname}->{'values'}[0], "\n";
}
} elsif ($parameter =~ /^device-property:/i ||
$parameter =~ /^device_property:/i) {
my %properties = %{ getconf($CNF_DEVICE_PROPERTY) };
my $propname = $parameter;
$propname =~ s/^device-property://i;
$propname =~ s/^device_property://i;
$propname = lc($propname);
if (exists $properties{$propname}) {
print $properties{$propname}->{'values'}[0], "\n";
}
} else {
my @strs = getconf_byname_strs($parameter, 0);
no_such_param($parameter)
unless @strs;
for my $str (@strs) {
print "$str\n";
}
}
}
Amanda::Util::setup_application("amgetconf", "server", $CONTEXT_SCRIPTUTIL, "amanda", "amanda");
## Command-line parsing
my $opt_list = '';
my $config_overrides = new_config_overrides($#ARGV+1);
my $execute_where = undef;
my $opt_platform,
my $opt_distro,
debug("Arguments: " . join(' ', @ARGV));
Getopt::Long::Configure(qw{bundling});
GetOptions(
'version' => \&Amanda::Util::version_opt,
'list|l' => \$opt_list,
'o=s' => sub { add_config_override_opt($config_overrides, $_[1]); },
'platform' => \$opt_platform,
'distro' => \$opt_distro,
'execute-where=s' => sub {
my $where = lc($_[1]);
fail("Invalid value ($_[1]) for --execute-where. Must be client or server.")
unless $where eq 'client' or $where eq 'server';
fail("--execute-where=server conflicts with --execute-where=client or --client.")
unless !defined($execute_where) || (
($where eq 'client' && $execute_where) ||
($where eq 'server' && !$execute_where));
$execute_where = ($where eq 'client')? $CONFIG_INIT_CLIENT : 0;
},
'client' => sub {
fail("--execute-where=server conflicts with --execute-where=client or --client.")
unless !defined($execute_where) || $execute_where;
$execute_where = $CONFIG_INIT_CLIENT;
}
) or usage();
my $config_name;
my $parameter;
if (defined $opt_platform) {
my $platform = Amanda::Util::get_platform();
print "$platform\n";
exit 0;
}
if (defined $opt_distro) {
my $distro = Amanda::Util::get_distro();
print "$distro\n";
exit 0;
}
if (@ARGV == 1) {
$parameter = $ARGV[0];
} elsif (@ARGV >= 2) {
# note that we ignore any arguments past these two. Amdump lazily passes
# such arguments on to us, so we have no choice.
$config_name = $ARGV[0];
$parameter = $ARGV[1];
} else {
usage();
}
## Now start looking at the parameter.
if ($parameter =~ /^build(?:\..*)?/) {
config_init($CONFIG_INIT_GLOBAL|$execute_where, undef);
build_param($parameter, $opt_list);
Amanda::Util::finish_application();
exit(0);
}
if ($parameter =~ /^db(open|close)\./) {
config_init($CONFIG_INIT_GLOBAL|$execute_where, undef);
db_param($parameter, $opt_list);
Amanda::Util::finish_application();
exit(0);
}
# finally, finish up the application startup procedure
set_config_overrides($config_overrides);
if ($execute_where == $CONFIG_INIT_CLIENT &&
defined($config_name) && $config_name eq '.') {
config_init_with_global($CONFIG_INIT_USE_CWD | $execute_where, undef);
} elsif ($execute_where == $CONFIG_INIT_CLIENT &&
defined($config_name) && $config_name ne '.') {
config_init_with_global($CONFIG_INIT_EXPLICIT_NAME | $execute_where, $config_name);
} elsif ($execute_where == $CONFIG_INIT_CLIENT) {
config_init($execute_where|$CONFIG_INIT_GLOBAL, undef);
} else {
config_init_with_global($CONFIG_INIT_EXPLICIT_NAME | $CONFIG_INIT_USE_CWD | $execute_where, $config_name);
}
my ($cfgerr_level, @cfgerr_errors) = config_errors();
if ($cfgerr_level >= $CFGERR_WARNINGS) {
config_print_errors();
if ($cfgerr_level >= $CFGERR_ERRORS) {
die("errors processing config file");
}
}
Amanda::Util::finish_setup($RUNNING_AS_ANY);
if ($execute_where != $CONFIG_INIT_CLIENT && defined $config_name) {
my $diskfile = Amanda::Config::config_dir_relative(getconf($CNF_DISKFILE));
$cfgerr_level = Amanda::Disklist::read_disklist('filename' => $diskfile);
if ($cfgerr_level >= $CFGERR_ERRORS) {
die "Errors processing disklist";
}
}
conf_param($parameter, $opt_list);
Amanda::Util::finish_application();