diff options
Diffstat (limited to 'sys-apps/yard/files/yard-2.2/sbin/write_rescue_disk')
-rw-r--r-- | sys-apps/yard/files/yard-2.2/sbin/write_rescue_disk | 566 |
1 files changed, 566 insertions, 0 deletions
diff --git a/sys-apps/yard/files/yard-2.2/sbin/write_rescue_disk b/sys-apps/yard/files/yard-2.2/sbin/write_rescue_disk new file mode 100644 index 000000000000..9b1642df164e --- /dev/null +++ b/sys-apps/yard/files/yard-2.2/sbin/write_rescue_disk @@ -0,0 +1,566 @@ +#! /usr/bin/perl +# -*- Mode: Perl -*- +# This script created automatically from scripts/write_rescue_disk.in +# $Header: /var/cvsroot/gentoo-x86/sys-apps/yard/files/yard-2.2/sbin/write_rescue_disk,v 1.1 2002/08/25 20:25:33 aliz Exp $ +############################################################################## +## +## WRITE_RESCUE_DISK +## Copyright (C) 1996,1997,1998 Tom Fawcett (fawcett@croftj.net) +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +############################################################################## +use strict; +use File::Basename; +use File::Find; +use File::Path; +use FileHandle; +use Cwd; +use English; +use lib "/etc/yard", "/usr/lib/yard"; +use yardconfig; + +BEGIN { require "yard_utils.pl" } + +require "Config.pl"; + +STDOUT->autoflush(1); + +start_logging_output(); +print "write_rescue_disk 2.0\n"; + +if ($CFG::disk_set !~ /^(single|double|base\+extra)$/) { + error "Config variable disk_set is set to \"$CFG::disk_set\"\n", + "which is not a valid value.\n"; +} + +############################################################################## +###### Global variables used in this file +############################################################################## +my($kernel_fs_blocks); # Number of blocks taken up by kernel + # on floppy, whether raw or within fs. +my($root_start); # Where the root starts on the floppy +my($rootfsz_blocks); # Number of blocks required by compressed root +my($seek_clause); # 'Seek' clause for dd root + + + +############################################################################## +##### Check a few things before starting. ##### +############################################################################## +$REAL_USER_ID == 0 or die "This script must be run as root!\n"; + +# Check mount point +if (-d $CFG::mount_point and -w $CFG::mount_point) { + info 1, "Using $CFG::mount_point as the floppy mount point\n"; +} else { + error "Mount point $CFG::mount_point must be a directory and\n", + "must be write-enabled.\n"; +} + +# This test is slightly pointless; an uncompressed kernel these days is +# much too large to fit anyway. +if (!-r $CFG::kernel) { + error "Can't read kernel file $CFG::kernel\n"; +} elsif (`file $CFG::kernel` =~ /executable/) { + error "It looks like the kernel you specified ($CFG::kernel)\n", + "is uncompressed. It should be the compressed version.\n"; +} + +# If user has set $CFG::double_disk_set, convert value +# to appropriate $CFG::disk_set setting. +if (!defined($CFG::disk_set) and defined($CFG::double_disk_set)) { + if ($CFG::double_disk_set == 1) { + $CFG::disk_set = "double"; + } elsif ($CFG::double_disk_set == 0) { + $CFG::disk_set = "single"; + } else { + error "Value of \$CFG::double_disk_set is $CFG::double_disk_set\n", + "Should be 1 or 0\n"; + } +} + + +# We only come back up here if we discover that there is not enough +# space on a single-disk rescue set, and the user has agreed to try +# a two-disk rescue set. +RESTART: + +if (&rootfsz_up_to_date) { + info 0, "***** There is an existing $CFG::rootfsz file, and\n", + " it appears that no relevant files have changed since\n", + " $CFG::rootfsz was created.\n", + " Using this $CFG::rootfsz file as root fs\n"; +} else { + compress_root(); +} + +#### At this point, the root filesystem has been copied and compressed +#### and resides in $CFG::rootfsz. $CFG::mount_point is free. +info 0, "Flushing $CFG::device buffer cache.\n"; +flush_device_buffer_cache($CFG::device); + +load_mount_info(); + +##### Dereference $CFG::device in case it's a symbolic link +while (-l $CFG::device) { + ($CFG::device = readlink($CFG::device)) + or die "Can't resolve CFG::device\n"; +} + + +if (defined($::mounted{$CFG::floppy})) { + error "Floppy device $CFG::floppy is mounted. It shouldn't be in use.\n", + "Unmount $mounted::{$CFG::floppy}, remove the disk and insert a fresh one.\n", + "Do NOT mount it.\n"; + +} elsif (defined($::mounted{$CFG::mount_point})) { + if ($::mounted{$CFG::device} eq $CFG::mount_point) { + sys("umount $CFG::mount_point"); + } else { + error "Some other device is already mounted on $CFG::mount_point\n", + "Unmount it before running write_rescue_disk.\n"; + } +} + +info 0, "Rescue disk set: $CFG::disk_set\n"; + +##### Major control branch here. Transfer the kernel to the floppy +##### either using Lilo or not. + +if ($CFG::use_lilo) { + setup_kernel_using_lilo(); +} else { + setup_kernel_raw(); +} + +##### At this point, kernel is rdev'd with root start address and +##### $kernel_fs_blocks is set. +##### Check remaining space. + +$rootfsz_blocks = bytes_to_K((-s $CFG::rootfsz)); +info 1, "Compressed root filesystem is $rootfsz_blocks blocks.\n"; + +if ($CFG::disk_set eq "double") { ########## DOUBLE DISK SET + if ($rootfsz_blocks > $CFG::floppy_capacity - 1) { + error "compressed root fs ($rootfsz_blocks blocks)", + "> space on floppy (", $CFG::floppy_capacity - 1, ")\n"; + } else { + sync(); + info 0, "\n\aRemove the floppy disk from the drive.\n", + "Label it BOOT DISK.\n\n"; + insert_fresh_floppy_in_drive(); + info 1, "Proceeding with root disk...\n"; + transfer_sentinel(); + $root_start = 1; + } + +} else { ########## SINGLE DISK + if ($kernel_fs_blocks + $rootfsz_blocks > $CFG::floppy_capacity) { + info 0, "Kernel fs ($kernel_fs_blocks K) + compressed root fs ", + "($rootfsz_blocks K) > floppy capacity ", + "($CFG::floppy_capacity)\n"; + ##### See whether rootfsz_blocks would fit on another disk. + ##### if so, offer to switch to a two-disk rescue set. + + if ($rootfsz_blocks <= $CFG::floppy_capacity - 1 + and $CFG::disk_set eq "single") { + + info 0, "\aBut the compressed root fs will fit on a second disk.\n", + "Do you want to try a two-disk set now?\n"; + if (<STDIN> =~ /^y/i) { + info 0, "OK, retrying...\n"; + ##### NB. We must start over because the kernel must be + ##### rdev'd with the new root fs location. + + $CFG::disk_set = "double"; + goto RESTART; # yechh, spaghetti code + + } else { # User didn't say yes. + error "Aborting $0\n"; + } + } else { # Root fs too large -- no way to continue. + error "and your compressed root fs is too large ", + "($rootfsz_blocks K)\nto fit on a second disk.", + " Trim down your file set or go to a larger disk.\n"; + } + } else { + + $root_start = $kernel_fs_blocks; + + info 0, "Kernel fs needs blocks 0-", $kernel_fs_blocks-1, + ", so root filesystem will begin at block $root_start\n", + "Kernel + filesystem = ", $kernel_fs_blocks + $rootfsz_blocks, + " blocks = ", + int(($kernel_fs_blocks + $rootfsz_blocks) / $CFG::floppy_capacity + * 100), + "% of floppy capacity\n"; + } +} + +info 0, "Transferring compressed root filesystem ($CFG::rootfsz) to floppy \n"; +sync(); +sys("dd if=$CFG::rootfsz of=$CFG::floppy bs=1k seek=$root_start"); +sync(); + +sleep 2; +info 0, "\a\n\nTransfer completed successfully.\n\n"; + +if ($CFG::disk_set eq "single") { + info 0, "Remove the floppy disk from the drive\n", + "This is a complete rescue disk.\n"; + +} elsif ($CFG::disk_set eq "double") { + info 0, "Remove the second floppy disk from the drive\n", + "and label it ROOT DISK.\n", + "During the boot process you will be prompted for this\n", + "second disk after the kernel has been loaded from the first.\n"; + +} elsif ($CFG::disk_set eq "base+extra") { + info 0, "Remove the floppy disk from the drive and label it BOOT DISK.\n", + "This will be the first disk to load.\n", + "The other disk, which you've already prepared,\n", + "will be loaded second after the kernel has booted.\n"; +} + +exit(0); + + +############################################################################## +# A typical LILO FS: +# +# total 361 +# 1 drwxr-xr-x 2 root root 1024 Jan 10 07:23 boot/ +# 1 drwxr-xr-x 2 root root 1024 Jan 10 07:22 dev/ +# 1 -rw-r--r-- 1 root root 176 Jan 10 07:22 lilo.conf +# 358 -rw-r--r-- 1 root root 362707 Jan 10 07:23 vmlinuz +# boot: +# total 8 +# 4 -rw-r--r-- 1 root root 3708 Jan 10 07:22 boot.b +# 4 -rw------- 1 root root 3584 Jan 10 07:23 map +# dev: +# total 0 +# 0 brw-r----- 1 root root 2, 0 Jan 10 07:22 fd0 +# 0 crw-r--r-- 1 root root 1, 3 Jan 10 07:22 null +# +sub setup_kernel_using_lilo { + + info 0, "Creating kernel filesystem for Lilo\n"; + + ##### Contants for use with EXT2 + my($inode_allocation) = 8192; # bytes requested per inode + + my($blocks_for_kernel) = bytes_to_K(-s $CFG::kernel); + # We have to guess how big the other files are going to be. + # We also need additional space for lilo to work with. + my($blocks_for_other_files) = 20; + + $kernel_fs_blocks = $blocks_for_kernel + $blocks_for_other_files; + $kernel_fs_blocks += bytes_to_K($::INODE_SIZE * ($kernel_fs_blocks * 1024 / + $inode_allocation)); + + insert_fresh_floppy_in_drive(); + + sys("mke2fs -b 1024 -i $inode_allocation -m 0 $CFG::floppy " + . $kernel_fs_blocks); + sys("mount -t ext2 $CFG::floppy $CFG::mount_point"); + sys("rm -rf $CFG::mount_point/lost+found"); + + info 0, "Copying kernel $CFG::kernel to kernel fs on $CFG::floppy\n"; + ## This is slightly bad -- we shouldn't be mucking in the CFG + ## package, but this var is necessary for c_f_w_s. + local($CFG::kernel_basename) = basename($CFG::kernel); + sys("cp $CFG::kernel $CFG::mount_point/"); + + ##### Put the mount point on the floppy, and /dev/null for lilo + sys("cp --parents -R $CFG::floppy $CFG::mount_point"); + sys("cp --parents -R /dev/null $CFG::mount_point"); + + ##### Set up lilo + mkdir("$CFG::mount_point/boot", 0777) or error "mkdir: $!"; + sys("cp /boot/boot.b $CFG::mount_point/boot"); + + my($lilo_conf) = resolve_file("./Replacements/etc/lilo.conf"); + copy_file_with_substitution($lilo_conf, "$CFG::mount_point/lilo.conf"); + + sys("lilo -v -v -C lilo.conf -r $CFG::mount_point"); + + set_ramdisk_word("$CFG::mount_point/$CFG::kernel_basename", + $kernel_fs_blocks); + + sys("umount $CFG::mount_point"); + +} ## End of setup_kernel_using_lilo + + +sub setup_kernel_raw { + + ##### These are returned at the end: + info 0, "Writing kernel file $CFG::kernel to $CFG::floppy\n"; + sync(); + insert_fresh_floppy_in_drive(); + sys("dd if=$CFG::kernel of=$CFG::floppy bs=8192"); + sync(); + + $kernel_fs_blocks = bytes_to_K(-s $CFG::kernel); + + set_ramdisk_word($CFG::floppy, $kernel_fs_blocks); + + sys("rdev $CFG::floppy $CFG::floppy"); + sys("rdev -R $CFG::floppy 0"); + sync(); + +}# End of setup_kernel_raw + + + +# SET_RAMDISK_WORD($kernel, $kernel_blocks) +# Sets the ramdisk word in kernel based on configuration options +# and $kernel_blocks. +sub set_ramdisk_word { + my($image_loc, $kernel_blocks) = @_; + + my($prompt_flag); + + if ($CFG::disk_set eq "double") { + $root_start = 1; # Skip a block for sentinel sector + $prompt_flag = $::RAMDISK_PROMPT_FLAG; + + } else { + $root_start = $kernel_blocks; + $prompt_flag = 0; + } + + my($RAMDISK_WORD) = $::RAMDISK_LOAD_FLAG + | $prompt_flag + | ($::RAMDISK_IMAGE_START_MASK & $root_start); + + info 1, "rdev'ing kernel with root fs addr\n"; + info 1, "RAMDISK_WORD = ", sprintf("%X", $RAMDISK_WORD), "\n"; + sync(); + sys("rdev -r $image_loc $RAMDISK_WORD"); + sync(); +} + +# TRANSFER_SENTINEL - transfer the boot sector sentinel to the second disk. +sub transfer_sentinel { + my($sentinel_sector) = "$lib_dest/extras/bsect.b"; + + if (!-e $sentinel_sector) { + error "Sentinel boot sector $sentinel_sector does not exist!\n" + + } else { + sys("dd if=$sentinel_sector of=$CFG::floppy bs=1k") + } +} + +# Return 0 if the contents file or any of the Replacements files are +# newer than rootfsz, else 1. +sub rootfsz_up_to_date { + return(0) unless -e $CFG::rootfsz; + my($rootfsz_age) = -C $CFG::rootfsz; + my($any_newer) = 0; + return(0) unless $rootfsz_age < -C $CFG::contents_file; + + sub any_newer + { if ($rootfsz_age > -C $File::Find::name) + { $any_newer = 1 } + }; + find(\&any_newer, $CFG::mount_point); + + $any_newer ? 0 : 1; +} + + + + +sub insert_fresh_floppy_in_drive { + info 0, "Insert a new, write-enabled, ${CFG::floppy_capacity}K floppy into", + " the drive.\n"; + info 0, "Press RETURN when ready.\n"; + scalar(<STDIN>); # read and discard + while (system("dd if=/dev/zero of=$CFG::floppy count=1 bs=1 >/dev/null 2>&1")) { + warn "\a**** Drive $CFG::floppy does not contain a write-enabled diskette\n"; + warn "**** Fix this and press RETURN\n"; + scalar(<STDIN>); + } +} + + +sub compress_root { + ##### Make sure $CFG::device isn't already mounted + load_mount_info(); + if (defined($::mounted{$CFG::device})) { + if ($::mounted{$CFG::device} ne $CFG::mount_point) { + error "Device $CFG::device is already mounted on ", + $::mounted{$CFG::device}, "\n", + "Are you sure it contains the root filesystem?\n"; + } + } elsif (defined($::mounted{$CFG::mount_point})) { + error "Another device ($::mounted{$CFG::mount_point}) is already mounted", + " on $CFG::mount_point\n", + "Unmount it.\n"; + + } else { + + ## Mount the root filesystem one last time. This accomplishes + ## two things: We can get a ls-alR listing for future reference, + ## and it checks that the root filesystem hasn't been trashed at + ## some point along the way (if so, the mount will fail). + + info 0, "Mounting $CFG::device on $CFG::mount_point\n"; + &mount_device(); + } + + info 1, "Listing filesystem contents\n"; + my($contents_base) = basename($CFG::contents_file); + my($logfile_dir) = ($CFG::yard_temp or getcwd()); + my($ls_file) = "${logfile_dir}/${contents_base}.ls"; + sys("cd $CFG::mount_point; ls -alR > $ls_file"); + info 0, "Listing of rootdisk is on $ls_file\n"; + + ## Siphon off base files if necessary + + if ($CFG::disk_set eq "base+extra") { + #### FIX THIS + patch_rc_to_load_extra(); + prepare_extra_disks(); + } + + sys("umount $CFG::mount_point"); + info 0, "Compressing root filesystem on $CFG::device to $CFG::rootfsz\n"; + sync(); + # Note to myself: + # Can't reroute dd STDERR in this command because of the pipe + sys("dd if=$CFG::device count=$CFG::fs_size bs=1k | gzip -v9 " + . "> $CFG::rootfsz"); + +}##### End of compress_root + +##### END OF WRITE_RESCUE_DISK +__END__ +$Log: write_rescue_disk,v $ +Revision 1.1 2002/08/25 20:25:33 aliz +Add missing files + fixup + +Revision 1.1 2001/04/09 03:01:00 achim +*** empty log message *** + +Revision 1.2 1998/05/23 13:42:57 fawcett +yard-1.15 + + +##### Code graveyard. + +sub prepare_extra_disks { + ### Figure out what has to be left on the base disk + my(@base_dirs) = qw(dev etc proc sbin lib); + push(@other_files, &find_tar_and_dependents); + + print "Otherfiles: @other_files\n"; + + my(%in_base); + @in_base{@base_dirs} = @base_dirs; + my(@dirs) = split(' ', `ls -1 $CFG::mount_point`); + my(@extra_dirs) = grep(!exists($in_base{$_}), @dirs); + my($tmpfile) = "/tmp/yard$$"; + + info 0, "Creating \"extra\" disk with dirs: @extra_dirs\n"; + sys("cd $CFG::mount_point; tar " . + join(' ', map("--exclude=$_ ", @other_files)) . + " --remove " . + " -czf $tmpfile @extra_dirs"); + insert_fresh_floppy_in_drive(); + sys("dd if=$tmpfile of=$CFG::floppy"); + + sync(); + info 0, "Done with this disk. This will be the second disk to load.\n"; +} + + +sub patch_rc_to_load_extra { + + # Grab name of rc script, just for propriety + my($INITTAB) = "$CFG::mount_point/etc/inittab"; + my($rc, $rc_text); + + open(INITTAB, "<$INITTAB") or error "$INITTAB: $!\n"; + while (<INITTAB>) { + chomp; + next if /^\#/ or /^\s*$/; + my($code, $runlevels, $action, $command) = split(':'); + if ($action eq 'sysinit') { + info 0, "Found sysinit command file $command\n"; + $rc = "$CFG::mount_point$command"; + last; + } + } + close(INITTAB); + + $ldconfig_path = `cd $CFG::mount_point ; find -name ldconfig -print`; + chomp($ldconfig_path); + $ldconfig_path =~ s|^\.||; # Remove leading dot + + open(RC, "<$rc") or error "$rc: $!"; + print "Patching $rc\n"; + { local($INPUT_RECORD_SEPARATOR); + $rc_text = <RC>; + }; + close(RC); + + open(RC, ">$rc") or error "$rc: $!"; + print RC "$ldconfig_path\n"; + print RC "echo Insert second floppy into drive and press RETURN\n"; + print RC ": \\$<\n"; + print RC "tar xvzf $CFG::floppy\n"; + print RC $rc_text, "\n$ldconfig_path\n"; + close(RC) or die "Writing $rc: $!"; +} + + +##### Finds the tar executable +sub find_tar_and_dependents { + my(@all_files); + ##### Find tar. For a "base+extras" disk, this was added to the + ##### root by make_root_fs, so we must find it now. + my($tar) = `find $CFG::mount_point -name tar -print`; + chomp($tar); + if (!$tar) { + error "tar executable is not on root fs"; + } else { + push(@all_files, $tar); + } + + ##### Now find dependents. Tar usually only needs libc, but we may + ##### as well be careful. + foreach $line (`ldd $tar`) { + my($rel_lib, $abs_lib) = $line =~ /(\S+) => (\S+)/; + next unless $abs_lib; + my($final) = $abs_lib; + + if ($abs_lib =~ /not found/) { + error "File $tar needs library $rel_lib, which does not exist!"; + } else { + my(@libs) = `find $CFG::mount_point -name \'$rel_lib*\' -print`; + chomp(@libs); + foreach (@libs) { s/(\.so).*$/$1*/ }; + push(@all_files, @libs); + } + } + + info 0, "Moving files to base disk: @all_files\n"; + foreach (@all_files) { s|^$CFG::mount_point/(.*)$|$1| }; + @all_files +} |