#! /usr/bin/perl -w # # Configure a NetWinder # $Id: install,v 1.79 2000/09/07 15:44:43 stewart Exp $ # # Andrew E. Mileski # andrewm@netwinder.org # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Configurable stuff # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # $ENV{'PATH'} = '/bin:/usr/bin:/sbin:/usr/sbin:/root'; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Board IDs. These are the last two digits if the board revision as see # from "cat /proc/cpuinfo" # Currently these two digits give information about the daughter card config. # FF -- standard plastic units (DM/OS) # 7F -- standard rack mount unit (OS) # BF -- plastic units with SCSI daughter cards (DM) # 3F -- rack mount units with SCSI daughter cards (DM) # 8F -- unit with no daughter card # 80 -- Early Rev 6.0 boards (defective) # 81 -- Early Rev 6.0 boards (defective) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # This is where the fun begins # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # sub read_config; sub msg; sub fatal_error; sub menu; sub ifconfig; sub read_ifconfig; sub setmac; sub query_drive; sub partition_scheme_6; sub partition_scheme_5; sub partition_scheme_4; sub partition_scheme_3; sub partition_scheme_2; sub format_scheme_6; sub format_scheme_5; sub format_scheme_4; sub format_scheme_3; sub format_scheme_2; sub mount_scheme_6; sub mount_scheme_5; sub mount_scheme_4; sub mount_scheme_3; sub mount_scheme_2; sub install_image; sub flash; sub detect; sub scsi_test; sub serial_test; sub eth100_test; sub parallel_test; sub do_everything; sub do_diskless; sub do_flash; sub do_tests; sub do_special_update; sub do_prodserv; sub set_time; sub kernel_version; sub backup_burn_in_data; sub sound_tests; sub disk_dma_tests; my @citrix = ('none', '', '--no-usergif'); my $redir = ' >/dev/tty2 2>&1 '; my $eth1_type = 'tulip'; my $build = ''; my $boardrev = ''; my $revision = ''; my $config = $0.'.conf'; # ANSI colour codes my $txt_black = "\033[0;30m"; my $txt_bblack = "\033[0;1;30m"; my $txt_red = "\033[0;31m"; my $txt_bred = "\033[0;1;31m"; my $txt_green = "\033[0;32m"; my $txt_bgreen = "\033[0;1;32m"; my $txt_orange = "\033[0;33m"; my $txt_yellow = "\033[0;1;33m"; my $txt_blue = "\033[0;34m"; my $txt_bblue = "\033[0;1;34m"; my $txt_magenta = "\033[0;35m"; my $txt_bmagenta = "\033[0;1;35m"; my $txt_cyan = "\033[0;36m"; my $txt_bcyan = "\033[0;1;36m"; my $txt_white = "\033[0;37m"; my $txt_bwhite = "\033[1;37m"; my $txt_norm = "\033[0;m"; # Codes we commonly use my $txt_clear = "\033[2J\033[H"; my $txt_check = $txt_yellow; my $txt_debug = $txt_bblack; my $txt_done = "\033[0;1;5;37;42m"; my $txt_fatal = "\033[0;1;5;37;41m"; my $txt_okay = $txt_bgreen; my $txt_prompt = $txt_bred; my $txt_warn = "\033[0;1;5;33m"; $0 =~ m#[^/]+$#; chdir $`; while (1) { menu(read_config($config)); } exit 0; # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Everything past here is a subroutine # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Read configuration file into @conf # # $conf[0] Number of default settings # $conf[1] Default firmware filename # $conf[2] Default logo filename # $conf[3] Default logo position # $conf[4] Default citrix firmware filename # $conf[5] Default citrix logo filename # $conf[6] Default citrix logo position # $conf[7] Default rescue image filename # sub read_config { my $ibuild; my $iname; my $iver; my $ifile; my $ipart; $config = $_[0]; my $state = 0; my @conf = (); my @tokens = ( "firmware", "logo", "partition", "position", "rescue", "version", "boardrev" ); open CONF, '<'.$config; while () { chop $_; s/^\s*#.*//; if ($state == 2 && m/^\s*file\s*=\s*(.*)\s*$/) { $ifile = $1; $state = 3; } if ($state == 3 && m/^\s*partition\s*=\s*(.*)\s*$/) { $ipart = $1; $state = 0; push @conf, $iname; push @conf, $iver; push @conf, $ifile; push @conf, $ipart; } if ($state == 1 && m/^\s*version\s*=\s*(.*)\s*$/) { $iver = $1; $state = 2; } if ($state == 0 && m/^\s*image\s*=\s*(.*)\s*$/) { $iname = $1; $state = 1; } if ($state == 0 && m/^\s*build\s*=\s*([0-9]+)\s*$/) { $build = $1; } if ($state == 0 && m/^\s*firmware\s*=\s*(.*)\s*$/) { $firmware = $1; } if ($state == 0 && m/^\s*citrix\s*=\s*(.*)\s*$/) { $citrix[0] = $1; $state = 4; } if ($state == 4 && m/^\s*logo\s*=\s*(.*)\s*$/) { $citrix[1] = $1; $state = 5; } if ($state == 5 && m/^\s*position\s*=\s*(.*)\s*$/) { $citrix[2] = $1; $state = 0; } if ($state == 0 && m/^\s*rescue\s*=\s*(.*)\s*$/) { $rescue = $1; } if ($state == 0 && m/^\s*boardrev\s*=\s*(.*)\s*$/) { $boardrev = $1; } } close CONF; fatal_error("Invalid Configuration file${txt_debug} ($state)") if ($state); return @conf; } # # Display a message # sub msg { my $date = `date`; chop $date; print STDERR "${txt_cyan}${date}: ${txt_norm}@_\n"; } # # Fatal error # sub fatal_error { msg($_[0]); msg("${txt_fatal}Fatal error!${txt_norm} Reset or CTRL-ALT-DEL to retry!"); do {} while(1); } # # Display a menu # sub menu { my @cfg = @_; my $iname; my $iver; my $ifile; my $ipart; my $item = 1; my $i = 0; my $create_prodserv = 0; # Change the tab stops print STDERR "\033[2J\033[3g"; print STDERR "\033[1;25H\033H"; print STDERR "\033[1;53H\033H"; print STDERR "\033[1;60H\033H"; print STDERR "\033[H"; print STDERR <; chop $cmd; } until ($cmd =~ m/^[0-9]+$/); print STDERR "\n"; # # Be very careful if you change this! # All the numbers are dependent on each other! # if ($cmd == $create_prodserv) { my $desc = $cfg[($cmd - 1) * 4]; $desc =~ s/\\.*//; print STDERR $txt_clear; msg("${txt_bwhite}Creating a ${desc}${txt_norm}"); do_prodserv($cfg[$cmd * 4 - 2], $cfg[$cmd * 4 - 1]); } elsif ($cmd <= $item - 6) { my $desc = $cfg[($cmd - 1) * 4]; $desc =~ s/\\.*//; print STDERR $txt_clear; msg("${txt_bwhite}Creating a ${desc}${txt_norm}"); do_everything($cfg[$cmd * 4 - 2], $cfg[$cmd * 4 - 1]); } elsif ($cmd == $item - 6) { do_citrix (); } elsif ($cmd == $item - 5) { do_diskless (); } elsif ($cmd == $item - 4) { do_flash (); } elsif ($cmd == $item - 3) { do_rescue(1); } elsif ($cmd == $item - 2) { do_special_update (); } elsif ($cmd == $item - 1) { do_tests (); } elsif ($cmd == $item) { exec '/sbin/shutdown -r now'; } } # # ifconfig - all comm interface setup goes here # sub ifconfig { my $ifc = $_[0]; my $state = $_[1]; my $plip_dev; # on 2.0 kernels the plip device is plip1 # where as on 2.2 kernels it is plip0 if (kernel_version () eq '2.0') { $plip_dev = 'plip1'; } else { $plip_dev = 'plip0'; } # msg("ifc($ifc) state($state) eth1_type($eth1_type)"); # Cannot change the eth0 config (needed for NFS root) if ($ifc eq 'eth0') { return; } # 10/100 interface if ($ifc eq 'eth1') { if ($state eq 'up') { system (<<"EOF"); { ( ifconfig \| grep -q eth1 ) \&\& ifconfig eth1 down rmmod $eth1_type modprobe $eth1_type ifup $ifc } $redir EOF } else { system (<<"EOF"); { ifconfig $ifc down rmmod $eth1_type } $redir EOF } } # PLIP (parallel port) if ($ifc eq $plip_dev) { if ($state eq 'up') { system (<<"EOF"); { ifconfig $ifc down rmmod plip modprobe plip ifup $ifc } $redir EOF } else { system (<<"EOF"); { ifconfig $ifc down rmmod plip } $redir EOF } } } # # Get the ifconfig report for an interface # sub read_ifconfig { my $eth = $_[0]; my $eth_mac = ''; my $eth_ip = ''; my $eth_bc = ''; my $eth_nm = ''; my $rc = 0; # Bring the interface up if necessary ifconfig($eth, 'up'); # Read the interface settings open IFCONFIG, "ifconfig $eth 2>/dev/null|"; while () { $eth_mac = "0x$1$2$3" if (m/HWaddr ..:..:..:(..):(..):(..)/); $eth_ip = $1 if (m/addr:([0-9\.]{7,})/); $eth_bc = $1 if (m/Bcast:([0-9\.]{7,})/); $eth_nm = $1 if (m/Mask:([0-9\.]{7,})/); } close IFCONFIG; eval "\$eth_mac = $eth_mac"; # Bring down interface up if necessary ifconfig($eth, 'down'); return ($eth, $eth_mac, $eth_ip, $eth_bc, $eth_nm); } # # Set the 10/100baseT MAC address # sub setmac { my $mac; my @eth0; my @eth1; my $eth1_upg; if (kernel_version () eq '2.0') { $eth1_upg = ''; } else { $eth1_upg = '-2.2'; } msg("${txt_check}Checking the 10/100baseT MAC address${txt_norm}"); @eth0 = read_ifconfig('eth0'); @eth1 = read_ifconfig('eth1'); $mac = $eth0[1] | 0xc00000; if ($eth1[1] != $mac) { msg('Setting the 10/100baseT MAC address'); system (<<"EOF"); { insmod -f ./${eth1_type}_upgd${eth1_upg}.o rmmod ${eth1_type}_upgd${eth1_upg} } $redir EOF msg("The 10/100baseT MAC address was reprogrammed, must reboot"); msg("${txt_bred}Reset or CTRL-ALT-DEL to try agian!"); do {} while(1); } else { msg("${txt_okay}10/100baseT MAC address okay${txt_norm}"); } } # # Get the drive specs # sub query_drive { my $hda_cyl; my $hda_hds; my $hda_sec; my $hda_size; msg('Reading drive specs'); $_ = `hdparm -g /dev/hda | grep geometry`; m#([0-9]+)/([0-9]+)/([0-9]+)#; $hda_cyl = $1; $hda_hds = $2; $hda_sec = $3; $hda_size = `/sbin/sfdisk -s /dev/hda`; chomp $hda_size; $hda_size *= 2; # Check for a large drive (16383/16/63 industry standard) if ($hda_cyl == 16383 && $hda_hds == 16 && $hda_sec == 63) { $hda_cyl = $hda_size / (16 * 63); $hda_cyl =~ s/\.*//; # while ($hda_cyl >= 16383) { # $hda_hds *= 2; # $hda_cyl = $hda_size / ($hda_hds * 63); # $hda_cyl =~ s/\.*//; # } } @_ = ($hda_cyl, $hda_hds, $hda_sec, $hda_size); } # # Partition the drive # sub partition_scheme_6 { my $hda_p1s; my $hda_p1e; my $hda_p2s; my $hda_p2e; my $hda_p3s; my $hda_p3e; my $hda_p4s; my $hda_p4e; my $cyl; my $root_cyl; my $swap_cyl; my $export_cyl; my $rescue_cyl; msg('Partitioning drive'); ($hda_cyl, $hda_hds, $hda_sec, $hda_size) = @_; fatal_error('Drive is too small.') if ($hda_size < 2400000); $cyl = $hda_hds * $hda_sec; # swap = 256 MB $swap_cyl = (2 * 256 * 1024 / $cyl) + 1; $swap_cyl =~ s/\..*//; # rescue = 15 MB $rescue_cyl = (2 * 15 * 1024 / $cyl) + 1; $rescue_cyl =~ s/\..*//; # / = 1000 MB $root_cyl = (2 * 1000 * 1024 / $cyl) + 1; $root_cyl =~ s/\..*//; # /export = whatever is left $export_cyl = $hda_cyl - $swap_cyl - $rescue_cyl - $root_cyl; # /dev/hda1 $hda_p1s = 1; $hda_p1e = $root_cyl - 1; # /dev/hda2 $hda_p2s = $hda_p1e + 1; $hda_p2e = $hda_p2s + $swap_cyl - 1; # /dev/hda3 $hda_p3s = $hda_p2e + 1; $hda_p3e = $hda_p3s + $export_cyl - 1; # /dev/hda4 $hda_p4s = $hda_p3e + 1; $hda_p4e = $hda_cyl; open PFDISK, '|/sbin/fdisk /dev/hda'.$redir; print PFDISK <<"EOF"; x c $hda_cyl h $hda_hds s $hda_sec r d 1 d 2 d 3 d 4 n p 1 $hda_p1s $hda_p1e n p 2 $hda_p2s $hda_p2e t 2 82 n p 3 $hda_p3s $hda_p3e n p 4 $hda_p4s $hda_p4e p w EOF close PFDISK; } # # Partition the drive # sub partition_scheme_5 { my $hda_p1s; my $hda_p1e; my $hda_p2s; my $hda_p2e; my $hda_p3s; my $hda_p3e; my $hda_p4s; my $hda_p4e; my $cyl; my $root_cyl; my $swap_cyl; my $homeftp_cyl; my $rescue_cyl; msg('Partitioning drive'); ($hda_cyl, $hda_hds, $hda_sec, $hda_size) = @_; $cyl = $hda_hds * $hda_sec; # swap = 64 MB $swap_cyl = (2 * 64 * 1024 / $cyl) + 1; $swap_cyl =~ s/\..*//; # /dev/hda1 # $root_cyl = $hda_cyl - $swap_cyl; $root_cyl = 1023; # /dev/hda1 $hda_p1s = 1; $hda_p1e = $root_cyl - 1; # /dev/hda2 $hda_p2s = $hda_p1e + 1; $hda_p2e = $hda_p2s + $swap_cyl - 1; if ($hda_p2e < ($hda_cyl - 1)) { $hda_p3t = 83; $hda_p3s = $hda_p2e + 1; $hda_p3e = $hda_cyl - 1; $hda_p3n = 'user'; } else { $hda_p3t = 0; $hda_p3s = 0; $hda_p3e = 0; $hda_p3n = ''; } open PFDISK, '|/sbin/fdisk /dev/hda'.$redir; print PFDISK <<"EOF"; x c $hda_cyl h $hda_hds s $hda_sec r d 1 d 2 d 3 d 4 n p 1 $hda_p1s $hda_p1e n p 2 $hda_p2s $hda_p2e t 2 82 n p 3 $hda_p3s $hda_p3e t 3 $hda_p3t p w EOF close PFDISK; } # # Partition the drive # sub partition_scheme_4 { my $hda_p1s; my $hda_p1e; my $hda_p2s; my $hda_p2e; my $hda_p3s; my $hda_p3e; my $hda_p4s; my $hda_p4e; my $cyl; my $root_cyl; my $swap_cyl; my $homeftp_cyl; my $rescue_cyl; msg('Partitioning drive'); ($hda_cyl, $hda_hds, $hda_sec, $hda_size) = @_; fatal_error('Drive is too small.') if ($hda_size < 2400000); $cyl = $hda_hds * $hda_sec; # swap = 64 MB $swap_cyl = (2 * 64 * 1024 / $cyl) + 1; $swap_cyl =~ s/\..*//; # rescue = 10 MB $rescue_cyl = (2 * 10 * 1024 / $cyl) + 1; $rescue_cyl =~ s/\..*//; # / = 200 MB $root_cyl = (2 * 300 * 1024 / $cyl) + 1; $root_cyl =~ s/\..*//; # /home/ftp = whatever is left $homeftp_cyl = $hda_cyl - $swap_cyl - $rescue_cyl - $root_cyl; # /dev/hda1 $hda_p1s = 1; $hda_p1e = $root_cyl - 1; # /dev/hda2 $hda_p2s = $hda_p1e + 1; $hda_p2e = $hda_p2s + $swap_cyl - 1; # /dev/hda3 $hda_p3s = $hda_p2e + 1; $hda_p3e = $hda_p3s + $homeftp_cyl - 1; # /dev/hda4 $hda_p4s = $hda_p3e + 1; $hda_p4e = $hda_cyl; open PFDISK, '|/sbin/fdisk /dev/hda'.$redir; print PFDISK <<"EOF"; x c $hda_cyl h $hda_hds s $hda_sec r d 1 d 2 d 3 d 4 n p 1 $hda_p1s $hda_p1e n p 2 $hda_p2s $hda_p2e t 2 82 n p 3 $hda_p3s $hda_p3e n p 4 $hda_p4s $hda_p4e p w EOF close PFDISK; } # # Partition the drive # sub partition_scheme_3 { my $hda_p1s; my $hda_p1e; my $hda_p2s; my $hda_p2e; my $hda_p3s; my $hda_p3e; my $hda_p4s; my $hda_p4e; my $cyl; my $root_cyl; my $swap_cyl; my $usr_cyl; my $usr_max; my $rescue_cyl; msg('Partitioning drive'); ($hda_cyl, $hda_hds, $hda_sec, $hda_size) = @_; fatal_error('Drive is too small.') if ($hda_size < 2400000); $cyl = $hda_hds * $hda_sec; # swap = 64 MB $swap_cyl = (2 * 64 * 1024 / $cyl) + 1; $swap_cyl =~ s/\..*//; # rescue = 10 MB $rescue_cyl = (2 * 10 * 1024 / $cyl) + 1; $rescue_cyl =~ s/\..*//; # 1.5 GB <= /usr <= 2 GB $usr_max = (2 * 2 * 1024 * 1024) / $cyl + 1; $usr_max =~ s/\..*//; $usr_min = (3 * 1024 * 1024) / $cyl + 1; $usr_min =~ s/\..*//; $usr_cyl = ($hda_cyl - $swap_cyl - $rescue_cyl) / 2 + 1; $usr_cyl =~ s/\..*//; if ($usr_cyl >= $usr_max) { $usr_cyl = $usr_max; } elsif ($usr_cyl < $usr_min) { $usr_cyl = $usr_min; } # / = whatever is left $root_cyl = $hda_cyl - $swap_cyl - $rescue_cyl - $usr_cyl - 1; $root_cyl =~ s/\..*//; # /dev/hda1 $hda_p1s = 1; $hda_p1e = $root_cyl - 1; # /dev/hda2 $hda_p2s = $hda_p1e + 1; $hda_p2e = $hda_p2s + $swap_cyl - 1; # /dev/hda3 $hda_p3s = $hda_p2e + 1; $hda_p3e = $hda_p3s + $usr_cyl - 1; # /dev/hda4 $hda_p4s = $hda_p3e + 1; $hda_p4e = $hda_cyl; open PFDISK, '|/sbin/fdisk /dev/hda'.$redir; print PFDISK </dev/tty2 | tar xzpf - -C /mnt/hda1"); } else { $rc = system ("wget ftp://$server/pub/$image -O - 2>/dev/tty2 | tar xpf - -C /mnt/hda1"); } fatal_error('Error installing image') if ($rc); } # # Prompt y/n for reboot # sub prompt_reboot { my $prompt; my $date = `date`; my $end = 0; chomp $date; # Empty the buffer in case anyone hit any extra keys. # Time out if there is no current data in the buffer. # Deal with multiple entry lines while ($end == 0) { eval { local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n required alarm 2; ; alarm 0; }; if ($@) { die unless $@ eq "alarm\n"; # propagate unexpected errors # timed out $end = 1; } } print STDERR "${txt_cyan}$date: ${txt_prompt}h to halt or Reboot (y/n)? ${txt_norm}"; $prompt = ; chop $prompt; $prompt =~ tr/[A-Z]/[a-z]/; if ($prompt =~ /y$/ || $prompt =~ /r$/ || $prompt =~ /yes$/) { exec '/sbin/shutdown -r now'; } if ($prompt =~ /h$/) { exec '/sbin/shutdown -h now'; } } # # Install rescue image # sub do_rescue { my $server = server(); my $rc; if ($_[0] == 1) { print STDERR $txt_clear; msg("${txt_bwhite}Installing Rescue Image"); msg('Formatting rescue partition'); $rc = system ("mke2fs -O sparse_super /dev/hda4 $redir"); fatal_error('Error formatting rescue partition') if ($rc); } msg("Installing Rescue Image ${txt_debug}($rescue)${txt_norm}"); if ($_[0] == 1) { $rc = system ("mount -n -t ext2 /dev/hda4 /mnt/hda4 $redir"); fatal_error('Error mounting rescue partition') if ($rc); } if ($rescue =~ m/\.gz$/) { $rc = system ("wget ftp://$server/pub/$rescue -O - 2>/dev/tty2 | tar xzpf - -C /mnt/hda4"); } else { $rc = system ("wget ftp://$server/pub/$rescue -O - 2>/dev/tty2 | tar xpf - -C /mnt/hda4"); } fatal_error('Error installing rescue image') if ($rc); if ($_[0] == 1) { $rc = system ("umount /dev/hda4 $redir"); fatal_error('Error unmounting rescue partition') if ($rc); msg("${txt_done}Installation complete!${txt_norm}"); prompt_reboot(); } } # # Update the flash # sub flash { my $rc; my $attempt; my $nettrom = '/mnt/hda1/boot/nettrom'; my $fw = '/home/ftp/pub/firmware'; # my $logo = "-x 90 -y 90 $fw/NW_Rebel.gif --no-netwinder"; my $logo = "-x 70 -y 90 NW_Rebel.gif --no-netwinder"; # This is necessary to get around an unknown issue/bug # with untarring and retarring the Licor build dm-2.1.12 stuff # if (-e '/mnt/hda1/boot/nettrom-2.0.4a.bin') { $nettrom = "/root/nettrom-2.1.16bl.bin"; system ("cp -fva /root/nettrom-2.1.16bl.bin /mnt/hda1/boot"); } elsif (-e "$nettrom.bin") { $nettrom = "$nettrom.bin"; } elsif (!(-e $nettrom)) { $nettrom = $firmware; } msg('Writing a logo to the flash'); $rc = system ("modprobe nwflash $redir"); $rc = system ("logowrite $logo $redir"); # rc = system ("logowrite --no-usergif $redir"); msg("${txt_check}Checking the firmware${txt_norm}"); $rc = system ("flash_check $nettrom $redir"); if ($rc == 0) { msg("${txt_okay}Firmware okay${txt_norm}"); system (<<"EOF"); { set_therm 10 8 sleep 1 set_therm 50 48 fan_ctrl on } $redir EOF return; } msg('Writing the firmware'); for ($attempt = 1, $rc = 1; $rc && $attempt <= 10; $attempt++) { open FLASHWRITE, "|flashwrite -base64 $nettrom 0 $redir"; print FLASHWRITE "Y\n"; close FLASHWRITE; $rc = system ("flash_check $nettrom $redir"); if ($rc) { msg("${txt_warn}Error writing firmware!${txt_norm} Trying again"); } }; if ($rc) { msg('Failed to write the firmware'); fatal_error('THIS BOARD IS LIKELY DEAD'); } system (<<"EOF"); { set_therm 8 10 sleep 1 set_therm 50 48 fan_ctrl on rmmod nwflash } $redir EOF msg("${txt_okay}Flash okay.${txt_norm}"); } # # Detect SCSI # sub detect { my $options = 0; # Get the board configuration open CPUINFO, ') { # 2.0 kernels if (m/Board Rev/) { tr/[a-z]/[A-Z]/; @_ = split /\s+/, $_; $revision = substr $_[3], 0, 2; $options = substr $_[3], 2, 2; } # 2.2 kernels elsif (m/Revision/) { tr/[a-z]/[A-Z]/; @_ = split /\s*:\s*/, $_; $revision = substr $_[1], 0, 2; $options = substr $_[1], 2, 2; } if (m/BogoMips\s*:\s*(\d*\.\d*).*/ ) { $bogomips = $1; } } close CPUINFO; # Set the ethernet driver module if not tulip (default) if ($options eq 'BF' or $options eq '3F') { $eth1_type = 'yellowfin'; } if (!($options eq 'FF' or $options eq 'BF' or $options eq '7F' or $options eq '3F')) { fatal_error ("Invalid daughter card ID (have: $options)\n\t" . "The current correct values are: FF, BF, 7F and 3F\n" . "\tThis needs to be fixed!!!"); } if (hex ($revision) < hex ($boardrev)) { fatal_error ("Invalid Board Revision (have: $revision)" . "\n\tNeed at least $boardrev.\nThis would indicate " . "the board has not had all the current ECOs applied." . "\nIf all ECOs have been applied, please contact " . "Rebel.com for assistance."); } if (!($bogomips eq '235.11' or $bogomips eq '262.14')) { fatal_error ("Invalid bogomips for main CPU clock.\n" . "Have: $bogomips\nAccepted values are currently " . "either 262.14 (old boards)\nor 235.11 after Rev " . "5A boards.\nThis could indicate a resistor " . "setting is incorrect?"); } return $options; } # # SCSI check # sub scsi_test { my $prompt; my $rc; msg('Connect the SCSI cable. Press ENTER'); $prompt = ; # Install the nedded modules system (<<"EOF"); { modprobe nls modprobe isofs modprobe sym53c8xx modprobe scsi_mod modprobe sr_mod } $redir EOF # Test by mounting $rc = system ("mount -o ro /dev/scd0 /mnt/cdrom $redir"); if ($rc) { fatal_error ('SCSI test failed! Stopping!'); } system ("umount /dev/scd0 $redir"); msg('SCSI test passed'); # BUG: removing causes kernel oops # system ("rmmod isofs $redir"); # system ("rmmod nls $redir"); # system ("rmmod sr_mod $redir"); # system ("rmmod sym53c8xx $redir"); # system ("rmmod scsi_mod $redir"); } # # Serial port check # sub serial_test { my $prompt; my $rc; msg('Connect serial dongle. Press ENTER'); $prompt = ; system ("modprobe serial $redir"); $rc = system ("sertest $redir"); system ("rmmod serial $redir"); if ($rc) { fatal_error ("Serial test failed! Stopped!"); } msg("${txt_okay}Serial port okay${txt_norm}"); } # # Check the ethernet100 # sub eth100_test { my $prompt; my $rc; my $ping; my $ping_s; msg('Connect cable to eth10/100 port. Press ENTER'); $prompt = ; # Bring the interface up msg('Now testing eth10/100'); ifconfig('eth1', 'up'); eval { local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n required alarm 50; open NETPERF, "netperf -H test-100 -l 25 2>/dev/null|"; while () { $speed = $1 if (m/(\d+\.\d+)\s*$/); } close NETPERF; alarm 0; }; if (! $! || $@) { ## die unless $@ eq "alarm\n"; # propagate unexpected errors # timed out if $@ is set system "killall netperf"; close NETPERF; fatal_error ("Unable to connect to server\n\tthe server " . "may be down, \n\tor the 100 Mbit ethernet has a " . "problem.\n\tEthernet 100 test failed! Stopped!!"); } # How did we do? if ($speed >= 50) { msg("Ethernet 100 test successful ($speed Mbits/sec)"); } else { fatal_error ("Ethernet 100 test failed! " . "($speed Mbits/sec)\n\tNeed a minimum through " . "put of 50 Mbits/sec.\n\tStopped!!"); } # Take the interface down ifconfig('eth1', 'down'); } # # Parallel port check # sub parallel_test { my $prompt; my $rc; my $ping; my $ping_s; my $plip_dev; # on 2.0 kernels the plip device is plip1 # where as on 2.1 kernels it is plip0 if (kernel_version () eq '2.0') { $plip_dev = 'plip1'; } else { $plip_dev = 'plip0'; } msg('Connect cable to parallel port. Press ENTER'); $prompt = ; # Bring the interface up msg("${txt_check}Checking the parallel port${txt_norm}"); ifconfig($plip_dev, 'up'); # Do the test - abort on first success PLIPLOOP: for ($ping = 1; $ping <= 5; $ping++) { open PING, "ping -nc 1 plip-server 2>&1|"; while () { last PLIPLOOP if (m/ 0%/); } } close PING; # Improve our vocabulary $ping_s = ($ping == 1) ? 'ping': 'pings'; # How'd we do? if ($ping <= 5) { msg("Parallel port test successful ($ping $ping_s)"); } else { fatal_error ("Parallel port test failed! Stopped!!"); } # Take the interface down ifconfig($plip_dev, 'down'); } # # Do everything # sub do_everything { my $prompt; my $image = $_[0]; my $scheme = $_[1]; my $options = detect(); # write the time to the board set_time (); # Set eth1 MAC address (tulip and yellowfin only) if ($options eq 'FF' or $options eq 'BF' or $options eq '7F' or $options eq '3F') { setmac(); } # check for and backup burn in data backup_burn_in_data (); # Format all partitions eval "partition_$scheme(query_drive())"; eval "format_$scheme()"; # Mount the partitions we'll be using eval "mount_$scheme('mount')"; if ($scheme ne 'scheme_1' and $scheme ne 'scheme_2' and $scheme ne 'scheme_5') { do_rescue(0); } # Install the drive image install_image($image); # Update the flash if necessary flash(); # Unmount the drives eval "mount_$scheme('umount')"; # Prompt for reboot msg("${txt_done}Installation complete!${txt_norm}"); prompt_reboot(); } # # Build diskless system - set eth10/100 mac address and write the flash # sub do_diskless { my $options = detect(); # write the time to the board set_time (); print STDERR $txt_clear; msg("${txt_bwhite}Creating a diskless system${txt_norm}"); # Set eth1 MAC address (tulip and yellowfin) if ($options eq 'FF' or $options eq 'BF' or $options eq '7F' or $options eq '3F') { setmac(); } # Write the flash flash(); # Prompt for reboot msg("${txt_done}Installation complete!${txt_norm}"); prompt_reboot(); } # # Update the flash # sub do_flash { # write the time to the board set_time (); print STDERR $txt_clear; msg("${txt_bwhite}Updating the firmware${txt_norm}"); flash(); msg("${txt_bwhite}Checking the eth100 MAC address${txt_norm}"); setmac(); # Prompt for reboot msg("${txt_done}Installation complete!${txt_norm}"); prompt_reboot(); } # # Testing # sub do_tests { my $options = detect(); # write the time on the board set_time (); # Sound test on Plastic Units if ($options eq 'FF') { sound_tests (); } # Serial test if ($options eq 'FF' or $options eq 'BF' or $options eq '7F' or $options eq '3F') { serial_test(); } # eth100 test (tulip and yellowfin) if ($options eq 'FF' or $options eq 'BF' or $options eq '7F' or $options eq '3F') { setmac(); eth100_test(); } # SCSI test (yellowfin only) if ($options eq 'BF' or $options eq '3F') { scsi_test(); } # Parrallel port test parallel_test(); # perform a disk DMA test disk_dma_tests (); # Prompt for reboot msg("${txt_done}Testing complete!${txt_norm}"); prompt_reboot(); } # # Create a Citrix Thin Client (TC) # sub do_citrix { my $rc; my $attempt; my $fw = '/root'; my $logo = "$citrix[2] $fw/$citrix[1]"; $nettrom = "$fw/$citrix[0]"; # write the time to the board set_time (); print STDERR $txt_clear; msg("${txt_bwhite}Creating a Thin Client (TC)${txt_norm}"); msg('Writing a logo to the flash'); $rc = system ("modprobe nwflash $redir"); $rc = system ("logowrite $logo $redir"); msg("${txt_check}Checking the firmware${txt_norm}"); $rc = system ("flash_check $nettrom $redir"); if ($rc == 0) { msg("${txt_okay}Flash okay${txt_norm}"); $rc = system ("set_therm 8 10 $redir"); $rc = system ("sleep 1 $redir"); return; } msg('Writing the firmware'); for ($attempt = 1, $rc = 1; $rc && $attempt <= 10; $attempt++) { open FLASHWRITE, "|flashwrite -base64 $nettrom 0 $redir"; print FLASHWRITE "Y\n"; close FLASHWRITE; $rc = system ("flash_check $nettrom $redir"); if ($rc) { msg("${txt_warn}Error writing the firmware!${txt_norm} Trying again"); } } if ($rc) { msg('Failed to write the flash'); fatal_error('THIS BOARD IS LIKELY DEAD'); } # Force the fan back on system (<<"EOF"); { set_therm 8 10 sleep 1 set_therm 50 48 fan_ctrl on } $redir EOF system ("rmmod nwflash $redir"); msg("${txt_okay}Flash okay${txt_norm}"); # Prompt for reboot msg("${txt_done}Installation complete!${txt_norm}"); prompt_reboot(); } # # Create a production server # sub do_prodserv { my $prompt; my $image = $_[0]; my $scheme = $_[1]; my $options = detect(); my $server = server(); print ("Enter the Sever number for the production server to create.\n"); print ("This is a number between 10 and 250, which does not\n"); print ("conflict with any existing server numbers: "); $prompt = ; chop $prompt; if ($prompt =~ /\D/ || $prompt < 10 || $prompt > 250) { print "\n\n\n\tInvalid number entered.\n"; print "\tYou need to enter a number between 10 and 250,\n"; print "\twhich will not conflict with any existing servers.\n"; print "\tPress any key to continue "; $prompt = ; return; } msg ("Creating Production server numbered: $prompt"); # write the time to the board set_time (); # Set eth1 MAC address (tulip and yellowfin only) if ($options eq 'FF' or $options eq 'BF' or $options eq '7F' or $options eq '3F') { setmac(); } # Format all partitions eval "partition_$scheme(query_drive())"; eval "format_$scheme()"; # Mount the partitions we'll be using eval "mount_$scheme('mount')"; if ($scheme ne 'scheme_1' and $scheme ne 'scheme_2') { do_rescue(0); } # Install the root install_image($image); # Create vncroot system ("mkdir -p /mnt/hda1/home/ftp/pub/vncroot"); system ("ln -s home/ftp/pub/tftpboot /mnt/hda1"); system ("ln -s home/ftp/pub/vncroot /mnt/hda1"); msg("Installing NFS root image ${txt_debug}($image)${txt_norm}"); if ($image =~ m/\.gz$/) { $rc = system ("wget ftp://$server/pub/$image -O - 2>/dev/tty2 | tar xzpf - -C /mnt/hda1/home/ftp/pub/vncroot"); } else { $rc = system ("wget ftp://$server/pub/$image -O - 2>/dev/tty2 | tar xpf - -C /mnt/hda1/home/ftp/pub/vncroot"); } fatal_error('Error installing image') if ($rc); # Install needed RPMS msg('Installing RPMS and configuring'); system (<<"EOF"); { ROOT=/mnt/hda1 SERVER=/server-root RPM_DIR=/server-root/home/ftp/pub rpm --root=\$ROOT -ihv \$RPM_DIR/RPMS/* rpm -e --root=\$ROOT/home/ftp/pub/vncroot kudzu rpm --root=\$ROOT/home/ftp/pub/vncroot -ihv \$RPM_DIR/RPMS-vncroot/* cd \$ROOT cp -av \$SERVER/root/* \$ROOT/root cd \$SERVER/home/ftp/pub cp -av firmware tftpboot RPMS SRPMS RPMS-vncroot \$ROOT/home/ftp/pub cd vncroot/root cp -av * \$ROOT/home/ftp/pub/vncroot/root } $redir EOF msg("Going into server setup for server: $prompt"); $rc = system ("./setup-server /mnt/hda1 $prompt $redir"); fatal_error("Error doing server setup for server: $prompt") if ($rc); msg("Copying over tar images"); $rc = system ("cd /mnt/hda1/home/ftp/pub; wget ftp://$server/pub/\*.tar.gz $redir"); fatal_error('Error copying over tar images') if ($rc); # Update the flash flash(); # Unmount the drives eval "mount_$scheme('umount')"; # Prompt for reboot msg("${txt_done}Installation complete!${txt_norm}"); prompt_reboot(); } # # Set the time on the machine # sub set_time { my $date = `date`; chop $date; msg("Syncing the time"); system ("ntpdate server $redir"); msg("Writing the time to the system"); system ("clock --utc -w $redir"); } # # get the first two digits of the kernel version # sub kernel_version { my $kern_vers; $kern_vers = `uname -r`; $kern_vers =~ /(^\d\.\d)/; return $1; } # # Check for burn in image data and back it up on the server if it exists # sub backup_burn_in_data { msg ("Checking for Burn-In data, backing up"); system (<<"EOF"); { mount -n /dev/hda1 /mnt/hda1 || exit 1 if [ -f /mnt/hda1/.burn_in_run ]; then mkdir -p /burn-data tar cvfz /burn-data/`/bin/date '+%Y%m%d==%H-%M-%S'`.tar.gz /mnt/hda1/tmp fi umount -n /dev/hda1 } $redir EOF } # # Do sound test on supported hardware # sub sound_tests { msg ("Starting Audio tests."); msg ("You should hear a ringing"); msg (" from the internal speaker."); msg('To begin, press ENTER'); $prompt = ; if (hex ($revision) < hex (60)) { system ("modprobe waveartist $redir"); } else { system ("modprobe pcsnd $redir"); } system ("play /usr/testscripts/stereo.wav $redir"); msg('Now turn up the volume.'); system ("play /usr/testscripts/stereo.wav $redir"); system ("play /usr/testscripts/stereo.wav $redir"); msg('Did you hear a bell ringing'); msg(' from the internal speaker?'); msg('Press "n" for no, any other key to continue.'); $prompt = ; chop $prompt; $prompt =~ tr/[A-Z]/[a-z]/; if ($prompt =~ /n$/) { fatal_error ("Sound test failed! Stopped!"); } msg("${txt_okay}Sound test passed${txt_norm}"); } # # A test to verify disk DMA works correctly. # Also test to verify the drive can maintain a disk reads speed of # minimun 5 MB/sec. # sub disk_dma_tests { my $rc; my $speed = 0 ; msg ("Beginning Disk DMA test"); system ("hdparm -p4 -X34 -d1 /dev/hda $redir"); system ("dmesg -c >/dev/null"); open HDPARM, "hdparm -t /dev/hda 2>/dev/null|"; while () { $speed = $1 if (m/\s*(\d*\.\d*)\s*MB/); } close HDPARM; # here we are looking for dma resets from a drive which does # not support DMA. $rc = system ("dmesg | egrep -i hda $redir"); fatal_error ('Disk DMA problem!') if (! $rc); if ($speed < 5.0) { fatal_error ("Disk speed is too slow. \n\tHave " . "reported: $speed MB/sec,\n\twhen a minimum " . "of 5 MB/sec is required."); } msg ("${txt_okay}Disk DMA test passed. Disk speed is " . "$speed MB/sec.${txt_norm}"); } # # Do a special updgrade for specific packages. # This assumes the machine has already been imaged. # sub do_special_update { my $scheme = 'scheme_3'; my $rc; my $kudzu = '/root/kudzu-0.9-1.armv4l.rpm'; print STDERR $txt_clear; msg ("${txt_bwhite}Doing a Special Upgrade of an existing system${txt_norm}"); msg ("Mounting file systems"); # Mount the drives eval "mount_$scheme('mount')"; msg ("Updating kudzu package to $kudzu"); $rc = system ("/bin/rpm -Uhv --root=/mnt/hda1 $kudzu $redir"); fatal_error ('Problem upgrading RPM, please reimage!') if ($rc); # Unmount the drives now # Mount the drives msg ("Unmounting file systems"); eval "mount_$scheme('umount')"; msg ("Update succeeded."); prompt_reboot(); }