[BACK]Return to update_trango.pl CVS log [TXT][DIR] Up to [local] / trango / Net-Telnet-Trango / scripts

Annotation of trango/Net-Telnet-Trango/scripts/update_trango.pl, Revision 1.6

1.1       andrew      1: #!/usr/bin/perl
1.6     ! andrew      2: # $RedRiver: update_trango.pl,v 1.5 2005/11/16 21:39:51 andrew Exp $
1.1       andrew      3: ########################################################################
                      4: # update_trango.pl *** Updates trango foxes with a new firmware
                      5: # 
                      6: # 2005.11.15 #*#*# andrew fresh <andrew@mad-techies.org>
                      7: ########################################################################
                      8: use strict;
                      9: use warnings;
                     10: 
                     11: use Net::Telnet;
1.2       andrew     12: use Net::TFTP;
1.4       andrew     13: use Fcntl ':flock'; # import LOCK_* constants
1.3       andrew     14: #use YAML;
1.2       andrew     15: 
                     16: 
1.4       andrew     17: my $config_file = shift || 'update_trango.conf';
1.3       andrew     18: my $conf = read_conf($config_file);
1.2       andrew     19: 
1.3       andrew     20: my $max_tries = 1;
1.2       andrew     21: 
1.4       andrew     22: my $log_file =  GetLogName('UT');
1.5       andrew     23: use constant LOG_SAVE => 1;
1.4       andrew     24: 
                     25: my $MYLOG;  # file handle for logging so we don't have to close and open it all the time
                     26: END {
                     27:   if ($MYLOG) {
                     28:     mylog("Closing log ($log_file)");
                     29:     close $MYLOG;
                     30:   }
                     31: }
                     32: 
                     33: 
                     34: 
1.2       andrew     35: 
                     36: 
                     37: 
                     38: 
                     39: 
