From a1e1334a15283c0e40a3cebf53921a6afa9928d2 Mon Sep 17 00:00:00 2001 From: freesource Date: Sun, 13 Aug 2000 04:43:39 +0000 Subject: [PATCH] *** empty log message *** --- .gitignore | 28 + gBootRoot | 1448 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1476 insertions(+) create mode 100644 .gitignore create mode 100644 gBootRoot diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..40caffa --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +# CVS default ignores begin +tags +TAGS +.make.state +.nse_depinfo +*~ +#* +.#* +,* +_$* +*$ +*.old +*.bak +*.BAK +*.orig +*.rej +.del-* +*.a +*.olb +*.o +*.obj +*.so +*.exe +*.Z +*.elc +*.ln +core +# CVS default ignores end diff --git a/gBootRoot b/gBootRoot new file mode 100644 index 0000000..e99daf7 --- /dev/null +++ b/gBootRoot @@ -0,0 +1,1448 @@ +#!/usr/bin/perl -w + +# gBootRoot Copyright (C) 2000 +# Jonathan Rosenbaum - mttrader@access.mountain.net +# http://the.netpedia.net/gBootRoot.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. + + +use Gtk; +use strict; + +init Gtk; + +# Perhaps you are wondering where I learned how to program with Gtk-Perl? +# There is an excellent tutorial by Stephen Wilhelm at +# http://personal.riverusers.com/~swilhelm/perlgtk/. Please +# help support his development of this tutorial. Another good place +# to learn from is test.pl in the Gtk/samples directory included with +# Gtk-Perl. + +# If you want gBootRoot to do it's stuff somewhere else, change the +# value for $tmp1. +my $tmp1 = "/tmp"; # tmp should be default - Cristian + +# CHANGES +# 1.0.3 - 08.09.2000 +# * Tmp and mnt are now created on the fly, +# along with a new error function for mkdir(), +# Gtk clean-up for this, and clean-up by signal handler +# which should please Perlish and helpful Cristian. +# +# 1.0.2 - 08.06.2000 +# * Changed logic slightly in submit() with returns rather +# than a scalar to resolve a minor bug caused by some +# changes in the previous version. +# +# 1.0.1 - 08.05.2000 +# * Zas provided a correction for a Perl 5.6 error complaint. +# * Zas found some unecessary GDK lines causing some Gtk +# warnings; these were commented out. +# * Cristian Ionescu-Idbohrn found a bug caused by putting +# the Kernel or RootImage below the mount point. An error +# check and error dialog were added. +# +# 1.0.0 - 08.02.2000 +# * First public release +# + +####################################################################### +# 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 and the size is checked). + +# I need to remember to edit this +my $version = "v1.0.3"; +my $date = "08.09.2000"; +my $pwd = `pwd`; chomp $pwd; +use File::Basename; + +my $initrd; +my $compress; +my $false = 0; +my $true = 1; +my $ok; +my $box2; +my $label; +my $order; +my $text_window; +my @container; +my @original_container; +my $file_dialog; +my $error_window; +my ($kernel,$root_image,$device,$size); +my $mtab; +my ($tmp,$mnt); + +# My own creation - the roots touch the ground if three lines are added. + my @xpm_data = ( +"32 45 3 1", +" c None", +". c SaddleBrown", +"X c black", +" ... ... ", +" ... ... ", +" ... ... ", +" ... ... ", +" ... ... ", +" ... ... ", +" ... ... ", +" ... ... ", +" ... ... ", +" ... .. ", +" ... ... ", +" ... ... ", +" .... ... ", +" .... ... ", +" .... ... ", +" .... ............. ", +" ..... ............. ", +" ...... ............. ", +" ....... ...", +"......... ..", +"................................", +"................................", +"............................... ", +"......... XXXXX ............ ", +"........ XXX .......... ", +"........ XXX ........ ", +" XXXXXX ", +" XXX XXX X XX XX ", +" X XXXXX X X X ", +" XX XXX X XX ", +" X XX X X ", +" X XX X XX X ", +" XX XX X XXXXX ", +" X XXXX XXX XXXXX X ", +" XX XX XX X XX ", +" X X X X X ", +" X XX X XX X ", +" X XX XX X ", +" X XX XXXXXXX XXX ", +" XX XX XXX ", +" XX XX XXXX XX XX ", +" XX XXX X XXXXXXX X ", +" X XXX X XX ", +" XX XXXXXXX XXX ", +" X XX X ", +" X X " + ); + +$SIG{INT} = \&signal; +$SIG{ABRT} = \&signal; +$SIG{TERM} = \&signal; +$SIG{QUIT} = \&signal; +$SIG{KILL} = \&signal; + +if (!-d $tmp1) { + if (-e $tmp1) { + error_window( + "gBootRoot: ERROR: A file exists where $tmp1 should be"); + } + else { + my @directory_parts = split(m,/,,$tmp1); + my $placement = "/"; + for (1 .. $#directory_parts) { + $_ == 1 ? ($placement = "/$directory_parts[$_]") + : ($placement = $placement . "/" . $directory_parts[$_]); + -d $placement or err_custom_perl( + "mkdir $placement","gBootRoot: ERROR: Could not make $tmp1"); + } + } +} + +if (!-d "$tmp1/gbootroot_tmp$$") { + $tmp = "$tmp1/gbootroot_tmp$$" if err_custom_perl( + "mkdir $tmp1/gbootroot_tmp$$", + "gBootRoot: ERROR: Could not make temporary directory") != 2; +} +if (!-d "$tmp1/gbootroot_mnt$$") { + $mnt = "$tmp1/gbootroot_mnt$$" if err_custom_perl( + "mkdir $tmp1/gbootroot_mnt$$", + "gBootRoot: ERROR: Could not make mount directory") != 2; +} + +my $window = new Gtk::Window("toplevel"); +$window->set_title("gBootRoot"); +$window->set_position('center'); +$window->signal_connect( "destroy", sub { + unlink "$tmp/verbose", "$tmp/initrd_image.gz"; + rmdir "$tmp/initrd_mnt"; rmdir "$tmp", rmdir "$mnt"; + Gtk->exit(0); } ); +$window->border_width(1); +$window->realize; + +# Do the iconizing thing +# "xpm/circles.xpm" can be @pixmap within file if not create_from_xpm. +my ($circles,$mask) = Gtk::Gdk::Pixmap->create_from_xpm_d($window->window, + $window->style->white, + @xpm_data); +$window->window->set_icon(undef, $circles, $mask); +$window->window->set_icon_name("gBootRoot"); +#$window->window->set_decorations(['all', 'menu']); # Zas +#$window->window->set_functions(['all', 'resize']); # Zas + +my $tooltips = new Gtk::Tooltips(); + +my $box1 = new Gtk::VBox($false,0); +$window->add($box1); +$box1->show(); + +# First row +hbox(); +my $entry = entry($false); + +# Menu - later this may be improved if new methods are added. +my $opt = new Gtk::OptionMenu(); +$tooltips->set_tip( $opt, "Choose the Boot method.", "" ); +my $menu = new Gtk::Menu(); +my $item = new Gtk::MenuItem("Method -> lilo" ); +$item->show(); +$item->signal_connect( 'activate',sub { $entry->set_text("lilo"); + $container[0] = "lilo"}); +$menu->append( $item ); +$opt->set_menu( $menu ); +$box2->pack_start( $opt, $true, $true, 0 ); +$opt->show(); +$box2->show(); + +# Second row +hbox(); +my $entry2 = entry($true,1); +button("Kernel Selection",$entry2,"Kernel Selection",1); + +# Third row +hbox(); +my $entry3 = entry($true,2); +button("Compressed Filesystem",$entry3,"Compressed Filesystem",2); + +# In the future, if experimenters send in data, there will be two +# different devices. +# Fourth row +hbox(); +my $entry4 = entry($true,3); +$entry4->set_text("/dev/fd0"); +$container[3] = "/dev/fd0"; +button("Device Selection",$entry4,"Device Selection",3,$true); + +# Fifth row +hbox("what"); +my $adj = new Gtk::Adjustment( 1440.0, 0.0, 360000000.0, 360.0, 360.0, 0.0 ); +my $spinner = new Gtk::SpinButton( $adj, 0, 0 ); +$tooltips->set_tip( $spinner, "Choose the Device Size.", "" ); +$spinner->set_wrap( $true ); +$spinner->set_numeric( $true ); +$spinner->set_shadow_type( 'in' ); +$spinner->show(); +$container[4] = 1440; +$adj->signal_connect( "value_changed", sub { + $container[4] = $spinner->get_value_as_int();}); +$box2->pack_start( $spinner, $true, $true, 0 ); +label("Device Size"); + +# gz and bz2 radio buttons +my $rbutton = new Gtk::RadioButton( "gz" ); +$tooltips->set_tip( $rbutton, "Choose Compression used on the Filesystem.", "" ); +my $gz_toggle = $rbutton; +$rbutton->set_active( $true ); +$box2->pack_start( $rbutton, $false, $false, 0 ); +$rbutton->show(); +$rbutton = new Gtk::RadioButton( "bz2", $rbutton ); +$rbutton->set_usize(1,1); +$tooltips->set_tip( $rbutton, "Choose Compression used on the Filesystem.", "" ); +my $bz2_toggle = $rbutton; +$box2->pack_start( $rbutton, $true, $true, 0); +$rbutton->show(); + +# Size status entry +my $entry5 = new Gtk::Entry(); +$entry5->set_editable( $false ); +$tooltips->set_tip( $entry5, "This shows room remaining on the Device.", "" ); +$entry5->set_usize(15,20); +$box2->pack_start( $entry5, $true, $true, 0 ); +$entry5->show(); + +# Separator +my $separator = new Gtk::HSeparator(); +$box1->pack_start( $separator, $false, $true, 0 ); +$separator->show(); + +# Status bar +my $align = new Gtk::Alignment( 0.5, 0.5, 0, 0 ); +$box1->pack_start( $align, $false, $false, 5); +$align->show(); +my $pbar = new Gtk::ProgressBar(); +$pbar->set_usize(321,10); # 321 10 +$align->add($pbar); +$pbar->show(); + +# Separator +$separator = new Gtk::HSeparator(); +$box1->pack_start( $separator, $false, $true, 0 ); +$separator->show(); + +# Submit button +hbox(); +my $sbutton = new Gtk::Button("Submit"); +$sbutton->signal_connect( "clicked", \&submit); +$tooltips->set_tip( $sbutton, "Generate the Boot/Root set.", "" ); +$sbutton->show(); +$box2->pack_start( $sbutton, $true, $true, 0 ); +$box2->show(); + +# Close button +my $cbutton = new Gtk::Button("Close"); +$cbutton->signal_connect( "clicked", sub { + unlink "$tmp/verbose", "$tmp/initrd_image.gz"; + rmdir "$tmp/initrd_mnt"; rmdir "$tmp", rmdir "$mnt"; + Gtk->exit(0); }); + +$tooltips->set_tip( $cbutton, "Exit gBootRoot.", "" ); +$cbutton->show(); +$box2->pack_start( $cbutton, $true, $true, 0 ); +$box2->show(); + +# Help button +my $hbutton = new Gtk::Button("Help"); +$hbutton->signal_connect( "clicked", \&create_text); +$tooltips->set_tip( $hbutton, "Help about gBootRoot.", "" ); +$hbutton->show(); +$box2->pack_start( $hbutton, $true, $true, 0 ); +$box2->show(); + +$window->show(); +main Gtk; +exit( 0 ); + +#---------------------------- + +# This works on GNU/Linux +sub signal { + $SIG{INT} = \&signal; + $SIG{ABRT} = \&signal; + $SIG{TERM} = \&signal; + $SIG{QUIT} = \&signal; + $SIG{KILL} = \&signal; + unlink "$tmp/verbose", "$tmp/initrd_image.gz"; + rmdir "$tmp/initrd_mnt"; rmdir "$tmp", rmdir "$mnt"; + Gtk->exit(0); +} + +sub create_text { + + if (not defined $text_window) { + $text_window = new Gtk::Window "toplevel"; + $text_window->signal_connect("destroy", \&destroy_window, + \$text_window); + $text_window->signal_connect("delete_event", \&destroy_window, + \$text_window); + $text_window->set_title("Help"); + $text_window->set_usize( 500, 600 ); + $text_window->set_policy( $true, $true, $false ); + $text_window->set_title( "gBootRoot Help" ); + $text_window->border_width(0); + + my $main_vbox = new Gtk::VBox( $false, 0 ); + $text_window->add( $main_vbox ); + $main_vbox->show(); + + my $vbox = new Gtk::VBox( $false, 10 ); + $vbox->border_width( 10 ); + $main_vbox->pack_start( $vbox, $true, $true, 0 ); + $vbox->show(); + + my $table = new Gtk::Table( 2, 2, $false ); + $table->set_row_spacing( 0, 2 ); + $table->set_col_spacing( 0, 2 ); + $vbox->pack_start( $table, $true, $true, 0 ); + $table->show(); + + # Create the GtkText widget + my $text = new Gtk::Text( undef, undef ); + $text->set_editable($false); + $table->attach( $text, 0, 1, 0, 1, + [ 'expand', 'shrink', 'fill' ], + [ 'expand', 'shrink', 'fill' ], + 0, 0 ); + $text->show(); + + # Add a vertical scrollbar to the GtkText widget + my $vscrollbar = new Gtk::VScrollbar( $text->vadj ); + $table->attach( $vscrollbar, 1, 2, 0, 1, 'fill', + [ 'expand', 'shrink', 'fill' ], 0, 0 ); + $vscrollbar->show(); + + $text->freeze(); + $text->insert( undef, undef, undef, help() ); + $text->thaw(); + + my $separator = new Gtk::HSeparator(); + $main_vbox->pack_start( $separator, $false, $true, 0 ); + $separator->show(); + + $vbox = new Gtk::VBox( $false, 10 ); + $vbox->border_width( 10 ); + $main_vbox->pack_start( $vbox, $false, $true, 0 ); + $vbox->show(); + + my $button = new Gtk::Button( "Close" ); + $button->signal_connect( 'clicked', sub { destroy $text_window; } ); + $vbox->pack_start( $button, $true, $true, 0 ); + $button->can_default( $true ); + $button->grab_default(); + $button->show(); + } + if (!visible $text_window) { + show $text_window; + } else { + destroy $text_window; + } +} # end sub create_text + +sub make_menu_item { + my( $name, $callback, $data ) = @_; + my $item; + + $item = new Gtk::MenuItem( $name ); + $item->signal_connect( "activate", $callback, $data ); + $item->show(); + + return $item; +} + +sub fileselect { + + my ($widget,$ent,$name,$order,$device) = @_; + + if (not defined $file_dialog) { + # Create a new file selection widget + $file_dialog = new Gtk::FileSelection( "$name" ); + $file_dialog->signal_connect( "destroy", + \&destroy_window, \$file_dialog); + $file_dialog->signal_connect( "delete_event", + \&destroy_window, \$file_dialog); + + # Connect the ok_button to file_ok_sel function + $file_dialog->ok_button->signal_connect( "clicked", + \&file_ok_sel, + $file_dialog,$ent,$order); + + # Connect the cancel_button to destroy the widget + $file_dialog->cancel_button->signal_connect( "clicked", + sub { destroy $file_dialog } ); + $file_dialog->set_filename( "/dev/fd0" ) if defined $device; + $file_dialog->set_position('mouse'); + + } + if (!visible $file_dialog) { + show $file_dialog; + } + else { + destroy $file_dialog; + } + +} # end sub fileselect + + +# Get the selected filename and print it to the text widget +sub file_ok_sel { + + my( $widget, $file_selection,$entry,$order) = @_; + my $file = $file_selection->get_filename(); + $entry->set_text($file); + $container[$order] = $file; + + # auto-detect compression if system has file + if ($container[2]) { + my $file = system "which file > /dev/null 2>&1"; + if ($file == 0) { + open(F,"file $container[2]|"); # no error check here + while () { + if (/gzip/) { + $gz_toggle->set_active( $true ); + } + elsif (/bzip2/) { + $bz2_toggle->set_active( $true ); + } + } + } + } + + destroy $file_dialog; + +} + +# pulled from test.pl +sub destroy_window { + my($widget, $windowref, $w2) = @_; + $$windowref = undef; + $w2 = undef if defined $w2; + 0; +} + + +sub hbox { + my $homogeneous; + defined $_[0] ? ($homogeneous = 0) : ($homogeneous = 1); + $box2 = new Gtk::HBox( $homogeneous, 5 ); + $box2->border_width( 2 ); # was 10 + $box1->pack_start( $box2, $true, $true, 0 ); + #$box1->pack_start( $box2, $false, $true, 0 ); + $box2->show(); +} + +sub label { + + my($text) = @_; + + $label = new Gtk::Label( $text ); + $label->set_justify( "fill" ); + $box2->pack_start( $label, $false, $false, 5 ); + $label->show(); + +} + +sub entry { + + my($edit,$num) = @_; + + my $entry = new Gtk::Entry(); + $entry->set_editable( $edit ); + # enter will have to be pressed, tried other solutions with a mess + $entry->signal_connect( "activate", sub { + $container[$num] = $entry->get_text();}); + if (defined $num) { + my $todo; + if ($num == 1) { + $todo = "the Kernel"; + } + elsif ($num == 2) { + $todo = "the Compressed Filesystem"; + } + else { + $todo = "the Device to use"; + } + $tooltips->set_tip( $entry, + "Type in the location of $todo and press [Enter].", "" ); + } + $box2->pack_start( $entry, $true, $true, 0 ); + $entry->show(); + + return $entry; + +} + +sub button { + + my ($text,$ent,$name,$order,$device) = @_; + + my $button = new Gtk::Button($text); + if ($order == 1) { + $tooltips->set_tip( $button, "Select the Kernel.", "" ); + } + elsif ($order == 2) { + $tooltips->set_tip( $button, "Select the Compressed Filesystem.", "" ); + } + else { + $tooltips->set_tip( $button, "Select the Device.", "" ); + } + $button->signal_connect( "clicked",\&fileselect,$ent,$name,$order,$device); + $button->show(); + $box2->pack_start( $button, $true, $true, 0 ); + $box2->show(); + +} + +sub submit { + + my($kernel,$root_image); + # comment this out for testing + unlink("$tmp/verbose"); + open (MTAB, "/etc/mtab") or die "no mtab!\n"; + while () { + if (m,$mnt,) { + system "umount $mnt >> $tmp/verbose 2>&1"; + } + } + close(MTAB); + $entry5->set_text(""); + pb("boot",0); + + if ($gz_toggle->active) { + $compress = "gzip"; + } + elsif ($bz2_toggle->active) { + $compress = "bzip2"; + } + +# Run some checks +if (!defined $container[0]) { + error_window("gBootRoot: ERROR: No method supplied"); + return; +} +if (defined $container[1] && -e $container[1] && !-d $container[1]) { + $kernel = $container[1]; + # Better be sure it isn't in the mount directory + if ($kernel =~ m,^$mnt,) { + error_window("gBootRoot: ERROR: Kernel found below Device mount point: $mnt"); + return; + } + +} +elsif (defined $container[0]) { + error_window("gBootRoot: ERROR: Kernel not found"); + return; +} +if (defined $container[2] && -e $container[2] && !-d $container[2] ) { + $root_image = $container[2]; + if ($root_image =~ m,^$mnt,) { + # Bug revealed by Cristian Ionescu-Idbohrn + error_window("gBootRoot: ERROR: Rootimage found below Device mount point: $mnt"); + return; + } +} +elsif (defined $container[0] && defined $container[1]) { + error_window("gBootRoot: ERROR: Rootimage not found"); + return; +} +# we need to check for this, too. +if (defined $container[3] && -e $container[3] && !-d $container[3] ) { + $device = $container[3]; +} +elsif (defined $container[0] && defined $container[1] + && defined $container[2]) { + error_window("gBootRoot: ERROR: Device not found"); + return; +} +if (defined $container[4]) { + $size = $container[4]; +} + +# pretty unlikely +elsif (defined $container[0] && defined $container[1] && + defined $container[2] && defined $container[3]) { + error_window("gBootRoot: ERROR: No size specified"); + return; +} + + # kernel value can change without effecting initrd + # no sense doing this until important stuff is filled in + if (defined $kernel && defined $root_image && + defined $device && defined $size) { + $container[5] = $compress; + if (@original_container) { # defined array deprecate Perl 5.6 - zas@metaconcept.com + # a hash check isn't perfect for two values which are the same + # no need to check all the values + my @temp_container = @container; + splice(@temp_container,1,1); + my %diff; + grep($diff{$_}++,@temp_container); + my @diff = grep(!$diff{$_},@original_container); + if ($#diff >= 0) { + # unlink initrd_image.gz, do initrd() + $ok = 1; + $initrd = "initrd_image"; + } + else { + $ok = 0; + } + } + else { + $ok = 2; # this is actually first (1 = diff, 0 = same) + $initrd = "initrd_image"; + } + # reset + @original_container = ($container[0],$root_image,$device,$size,$compress); + + lilo(); + } + +} # end sub submit + +sub error_window { + my ($error) = @_; + + if (not defined $error_window) { + $error_window = new Gtk::Dialog; + $error_window->signal_connect("destroy", \&destroy_window, \$error_window); + $error_window->signal_connect("delete_event", \&destroy_window, \$error_window); + $error_window->set_title("gBootRoot ERROR"); + $error_window->border_width(15); + my $label = new Gtk::Label($error); + $error_window->vbox->pack_start( $label, $true, $true, 15 ); + $label->show(); + my $button = new Gtk::Button("OK"); + $button->signal_connect("clicked", sub {destroy $error_window}); + $button->can_default(1); + $error_window->action_area->pack_start($button, $false, $false,0); + $button->grab_default; + $button->show; + } + if (!visible $error_window) { + show $error_window; + } + else { + destroy $error_window; + } + +} # end sub error_window + +sub errmk { + error_window("gBootRoot: ERROR: Could not make important directories") if $? != 0; + if (defined $error_window) { + if ($error_window->visible) { + return 2; + } + } +} + +sub errcp { + error_window("gBootRoot: ERROR: Could not copy over important stuff") if $? != 0; + if (defined $error_window) { + if ($error_window->visible) { + return 2; + } + } +} + +sub errum { + error_window("gBootRoot: ERROR: Could not umount the device") if $? != 0; + if (defined $error_window) { + if ($error_window->visible) { + return 2; + } + } +} + +sub errm { + error_window("gBootRoot: ERROR: Could not mount device") if $? != 0; + if (defined $error_window) { + if ($error_window->visible) { + return 2; + } + } +} + +sub errrm { + error_window("gBootRoot: ERROR: Could not remove a directory or file") + if $? != 0; + if (defined $error_window) { + if ($error_window->visible) { + return 2; + } + } +} + +sub err { + error_window("gBootRoot: ERROR: Not enough space after all") if ($? > 0); + if (defined $error_window) { + if ($error_window->visible) { + return 2; + } + } +} + +sub err_custom { + + if (defined $_[2]) { + system("$_[0] > /dev/null 2>&1"); + } + else { + system("$_[0] >> $tmp/verbose 2>&1"); + } + error_window($_[1]) if ($? != 0); + if (defined $error_window) { + if ($error_window->visible) { + return 2; + } + } +} + +sub err_custom_perl { + + if ((split(/ /, $_[0]))[0] eq "mkdir") { + my $two = (split(/ /, $_[0]))[1]; + mkdir($two,0755); # Anyone allowed in + } + error_window($_[1]) if ($? != 0); + if (defined $error_window) { + if ($error_window->visible) { + return 2; + } + } +} + +sub lilo { + + # Do a little cleanup just in case + system "rm $tmp/initrd_image.gz 2> /dev/null" if $ok == 1; + system "umount $tmp/initrd_mnt 2> /dev/null"; + + $kernel = $container[1]; + $root_image = $container[2]; + $device = $container[3]; + $size = $container[4]; + + if ($ok == 1 || $ok == 2) { + my $value = initrd($kernel,$root_image,$device,$size); + mtab(0) if defined $value; + } + elsif ($ok == 0) { + mtab(0); + } + +} # end sub lilo + +sub lilo_put_it_together { + + my $B = "boot"; + # Time to do a little calculations + my $device_size = (split(/\s+/,`df $mnt`))[8]; + my $boot_size = (stat($kernel))[12]/2 + (stat("$tmp/$initrd"))[12]/2; + my $remain_boot = $device_size - $boot_size; + pb($B,1); + + # A little output + if ($remain_boot =~ /^-+\d+$/) { + error_window("gBootRoot: ERROR: Not enough room: boot stuff = $boot_size k, device = $device_size k"); + return; + } + else { + $entry5->set_text("$remain_boot k"); + } + + # Better do this first + #V#print "Copy over initrd ramdisk\n"; + return if err_custom("cp $tmp/$initrd $mnt/$initrd","gBootRoot: ERROR: Could not copy over initrd") == 2; + pb($B,2); + + #V#print "Copying over kernel\n"; + return if + err_custom("rm -rf $mnt/lost+found; cp $kernel $mnt/kernel", + "gBootRoot: ERROR: Could not copy over the kernel") == 2; + pb($B,3); + + #V#print "Making stuff for lilo\n"; + return if err(system "mkdir $mnt/{boot,dev} >> $tmp/verbose 2>&1; cp -a /dev/{null,fd?,hda1} $mnt/dev >> $tmp/verbose 2>&1") == 2; + # Hopefully, this works, but have never tested it + if ($device !~ m,/dev/fd\d{1}$,) { + return if err( + system "cp -a $device $mnt/dev >> $tmp/verbose 2>&1") == 2; + } + + #pb($B,3); + #V#print "Copy over important lilo stuff\n"; + return if + err_custom("cp /boot/boot.b $mnt/boot", + "gBootRoot: ERROR: Not enough space or can't find /boot/boot.b") == 2; + pb($B,4); + # 3k sort of accounts for dev & dirs assuming dev is reasonable + $remain_boot = $remain_boot - (stat("/boot/boot.b"))[12]/2 - 3; + $entry5->set_text("$remain_boot k"); + + # Write out the HEREDOCS + open(LC, ">$mnt/brlilo.conf") or die "Couldn't write $mnt/brlilo.conf\n"; + print LC brlilo($device); close(LC); + open(M, ">$mnt/message") or die "Couldn't write $mnt/message\n"; + print M message(); close(M); + pb($B,5); + $remain_boot = $remain_boot - ( (stat("$mnt/brlilo.conf"))[12]/2 + + (stat("$mnt/message"))[12]/2 ); + $entry5->set_text("$remain_boot k"); + + # Got to umount,mount, and umount again to make sure everything is + # copied over before doing lilo + return if errum(system "umount $mnt >> $tmp/verbose 2>&1") == 2; + #V#print "Umount device\n"; + #V#print "Remount device\n"; + pb($B,6); + return if errm(system "mount -t ext2 $device $mnt >> $tmp/verbose 2>&1") == 2; + #V#print "Configuring lilo\n"; + pb($B,7); + chdir("$mnt"); #"boot_root: ERROR: Could not change directories\n"; + if (err_custom("lilo -v -C brlilo.conf -r $mnt", + "gBootRoot: ERROR: lilo failed") == 2) { + chdir($pwd); return; + } + $remain_boot = $remain_boot - (stat("$mnt/boot/map"))[12]/2; + $entry5->set_text("$remain_boot k"); + pb($B,8); + + chdir($pwd); # or die "boot_root: ERROR: Could not change directories\n"; + + #V#print "Umounting $mnt\n"; + my $um = errum(system "umount $mnt >> $tmp/verbose 2>&1"); + pb($B,10); + + if ($ok == 1 || $ok == 2) { + return if + errrm(system "rmdir $tmp/initrd_mnt >> $tmp/verbose 2>&1") == 2; + } + +# 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(1); +} +else { + error_window("gBootRoot: ERROR: Boot disk was never umounted"); +} # copy over the compressed + +} # end sub lilo_put_it_together + +sub device2 { + + my $device_size = (split(/\s+/,`df $mnt`))[8]; + my $root_image_size = (stat($root_image))[12]/2; + my $remain_root = $device_size - $root_image_size; + + if ($remain_root =~ /^-+\d+$/) { + error_window("gBootRoot: ERROR: Not enough room: root stuff = $root_image_size k, device = $device_size k"); + } + else { + $entry5->set_text("$remain_root k"); + } + + + #V#print "Copy over the compressed filesystem\n"; + return if errrm(system "rmdir $mnt/lost+found >> $tmp/verbose 2>&1") == 2; + my $broot_image = basename($root_image); + + my $FS = "filesystem"; + my $line_count = `wc -l < $root_image`; chomp $line_count; + my $half_line_count = $line_count/2; + my $count = 1; + open(CF, ">$mnt/$broot_image") or error_window( + "gBootRoot: ERROR: Could not copy over the root filesystem") and return; + open(CR, "$root_image") or error_window( + "gBootRoot: ERROR: Could not copy over the root filesystem") and return; + while () { + print CF $_; + pb($FS,$count,$line_count) if $count < $half_line_count; + $count++; + } + close(CF); close(CR); + + return if + err_custom("umount $mnt", + "gBootRoot: ERROR: Root disk did not properly umount") == 2; + pb($FS,$count,$line_count); + #V#print "Finished!\n"; + +} # end sub device 2 + +sub initrd_size { + + my ($linuxrc_size) = @_; + my ($what,$lib); + #V#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 + my $dir_size = 9 + 1; + my $initrd_size = $dir_size + $linuxrc_size; + + # add other executables here + my @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") { + $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 () { + $lib = (split(/=>/,$_))[0]; + $lib =~ s/\s+//; + $lib = basename($lib); + $lib =~ s/\s+$//; + open (SL,"ls -l /lib/$lib|") or die "humm: $!\n"; + while () { + # 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 pb { + + # Will have to count by hand + if ($_[0] eq "initrd") { + $pbar->configure( 10, 0, 10 ); + } + elsif ($_[0] eq "boot") { + $pbar->configure( 10, 0, 10 ); + } + elsif ($_[0] eq "filesystem") { + $pbar->configure($_[2], 0, $_[2]); + } + + $pbar->set_value($_[1]); + # Found this at Gnome .. + # http://www.uk.gnome.org/mailing-lists/archives/gtk-list/ + # 1999-October/0401.shtml + # Also, http://www.gtk.org/faq/ 5.14 + while (Gtk->events_pending) { Gtk->main_iteration; } + +} + +sub initrd { + + my($kernel,$root_image,$device,$size) = @_; + my($lib,$what); + my $I = "initrd"; + + my $broot_image = basename($root_image); + open(LC, ">$tmp/linuxrc") or die "Couldn't write linuxrc to loop device\n"; + print LC initrd_heredoc($broot_image); close(LC); + pb($I,1); + my $size_needed = initrd_size((stat("$tmp/linuxrc"))[12]/2); + unlink("$tmp/linuxrc"); + + #print V "Using loop device to make initrd\n"; + #V#print V "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 >> $tmp/verbose 2>&1"; + pb($I,2); + # no need to enter y every time + open(T,"|mke2fs -m0 -i8192 $tmp/$initrd >> $tmp/verbose 2>&1") or die "Problem here: $!\n"; print T "y\n"; close(T); + pb($I,3); + #V#print V "Mounting initrd in tmp\n"; + +return if errmk(system "mkdir $tmp/initrd_mnt >> $tmp/verbose 2>&1; mount -o loop -t ext2 $tmp/$initrd $tmp/initrd_mnt >> $tmp/verbose 2>&1") == 2; + pb($I,4); + + #V#print "Putting everything together\n"; + open(LC, ">$tmp/initrd_mnt/linuxrc") or die "Couldn't write linuxrc to loop device\n"; + print LC initrd_heredoc($broot_image); close(LC); + # I could test this but somebody's system may do permissions differently + system "chmod 755 $tmp/initrd_mnt/linuxrc >> $tmp/verbose 2>&1"; + system "rmdir $tmp/initrd_mnt/lost+found >> $tmp/verbose 2>&1"; + pb($I,5); + + #V#print "... the dirs\n"; + return if errmk(system "mkdir $tmp/initrd_mnt/{bin,dev,etc,lib,mnt,proc,sbin,usr} >> $tmp/verbose 2>&1; mkdir $tmp/initrd_mnt/usr/lib >> $tmp/verbose 2>&1") == 2; + pb($I,6); + + return if errcp(system "cp -a /dev/{console,fd0,null,ram0,ram1,tty0} $tmp/initrd_mnt/dev >> $tmp/verbose 2>&1") == 2; + # future implementation + #errcp(system "cp -a $device $tmp/initrd_mnt/dev"); + pb($I,7); + + #V#print ".. the bins\n"; + return if errcp(system "cp -a /bin/{ash,gzip,mount,umount} $tmp/initrd_mnt/bin >> $tmp/verbose 2>&1") == 2; + if ($compress eq "bzip2") { + if (-e "/usr/bin/$compress") { + return if errcp(system "cp -a /usr/bin/$compress $tmp/initrd_mnt/bin >> $tmp/verbose 2>&1") == 2; + } + } + + # Testing init is sufficient for grabbing the correct libraries for the + # executables immediately above. This could be modified to test a + # list of executables. + #V#print ".. the libs\n"; + open(L,"ldd /sbin/init|") or die "Oops, no init could be found :)\n"; # safe to use ldd + while () { + $lib = (split(/=>/,$_))[0]; + $lib =~ s/\s+//; + $lib = basename($lib); + $lib =~ s/\s+$//; + open (SL,"ls -l /lib/$lib|") or die "humm: $!\n"; + while () { + # symbolic link + if (-l "/lib/$lib") { + $what = (split(/\s+/,$_))[10]; + return if errcp(system "cp -a /lib/$lib $tmp/initrd_mnt/lib >> $tmp/verbose 2>&1") == 2; + return if errcp(system "cp -a /lib/$what $tmp/initrd_mnt/lib >> $tmp/verbose 2>&1") == 2; + } + # no symbolic link + else { + return if errcp(system "cp -a /lib/$lib $tmp/initrd_mnt/lib >> $tmp/verbose 2>&1") == 2; + } + } + } + + #V#print "Determine run-time link bindings\n"; + # Has a return code of 0 regardless + system "ldconfig -r $tmp/initrd_mnt"; + #V#print "Umounting loop device, and compressing initrd"; + return if errum(system "umount $tmp/initrd_mnt >> $tmp/verbose 2>&1") == 2; + system "gzip -f9 $tmp/$initrd >> $tmp/verbose 2>&1"; + pb($I,10); # This takes the longest. + + $initrd = $initrd . ".gz"; + + +} # end sub initrd + +sub mtab_window { +# Will just use a dialog box. + my ($dialog,$error,$count,$pattern) = @_; + + if (not defined $mtab) { + $mtab = new Gtk::Dialog; + $mtab->signal_connect("destroy", \&destroy_window, \$mtab); + $mtab->signal_connect("delete_event", \&destroy_window, \$mtab); + $mtab->set_title("gBootRoot: Device check"); + $mtab->border_width(15); + $mtab->set_position('center'); + my $label = new Gtk::Label($dialog); + $label->set_justify( 'left' ); + $label->set_pattern("_________") if defined $pattern; + $mtab->vbox->pack_start( $label, $true, $true, 15 ); + $label->show(); + my $button = new Gtk::Button("OK"); + $button->signal_connect("clicked", \&mtab_check, $count); + $button->can_default(1); + $mtab->action_area->pack_start($button, $false, $false,0); + $button->grab_default; + $button->show; + $button = new Gtk::Button("Cancel"); + $button->signal_connect("clicked", sub { destroy $mtab} ); + $mtab->action_area->pack_start($button, $false, $false,0); + $button->show; + } + if (!visible $mtab) { + show $mtab; + } + else { + destroy $mtab; + mtab_window($dialog,$error,$count) if $error == 0; + } + +} # end sub mtab_window + +sub mtab{ + +# /proc/mount could be used, but maybe there is no /proc +# Press OK when drive and storage medium are ready. The drive should not +# be mounted. + + if ($_[0] == 0) { + my $dialog = "BOOTDISK:\n" + ."Press OK when the drive and its storage medium are ready.\n" + ."The Boot Disk will now be made. All data already on\n" + ."the storage medium will be erased."; + mtab_window($dialog,1,$_[0],1); + } + elsif ($_[0] == 1) { + my $dialog = "ROOTDISK:\n" + ."Press OK when the drive and its storage medium are ready.\n" + ."The Root Disk will now be made. All data already on\n" + ."the storage medium will be erased."; + mtab_window($dialog,1,$_[0],1); + } + + +} # end sub mtab + + +sub mtab_check { + + my($widget,$count) = @_; + + my $dialog; + my $error = 1; + +# Check to see if $device is mounted +open (MTAB, "/etc/mtab") or die "no mtab!\n"; +while () { + if (m,$device,) { + # Safety Check: + $dialog = "Please umount the device first.\nPress OK when you are ready."; + $error = 0; + } +} +close(MTAB); + +mtab_window($dialog,$error,$count) if $error == 0; + + # Make sure the drive and storage medium are accessible + # Keep asking until they are. + if ($error == 1) { + destroy $mtab; + system "mke2fs -m0 -i8192 $device $size >> $tmp/verbose 2>&1"; + if ($? != 0) { + $dialog = "gBootRoot: ERROR: You need to insert a disk\n"; + mtab_window($dialog,$error,$count); + return; + } + return if errm(system "mount -t ext2 $device $mnt >> $tmp/verbose 2>&1") == 2; + lilo_put_it_together() if $count == 0; + device2() if $count == 1; + } + +} # end sub mtab_check + + +sub initrd_heredoc { + + my($broot_image) = @_; + +# Here's where the initrd is put together using a loop device +# HEREDOC +my $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 + + return $initrd_exec; + +} # end sub initrd_heredoc + + +sub brlilo { + + my ($device) = @_; + +# HEREDOC +my $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 + + return $brlilo; + +} # end sub brlilo + + +sub message { +# HEREDOC +my $message = << "MESSAGE"; + +gBootRoot $version written by Jonathan Rosenbaum $date GNU 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 + + return $message; + +} # end sub message + +sub help { + +<< "HELP"; + +gBootRoot $version written by Jonathan Rosenbaum $date GNU GPL +email:mttrader\@access.mountain.net +site -> http://the.netpedia.net/gBootRoot.html + +gBootRoot is a Gtk+/Perl program useful for both beginners and advanced +GNU/Linux users. It makes the construction/development of emergency and +mini distributions simple. + +- A GNU/Linux user can easily create an emergency Boot/Root set. There +are a multitude of pre-existing compressed filesystems readily available. +Please check the gBootRoot FAQ at the gBootRoot site listed above. +** If you are a developer please send me links to Kernel/Filesystems which +I can share with users of gBootRoot. + +- A developer creating a mini distribution can concentrate his efforts on +perfecting the filesystem, and then he can use gBootRoot to quickly create a +Boot/Root set to run tests. + +- Disk sets allow for more space to include interesting and necessary things. +The size of the Kernel is increasing every day making sets advantageous. + +How to Use gBootRoot: + +gBootRoot is similar to BootRoot, but it is more efficient +and powerful. The most important button to familiarize yourself +with is the Submit button which starts the whole process, dialogs are +presented as the process continues asking you if you want to continue "OK" or +stop "Cancel". + +There are 5 rows. The boot method column has only one choice "lilo." +Clicking on the menu on the right selects the method. + +The second row allows you to select the kernel for the Boot/Root set. You +may either use the file selector button on the right hand side, or you may +type in the location on the left hand side. + +NOTE: +Presently you need to press [Enter] on your keyboard to select what you +typed in, but one advantage of this is that gBootRoot understands shell +notation like ../twobelow/kernel. The only disadvantage of this is that my +program may be written up as an example in a GUI blooper book. :) + +The third row allows you to select the compressed filesystem you are +providing, using either of the two ways mentioned before. + +The fourth row allows you to select the device you want to use. The default +device is the first floppy disk (/dev/fd0). + +The fifth row allows you to choose the size of the device being used. +If you choose the compressed filesystem with the file selector the program +should automatically detect the compression used, otherwise, click on the +appropriate radio button to choose either gzip or bzip2 compression. + +Little things you may want to know: + +* gBootRoot requires ash for initrd. Ash is a feather weight version of Bash. + +HELP + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +