#!/usr/local/bin/perl use POSIX ":sys_wait_h"; # cfgstore - grab cisco configs and store them away in CVS # # -d debug # -c configfile # -l logfile # -q don't check out current playground. # # maf@net.ohio-state.edu Nov 1998 require "getopts.pl"; require "flush.pl"; &Getopts('c:dq'); $CFGFILE = ($opt_c eq '') ? "/var/cisco/cfgstore.cfg" : $opt_c; $WHERE=0; # 0=base 1=device $| = 1; open (CFG, "<$CFGFILE") || die "open($CFGFILE): $!\n"; # parse config file while () { next if (/^\s*#/); next if (/^\s+$/); chomp; &parse_line; } # while close CFG; # debug if ($opt_d) { foreach $dev (@dev_list) { print STDERR "dev=$dev\n"; print STDERR " gather_script=$dev{\"$dev.gather_script\"}\n"; print STDERR " post_process=$dev{\"$dev.post_process\"}\n"; print STDERR " cvs_path=$dev{\"$dev.cvs_path\"}\n"; } } # init $cvs = $dev{"default.cvs_bin"}; $workdir = $dev{"default.workdir"}; $module = $dev{"default.cvs_module"}; $ENV{'CVSROOT'} = $dev{"default.cvs_root"}; $total_dev = @dev_list; $parallel = ($dev{"default.parallel"}) ? $dev{"default.parallel"} : 1; if (!$opt_q) { # prepare cvs playground chdir ("$workdir") || die "chdir($workdir): $!\n"; system ("rm -rf $module.old"); rename ($module, "$module.old"); system ("$cvs/cvs co $module"); # # CVS doesn't deal with multiple add's going on in the same directory # in the same playground at the same time. Don't try this in parallel. # foreach $dev (@dev_list) { $gather = $dev{"$dev.gather_script"}; $dir = $dev{"$dev.cvs_path"}; # skip this device if no gather script defined next if ($gather eq ''); chdir ("$workdir/$module") || die "chdir($workdir/$module): $!\n"; if (! -d "$dir") { mkdir ("$dir", 0755) || die "mkdir($dir)\n"; system ("$cvs/cvs add $dir"); } } # dev_list } # quick # # grab configs in parallel # $i = 0; $running = 0; while (1) { for (;$i < $total_dev; ++$i) { last if ($running == $parallel); print STDERR "i=$i running=$running\n" if ($opt_d); $pid = fork(); defined($pid) || die "fork(): i=$i $!\n"; if ($pid) { # parent ++$running; push @running, $pid; } else { # child $dev = $dev_list[$i]; $gather = $dev{"$dev.gather_script"}; $process = $dev{"$dev.post_process"}; $dir = $dev{"$dev.cvs_path"}; $end_output = $dev{"$dev.end_output"}; $destination = $dev{"$dev.destination"}; # skip this device if no gather script defined exit (0) if ($gather eq ''); # construct the config gather command $cmd = $gather; $cmd .= "|$process" if ($process ne ''); chdir ("$workdir/$module/$dir") || die "chdir($workdir/$module/$dir): $!\n"; print STDERR "$$: in $workdir/$module/$dir\n" if ($opt_d); print STDERR "$$: Started $cmd\n" if ($opt_d); open (CFG, "$cmd|") || die "popen($cmd): $!\n"; open (NEW, ">$destination.tmp") || die "open($destination.tmp): $!\n"; $cfgerr = 0; $lines = 0; $end = 0; while () { if ( /^Non-Volatile memory is in use/ || /^%No memory available/) { $cfgerr = 1; last; } ++$lines; ++$end if (/$end_output/); print NEW; } # while close CFG; close NEW; $end=1 if ($end_output eq ''); print STDERR "$$: grab config cfgerr=$cfgerr lines=$lines\n" if ($opt_d); if (($cfgerr) || (!$lines) || ($end != 1)) { unlink ("$destination.tmp"); print STDERR "$$: Grab Config error: $dev: end=$end lines=$lines cfgerr=$cfgerr: last=$_\n"; } else { unlink "$destination" || print STDERR "unlink($destination): $!\n"; rename "$destination.tmp", "$destination" || print STDERR "rename($destination.tmp,$destination): $!\n"; } print STDERR "$$: child exit\n" if ($opt_d); exit (0); } # child } # for $completed = 0; foreach (@running) { next if ($_ == undef); $ret = waitpid($_,&WNOHANG); print STDERR " running=$_ ret=$ret\n" if ($opt_d); if ($ret == $_) { --$running; ++$completed; undef $_; } } # foreach last if ($i == $total_dev && (!$running)); if (!$completed) { select(undef, undef, undef, .75); } } # while 1 # add/commit file to cvs repository for ($i = 0; $i < $total_dev; ++$i) { $dev = $dev_list[$i]; $dir = $dev{"$dev.cvs_path"}; $destination = $dev{"$dev.destination"}; chdir ("$workdir/$module/$dir") || die "chdir($workdir/$module/$dir): $!\n"; if (-s "$destination") { system ("$cvs/cvs add $destination 2>/dev/null"); system ("$cvs/cvs commit -m cfgstore_update $destination"); } else { print STDERR "Skipped $dir\n"; } } sub parse_line { @l = split; $ok = 0; if ($WHERE == 0) { if ($l[0] eq 'cvs_root') { $dev{"default.cvs_root"} = $l[1]; $ok = 1; } elsif ($l[0] eq 'cvs_bin') { $dev{"default.cvs_bin"} = $l[1]; $ok = 1; } elsif ($l[0] eq 'cvs_module') { $dev{"default.cvs_module"} = $l[1]; $ok = 1; } elsif ($l[0] eq 'workdir') { $dev{"default.workdir"} = $l[1]; $ok = 1; } elsif ($l[0] eq 'parallel') { $dev{"default.parallel"} = $l[1]; $ok = 1; } elsif ($l[0] eq 'trim_domain') { $dev{"default.trim_domain"} = $l[1]; $ok = 1; } } if ($l[0] eq 'device') { $WHERE = 1; if ($l[1] eq 'default') { $default = 1;} else { $default = 0; } $dev{"$l[1].name"} = $l[1]; $dev = $l[1]; if (!$default) { push @dev_list, $dev; $_ = "gather_script $dev{\"default.gather_script\"}"; &parse_line; $_ = "post_process $dev{\"default.post_process\"}"; &parse_line; $_ = "cvs_path $dev{\"default.cvs_path\"}"; &parse_line; $_ = "end_output $dev{\"default.end_output\"}"; &parse_line; $_ = "destination $dev{\"default.destination\"}"; &parse_line; } $ok = 1; } elsif ($WHERE == 1) { $dev_trim = $dev; if ($dev{'default.trim_domain'} ne '') { $dev_trim =~s/$dev{'default.trim_domain'}$//; } $line = $_; $line =~ s/^\s+//g; if (!$default) { $line =~ s/\\D/$dev/g; $line =~ s/\\d/$dev_trim/g; } if ($l[0] eq 'gather_script') { $dev{"$dev.gather_script"} = substr($line, 14); $dev{"$dev.gather_script"} =~s/^\s+//; $ok = 1; } elsif ($l[0] eq 'post_process') { $dev{"$dev.post_process"} = substr($line, 13); $dev{"$dev.post_process"} =~s/^\s+//; $ok = 1; } elsif ($l[0] eq 'cvs_path') { $dev{"$dev.cvs_path"} = substr($line, 9); $dev{"$dev.cvs_path"} =~s/^\s+//; $ok = 1; } elsif ($l[0] eq 'end_output') { $dev{"$dev.end_output"} = substr($line, 11); $dev{"$dev.end_output"} =~s/^\s+//; $ok = 1; } elsif ($l[0] eq 'destination') { $dev{"$dev.destination"} = substr($line, 11); $dev{"$dev.destination"} =~s/^\s+//; $ok = 1; } } # WHERE==1 if (!$ok) { print STDERR "syntax error: $_\n"; exit (1); } } # parse_line