1.3       andrew     40: foreach my $fox (@{ $conf->{'ips'} }) {
1.5       andrew     41:   mylog("Updating: $fox", LOG_SAVE);
1.2       andrew     42: 
                     43:   ## Connect and login.
                     44:   my $host = new Net::Telnet (Timeout => 5,
                     45:                               Prompt => '/#> *$/');
1.4       andrew     46:   mylog("Connecting to $fox");
1.6     ! andrew     47:   unless ( $host->open( Host => $fox, Errmode => 'return') ) {
        !            48:     mylog("Couldn't connect to $fox.  Connection timed out.", LOG_SAVE);
        !            49:     next;
        !            50:   }
1.2       andrew     51:   $host->dump_log('dump.log');
                     52: 
                     53:   ## Login to remote host.
1.6     ! andrew     54:   unless ($host->waitfor(
1.2       andrew     55:     -match => '/password: ?$/i',
                     56:     -errmode => "return",
1.6     ! andrew     57:   ) ) {
        !            58:     mylog("problem connecting to host ($fox): " . $host->lastline, LOG_SAVE);
        !            59:     next;
        !            60:   }
1.3       andrew     61: 
                     62:   my $login_banner = $host->lastline;
                     63:   my ($type, $version) = $login_banner =~ 
                     64:     /Welcome to Trango Broadband Wireless (\w+)-(.+)$/i;
                     65: 
                     66:   if ($type ne $conf->{'type'}) {
1.5       andrew     67:     mylog("Wrong type of unit ('$type' should be '$conf->{'type'}')", LOG_SAVE);
1.3       andrew     68:     $host->close;
                     69:     next;
                     70:   }
                     71: 
                     72:   if ($version eq $conf->{'ver'}) {
1.5       andrew     73:     mylog("Already up to date with firmware version '$version'", LOG_SAVE);
1.3       andrew     74:     $host->close;
                     75:     next;
                     76:   }
                     77: 
1.4       andrew     78:   mylog("Logging in");
1.3       andrew     79:   $host->print($conf->{'password'});
1.5       andrew     80:   unless ($host->waitfor(
1.2       andrew     81:     -match => $host->prompt,
                     82:     -errmode => "return",
1.5       andrew     83:   ) ) {
                     84:     mylog("login ($fox) failed: " . $host->lastline);
                     85:     next;
                     86:   }
1.2       andrew     87: 
1.3       andrew     88: 
1.4       andrew     89:   mylog("Sending commands");
1.2       andrew     90:   ## Send commands
1.3       andrew     91:   if ( upload($host, $fox, $conf->{'file_name'}) ) {
1.4       andrew     92:     mylog("Rebooting");
1.3       andrew     93:     $host->print("reboot\n");
                     94:     $host->getline;
1.2       andrew     95:   } else {
1.4       andrew     96:     mylog("Exiting");
1.3       andrew     97:     $host->print("exit\n");
                     98:     $host->getline;
1.2       andrew     99:   }
                    100:   $host->close;
1.5       andrew    101:   mylog("", LOG_SAVE);
1.2       andrew    102: }
                    103: 
                    104: sub upload
                    105: {
                    106:   my $host = shift;
1.3       andrew    107:   my $fox  = shift;
1.2       andrew    108:   my $file = shift;
1.3       andrew    109: 
1.4       andrew    110:   mylog("Getting current version");
1.2       andrew    111:   my $ver = get_ver($host);
                    112: 
                    113:   if (
1.3       andrew    114:     $ver->{'Firmware Version'}  eq $conf->{'ver'} && 
                    115:     $ver->{'Firmware Checksum'} eq $conf->{'cksum'}
1.2       andrew    116:   ) {
1.5       andrew    117:     mylog("Already updated!", LOG_SAVE);
1.2       andrew    118:     return 1;
                    119:   }
                    120: 
                    121:   my $try = 0;
                    122:   while (1) {
1.3       andrew    123:     if ($try >= $max_tries) {
1.4       andrew    124:       mylog("Couldn't update in $max_tries tries!");
1.3       andrew    125:       return undef;
                    126:     }
1.2       andrew    127:     $try++;
                    128: 
1.3       andrew    129:     #sysinfo($host);
                    130:     
1.4       andrew    131:     mylog("Enabling TFTPd");
1.2       andrew    132:     enable_tftpd($host) || die "Couldn't enable tftpd";
                    133: 
1.5       andrew    134:     mylog("Uploading file ($file)");
1.2       andrew    135:     # use tftp to push the file up
1.3       andrew    136:     my $tftp = Net::TFTP->new($fox, Mode => 'octet');
                    137: 
                    138:     $tftp->put($file, $file) 
                    139:       or die "Error uploading: " . $tftp->error;
1.2       andrew    140: 
                    141:     # waitfor some sort of output
                    142:     # make sure it says 'Success.' otherwise error
1.3       andrew    143:     #print "LAST: " . $host->lastline;
                    144:     #my @lines = $host->getlines;
                    145:     #print Dump \@lines;
1.2       andrew    146:     
1.5       andrew    147:     mylog("Checking upload ($conf->{'file_cksum'})");
1.2       andrew    148:     my $results = check_tftpd($host);
                    149:     # check the 'File Length' against ???
1.3       andrew    150:     if ( $results->{'File Checksum'} ne $conf->{'file_cksum'}) {
1.5       andrew    151:       mylog("File checksum does not match config file!", LOG_SAVE);
1.3       andrew    152:       next;
1.5       andrew    153:     } 
                    154:     mylog("File checksum ($results->{'File Checksum'}) " . 
                    155:           "matches ($conf->{'file_cksum'})");
1.3       andrew    156: 
                    157:     if ($results->{'File Length'}   !~ /^$conf->{'file_size'} bytes/) {
1.5       andrew    158:       mylog("File length does not match config file!", LOG_SAVE);
1.3       andrew    159:       next;
                    160:     }
1.5       andrew    161:     mylog("File length ($results->{'File Length'}) " . 
                    162:           "matches ($conf->{'file_size'})");
1.2       andrew    163: 
1.3       andrew    164:     if ( uc($results->{'File Name'}) ne uc($conf->{'file_name'}) ) {
1.5       andrew    165:       mylog("File name does not match config file!", LOG_SAVE);
1.3       andrew    166:       next;
                    167:     }
1.5       andrew    168:     mylog("File name ($results->{'File Name'}) " . 
                    169:           "matches ($conf->{'file_name'})");
1.2       andrew    170: 
1.5       andrew    171:     mylog("Updating flash (new checksum '$conf->{'cksum'}')");
1.3       andrew    172:     $results = updateflash(
                    173:       $host, $ver->{'Firmware Checksum'}, $conf->{'cksum'}
                    174:     ) or die "Couldn't update flash: " . $host->lastline;
                    175:     unless (
                    176:       defined $results->{'Checksum'} && 
                    177:       $results->{'Checksum'} eq $conf->{'cksum'}
                    178:     ) {
1.5       andrew    179:       mylog("Saved checksum does not match config file!", LOG_SAVE);
1.3       andrew    180:       next;
1.2       andrew    181:     }
1.5       andrew    182:     mylog("Uploaded checksum ($results->{'Checksum'}) " . 
                    183:           "matches ($conf->{'cksum'})");
1.3       andrew    184:     
1.5       andrew    185:     mylog("Successfully updated!", LOG_SAVE);
1.3       andrew    186:     return 1;
1.2       andrew    187:   }
                    188: }
                    189: 
                    190: sub get_ver
                    191: {
                    192:   my $host = shift;
                    193:   return cmd($host, 'ver');
                    194: }
                    195: 
                    196: sub enable_tftpd
                    197: {
                    198:   my $host = shift;
                    199: 
1.3       andrew    200:   my $vals = cmd($host, 'tftpd on', 'Success.');
1.2       andrew    201: 
                    202:   if ($vals->{'Tftpd'} eq 'listen') {
1.3       andrew    203:     return $vals;
1.2       andrew    204:   } else {
                    205:     return undef;
                    206:   }
                    207: }
                    208: 
                    209: sub check_tftpd
                    210: {
                    211:   my $host = shift;
1.3       andrew    212:   return cmd($host, 'tftpd', 'Success.');
                    213: }
                    214: 
                    215: sub sysinfo
                    216: {
                    217:   my $host = shift;
                    218:   return cmd($host, 'sysinfo', 'Success.');
                    219: }
                    220: 
                    221: sub updateflash
                    222: {
                    223:   my $host = shift;
                    224:   my $old = shift;
                    225:   my $new = shift;
                    226: 
                    227:   return undef unless $new;
                    228: 
                    229:   return cmd($host, "updateflash mainimage $old $new", 'Success.', 90);
1.2       andrew    230: }
                    231: 
                    232: sub cmd
                    233: {
                    234:   my $host   = shift;
                    235:   my $string = shift;
1.3       andrew    236:   my $expect_last = shift;
                    237:   my $timeout = shift || 5;
1.2       andrew    238: 
1.3       andrew    239:   my @lines = $host->cmd(String => $string, Timeout => $timeout);
1.2       andrew    240: 
                    241:   my $vals = decode_lines(@lines);
1.3       andrew    242: 
                    243:   my $last = $host->lastline;
                    244: 
                    245:   unless ($expect_last) {
                    246:     return $vals;
                    247:   }
                    248: 
                    249:   if ($last =~ /$expect_last$/) {
                    250:     return $vals;
                    251:   } else {
                    252:     warn "Error with command ($string): $last";
                    253:     return undef;
                    254:   }
1.2       andrew    255: }
                    256: 
                    257: sub decode_lines
                    258: {
                    259:   my @lines = @_;
                    260: 
                    261:   my %conf;
                    262: 
                    263:   my $key = '';
                    264:   my $val = '';
                    265:   my $in_key = 0;
                    266:   my $in_val = 0;
                    267: 
                    268:   foreach my $line (@lines) {
                    269:     my @chars = split //, $line;
                    270: 
1.3       andrew    271:     my $last_key = '';
1.2       andrew    272:     foreach my $c (@chars) {
                    273: 
1.3       andrew    274:       if ($c eq '[' || $c eq "\r" || $c eq "\n") {
                    275:         if ($c eq '[') {
                    276:           $in_key = 1;
                    277:           $in_val = 0;
                    278:         } else {
                    279:           $in_key = 0;
                    280:           $in_val = 0;
                    281:         }
                    282: 
1.2       andrew    283:         if ($key) {
1.3       andrew    284:           $key =~ s/^\s+//;
                    285:           $key =~ s/\s+$//;
                    286: 
                    287:           $val =~ s/^\s+//;
1.2       andrew    288:           $val =~ s/\s+$//;
1.3       andrew    289: 
                    290:           if ($key eq 'Checksum' && $last_key) {
                    291:             # Special case for these bastids.
                    292:             my $new = $last_key;
                    293:             $new =~ s/\s+\S+$//;
                    294:             $key = $new . " " . $key;
                    295:           }
                    296: 
                    297:           $last_key = $key;
1.2       andrew    298:           $conf{$key} = $val;
                    299:           $key = '';
                    300:           $val = '';
                    301:         }
                    302: 
                    303:       } elsif ($c eq ']') {
                    304:         $in_val = 1;
                    305:         $in_key = 0;
                    306:         $c = shift @chars;
                    307: 
                    308:       } elsif ($in_key) {
                    309:         $key .= $c;
                    310: 
                    311:       } elsif ($in_val) {
                    312:         $val .= $c;
                    313:       }
                    314:     }
                    315:   }
1.3       andrew    316:   #print Dump \%conf;
1.2       andrew    317: 
                    318:   if (%conf) {
                    319:     return \%conf;
                    320:   } else {
                    321:     return \@lines;
                    322:   }
                    323: }
