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

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

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