[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.8

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

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