1.1       andrew    324: 
1.3       andrew    325: sub read_conf
                    326: {
                    327:   my $file = shift;
                    328:   my %conf;
                    329:   my $in_ip_list = 0;
                    330:   open my $fh, $file or die "Couldn't open file $file: $!";
                    331:   while (<$fh>) {
                    332:     chomp;
                    333:     next if /^#/;
                    334:     next if /^$/;
                    335:     if ($in_ip_list) {
                    336:       push @{ $conf{'ips'} }, $_;
                    337:     } else {
                    338:       my ($key, $val) = split /\s+/, $_, 2;
                    339: 
                    340:       if (lc($key) eq 'ips') {
                    341:         $in_ip_list = 1;
                    342:         next;
                    343:       }
                    344: 
                    345:       $conf{ lc($key) } = $val;
                    346:     }
                    347:   }
                    348:   close $fh;
                    349: 
                    350:   #print Dump \%conf;
                    351:   foreach (
                    352:     'password', 
                    353:     'file_name', 'file_size', 'file_cksum', 
                    354:     'ver', 'cksum', 'ips',
                    355:   ) {
                    356:     die "No $_ specified in config file!"
                    357:       if (not exists $conf{$_});
                    358:   }
                    359: 
                    360:   return \%conf;
1.4       andrew    361: }
                    362: 
                    363: sub mylog
                    364: {
1.5       andrew    365:   my $thing = shift;
                    366:   chomp $thing;
                    367:   my $save = shift;
                    368: 
                    369:   print $thing, "\n";
                    370: 
                    371:   if (defined $save && $save == LOG_SAVE) {
                    372:     unless ($MYLOG) {
                    373:       open ($MYLOG, '>>', $log_file) 
                    374:         or die "Couldn't open logfile!\n";
                    375:       my $ofh = select $MYLOG;
                    376:       $|=1;
                    377:       select $ofh;
                    378:       mylog("Opened log ($log_file)");
                    379:     }
1.4       andrew    380: 
1.5       andrew    381:     flock($MYLOG, LOCK_EX);
                    382:     print $MYLOG (scalar gmtime), "\t", $thing, "\n" 
                    383:       or die "Couldn't print to MYLOG: $!";
                    384:     flock($MYLOG, LOCK_UN);
                    385:   }
1.4       andrew    386: }
                    387: 
                    388: sub GetLogName
                    389: {
                    390:   my $prefix  = shift || die "Invalid prefix passed for log";
                    391: 
                    392:   my $logdate = GetLogDate();
                    393:   my $logver  = 0;
                    394:   my $logname;
                    395: 
                    396:   do {
                    397:     $logname = $prefix . $logdate . sprintf("%02d", $logver) . '.log';
                    398:     $logver++;
                    399:   } until (not -e $logname);
                    400: 
                    401:   return $logname;
                    402: }
                    403: 
                    404: sub GetLogDate
                    405: {
                    406:   my ($sec,$min,$hour,$mday,$mon,$year,,,) = localtime();
                    407: 
                    408:   $mon++;
                    409:   $year += 1900;
                    410: 
                    411:   if ($min  < 10) { $min  = "0$min"  }
                    412:   if ($sec  < 10) { $sec  = "0$sec"  }
                    413:   if ($hour < 10) { $hour = "0$hour" }
                    414:   if ($mday < 10) { $mday = "0$mday" }
                    415:   if ($mon  < 10) { $mon  = "0$mon"  }
                    416: 
                    417:   my $time = $year . $mon . $mday;
                    418: 
                    419:   return $time;
1.3       andrew    420: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>