mirror of https://github.com/fspc/gbootroot.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
546 lines
17 KiB
546 lines
17 KiB
#!/usr/bin/perl -w
|
|
|
|
# BootRoot 0.4 by freesource 4.14.2000 Copyright (C) 2000
|
|
# Jonathan Rosenbaum - mttrader@access.mountain.net
|
|
# http://the.netpedia.net/bootroot.html
|
|
|
|
# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
|
# CHANGES
|
|
#
|
|
# 0.4 - 4.14.2000
|
|
# * copy over bzip2 only if specified in configuration
|
|
# * check and adjust the size of the initrd image, thanks
|
|
# to Magnus Holmberg for reporting the bug when stuff
|
|
# didn't fit the old default size for his setup, also
|
|
# will make a leaner boot if the reverse is true.
|
|
# * add a new question by Magnus to the FAQ
|
|
#
|
|
# 0.3 - 3.17.2000
|
|
# * added more error checking
|
|
#
|
|
# 0.2 - 3.16.2000
|
|
# * beta .. works nicely
|
|
# * automatic y when mke2fs on loop device
|
|
# * extra cleanup for aborted attempt
|
|
# * removed init from boot
|
|
# * size check - will abort if cp or mkdir fail and
|
|
# output to find out how much space is left.
|
|
# * added normalboot to lilo for booting from normal disk -
|
|
# requires root=device otherwise will default to /dev/hda1
|
|
# * added a message with lilo
|
|
|
|
# 0.1 - 3.12.2000
|
|
# * initial alpha release, will implement size test
|
|
# in next version.
|
|
#
|
|
|
|
# What are the REQUIREMENTS?
|
|
#
|
|
# Check to make sure you have thes things, in these directories or the
|
|
# program won't work correctly:
|
|
# /bin/{ash,gzip,mount,umount}
|
|
# /sbin/init (you better have this! .. only used for a test.)
|
|
# /usr/bin/bzip2 (optional)
|
|
|
|
# What does this program do?
|
|
#
|
|
# BootRoot creates a boot disk with lilo, a kernel and an initrd image.
|
|
# The initrd script mounts another root disk with a compressed (gzip or
|
|
# bzip2) filesystem.
|
|
#
|
|
# The root filesystem isn't made by this program. This program is
|
|
# patterned after mkrboot, but unlike mkrboot it creates an unique bootdisk
|
|
# and a separate root disk.
|
|
|
|
# What's the advantage of using this program?
|
|
#
|
|
# You can use a bzip2 compressed filesystem, this program is
|
|
# easy to use, and it provides a framework showing a simple initrd method
|
|
# which you can freely modify. Run a search for HEREDOC. I wrote this
|
|
# program as a solution to help oster at EE (www.experts-exchange.com)
|
|
# create separate boot and root floppies for an emergency system for his
|
|
# customers.
|
|
#
|
|
# If you make a cool change to this program, or if this program helps you
|
|
# I'd love to know, that's better than receiving pizza :)
|
|
|
|
# How can I test BootRoot?
|
|
#
|
|
# Get SETUP.GZ as the filesystem from looplinux at
|
|
# http://www.tux.org/pub/people/kent-robotti/index.htm.
|
|
# This filesystem works with 2.2 kernels.
|
|
#
|
|
# [Ctrl] ([Tab] to see available images)
|
|
# boot: bootdisk single [Enter]
|
|
# ( now filesystem is single user mode)
|
|
# exit [Enter]
|
|
# (now you are in multi user mode)
|
|
#
|
|
# Better yet, do [Ctrl]
|
|
# boot: bootdisk 2 [Enter]
|
|
#
|
|
# This works nicely with a compressed root filesystems made with yard
|
|
# without "single" .. but looplinux comes with mc (mcedit)
|
|
|
|
# Why doesn't looplinux work as "bootdisk 1?"
|
|
#
|
|
# There is a difference between "1" and "single." Looplinux was written
|
|
# in a way that runlevel 1 doesn't work properly in relation to BootRoot
|
|
# unless single is used. And you thought they were the same thing.
|
|
# BootRoot proves otherwise.
|
|
|
|
# What sort of configuration can I do?
|
|
#
|
|
# Edit the variable $compress to either gzip (default) or bzip2.
|
|
|
|
# How do I use the program?
|
|
#
|
|
# program_name lilo linux-kernel compressed-filesystem
|
|
#
|
|
# "lilo" is the only method supported at the present.
|
|
#
|
|
# For instance .. "linux-kernel" could be: /boot/vmlinuz-2.2.14
|
|
# "compressed-filesystem": /home/createit/my_creation.gz
|
|
# (if found in same directory when running the program)
|
|
# "linux-kernel could be": vmlinuz-2.2.14
|
|
# "compressed-filesystem": my_creation.gz
|
|
#
|
|
# "device" could be /dev/fd0 (default) or /dev/fd1 .. etc.
|
|
# "size" is usually 1440 (default)
|
|
|
|
# Edit to "gzip" or "bzip2"
|
|
$compress = "gzip";
|
|
|
|
#######################################################################
|
|
# Don't edit from here, but you can if you want to change the here docs
|
|
# and/or the contents of initrd (in which case you need to make sure the
|
|
# right libraries are copied over to initrd).
|
|
|
|
# I need to remember to edit this
|
|
$version = "v0.4";
|
|
$date = "4.14.2000";
|
|
|
|
$device = "/dev/fd0";
|
|
$size = 1440;
|
|
$initrd = "initrd_image";
|
|
$pwd = `pwd`; chomp $pwd;
|
|
use File::Basename;
|
|
$compress eq "gzip" ? ($compress = "gzip") : ($compress = "bzip2");
|
|
|
|
if ($#ARGV == -1) {
|
|
print "boot_root - Make a separate boot and root disk\n";
|
|
print "-----------------------------------------------\n";
|
|
print "boot_root <method> [ <linux-kernel > [ <root-image> [ <device> [ <size> ]]]]\n";
|
|
print "\nMethods available:\n\nlilo -> Generates a separate boot and root disk for lilo\n\n";
|
|
exit;
|
|
}
|
|
if ($ARGV[0] ne "lilo") {
|
|
die "Please supply a method\n";
|
|
}
|
|
$method = $ARGV[0];
|
|
if (defined $ARGV[1] && -e $ARGV[1] && !-d $ARGV[1]) {
|
|
$kernel = $ARGV[1];
|
|
}
|
|
else {
|
|
die "boot_root: ERROR: Kernel not found\n";
|
|
}
|
|
if (defined $ARGV[2] && -e $ARGV[1] && !-d $ARGV[1] ) {
|
|
$root_image = $ARGV[2];
|
|
}
|
|
else {
|
|
die "boot_root: ERROR: Rootimage not found\n";
|
|
}
|
|
$device = $ARGV[3] if defined $ARGV[3];
|
|
$size = $ARGV[4] if defined $ARGV[4];
|
|
|
|
# lilo method
|
|
if ($method eq "lilo") {
|
|
|
|
|
|
# Do a little cleanup just in case
|
|
system "rm /tmp/initrd_image.gz 2> /dev/null; rmdir /tmp/initrd_mnt 2> /dev/null";
|
|
|
|
initrd();
|
|
mtab();
|
|
|
|
|
|
print "Making ext2 filesystem\n";
|
|
system "mke2fs -m0 -i8192 $device $size";
|
|
die "boot_root: ERROR: You need to insert a disk\n" if $? != 0;
|
|
print "Mounting the device\n";
|
|
errm(system "mount -t ext2 $device /mnt");
|
|
|
|
# Time to do a little calculations
|
|
$device_size = (split(/\s+/,`df /mnt`))[8];
|
|
$boot_size = (stat($kernel))[12]/2 + (stat("/tmp/$initrd"))[12]/2;
|
|
$root_image_size = (stat($root_image))[12]/2;
|
|
$enough_boot = $device_size - $boot_size;
|
|
$enough_root = $device_size - $root_image_size;
|
|
$remain_boot = $device_size - $boot_size;
|
|
$remain_root = $device_size - $root_image_size;
|
|
|
|
# A little output
|
|
$enough_boot =~ /^-+\d+$/ ?
|
|
die "boot_root: ERROR: Not enough room: boot stuff = $boot_size k, device = $device_size\n" :
|
|
print "boot_root: Looks good so far: boot stuff = $boot_size k, device = $device_size k, remaining = $remain_boot k\n";
|
|
|
|
# Better do this first
|
|
print "Copy over initrd ramdisk\n";
|
|
system "cp /tmp/$initrd /mnt/$initrd";
|
|
die "boot_root: ERROR: Could not copy over initrd\n" if $? != 0;
|
|
|
|
print "Copying over kernel\n";
|
|
system "rm -rf /mnt/lost+found; cp $kernel /mnt/kernel";
|
|
die "boot_root: ERROR: Could not copy over the kernel\n" if $? != 0;
|
|
print "Making stuff for lilo\n";
|
|
err(system "mkdir /mnt/{boot,dev}; cp -a /dev/{null,fd?,hda1} /mnt/dev");
|
|
print "Copy over important lilo stuff\n";
|
|
err(system "cp /boot/boot.b /mnt/boot");
|
|
|
|
# HEREDOC
|
|
$brlilo = << "LILOCONF";
|
|
boot = $device
|
|
message = message
|
|
delay = 50
|
|
vga = normal
|
|
install = /boot/boot.b
|
|
map = /boot/map
|
|
backup = /dev/null
|
|
compact
|
|
|
|
# bootdisk
|
|
image = kernel
|
|
append = "load_ramdisk = 1 debug"
|
|
initrd = $initrd
|
|
root = $device
|
|
label = bootdisk
|
|
read-write
|
|
|
|
# normalboot
|
|
image = kernel
|
|
root = /dev/hda1
|
|
label = normalboot
|
|
read-only
|
|
LILOCONF
|
|
open(LC, ">/mnt/brlilo.conf") or die "Couldn't write /mnt/brlilo.conf\n";
|
|
print LC $brlilo; close(LC);
|
|
|
|
|
|
# HEREDOC
|
|
$message = << "MESSAGE";
|
|
|
|
BootRoot $version written by Jonathan Rosenbaum $date GPL
|
|
mailto:mttrader\@access.mountain.net
|
|
|
|
Press [Ctrl] to see the lilo prompt.
|
|
|
|
Press [Tab] to see a list of boot options.
|
|
|
|
bootdisk = This will boot a compressed root filesystem
|
|
on another floppy.
|
|
normalboot = This will boot up a specified filesystem.
|
|
default: /dev/hda1 a = 1st drive
|
|
1 = 1st partition
|
|
Use root=/dev/(h or s)dXX
|
|
h = IDE Drive
|
|
s = SCSI Drive
|
|
|
|
Trouble: Do not forget boot: option single
|
|
Fix a filesystem: e2fsck /dev/(h or s)dXX
|
|
Bad superblock: e2fsck -b 8192 /dev/(h or s)dXX
|
|
|
|
MESSAGE
|
|
open(M, ">/mnt/message") or die "Couldn't write /mnt/message\n";
|
|
print M $message; close(M);
|
|
|
|
# Got to umount,mount, and umount again to make sure everything is
|
|
# copied over before doing lilo
|
|
errum(system "umount /mnt");
|
|
print "Umount device\n";
|
|
print "Remount device\n";
|
|
errm(system "mount -t ext2 $device /mnt");
|
|
print "Configuring lilo\n";
|
|
chdir("/mnt") or die "boot_root: ERROR: Could not change directories\n";
|
|
system "lilo -v -C brlilo.conf -r /mnt";
|
|
die "boot_root: ERROR: lilo failed\n" if $? != 0; # code 0 regardless
|
|
chdir($pwd) or die "boot_root: ERROR: Could not change directories\n";
|
|
print "Umounting /mnt\n";
|
|
# y I know
|
|
$um = system "umount /mnt";
|
|
|
|
print "Doing a little cleanup\n";
|
|
system "rm /tmp/$initrd; rmdir /tmp/initrd_mnt";
|
|
|
|
# This could be put on the top, but all that needs to be done now is
|
|
# to mke2fs & cp over /compressed_filesystem
|
|
$enough_root =~ /^-+\d+$/ ?
|
|
die "boot_root: ERROR: Not enough room: root stuff = $root_image_size k, device = $device_size\n" :
|
|
print "boot_root: Looks good: boot stuff = $boot_size k, device = $device_size k, remaining = $remain_root k\n";
|
|
|
|
|
|
# Here's where we copy over that compressed filesystem
|
|
# We could separate $device = boot,root allowing two
|
|
# different devices to be used.
|
|
if ($um == 0) {
|
|
mtab();
|
|
print "Making ext2 filesystem\n";
|
|
system "mke2fs -m0 -i8192 $device $size";
|
|
die "boot_root: ERROR: You need to insert a disk\n" if $? != 0;
|
|
errm(system "mount -t ext2 /dev/fd0 /mnt");
|
|
print "Copy over the compressed filesystem\n";
|
|
system "rmdir /mnt/lost+found";
|
|
$broot_image = basename($root_image);
|
|
system "cp $root_image /mnt/$broot_image";
|
|
die "boot_root: ERROR: Could not copy over the root filesystem\n" if $? != 0;
|
|
errum(system "umount /mnt");
|
|
print "Root disk did not properly umount\n" if $? != 0;
|
|
print "Finished!\n";
|
|
}
|
|
else {
|
|
die "boot_root: ERROR: Boot disk was never umounted\n";
|
|
} # copy over the compressed
|
|
|
|
|
|
} # lilo method
|
|
|
|
|
|
# Some functions
|
|
|
|
sub errmk {
|
|
die "boot_root: ERROR: Could not make important directories\n" if $? != 0;
|
|
}
|
|
|
|
sub errcp {
|
|
die "boot_root: ERROR: Could not copy over important stuff\n" if $? != 0;
|
|
}
|
|
|
|
sub errum {
|
|
die "boot_root: ERROR: Could not umount the device\n" if $? != 0;
|
|
}
|
|
|
|
sub errm {
|
|
die "boot_root: ERROR: Could not mount device\n" if $? != 0;
|
|
}
|
|
|
|
sub err {
|
|
die "boot_root: ERROR: Not enough space after all\n" if ($? > 0);
|
|
}
|
|
|
|
sub mtab {
|
|
|
|
# /proc/mount could be used, but maybe there is no /proc
|
|
|
|
# \n from initrd()
|
|
print "\nPlease insert a floppy and then press [Enter]: ";
|
|
<STDIN>;
|
|
# Check to see if $device is mounted
|
|
open (MTAB, "/etc/mtab") or die "no mtab!\n";
|
|
while (<MTAB>) {
|
|
if (m,$device,) {
|
|
print "DANGER!\n";
|
|
print "This next step will create a new filesystem on the floppy removing all data\n";
|
|
print "Please umount the device first, and put in a new floppy.\n";
|
|
exit;
|
|
}
|
|
}
|
|
close(MTAB);
|
|
} # end sub mtab
|
|
|
|
|
|
sub initrd_size {
|
|
|
|
($linuxrc_size) = @_;
|
|
print "Checking size needed for initrd\n";
|
|
|
|
# the size of the loop device should be at least 1.63% larger than what
|
|
# it will contain (i.e. 8192 inode), but to keep on the safe size it will
|
|
# be 2.00% larger.
|
|
# 9 dirs = 1024 each (increase if modified)
|
|
# {ash,gzip,mount,umount} (required executables)
|
|
# bzip2 if $compress eq bzip2 (optional)
|
|
# 1 for ld.so.cache
|
|
|
|
# change dir size if needed
|
|
$dir_size = 9 + 1;
|
|
$initrd_size = $dir_size + $linuxrc_size;
|
|
|
|
# add other executables here
|
|
@initrd_stuff = qw(ash gzip mount umount);
|
|
foreach (@initrd_stuff) {
|
|
$initrd_size = $initrd_size + ((stat("/bin/$_"))[12]/2);
|
|
}
|
|
|
|
if ($compress eq "bzip2" && -e "/usr/bin/$compress") {
|
|
print "hi\n";
|
|
$initrd_size = $initrd_size + ((stat("/usr/bin/$compress"))[12]/2);
|
|
}
|
|
|
|
# lib sizes
|
|
open(L,"ldd /sbin/init|") or die "Oops, no init could be found :)\n"; # safe to use ldd
|
|
while (<L>) {
|
|
$lib = (split(/=>/,$_))[0];
|
|
$lib =~ s/\s+//;
|
|
$lib = basename($lib);
|
|
$lib =~ s/\s+$//;
|
|
open (SL,"ls -l /lib/$lib|") or die "humm: $!\n";
|
|
while (<SL>) {
|
|
# symbolic link
|
|
if (-l "/lib/$lib") {
|
|
$what = (split(/\s+/,$_))[10];
|
|
$initrd_size = $initrd_size + 1;
|
|
$initrd_size = $initrd_size + ((stat("/lib/$what"))[12]/2);
|
|
}
|
|
# no symbolic link
|
|
else {
|
|
$initrd_size = $initrd_size + ((stat("/lib/$lib"))[12]/2);
|
|
}
|
|
}
|
|
}
|
|
|
|
$initrd_size = $initrd_size + ($initrd_size * 0.02);
|
|
# For perfection 1 (rounded up) is o.k., but for safety 10 would be
|
|
# better
|
|
$initrd_size = sprintf("%.f",$initrd_size) + 10;
|
|
return $initrd_size;
|
|
|
|
} # end sub initrd_size
|
|
|
|
|
|
sub initrd {
|
|
|
|
$broot_image = basename($root_image);
|
|
|
|
# Here's where the initrd is put together using a loop device
|
|
# HEREDOC
|
|
$initrd_exec = << "INITRD";
|
|
#!/bin/ash
|
|
|
|
export PATH=/bin:/sbin:/usr/bin:
|
|
|
|
echo Preparing to setup ramdisk.
|
|
|
|
mount -o remount,rw / 2>/dev/null
|
|
|
|
echo Mounting proc...
|
|
mount -t proc none /proc
|
|
|
|
echo -n 'Please insert the root floppy, and press [Enter]: '
|
|
read ENTER
|
|
|
|
echo Mounting floppy drive readonly ...
|
|
mount -o ro -t ext2 /dev/fd0 /mnt
|
|
|
|
echo -n Copying new root to ramdisk .. please wait ...
|
|
$compress -cd /mnt/$broot_image > /dev/ram1
|
|
echo done.
|
|
|
|
echo -n Unmounting floppy ...
|
|
umount /mnt
|
|
echo done.
|
|
|
|
echo Changing to the new root.
|
|
echo 257 >/proc/sys/kernel/real-root-dev
|
|
|
|
echo -n Unmounting proc ...
|
|
umount /proc
|
|
echo done.
|
|
|
|
echo Continuing normal boot procedure from ramdisk.
|
|
INITRD
|
|
|
|
open(LC, ">/tmp/linuxrc") or die "Couldn't write linuxrc to loop device\n";
|
|
print LC $initrd_exec; close(LC);
|
|
$size_needed = initrd_size((stat("/tmp/linuxrc"))[12]/2);
|
|
unlink("/tmp/linuxrc");
|
|
|
|
print "Using loop device to make initrd\n";
|
|
print "Make sure you have loop device capability in your running kernel\n";
|
|
system "dd if=/dev/zero of=/tmp/$initrd bs=1024 count=$size_needed";
|
|
# no need to enter y every time
|
|
open(T,"|mke2fs -m0 -i8192 /tmp/$initrd") or die "Problem here: $!\n"; print T "y\n"; close(T);
|
|
print "Mounting initrd in tmp\n";
|
|
errmk(system "mkdir /tmp/initrd_mnt; mount -o loop -t ext2 /tmp/$initrd /tmp/initrd_mnt");
|
|
print "Putting everything together\n";
|
|
open(LC, ">/tmp/initrd_mnt/linuxrc") or die "Couldn't write linuxrc to loop device\n";
|
|
print LC $initrd_exec; close(LC);
|
|
# I could test this but somebody's system may do permissions differently
|
|
system "chmod 755 /tmp/initrd_mnt/linuxrc";
|
|
system "rmdir /tmp/initrd_mnt/lost+found";
|
|
|
|
print "... the dirs\n";
|
|
errmk(system "mkdir /tmp/initrd_mnt/{bin,dev,etc,lib,mnt,proc,sbin,usr}; mkdir /tmp/initrd_mnt/usr/lib");
|
|
errcp(system "cp -a /dev/{console,fd0,null,ram0,ram1,tty0} /tmp/initrd_mnt/dev");
|
|
# future implementation
|
|
#errcp(system "cp -a $device /tmp/initrd_mnt/dev");
|
|
|
|
print ".. the bins\n";
|
|
errcp(system "cp -a /bin/{ash,gzip,mount,umount} /tmp/initrd_mnt/bin");
|
|
if ($compress eq "bzip2") {
|
|
errcp(system "cp -a /usr/bin/$compress /tmp/initrd_mnt/bin") if -e "/usr/bin/$compress";
|
|
}
|
|
|
|
# Testing init is sufficient for grabbing the correct libraries for the
|
|
# executables immediately above. This could be modified to test a
|
|
# list of executables.
|
|
print ".. the libs\n";
|
|
open(L,"ldd /sbin/init|") or die "Oops, no init could be found :)\n"; # safe to use ldd
|
|
while (<L>) {
|
|
$lib = (split(/=>/,$_))[0];
|
|
$lib =~ s/\s+//;
|
|
$lib = basename($lib);
|
|
$lib =~ s/\s+$//;
|
|
open (SL,"ls -l /lib/$lib|") or die "humm: $!\n";
|
|
while (<SL>) {
|
|
# symbolic link
|
|
if (-l "/lib/$lib") {
|
|
$what = (split(/\s+/,$_))[10];
|
|
errcp(system "cp -a /lib/$lib /tmp/initrd_mnt/lib");
|
|
errcp(system "cp -a /lib/$what /tmp/initrd_mnt/lib");
|
|
}
|
|
# no symbolic link
|
|
else {
|
|
errcp(system "cp -a /lib/$lib /tmp/initrd_mnt/lib");
|
|
}
|
|
}
|
|
}
|
|
|
|
print "Determine run-time link bindings\n";
|
|
# Has a return code of 0 regardless
|
|
system "ldconfig -r /tmp/initrd_mnt";
|
|
print "Umounting loop device, and compressing initrd";
|
|
errum(system "umount /tmp/initrd_mnt; gzip -9 /tmp/$initrd");
|
|
$initrd = $initrd . ".gz";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|