930 lines
26 KiB
Perl
Executable File
930 lines
26 KiB
Perl
Executable File
#!/usr/bin/perl -w
|
|
|
|
#
|
|
# A simple configuration file builder based on questions listed in
|
|
# its own configuration file. It would certainly be easy to use this
|
|
# for other (non-snmp) programs as well.
|
|
#
|
|
|
|
use Getopt::Std;
|
|
use Term::ReadLine;
|
|
use IO::File;
|
|
use Data::Dumper;
|
|
use File::Copy;
|
|
if ($^O eq 'MSWin32') {
|
|
eval 'require Win32::Registry;';
|
|
if ($@) {
|
|
print "\nWarning: Perl module Win32::Registry is not installed. This module is\n";
|
|
print " required to read the SNMPSHAREPATH and SNMPCONFPATH values from \n";
|
|
print " the registry. To use snmpconf without the module you need to\n";
|
|
print " define SNMPSHAREPATH and SNMPCONFPATH as environment variables\n";
|
|
print " or use the -c and -I command line options.\n";
|
|
}
|
|
}
|
|
|
|
# globals
|
|
%tokenitems=qw(line 1 info 1 comment 1);
|
|
%arrayitems=qw(question 1 validanswer 1);
|
|
|
|
# default folder for snmpconf-data
|
|
if (defined(&my_getenv("SNMPSHAREPATH"))) {
|
|
$opts{'c'} = &my_getenv("SNMPSHAREPATH") . "/snmpconf-data";
|
|
}
|
|
else {
|
|
$opts{'c'} = "/usr/local/share/snmp/snmpconf-data";
|
|
}
|
|
|
|
# default config file path
|
|
if (defined(&my_getenv("SNMPCONFPATH"))) {
|
|
$confpath = &my_getenv("SNMPCONFPATH");
|
|
}
|
|
else {
|
|
$confpath = "/usr/local/share/snmp";
|
|
}
|
|
|
|
# home environment variable
|
|
if (defined(&my_getenv("HOME"))) {
|
|
$home = &my_getenv("HOME") . "/.snmp";
|
|
}
|
|
else {
|
|
$home = "(HOME dir - n/a)";
|
|
}
|
|
|
|
# read the argument string
|
|
getopts("qadhfc:piI:r:R:g:G", \%opts);
|
|
|
|
# display help
|
|
if ($opts{'h'}) {
|
|
print "$0 [options] [FILETOCREATE...]\n";
|
|
print "options:\n";
|
|
print " -f overwrite existing files without prompting\n";
|
|
print " -i install created files into $confpath.\n";
|
|
print " -p install created files into $home.\n";
|
|
print " -I DIR install created files into DIR.\n";
|
|
print " -a Don't ask any questions, just read in current\n";
|
|
print " current .conf files and comment them\n";
|
|
print " -r all|none Read in all or none of the .conf files found.\n";
|
|
print " -R file,... Read in a particular list of .conf files.\n";
|
|
print " -g GROUP Ask a series of GROUPed questions.\n";
|
|
print " -G List known GROUPs.\n";
|
|
print " -c conf_dir use alternate configuration directory.\n";
|
|
print " -q run more quietly with less advice.\n";
|
|
print " -d turn on debugging output.\n";
|
|
print " -D turn on debugging dumper output.\n";
|
|
exit;
|
|
}
|
|
|
|
# setup terminal interface.
|
|
$ENV{'PERL_RL'}='o=0' if (!exists($ENV{'PERL_RL'}));
|
|
$term = new Term::ReadLine 'snmpconf';
|
|
|
|
# read in configuration file set
|
|
read_config_files($opts{'c'}, \%filetypes);
|
|
debug(my_Dumper(\%filetypes));
|
|
|
|
if ($opts{'G'}) {
|
|
Print("\nKnown GROUPs of tokens:\n\n");
|
|
foreach my $group (keys(%groups)) {
|
|
print " $group\n";
|
|
}
|
|
Print("\n");
|
|
exit;
|
|
}
|
|
|
|
#
|
|
# Expand the search path in case it contains multiple directories.
|
|
#
|
|
my $ENV_SEPARATOR = '@ENV_SEPARATOR@';
|
|
my @searchpath = split(/$ENV_SEPARATOR/, $confpath);
|
|
push @searchpath, "/usr/local/etc/snmp";
|
|
push @searchpath, ".";
|
|
push @searchpath, "$home";
|
|
|
|
# Remove trailing /'s or \'s
|
|
for (my $i=0; $i <= $#searchpath; $i++) {
|
|
$searchpath[$i] =~ /(.*?)([\/\\])*$/;
|
|
$searchpath[$i] = $1;
|
|
}
|
|
|
|
# Determine persistent directory. Order of preference:
|
|
#
|
|
# file in SNMP_PERSISTENT_FILE environment variable
|
|
# directory defined by persistentDir snmp.conf variable
|
|
# directory in SNMP_PERSISTENT_DIR environment variable
|
|
# default PERSISTENT_DIRECTORY directory
|
|
my $persistentDir = "";
|
|
my $persistentFile = "";
|
|
|
|
# SNMP_PERSISTENT_FILE environment variable
|
|
if (defined(&my_getenv("SNMP_PERSISTENT_FILE"))) {
|
|
$persistentFile = &my_getenv("SNMP_PERSISTENT_FILE");
|
|
debug ("persistent file: SNMP_PERSISTENT_FILE environment variable set\n");
|
|
}
|
|
|
|
# snmp.conf persistentDir
|
|
if (!($persistentDir) && !($persistentFile)) {
|
|
foreach my $i (@searchpath) {
|
|
debug ("Searching file $i/snmp.conf for persistentDir\n");
|
|
my $temp = get_persistentDir("$i/snmp.conf");
|
|
if ($temp) {
|
|
debug("persistent directory: set to $temp in $i/snmp.conf\n");
|
|
$persistentDir = $temp;
|
|
last;
|
|
}
|
|
}
|
|
}
|
|
|
|
# SNMP_PERSISTENT_DIR environment variable
|
|
if (!($persistentDir) && !($persistentFile)) {
|
|
if (&my_getenv("SNMP_PERSISTENT_DIR")) {
|
|
$persistentDir = &my_getenv("SNMP_PERSISTENT_DIR");
|
|
debug ("persistent directory: SNMP_PERSISTENT_DIR environment variable set\n");
|
|
}
|
|
}
|
|
|
|
# PERSISTENT_DIRECTORY default variable
|
|
if (!($persistentDir) && !($persistentFile)) {
|
|
$persistentDir = "/var/net-snmp";
|
|
debug ("persistent directory: Using default value\n");
|
|
}
|
|
|
|
# Rebuild search path without persistent folder
|
|
# Note: persistent file handled in Find existing
|
|
# files to possibly read in section
|
|
if ($persistentDir) {
|
|
# Remove trailing /'s or \'s
|
|
$persistentDir =~ /(.*?)([\/\\])*$/;
|
|
$persistentDir = $1;
|
|
debug ("persistent directory: $persistentDir\n");
|
|
|
|
my @searchpath_old = @searchpath;
|
|
@searchpath = ();
|
|
foreach my $path_temp (@searchpath_old) {
|
|
if ($path_temp eq $persistentDir) {
|
|
debug("skipping persistent directory $path_temp\n");
|
|
next;
|
|
}
|
|
push @searchpath, $path_temp;
|
|
}
|
|
}
|
|
|
|
# Reset $confpath to the first path
|
|
$confpath = $searchpath[0];
|
|
|
|
#
|
|
# Find existing files to possibly read in.
|
|
#
|
|
push @searchpath, $opts{I} if ($opts{I});
|
|
foreach my $i (@searchpath) {
|
|
debug("searching $i\n");
|
|
foreach my $ft (keys(%filetypes)) {
|
|
if ("$i/$ft" eq $persistentFile) {
|
|
debug("skipping persistent file $i/$ft\n");
|
|
next;
|
|
}
|
|
debug("searching for $i/$ft\n");
|
|
$knownfiles{"$i/$ft"} = $ft if (-f "$i/$ft");
|
|
my $localft = $ft;
|
|
$localft =~ s/.conf/.local.conf/;
|
|
$knownfiles{"$i/$localft"} = $ft if (-f "$i/$localft");
|
|
}
|
|
}
|
|
|
|
#
|
|
# Ask the user if they want them to be read in and read them
|
|
#
|
|
if (keys(%knownfiles)) {
|
|
my @files;
|
|
if (defined($opts{'r'})) {
|
|
if ($opts{'r'} eq "all" || $opts{'r'} eq "a") {
|
|
@files = keys(%knownfiles);
|
|
} elsif ($opts{'r'} ne "none" && $opts{'r'} ne "n") {
|
|
print "unknown argument to -r: $opts{'r'}\n";
|
|
exit(1);
|
|
}
|
|
} elsif(defined($opts{'R'})) {
|
|
@files = split(/\s*,\s*/,$opts{'R'});
|
|
foreach my $i (@files) {
|
|
my $x = $i;
|
|
$x =~ s/.*\/([^\/]+)$/$1/;
|
|
$knownfiles{$i} = $x;
|
|
}
|
|
Print("reading: ", join(",",@files),"\n");
|
|
} else {
|
|
@files = display_menu(-head => "The following installed configuration files were found:\n",
|
|
-tail => "Would you like me to read them in? Their content will be merged with the\noutput files created by this session.\n\nValid answer examples: \"all\", \"none\",\"3\",\"1,2,5\"\n",
|
|
-multiple => 1,
|
|
-question => 'Read in which',
|
|
-defaultvalue => 'all',
|
|
sort keys(%knownfiles));
|
|
}
|
|
foreach my $i (@files) {
|
|
debug("reading $i\n");
|
|
read_config($i, $knownfiles{$i});
|
|
}
|
|
}
|
|
|
|
if ($opts{'g'}) {
|
|
my @groups = split(/,:\s/,$opts{'g'});
|
|
foreach my $group (@groups) {
|
|
do_group($group);
|
|
}
|
|
} elsif ($#ARGV >= 0) {
|
|
#
|
|
# loop through requested files.
|
|
#
|
|
foreach my $i (@ARGV) {
|
|
if (!defined($filetypes{$i})) {
|
|
warn "invalid file: $i\n";
|
|
} else {
|
|
if ($opts{'a'}) {
|
|
$didfile{$i} = 1;
|
|
} else {
|
|
build_file($term, $i, $filetypes{$i});
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
#
|
|
# ask user to select file type to operate on.
|
|
#
|
|
while(1) {
|
|
my $line = display_menu(-head => "I can create the following types of configuration files for you.\nSelect the file type you wish to create:\n(you can create more than one as you run this program)\n",
|
|
-question => 'Select File',
|
|
-otheranswers => ['quit'],
|
|
-mapanswers => { 'q' => 'quit' },
|
|
keys(%filetypes));
|
|
last if ($line eq "quit");
|
|
debug("file selected: $line\n");
|
|
build_file($term, $line, $filetypes{$line});
|
|
}
|
|
}
|
|
|
|
#
|
|
# Write out the results to the output files.
|
|
#
|
|
output_files(\%filetypes, $term);
|
|
|
|
|
|
#
|
|
# Display the files that have been created for the user.
|
|
#
|
|
Print("\n\nThe following files were created:\n\n");
|
|
@didfiles = keys(%didfile);
|
|
foreach my $i (@didfiles) {
|
|
if ($didfile{$i} ne "1") {
|
|
if ($opts{'i'} || $opts{'I'}) {
|
|
$opts{'I'} = "$confpath" if (!$opts{'I'});
|
|
|
|
if (! (-d "$opts{'I'}") && ! (mkdir ("$opts{'I'}", 0755))) {
|
|
print "\nCould not create $opts{'I'} directory: $!\n";
|
|
print ("File $didfile{$i} left in current directory\n");
|
|
}
|
|
else {
|
|
move ("$opts{'I'}/$i", "$opts{'I'}/$i.bak") if (-f "$opts{'I'}/$i");
|
|
if (move ("$didfile{$i}", "$opts{'I'}")) {
|
|
print(" $didfile{$i} installed in $opts{'I'}\n");
|
|
}
|
|
else {
|
|
print "\nCould not move file $didfile{$i} to $opts{'I'}/$i: $!\n";
|
|
print ("File $didfile{$i} left in current directory\n");
|
|
}
|
|
}
|
|
} elsif ($opts{'p'}) {
|
|
if (! (-d "$home") && ! (mkdir ("$home", 0755))) {
|
|
print "\nCould not create $home directory: $!\n";
|
|
print ("File $didfile{$i} left in current directory\n");
|
|
}
|
|
else {
|
|
move ("$home/$i", "$home/$i.bak") if (-f "$home/$i");
|
|
if (move ("$didfile{$i}", "$home")) {
|
|
print(" $didfile{$i} installed in $home\n");
|
|
}
|
|
else {
|
|
print "\nCould not move file $didfile{$i} to $home: $!\n";
|
|
print ("File $didfile{$i} left in current directory\n");
|
|
}
|
|
}
|
|
} else {
|
|
Print(" $didfile{$i} ",
|
|
($i ne $didfile{$i})?"[ from $i specifications]":" ","\n");
|
|
if ($opts{'d'}) {
|
|
open(I,$didfile{$i});
|
|
debug(" " . join(" ",<I>) . "\n");
|
|
close(I);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!$opts{'p'} && !$opts{'i'} && !$opts{'I'}) {
|
|
Print("\nThese files should be moved to $confpath if you
|
|
want them used by everyone on the system. In the future, if you add
|
|
the -i option to the command line I'll copy them there automatically for you.
|
|
|
|
Or, if you want them for your personal use only, copy them to
|
|
$home . In the future, if you add the -p option to the
|
|
command line I'll copy them there automatically for you.
|
|
|
|
");
|
|
}
|
|
|
|
###########################################################################
|
|
# Functions
|
|
###########################################################################
|
|
|
|
sub Print {
|
|
print @_ if (!$opts{'q'});
|
|
}
|
|
#
|
|
# handle a group of questions
|
|
#
|
|
sub get_yn_maybe {
|
|
my $question = shift;
|
|
my $ans = "y";
|
|
if ($question ne "") {
|
|
$ans = get_answer($term, $question,
|
|
valid_answers(qw(yes y no n)), 'y');
|
|
}
|
|
return ($ans =~ /^y/)?1:0;
|
|
}
|
|
|
|
sub do_group {
|
|
my $group = shift;
|
|
die "no such group $group\n" if (!$groups{$group});
|
|
foreach my $token (@{$groups{$group}}) {
|
|
if ($token->[0] eq "message") {
|
|
Print ("$token->[1] $token->[2]\n");
|
|
} elsif ($token->[0] eq "subgroup") {
|
|
do_group($token->[1]) if (get_yn_maybe($token->[2]));
|
|
} elsif (defined($tokenmap{$token->[1]})) {
|
|
if (get_yn_maybe($token->[2])) {
|
|
do {
|
|
do_line($token->[1], $tokenmap{$token->[1]});
|
|
} until ($token->[0] ne "multiple" ||
|
|
get_answer($term, "Do another $token->[1] line?",
|
|
valid_answers(qw(yes y no n)), 'y')
|
|
=~ /n/);
|
|
}
|
|
} elsif (defined($filetypes{$token->[1]})) {
|
|
$didfile{$token->[1]} = 1;
|
|
} else {
|
|
die "invalid member $token->[1] of group $group\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
#
|
|
# build a particular type of file by operating on sections
|
|
#
|
|
sub build_file {
|
|
my ($term, $filename, $fileconf) = @_;
|
|
$didfile{$filename} = 1;
|
|
my (@lines);
|
|
while(1) {
|
|
my $line = display_menu(-head => "The configuration information which can be put into $filename is divided\ninto sections. Select a configuration section for $filename\nthat you wish to create:\n",
|
|
-otheranswers => ['finished'],
|
|
-mapanswers => { 'f' => 'finished' },
|
|
-question => "Select section",
|
|
-numeric => 1,
|
|
map { $_->{'title'}[0] } @$fileconf);
|
|
|
|
return @lines if ($line eq "finished");
|
|
do_section($fileconf->[$line-1]);
|
|
}
|
|
}
|
|
|
|
#
|
|
# configure a particular section by operating on token types
|
|
#
|
|
sub do_section {
|
|
my $confsect = shift;
|
|
my @lines;
|
|
while(1) {
|
|
Print ("\nSection: $confsect->{'title'}[0]\n");
|
|
Print ("Description:\n");
|
|
Print (" ", join("\n ",@{$confsect->{'description'}}),"\n");
|
|
my $line =
|
|
display_menu(-head => "Select from:\n",
|
|
-otheranswers => ['finished','list'],
|
|
-mapanswers => { 'f' => 'finished',
|
|
'l' => 'list' },
|
|
-question => 'Select section',
|
|
-descriptions => [map { $confsect->{$_}{info}[0] }
|
|
@{$confsect->{'thetokens'}}],
|
|
@{$confsect->{'thetokens'}});
|
|
return @lines if ($line eq "finished");
|
|
if ($line eq "list") {
|
|
print "Lines defined for section \"$confsect->{title}[0]\" so far:\n";
|
|
foreach my $i (@{$confsect->{'thetokens'}}) {
|
|
if ($#{$confsect->{$i}{'results'}} >= 0) {
|
|
print " ",join("\n ",@{$confsect->{$i}{'results'}}),"\n";
|
|
}
|
|
}
|
|
next;
|
|
}
|
|
do_line($line, $confsect->{$line});
|
|
}
|
|
return;
|
|
}
|
|
|
|
#
|
|
# Ask all the questions related to a particular line type
|
|
#
|
|
sub do_line {
|
|
my $token = shift;
|
|
my $confline = shift;
|
|
my (@answers, $counter, $i);
|
|
# debug(my_Dumper($confline));
|
|
Print ("\nConfiguring: $token\n");
|
|
Print ("Description:\n ",join("\n ",@{$confline->{'info'}}),"\n\n");
|
|
for($i=0; $i <= $#{$confline->{'question'}}; $i++) {
|
|
if (defined($confline->{'question'}[$i]) &&
|
|
$confline->{'question'}[$i] ne "") {
|
|
my $q = $confline->{'question'}[$i];
|
|
$q =~ s/\$(\d+)/$answers[$1]/g;
|
|
debug("after: $term, $q, ",$confline->{'validanswer'}[$i],"\n");
|
|
$answers[$i] = get_answer($term, $q,
|
|
$confline->{'validanswer'}[$i]);
|
|
$answers[$i] =~ s/\"/\\\"/g;
|
|
$answers[$i] = '"' . $answers[$i] . '"' if ($answers[$i] =~ /\s/);
|
|
}
|
|
}
|
|
if ($#{$confline->{'line'}} == -1) {
|
|
my ($i,$line);
|
|
for($i=0; $i <= $#{$confline->{'question'}}; $i++) {
|
|
next if (!defined($confline->{'question'}[$i]) ||
|
|
$confline->{'question'}[$i] eq "");
|
|
$line .= " \$" . $i;
|
|
}
|
|
push @{$confline->{'line'}}, $line;
|
|
}
|
|
|
|
foreach my $line (@{$confline->{'line'}}) {
|
|
my $finished = $line;
|
|
debug("preline: $finished\n");
|
|
debug("answers: ",my_Dumper(\@answers));
|
|
$finished =~ s/\$(\d+)/$answers[$1]/g;
|
|
if ($line =~ s/^eval\s+//) {
|
|
debug("eval: $finished\n");
|
|
$finished = eval $finished;
|
|
debug("eval results: $finished\n");
|
|
}
|
|
$finished = $token . " " . $finished;
|
|
Print ("\nFinished Output: $finished\n");
|
|
push @{$confline->{'results'}},$finished;
|
|
}
|
|
}
|
|
|
|
#
|
|
# read all sets of config files in the various subdirectories.
|
|
#
|
|
sub read_config_files {
|
|
my $readdir = shift;
|
|
my $filetypes = shift;
|
|
opendir(DH, $readdir) || die "no such directory $readdir, did you run make install?\n";
|
|
my $dir;
|
|
my $configfilename="snmpconf-config";
|
|
|
|
while(defined($dir = readdir(DH))) {
|
|
next if ($dir =~ /^\./);
|
|
next if ($dir =~ /CVS/);
|
|
debug("dir entry: $dir\n");
|
|
if (-d "$readdir/$dir" && -f "$readdir/$dir/$configfilename") {
|
|
|
|
my $conffile;
|
|
|
|
# read the top level configuration inforamation about the direcotry.
|
|
open(I, "$readdir/$dir/$configfilename");
|
|
while(<I>) {
|
|
$conffile = $1 if (/forconffile: (.*)/);
|
|
}
|
|
close(I);
|
|
|
|
# no README informatino.
|
|
if ($conffile eq "") {
|
|
print STDERR "Warning: No 'forconffile' information in $readdir/$dir/$configfilename\n";
|
|
next;
|
|
}
|
|
|
|
# read all the daat in the directory
|
|
$filetypes->{$conffile} = read_config_items("$readdir/$dir", $conffile);
|
|
} else {
|
|
# no README informatino.
|
|
print STDERR "Warning: No $configfilename file found in $readdir/$dir\n";
|
|
}
|
|
}
|
|
closedir DH;
|
|
}
|
|
|
|
#
|
|
# read each configuration file in a directory
|
|
#
|
|
sub read_config_items {
|
|
my $itemdir = shift;
|
|
my $type = shift;
|
|
opendir(ITEMS, $itemdir);
|
|
my $file;
|
|
my @results;
|
|
while(defined($file = readdir(ITEMS))) {
|
|
next if ($file =~ /~$/);
|
|
next if ($file =~ /^snmpconf-config$/);
|
|
if (-f "$itemdir/$file") {
|
|
my $res = read_config_item("$itemdir/$file", $type);
|
|
if (scalar(keys(%$res)) > 0) {
|
|
push @results, $res;
|
|
}
|
|
}
|
|
}
|
|
closedir(ITEMS);
|
|
return \@results;
|
|
}
|
|
|
|
#
|
|
# mark a list of tokens as a special "group"
|
|
#
|
|
sub read_config_group {
|
|
my ($fh, $group, $type) = @_;
|
|
my $line;
|
|
debug("handling group $group\n");
|
|
push (@{$groups{$group}},['filetype', $type]);
|
|
while($line = <$fh>) {
|
|
chomp($line);
|
|
next if ($line =~ /^\s*$/);
|
|
next if ($line =~ /^\#/);
|
|
return $line if ($line !~ /^(single|multiple|message|filetype|subgroup)/);
|
|
my ($type, $token, $rest) = ($line =~ /^(\w+)\s+([^\s]+)\s*(.*)/);
|
|
debug ("reading group $group : $type -> $token -> $rest\n");
|
|
push (@{$groups{$group}}, [$type, $token, $rest]);
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
#
|
|
# Parse one file
|
|
#
|
|
sub read_config_item {
|
|
my $itemfile = shift;
|
|
my $itemcount;
|
|
my $type = shift;
|
|
my $fh = new IO::File($itemfile);
|
|
return if (!defined($fh));
|
|
my (%results, $curtoken);
|
|
debug("tokenitems: ", my_Dumper(\%tokenitems));
|
|
topwhile:
|
|
while($line = <$fh>) {
|
|
next if ($line =~ /^\s*\#/);
|
|
my ($token, $rest) = ($line =~ /^(\w+)\s+(.*)/);
|
|
next if (!defined($token) || !defined($rest));
|
|
while ($token eq 'group') {
|
|
# handle special group list
|
|
my $next = read_config_group($fh, $rest,$type);
|
|
if ($next) {
|
|
($token, $rest) = ($next =~ /^(\w+)\s+(.*)/);
|
|
} else {
|
|
next topwhile;
|
|
}
|
|
}
|
|
debug("token: $token => $rest\n");
|
|
if ($token eq 'steal') {
|
|
foreach my $stealfrom (keys(%{$results{$rest}})) {
|
|
if (!defined($results{$curtoken}{$stealfrom})) {
|
|
@{$results{$curtoken}{$stealfrom}} =
|
|
@{$results{$rest}{$stealfrom}};
|
|
}
|
|
}
|
|
} elsif (defined($tokenitems{$token})) {
|
|
if (!defined($curtoken)) {
|
|
die "error in configuration file $itemfile, no token set\n";
|
|
}
|
|
$rest =~ s/^\#//;
|
|
push @{$results{$curtoken}{$token}},$rest;
|
|
} elsif (defined($arrayitems{$token})) {
|
|
if (!defined($curtoken)) {
|
|
die "error in configuration file $itemfile, no token set\n";
|
|
}
|
|
my ($num, $newrest) = ($rest =~ /^(\d+)\s+(.*)/);
|
|
if (!defined($num) || !defined($newrest)) {
|
|
warn "invalid config line: $line\n";
|
|
} else {
|
|
$results{$curtoken}{$token}[$num] = $newrest;
|
|
}
|
|
} elsif ($token =~ /^token\s*$/) {
|
|
$rest = lc($rest);
|
|
$curtoken = $rest;
|
|
if (! exists $results{$curtoken}{'defined'}) {
|
|
push @{$results{'thetokens'}}, $curtoken;
|
|
$results{$curtoken}{'defined'} = 1;
|
|
}
|
|
$tokenmap{$curtoken} = $results{$curtoken};
|
|
debug("current token set to $token\n");
|
|
} else {
|
|
push @{$results{$token}},$rest;
|
|
}
|
|
}
|
|
return \%results;
|
|
}
|
|
|
|
sub debug {
|
|
print @_ if ($opts{'d'});
|
|
}
|
|
|
|
sub output_files {
|
|
my $filetypes = shift;
|
|
my $term = shift;
|
|
foreach my $ft (keys(%$filetypes)) {
|
|
next if (!$didfile{$ft});
|
|
my $outputf = $ft;
|
|
if (-f $outputf && !$opts{'f'}) {
|
|
print "\nError: An $outputf file already exists in this directory.\n\n";
|
|
my $ans = get_answer($term,"'overwrite', 'skip', 'rename' or 'append'? ",valid_answers(qw(o overwrite r rename s skip a append)));
|
|
next if ($ans =~ /^(s|skip)$/i);
|
|
if ($ans =~ /^(a|append)/) {
|
|
$outputf = ">$outputf";
|
|
} elsif ($ans =~ /^(r|rename)$/i) {
|
|
# default to rename for error conditions
|
|
$outputf = $term->readline("Save to what new file name instead (or 'skip')? ");
|
|
}
|
|
}
|
|
$didfile{$ft} = $outputf;
|
|
open(O,">$outputf") || warn "couldn't write to $outputf\n";
|
|
print O "#" x 75,"\n";
|
|
print O "#\n# $ft\n";
|
|
print O "#\n# - created by the snmpconf configuration program\n#\n";
|
|
foreach my $sect (@{$filetypes->{$ft}}) {
|
|
my $secthelp = 0;
|
|
foreach my $token (@{$sect->{'thetokens'}}) {
|
|
if ($#{$sect->{$token}{'results'}} >= 0) {
|
|
if ($secthelp++ == 0) {
|
|
print O "#" x 75,"\n# SECTION: ",
|
|
join("\n# ", @{$sect->{title}}), "\n#\n";
|
|
print O "# ", join("\n# ",@{$sect->{description}}),
|
|
"\n";
|
|
}
|
|
print O "\n# $token: ",
|
|
join("\n# ",@{$sect->{$token}{info}}), "\n\n";
|
|
foreach my $result (@{$sect->{$token}{'results'}}) {
|
|
print O "$result\n";
|
|
}
|
|
}
|
|
}
|
|
print O "\n\n\n";
|
|
}
|
|
if ($#{$unknown{$ft}} > -1) {
|
|
print O "#\n# Unknown directives read in from other files by snmpconf\n#\n";
|
|
foreach my $unknown (@{$unknown{$ft}}) {
|
|
print O $unknown,"\n";
|
|
}
|
|
}
|
|
close(O);
|
|
}
|
|
}
|
|
|
|
sub get_answer {
|
|
my ($term, $question, $regexp, $defaultval) = @_;
|
|
$question .= " (default = $defaultval)" if (defined($defaultval) && $defaultval ne "");
|
|
$question .= ": ";
|
|
my $ans = $term->readline($question);
|
|
return $defaultval if ($ans eq "" && defined($defaultval) &&
|
|
$defaultval ne "");
|
|
while (!(!defined($regexp) ||
|
|
$regexp eq "" ||
|
|
$ans =~ /$regexp/)) {
|
|
print "invalid answer! It must match this regular expression: $regexp\n";
|
|
$ans = $term->readline($question);
|
|
}
|
|
return $defaultval if ($ans eq "" && defined($defaultval) &&
|
|
$defaultval ne "");
|
|
return $ans;
|
|
}
|
|
|
|
sub valid_answers {
|
|
my @list;
|
|
foreach $i (@_) {
|
|
push @list, $i if ($i);
|
|
}
|
|
return "^(" . join("|",@list) . ")\$";
|
|
}
|
|
|
|
sub read_config {
|
|
my $file = shift;
|
|
my $filetype = shift;
|
|
return if (!defined($filetypes{$filetype}));
|
|
if (! -f $file) {
|
|
warn "$file does not exist\n";
|
|
return;
|
|
}
|
|
open(I,$file);
|
|
while(<I>) {
|
|
next if (/^\s*\#/);
|
|
next if (/^\s*$/);
|
|
chomp;
|
|
my ($token, $rest) = /^\s*(\w+)\s+(.*)/;
|
|
$token = lc($token);
|
|
next if (defined($alllines{$_})); # drop duplicate lines
|
|
if (defined($tokenmap{$token})) {
|
|
push @{$tokenmap{$token}{'results'}},$_;
|
|
} else {
|
|
push @{$unknown{$filetype}},$_;
|
|
}
|
|
$alllines{$_}++;
|
|
}
|
|
close(I);
|
|
}
|
|
|
|
sub display_menu {
|
|
my %config;
|
|
|
|
while ($#_ > -1 && $_[0] =~ /^-/) {
|
|
my $key = shift;
|
|
$config{$key} = shift;
|
|
}
|
|
|
|
my $count=1;
|
|
print "\n" if (!defined($config{'-dense'}));
|
|
if ($config{'-head'}) {
|
|
print $config{'-head'};
|
|
print "\n" if (!defined($config{'-dense'}));
|
|
}
|
|
my @answers = @_;
|
|
my @list;
|
|
if (defined($config{'-descriptions'}) &&
|
|
ref($config{'-descriptions'}) eq "ARRAY") {
|
|
@list = @{$config{'-descriptions'}}
|
|
} else {
|
|
@list = @_;
|
|
}
|
|
foreach my $i (@list) {
|
|
printf " %2d: $i\n", $count++ if ($i);
|
|
}
|
|
print "\n" if (!defined($config{'-dense'}));
|
|
if (defined($config{'-otheranswers'})) {
|
|
if (ref($config{'-otheranswers'}) eq 'ARRAY') {
|
|
print "Other options: ", join(", ",
|
|
@{$config{'-otheranswers'}}), "\n";
|
|
push @answers, @{$config{'-otheranswers'}};
|
|
push @answers, keys(%{$config{'-mapanswers'}});
|
|
} else {
|
|
my $maxlen = 0;
|
|
push @answers,keys(%{$config{'-otheranswers'}});
|
|
foreach my $i (keys(%{$config{'-otheranswers'}})) {
|
|
$maxlen = length($i) if (length($i) > $maxlen);
|
|
}
|
|
foreach my $i (keys(%{$config{'-otheranswers'}})) {
|
|
printf(" %-" . $maxlen . "s: %s\n", $i,
|
|
$config{'-otheranswers'}{$i});
|
|
}
|
|
}
|
|
print "\n" if (!defined($config{'-dense'}));
|
|
}
|
|
if ($config{'-tail'}) {
|
|
print $config{'-tail'};
|
|
print "\n" if (!defined($config{'-dense'}));
|
|
}
|
|
|
|
if (defined($config{'-question'})) {
|
|
while(1) {
|
|
my $numexpr;
|
|
if ($config{'-multiple'}) {
|
|
$numexpr = '[\d\s,]+|all|a|none|n';
|
|
} else {
|
|
$numexpr = '\d+';
|
|
}
|
|
push @answers,"" if ($config{'-defaultvalue'});
|
|
$ans = get_answer($term, $config{'-question'},
|
|
valid_answers($numexpr,@answers),
|
|
$config{'-defaultvalue'});
|
|
if ($config{'-mapanswers'}{$ans}) {
|
|
$ans = $config{'-mapanswers'}{$ans};
|
|
}
|
|
|
|
if ($ans =~ /^$numexpr$/) {
|
|
if ($config{'-multiple'}) {
|
|
my @list = split(/\s*,\s*/,$ans);
|
|
my @ret;
|
|
$count = 0;
|
|
foreach my $i (@_) {
|
|
$count++;
|
|
if ($ans eq "all" || $ans eq "a"
|
|
|| grep(/^$count$/,@list)) {
|
|
push @ret, $i;
|
|
}
|
|
}
|
|
return @ret;
|
|
} else {
|
|
if ($ans <= 0 || $ans > $#_+1) {
|
|
warn "invalid selection: $ans [must be 1-" .
|
|
($#_+1) . "]\n";
|
|
} else {
|
|
return $ans if ($config{'-numeric'});
|
|
$count = 0;
|
|
foreach my $i (@_) {
|
|
$count++;
|
|
if ($ans eq $count) {
|
|
return $i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
return $ans;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
sub my_Dumper {
|
|
if ($opts{'D'}) {
|
|
return Dumper(@_);
|
|
} else {
|
|
return "\n";
|
|
}
|
|
}
|
|
|
|
sub get_persistentDir {
|
|
my $file = shift;
|
|
my $result = 0;
|
|
if (! -f $file) {
|
|
return 0;
|
|
}
|
|
open(I,$file);
|
|
while(<I>) {
|
|
next if (/^\s*\#/);
|
|
next if (/^\s*$/);
|
|
chomp;
|
|
my ($token, $rest) = /^\s*(\w+)\s+(.*)/;
|
|
if (lc($token) eq "persistentdir") {
|
|
$result = $rest;
|
|
}
|
|
next;
|
|
}
|
|
close(I);
|
|
return $result;
|
|
}
|
|
|
|
# Usage: &win32_reg_read("key", "value")
|
|
# Example: &win32_reg_read("SOFTWARE\\Net-SNMP","SNMPSHAREPATH");
|
|
# Returns: Value if found in HKCU or HCLM. Otherwise an empty string.
|
|
sub win32_reg_read {
|
|
my $sub_key = shift;
|
|
my $value = shift;
|
|
|
|
require Win32::Registry;
|
|
|
|
my ($hkey, %key_values, $temp, $no_warn);
|
|
|
|
# Try HKCU first
|
|
$no_warn = $HKEY_CURRENT_USER;
|
|
if ($HKEY_CURRENT_USER->Open($sub_key, $hkey))
|
|
{
|
|
$hkey->GetValues(\%key_values);
|
|
foreach $temp (sort keys %key_values) {
|
|
if ($temp eq $value) {
|
|
return $key_values{$temp}[2];
|
|
}
|
|
}
|
|
$hkey->Close();
|
|
}
|
|
|
|
# Try HKLM second
|
|
$no_warn = $HKEY_LOCAL_MACHINE;
|
|
if ($HKEY_LOCAL_MACHINE->Open($sub_key, $hkey))
|
|
{
|
|
$hkey->GetValues(\%key_values);
|
|
foreach $temp (sort keys %key_values) {
|
|
if ($temp eq $value) {
|
|
return $key_values{$temp}[2];
|
|
}
|
|
}
|
|
$hkey->Close();
|
|
}
|
|
return "";
|
|
}
|
|
|
|
# Usage: &my_getenv("key")
|
|
# Example: &my_getenv("SNMPSHAREPATH");
|
|
# Returns: Unix: Environment variable value (undef if not defined)
|
|
# Win32: HKCU\Software\Net-SNMP\(key) or
|
|
# Win32: HKLM\Software\Net-SNMP\(key) or
|
|
# Win32: Environment variable value (undef if not defined)
|
|
sub my_getenv {
|
|
my $key = shift;
|
|
|
|
# Unix
|
|
if ($^O ne 'MSWin32') {
|
|
return $ENV{$key};
|
|
}
|
|
# Windows
|
|
else {
|
|
my $temp = &win32_reg_read("SOFTWARE\\Net-SNMP","$key");
|
|
if ($temp ne "") {
|
|
return $temp;
|
|
}
|
|
else {
|
|
return $ENV{$key};
|
|
}
|
|
}
|
|
}
|
|
|