Blame local/snmpconf.in

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