From 3a5c8fe36b25fa5bf108ab68dd4583f5d01dfa74 Mon Sep 17 00:00:00 2001 From: freesource Date: Tue, 31 Jul 2001 04:45:20 +0000 Subject: [PATCH] Used to be gBootRoot :) --- gbootroot | 2888 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2888 insertions(+) create mode 100755 gbootroot diff --git a/gbootroot b/gbootroot new file mode 100755 index 0000000..0317da3 --- /dev/null +++ b/gbootroot @@ -0,0 +1,2888 @@ +#!/usr/bin/perl -w + +# gBootRoot Copyright (C) 2000 +# Lead Developer and Project Coordinator +# Jonathan Rosenbaum +# +# Developer +# Cristian Ionescu-Idbohrn +# +# Tester +# Magnus Holmberg +# +# Helper +# Yahshua Mashiyach +# +# 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; +use Yard; +use YardBox; +use Error; +use File::Basename; +init Gtk; +set_locale Gtk; + +# Perhaps you are wondering where to learn 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. A good reference can be found at +# http://projects.prosa.it/gtkperl/reference.html + + +# If you want gBootRoot to do it's stuff somewhere else, change the +# value for $tmp1. +my $tmp1 = "/tmp"; # tmp should be default - Cristian +my $lilo_conf = "/etc/lilo.conf"; +my $home = "$ENV{HOME}/.gbootroot"; +my $uml_xterm = "xterm -e"; + +# CHANGES +# +# 1.2.2 - 09/03/2000 +# * Development is now at sourceforge.net/projects/gbootroot. +# * Cristian Ionescu-Idbohrn 'cretzu' added as developer +# 08/13/2000. +# * Advanced Section GUI added. +# * Stripping (new) is now the default behavior. Stripping +# options are in AS. +# * Cretzu's gdkbirdaao() " Guess Default Kernel Boot Image +# Root Device And Append Options" is incorporated both in +# beginner section and AS. +# * Cameron Caffee sends +# detailed reports and helps with testing. This leads to +# the discovery of the need for stripping, as well as a +# version check being incorporated into the program. +# * Option for additional devices in boot disk added to AS. +# * 'Changed' signal replaces 'activate' in entry widgets. +# * Hard wired coding changes in initrd_heredoc(); +# development drive can be different than boot drive; +# added as an option to AS. +# * Step increment changed for device size spinner button. +# * New documentation and grammar corrections. +# * Bugs closed: 111579, 112555, 112949, 111580, 11636, 12073, +# 12215, 13385, 13453, 13455. +# +# 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 = "1.2.2"; +my $date = "09.03.2000"; +my $gtk_perl_version = "0.7002"; +my $pwd = `pwd`; chomp $pwd; +my $home_rootfs = "$home/root_filesystem/"; +my $home_uml_kernel = "$home/uml_kernel/"; + +# Yard Stuff +my $home_yard = "$home/yard"; +my $template_dir = "$home_yard/templates"; +my $home_yard_replacements = "$home_yard/replacements"; + +my $initrd; +my $compress; +my $false = 0; +my $true = 1; +my $ok; +my $box2; +my $label; +my $label_advanced; +my $separator; +my $order; +my $text_window; +my $verbosity_window; +my @container; + +# Make container verbose +use constant METHOD => 0 ; +use constant KERNEL => 1 ; +use constant ROOT_DEVICE => 2 ; +use constant BOOT_DEVICE => 3 ; +use constant SIZE => 4 ; +use constant COMPRESS => 5 ; +use constant LIB_STRIP => 6 ; +use constant BIN_STRIP => 7 ; +use constant OBJCOPY_BOOL => 8 ; +use constant ABS_DEVICE => 9 ; +use constant ABS_OPT_DEVICE => 10 ; +use constant ABS_APPEND => 11 ; +my @original_container; +my $file_dialog; +my ($kernel,$root_image,$device,$size); +my $mtab; +my ($tmp,$mnt); +my $norm_root_device; +my ($hbox_advanced); +my $separator_advanced; +my @entry_advanced; +my $entry_advanced; +my ($ea1,$ea2,$ea3); # entry advanced boot +my ($ear1,$ear2,$ear3,$ear4); # entry advanced root +my ($eab1,$eab2,$eab3); # entry advanced uml +my $uml_window; +my $table_advanced; +my $table_advanced_root; +my ($spinner_advanced,$spinner_size); +my $button_count = 0; +my $button_count_root = 0; +my $obj_count = 0; +my $obj_count_root = 0; +my ($lib_strip_check,$bin_strip_check); +my ($bz2_toggle,$gz_toggle); +my ($bz2_toggle_root,$gz_toggle_root,$compression_off); +my ($combo); +my ($adj2,$adj3); +my @strings; +my ($root_device,$root_filename,$method,$template,$filesystem_size, + $root_device_size); +my $ars = {}; # anonymous hash + +# 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; + +(undef,$container[KERNEL],$container[ABS_APPEND]) = gdkbirdaao(); + +# /tmp +home_builder($tmp1); + +# $HOME/.gbootroot/root_filesystem +home_builder($home_rootfs); + +# $HOME/.gbootroot/uml_kernel +home_builder($home_uml_kernel); +symlink_builder("/usr/bin/linux","$home_uml_kernel/linux"); +if (!-e "$home_uml_kernel/.options") { + open(OPTIONS,">$home_uml_kernel/.options") + or die "Couldn't write $home_uml_kernel/.options at $?\n"; + print OPTIONS "root=/dev/ubd0\n"; + close(OPTIONS); +} + +# $HOME/.gbootroot/yard/templates +home_builder($template_dir); + +# $HOME/.gbootroot/yard/replacements +home_builder($home_yard_replacements); + +# Basically so different users get the same things in +# their personal directories. +sub symlink_builder { + + my ($oldfile,$newfile) = @_; + + if (!-e $newfile && !-l $newfile) { + my $error; + symlink($oldfile,$newfile) or + ($error = error("Can not make symlink to $oldfile + from $newfile.\n")); + } + +} + +sub home_builder { + + my ($home_builder) = @_; + + if (!-d $home_builder) { + if (-e $home_builder) { + error_window( + "gBootRoot: ERROR: A file exists where $home_builder should be"); + } + else { + my @directory_parts = split(m,/,,$home_builder); + 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 $home_builder"); + } + } + } + +} # end home_builder + +my ($sec,$min,$hour,$day,$month,$year) = (localtime)[0,1,2,3,4,5]; +my $time = sprintf("%02d:%02d:%02d-%02d-%02d-%04d", + $hour, $min, $sec, $month+1, $day, $year+1900); +if (!-d "$tmp1/gbootroot_tmp$time") { + $tmp = "$tmp1/gbootroot_tmp$time" if err_custom_perl( + "mkdir $tmp1/gbootroot_tmp$time", + "gBootRoot: ERROR: Could not make temporary directory") != 2; +} +if (!-d "$tmp1/gbootroot_mnt$time") { + $mnt = "$tmp1/gbootroot_mnt$time" if err_custom_perl( + "mkdir $tmp1/gbootroot_mnt$time", + "gBootRoot: ERROR: Could not make mount directory") != 2; +} + + +# Verbosity is universal for all methods, and controlled by a scale slider. +# Yard +# 0 --> only the important messages. +# 1 --> all messages. +my $verbosity = 1; # info & sys use this as Global + +## One hard copy log file is saved for the session, and the user can also +## save from the verbosity box including saving a selection. +#my $verbosefn = "$tmp/verbose"; # All verbosity +my $verbosefn = "/tmp/verbose"; # Yard - always logged, but 0&1 = STDOUT + +# Need this before everything. +Gtk::Rc->parse("gbootrootrc"); + +verbosity_box(); +start_logging_output($verbosefn,$verbosity); # Yard "tmp dir name" + # "verbosity level" + + +# Gtk::check_version expects different arguments than .7004 so will have +# to check for the version instead. +# Right now >= 0.7002 is o.k. +#if (Gtk::check_version(undef,"1","0","7") =~ /too old/) { + +if (Gtk->major_version < 1) { + et(); +} +elsif (Gtk->micro_version < 7) { + et(); +} +elsif (Gtk->minor_version < 2) { + et(); +} + +sub et { + error_window("gBootRoot is presently being developed with gtk-perl" . + " version $gtk_perl_version.\nYou are using a" . + " version of gtk-perl < 0.7002. You may still be able\n" . + " to use this program, but you may encounter problems." . + " See the FAQ\nfor places to get a newer gtk-perl version." . + " \n\nThe most common error reported:\n\"Can't locate" . + " object method\""); + #,"center"); + print "Using a version of gtk-perl < 0.7002\n"; +} + +my $window = Gtk::Window->new("toplevel"); +# special policy +$window->set_policy( $false, $true, $true ); +$window->set_title("gBootRoot"); +$window->set_position('none'); +$window->signal_connect("destroy", + sub { + unlink "$verbosefn", "$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"); +# Zas - bug in gtk-perl < .7002 +$window->window->set_decorations(['all', 'menu']); +$window->window->set_functions(['all', 'resize']); + +my $tooltips = Gtk::Tooltips->new(); + +my $box1 = Gtk::VBox->new($false,0); +$window->add($box1); +$box1->show(); + +# First row +hbox(); +my $entry = entry($false,0); + +# Menu - later this may be improved if new methods are added. +my $opt = Gtk::OptionMenu->new(); +$tooltips->set_tip( $opt, "Choose the Boot method.", "" ); +my $menu = Gtk::Menu->new(); +my $item = Gtk::MenuItem->new("Method -> lilo" ); +$item->show(); +# Eventually get_menu, or something totally different will be used. +$item->signal_connect( 'activate',sub { $entry->set_text("lilo"); + $container[METHOD] = "lilo"}); +$menu->append( $item ); +$opt->set_menu( $menu ); +$box2->pack_start( $opt, $true, $true, 0 ); +$opt->show(); +$box2->show(); + +# Second row +# Get to look three places for kernel value +# default ( null|gdkkbirdaao) && entry() && fileselect->file_ok_sel +hbox(); +my $entry2 = entry($true,1); +$entry2->set_text($container[KERNEL]); +if ($container[KERNEL]) { + $ars->{kernel} = $container[KERNEL]; + ars($ars); +} +button("Kernel Selection",$entry2,"Kernel Selection",1); + +# Third row +hbox(); +my $entry3 = entry($true,2); +button("Root Filesystem",$entry3,"Root Filesystem",2,$home_rootfs); + +# In the future, if experimenters send in data, there will be two +# different devices. +# Fourth row +hbox(); +my $entry4 = entry($true,3); +$container[BOOT_DEVICE] = "/dev/fd0"; +$entry4->set_text($container[BOOT_DEVICE]); +button("Device Selection",$entry4,"Device Selection",3,"/dev/fd0"); + +# Fifth row +hbox("what"); +my $adj = Gtk::Adjustment->new( 1440.0, 0.0, 360000000.0, 282.0, 360.0, 0.0 ); +my $spinner = Gtk::SpinButton->new( $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[SIZE] = 1440; # A better value - a rtbt trick. +$adj->signal_connect( "value_changed", sub { + $container[SIZE] = $spinner->get_value_as_int(); + $adj2->set_value($container[SIZE]) if defined $adj2;}); +$box2->pack_start( $spinner, $true, $true, 0 ); +#label("Device Size"); + +# gz and bz2 radio buttons +my $rbutton = Gtk::RadioButton->new( "gz" ); +$tooltips->set_tip( $rbutton, "Choose Compression used on the Filesystem.", "" ); +$gz_toggle = $rbutton; +$rbutton->set_active( $true ); +$box2->pack_start( $rbutton, $false, $false, 0 ); +$rbutton->show(); +$rbutton = Gtk::RadioButton->new( "bz2", $rbutton ); +$rbutton->set_usize(1,1); +$tooltips->set_tip( $rbutton, "Choose Compression used on the Filesystem.", "" ); +$bz2_toggle = $rbutton; +$box2->pack_start( $rbutton, $true, $true, 0); +$rbutton->show(); + +# Verbosity adjustment +my $adj1 = Gtk::Adjustment->new( 2.0, 0.0, 2.0, 0.0, 1.0, 0.0 ); +my $verbosity_scale = Gtk::HScale->new($adj1); +$verbosity_scale->set_value_pos("right"); +$verbosity_scale->set_digits(0); +$tooltips->set_tip( $verbosity_scale, "Adjust the Verbosity Level.", "" ); +$verbosity_scale->show(); +# Verbosity Box can be turned on/off here +$adj1->signal_connect( "value_changed", sub { + $verbosity = $verbosity_scale->get_adjustment->value - 1; + verbosity($verbosity); + + if ($verbosity == -1) { + if ($verbosity_window) { + destroy $verbosity_window if visible $verbosity_window; + } + } + elsif (!$verbosity_window) { + close(LOGFILE); + verbosity_box(); + start_logging_output($verbosefn,$verbosity); + } + + } ); +$box2->pack_start( $verbosity_scale, $false, $false, 0); + +#start_logging_output($yard_temp,$verbosity); + +# Size status entry +my $entry5 = Gtk::Entry->new(); +$entry5->set_editable( $false ); +$tooltips->set_tip( $entry5, "This shows room remaining on the Device.", "" ); +$entry5->set_usize(20,20); +$box2->pack_start( $entry5, $true, $true, 0 ); +$entry5->show(); + + +my $button_advanced; +########################### +# The ADVANCED BOOT SECTION +########################### +# Separator +$separator = Gtk::HSeparator->new(); +$box1->pack_start( $separator, $false, $true, 0 ); +$separator->show(); + +# This is cool how this works. +my $vbox_advanced = Gtk::VBox->new($false,0); +$box1->add($vbox_advanced); +$vbox_advanced->show(); + +# The Advanced Boot Section button +hbox_advanced($vbox_advanced); +$button_advanced = Gtk::Button->new("Advanced Boot Section"); +$tooltips->set_tip( $button_advanced, + "Change settings for the Boot Disk Image.", "" ); +$button_advanced->signal_connect("clicked",\&advanced_boot_section ); +$hbox_advanced->pack_start( $button_advanced, $true, $true, 0 ); +$button_advanced->show(); + +########################### +# The ADVANCED ROOT SECTION +########################### +my $vbox_advanced_root = Gtk::VBox->new($false,0); +$box1->add($vbox_advanced_root); +$vbox_advanced_root->show(); + +hbox_advanced($vbox_advanced_root); +$button_advanced = Gtk::Button->new("Advanced Root Section"); +$tooltips->set_tip( $button_advanced, + "Generate a Root Filesystem and/or use a different Root Device.", "" ); +$button_advanced->signal_connect("clicked",\&advanced_root_section ); +$hbox_advanced->pack_start( $button_advanced, $true, $true, 0 ); +$button_advanced->show(); +########################### + +############################# +# The ADVANCED KERNEL SECTION +############################# +my $vbox_advanced_kernel = Gtk::VBox->new($false,0); +$box1->add($vbox_advanced_kernel); +$vbox_advanced_kernel->show(); + +hbox_advanced($vbox_advanced_kernel); +$button_advanced = Gtk::Button->new("Advanced Kernel Section"); +$tooltips->set_tip( $button_advanced, + "Retrieve/Make Kernel Sources.", "" ); +#$button_advanced->signal_connect("clicked",\&advanced_root_section ); +$hbox_advanced->pack_start( $button_advanced, $true, $true, 0 ); +$button_advanced->show(); +############################# + + + +# Separator +$separator = Gtk::HSeparator->new(); +$box1->pack_start( $separator, $false, $true, 0 ); +$separator->show(); + +# Status bar +my $align = Gtk::Alignment->new( 0.5, 0.5, 0, 0 ); +$box1->pack_start( $align, $false, $false, 5); +$align->show(); +my $pbar = Gtk::ProgressBar->new(); +$pbar->set_usize(321,10); # 321 10 +$align->add($pbar); +$pbar->show(); + +# Separator +$separator = Gtk::HSeparator->new(); +$box1->pack_start( $separator, $false, $true, 0 ); +$separator->show(); + +# Submit button +hbox(); +my $sbutton = Gtk::Button->new("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 = Gtk::Button->new("Close"); +$cbutton->signal_connect("clicked", + sub { + unlink "$verbosefn", "$tmp/initrd_image", + "$tmp/initrd_image.gz"; + system "umount $tmp/initrd_mnt"; + 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 = Gtk::Button->new("Help"); +$hbutton->signal_connect( "clicked", sub { create_text("help") }); +$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 { + + unlink "$verbosefn", "$tmp/initrd_image.gz"; + system "umount $tmp/initrd_mnt"; + rmdir "$tmp/initrd_mnt"; + rmdir "$tmp"; + rmdir "$mnt"; + + $SIG{INT} = \&signal; + $SIG{ABRT} = \&signal; + $SIG{TERM} = \&signal; + $SIG{QUIT} = \&signal; + $SIG{KILL} = \&signal; + + + Gtk->exit(0); +} + +sub hbox_advanced { + $hbox_advanced = Gtk::HBox->new(1,1 ); + $hbox_advanced->border_width( 2 ); # was 10 + $hbox_advanced->set_usize(321, 20); + $_[0]->pack_start( $hbox_advanced, $false, $false, 0 ); + show $hbox_advanced; +} + +sub objcopy_right_click_advanced { + + my ( @data ) = @_; + my $event = pop( @data ); + + if ( ( defined( $event->{'type'} ) ) + and ( $event->{'type'} eq 'button_press' ) ) { + if ( $event->{'button'} == 3 ) { + if (defined $lib_strip_check) { + if ($obj_count == 0) { + $tooltips->set_tip( $lib_strip_check, + "This is generally a good idea." . + " Press the right mouse button to" . + " change from [objcopy --strip-all]" . + " to [objcopy --strip-debug].", "" ); + $obj_count++; + } + else { + $tooltips->set_tip( $lib_strip_check, + "This is generally a good idea." . + " Press the right mouse button to" . + " change from [objcopy --strip-debug]". + " to [objcopy --strip-all].", "" ); + $obj_count--; + } + } + } + } + +} # end obj_right_click_advanced + +sub advanced_boot_section { + + if ($button_count == 0) { + #$vbox_advanced->set_usize(321,300); + my $boolean; + + # The table section + $table_advanced = Gtk::Table->new( 4, 3, $true ); + $vbox_advanced->pack_start( $table_advanced, $true, $true, 0 ); + $table_advanced->show(); + + #_______________________________________ + # lib_strip_check + label_advanced("Stripping:",0,1,0,1,$table_advanced); + !defined $lib_strip_check ? ($boolean = 1) + : ($boolean = $lib_strip_check->get_active()); + $lib_strip_check = Gtk::CheckButton->new("Libraries"); + $lib_strip_check->set_active($boolean); + $lib_strip_check->signal_connect( "button_press_event", + \&objcopy_right_click_advanced); + $tooltips->set_tip( $lib_strip_check, + "This is generally a good idea. Press the" . + " right mouse button to change from" . + " [objcopy --strip-debug] to" . + " [objcopy --strip-all].", "" ); + $table_advanced->attach($lib_strip_check,1,2,0,1, + ['expand'],['fill','shrink'],0,0); + show $lib_strip_check; + + # bin_strip_check + !defined $bin_strip_check ? ($boolean = 1) + : ($boolean = $bin_strip_check->get_active()); + $bin_strip_check = Gtk::CheckButton->new("Binaries"); + $bin_strip_check->set_active($boolean); + $tooltips->set_tip( $bin_strip_check, + "This is generally a good idea." . + " [objcopy --strip-all]", "" ); + $table_advanced->attach($bin_strip_check,2,3,0,1, + ['expand'],['fill','shrink'],0,0); + show $bin_strip_check; + + #_______________________________________ + # Development Drive + label_advanced("Devel Device:",0,1,1,2,$table_advanced); + $ea1 = entry_advanced(1,2,1,2,0,$table_advanced); + $tooltips->set_tip( $ea1, "If the device used for development" . + " is different than the actual boot" . + " device, use this field" . + " to indicate that device." . + " You will have to run" . + " lilo -v -C brlilo.conf -r" . + " \"device mount point\" manually at a" . + " later time on the actual" . + " boot device.", + "" ); + $ea1->set_text($container[BOOT_DEVICE]) if defined $container[BOOT_DEVICE]; + + #_______________________________________ + # Optional Device(s) + label_advanced("Opt. Device(s)",0,1,2,3,$table_advanced); + $ea2 = entry_advanced(1,2,2,3,1,$table_advanced); + $tooltips->set_tip( $ea2, "Add devices to the boot disk which are" . + " necessary for the kernel to function" . + " properly. Put a space between each" . + " device. For instance, /dev/fb0 for" . + " frame buffer devices.", + ""); + $ea2->set_text($entry_advanced[1]) if defined $entry_advanced[1]; + + #_______________________________________ + # Append Options + label_advanced("append =",0,1,3,4,$table_advanced); + $ea3 = entry_advanced(1,3,3,4,2,$table_advanced); + my $append; (undef,undef,$append) = gdkbirdaao(); + $tooltips->set_tip( $ea3, "Add append options to brlilo.conf.", ""); + $ea3->set_text($append) if defined $append; + + # Verbosity section + + $button_count++; + } + else { + destroy $table_advanced; + $button_count--; + } + +} # end sub advanced_boot_section + +sub advanced_root_section { + + if ($button_count_root == 0) { + my $boolean; + + + $table_advanced_root = Gtk::Table->new( 9, 3, $true ); + # temp solution? + #$table_advanced_root->set_row_spacings( 3 ); + $vbox_advanced_root->pack_start( $table_advanced_root, $true, + $true, 0 ); + #_______________________________________ + # Root Device selection + # $::device $device already exist + label_advanced("Root Device:",0,1,0,1,$table_advanced_root); + # $_[4] shares with advanced_boot_sections @entry_advanced + $ear1 = entry_advanced(1,2,0,1,3,$table_advanced_root); + if ($entry_advanced[3]) { + $ear1->set_text($entry_advanced[3]); + } + else { + $ear1->set_text($container[BOOT_DEVICE]); + } + $tooltips->set_tip( $ear1, + "Type in the location of the Root Device to use.", + "" ); + # $order is important because it is put in $container[$order] + button_fileselect_advanced(2,3,0,1,"Selection",$ear1,"Selection",12, + $table_advanced_root,"/dev/fd0"); + + #_______________________________________ + # Root Device Size + # gBootRoot methods + label_advanced("Root Device Size:",0,1,1,2,$table_advanced_root); + $adj2 = Gtk::Adjustment->new( 1440.0, 0.0, 360000000.0, 282.0, + 360.0, 0.0 ); + $spinner_advanced = Gtk::SpinButton->new( $adj2, 0, 0 ); + $table_advanced_root->attach($spinner_advanced,1,2,1,2, + ['shrink','fill','expand'],['fill','shrink'], + 0,0); + $tooltips->set_tip( $spinner_advanced, + "Choose the Root Device Size.", + "" ); + $spinner_advanced->set_wrap( $true ); + $spinner_advanced->set_numeric( $true ); + $spinner_advanced->set_shadow_type( 'in' ); + $spinner_advanced->show(); + $root_device_size = 1440 if !$root_device_size; + $adj2->signal_connect( "value_changed", sub { + $root_device_size = $spinner_advanced->get_value_as_int();}); + # For some reason $container[SIZE] is tranforming into [3] when + # device selection is changed. & in ABS devel device doesn't keep + # state. + if ($root_device_size) { + $spinner_advanced->set_value($root_device_size); + } + else { + $adj2->set_value($container[SIZE]) if defined $adj2; + } + + + #_______________________________________ + # Root File Name + # gBootRoot methods + label_advanced("Root Filename:",0,1,2,3,$table_advanced_root); + $ear2 = entry_advanced(1,2,2,3,4,$table_advanced_root); + $ear2->set_text("root_fs"); + $ars->{filename} = "root_fs"; + ars($ars); + $tooltips->set_tip( $ear2, "Give the Root Filesystem file a name.", + "" ); + my $ear2_save = Gtk::CheckButton->new("save"); + $ear2_save->set_active($true); + +# "Save Root File. Press right button to change" . +# " the Directory the file is saved in.", + $tooltips->set_tip( $ear2_save, + "Saves the Root Filesystem in your" . + " $ENV{HOME}/.gbootroot/root_filesystem" . + " directory.", + "" ); + $table_advanced_root->attach($ear2_save,2,3,2,3, + ['expand'],['fill','shrink'],0,0); + show $ear2_save; + + + #_______________________________________ + # Filesystem Size + # $::fs_device + label_advanced("Filesystem Size:",0,1,3,4,$table_advanced_root); + $adj3 = Gtk::Adjustment->new( 4096.0, 0.0, 1000000000.0, 128.0, + 1024.0, 0.0 ); + $spinner_size = Gtk::SpinButton->new( $adj3, 0, 0 ); + $table_advanced_root->attach($spinner_size,1,2,3,4, + ['shrink','fill','expand'],['fill','shrink'], + 0,0); + $tooltips->set_tip( $spinner_size, + "Choose the Filesystem Size.", + "" ); + $spinner_size->set_wrap( $true ); + $spinner_size->set_numeric( $true ); + $spinner_size->set_shadow_type( 'in' ); + $spinner_size->show(); + $filesystem_size = 4096 if !$filesystem_size; + $ars->{filesystem_size} = $filesystem_size; + ars($ars); + $adj3->signal_connect( "value_changed", sub { + $filesystem_size = $spinner_size->get_value_as_int(); + $ars->{filesystem_size} = $filesystem_size; + ars($ars); + }); + $spinner_size->set_value($filesystem_size) if $filesystem_size; + + #_______________________________________ + # Compression + # gBootRoot methods + + + my $hbox_between = Gtk::HBox->new(0,1); + $table_advanced_root->attach($hbox_between,0,3,4,5, + ['fill'], + ['fill','shrink'],15,0 ); + $hbox_between->show; + + # label + my $label_compression = Gtk::Label->new( "Compression:" ); + $label_compression->set_justify( "right" ); + $hbox_between->pack_start( $label_compression, $false, $false, 0 ); + $label_compression->show(); + + # gz + $rbutton = Gtk::RadioButton->new( "gz" ); + $tooltips->set_tip( $rbutton, + "Choose Compression used on the Filesystem.", "" ); + $gz_toggle_root = $rbutton; + $rbutton->set_active( $true ); + $hbox_between->pack_start( $rbutton, $true, $false, 0 ); + $rbutton->show(); + + # bz2 + $rbutton = Gtk::RadioButton->new( "bz2", $rbutton ); + $tooltips->set_tip( $rbutton, + "Choose Compression used on the Filesystem.", "" ); + $bz2_toggle_root = $rbutton; + $hbox_between->pack_start( $rbutton, $true, $false, 0 ); + $rbutton->show(); + + # compression off + $compression_off = Gtk::CheckButton->new( "off"); + $tooltips->set_tip( $compression_off, + "Turn Compression off.", "" ); + $hbox_between->pack_start( $compression_off, $true, $false, 0 ); + $compression_off->set_active($true); + $compression_off->show(); + + #_______________________________________ + # UML Kernel + label_advanced("UML Kernel:",0,1,5,6,$table_advanced_root); + # $_[4] shares with advanced_boot_sections @entry_advanced + $ear3 = entry_advanced(1,2,5,6,5,$table_advanced_root); + $ear3->set_text("$home_uml_kernel" . "linux"); + $tooltips->set_tip( $ear3, + "If you have a User Mode Linux Kernel, type in" . + " the Kernel's location," . + " and any Kernel options desired afterwards.", + "" ); + button_fileselect_advanced(2,3,5,6,"Selection",$ear3,"Selection",13, + $table_advanced_root); + + #_______________________________________ + # Method + label_advanced("Method:",0,1,6,7,$table_advanced_root); + $ear4 = entry_advanced(1,2,6,7,6,$table_advanced_root); + $ear4->set_editable($false); + $tooltips->set_tip( $ear4, + "Choose the Root Filesystem Generation Method.", + "" ); + + my $opt_root = Gtk::OptionMenu->new(); + $tooltips->set_tip( $opt_root, + "Choose the Root Filesystem Generation Method.", + "" ); + my $menu_root = Gtk::Menu->new(); + + my $yard = Gtk::MenuItem->new("Yard" ); + + $menu_root->append( $yard ); + + $yard->signal_connect( 'activate', sub { + $ear4->set_text("yard"); + $entry_advanced[6] = $ear4->get_text(); + opendir(DIR,$template_dir) if -d $template_dir; + @strings = grep { m,\.yard$, } readdir(DIR); + closedir(DIR); + $combo->set_popdown_strings( @strings ) if @strings; + } ); + + $ear4->set_text($entry_advanced[6]) if $entry_advanced[6]; + if ($yard) { + opendir(DIR,$template_dir) if -d $template_dir; + @strings = grep { m,\.yard$, } readdir(DIR) if $yard; + closedir(DIR) + } + + $yard->show(); + + $opt_root->set_menu( $menu_root ); + $table_advanced_root->attach($opt_root,2,3,6,7, + ['expand','fill'],['fill','shrink'],0,0); + $opt_root->show(); + + #_______________________________________ + # Template + # $::contents_file + label_advanced("Template:",0,1,7,8,$table_advanced_root); + $combo = Gtk::Combo->new(); + $combo->entry->set_text($entry_advanced[7]) if $entry_advanced[7]; + #$button_count_root_open = 1 + $button_count_root_open; + #print $button_count_root_open; + #if ($button_count_root_open > 1) { + # $combo->set_popdown_strings( @strings ) + # if $entry_advanced[7] ne ""; + #} + $tooltips->set_tip( Gtk::Combo::entry($combo), + "Choose a Template for the Method.", + "" ); + $entry_advanced[7] = $combo->entry->get_text(); # nothing selected + $combo->entry->signal_connect("changed", sub { + $entry_advanced[7] = $combo->entry->get_text(); + $ars->{template} = $entry_advanced[7]; + ars($ars); + } ); + $table_advanced_root->attach($combo,1,3,7,8, + ['expand','fill'],['fill','shrink'],0,0); + show $combo; + + #_______________________________________ + # Generate - UML - Accept buttons + $table_advanced_root->set_row_spacing( 7, 9); + + # The Generation process is determined by the method chosen. Yard - + # asks the user if they want to modify the template, and/or save a + # new template with modifications (to be added to Template menu). + my $generate_b = button_advanced(0,1,8,9,"Generate",$table_advanced_root); + $generate_b->signal_connect("clicked",\&Generate); + $tooltips->set_tip( $generate_b, "Generate Root Filesystem.", "" ); + + my $UML_b = button_advanced(1,2,8,9,"UML",$table_advanced_root); + + $UML_b->signal_connect("clicked", \¨_box); + $tooltips->set_tip( $UML_b, "Test Filesystem with User Mode Linux.", + "" ); + + # UML kernel doesn't look like a normal kernel + ##if (!-d $entry_advanced[5] && -f $entry_advanced[5]) { + ##$k_error = kernel_version_check($entry_advanced[5]); + ##return if $k_error && $k_error eq "ERROR";} + ## else { + ##error_window("Kernel Selection required"); + ##return; } + + # Will check to make sure that Filesystem fits device. + # Method determines whether or not compression is used. + my $accept_b = button_advanced(2,3,8,9,"Accept",$table_advanced_root); + $accept_b->signal_connect("clicked", \&accept_button, $ear2_save); + $tooltips->set_tip( $accept_b, "Accept Filesystem.", "" ); + + + $table_advanced_root->show(); + $button_count_root++; + + } + else { + destroy $table_advanced_root; + $button_count_root--; + } + + +} # end sub advanced_root_section + +sub uml_box { + + $uml_window = Gtk::Window->new("toplevel"); + $uml_window->signal_connect("destroy", \&destroy_window, + \$uml_window); + $uml_window->signal_connect("delete_event", \&destroy_window, + \$uml_window); + #$uml_window->set_usize( 450, 175 ); # 500 600 + $uml_window->set_policy( $true, $true, $false ); + $uml_window->set_title( "Uml Box" ); + $uml_window->border_width(1); + + my $main_vbox = Gtk::VBox->new( $false, 0 ); + $uml_window->add( $main_vbox ); + $main_vbox->show(); + + my $table_uml = Gtk::Table->new( 4, 3, $true ); + $main_vbox->pack_start( $table_uml, $true, $true, 0 ); + $table_uml->show(); + + #_______________________________________ + # Xterm and execute options + label_advanced("Xterm:",0,1,0,1,$table_uml); + $eab1 = entry_advanced(1,2,0,1,8,$table_uml); + $eab1->set_text($uml_xterm); + $tooltips->set_tip( $eab1, + "Choose an xterm with " . + "its executable option switch.", + "" ); + + #_______________________________________ + # UML options + label_advanced("Options:",0,1,1,2,$table_uml); + $eab2 = Gtk::Combo->new(); + $table_uml->attach($eab2,1,3,1,2, + ['expand','fill'],['fill','shrink'],0,0); + open(OPTIONS,"$home_uml_kernel/.options"); + my @initial_options = ; + close(OPTIONS); chomp @initial_options; + $eab2->entry->set_text($initial_options[0]); + $entry_advanced[9] = $eab2->entry->get_text(); + $eab2->set_popdown_strings( @initial_options ) ; + $eab2->entry->signal_connect("changed", sub { + $entry_advanced[9] = $eab2->entry->get_text(); + open(OPTIONS,">$home_uml_kernel/.options"); + $entry_advanced[9] =~ s/\n/ /g; + print OPTIONS "$entry_advanced[9]\n"; + foreach (@initial_options) { + if ($_ ne "$entry_advanced[9]") { + print OPTIONS "$_\n"; + } + } + close(OPTIONS); + } ); + $tooltips->set_tip( Gtk::Combo::entry($eab2), + "Enter uml command-line options.", + "" ); + $eab2->show(); + + #_______________________________________ + # Root Filesystem defaults to generated one if found. + label_advanced("Root_Fs:",0,1,2,3,$table_uml); + $eab3 = entry_advanced(1,2,2,3,10,$table_uml); + button_fileselect_advanced(2,3,2,3,"Selection",$eab3,"Selection",14, + $table_uml,$home_rootfs); + $eab3->set_text("ubd0=$tmp/$entry_advanced[4]") + if -e "$tmp/$entry_advanced[4]"; + $tooltips->set_tip( $eab3, + "Choose an uncompressed root filesystem." . + "Append with uml?=.", + "" ); + + $table_uml->set_row_spacing( 2, 4); + + #_______________________________________ + # Submit Button + my $submit_b = button_advanced(0,1,3,4,"Submit",$table_uml); + $tooltips->set_tip( $submit_b, + "Start uml kernel processes.", + "" ); + $submit_b->signal_connect("clicked", + sub { + # UML kernel = $entry_advanced[5] + # xterm -e linux ubd#=root_fs + # root=/dev/ubd# + open(OPTIONS,"$home_uml_kernel/.options"); + @initial_options = ; + close(OPTIONS); chomp @initial_options; + $eab2->set_popdown_strings( @initial_options ) ; + + my $pid; + if ($entry_advanced[8] && + $entry_advanced[10]) { + # Check to see if it actually exists + my $executable = (split(/\s+/,$entry_advanced[8]))[0]; + if (!find_file_in_path(basename($executable))) { + error_window("gBootRoot Error: " . + "Enter a valid xterm, and " . + "executable option."); + return; + } + if ($executable =~ m,/,) { + if (! -e $executable) { + error_window("gBootRoot Error: " . + "Enter a valid path for the xterm."); + return; + } + } + + unless ($pid = fork) { + unless (fork) { + if ($pid == 0) { + sys("$entry_advanced[8] $entry_advanced[5] $entry_advanced[9] $entry_advanced[10]"); + Gtk->_exit($pid); + } + + } + + } + waitpid($pid,0); + + } + else { + if (!$entry_advanced[8]) { + error_window("gBootRoot Error: " . + "Enter an xterm, and executable " . + "option."); + return; + } + if (!$entry_advanced[10]) { + error_window("gBootRoot Error: " . + "Enter the ubd?=Root_Filesystem " . + "and its location."); + return; + } + + } + + } ); + + + #_______________________________________ + # Cancel button also kills UML kernel if still open + my $abort_b = button_advanced(1,2,3,4,"Abort",$table_uml); + $tooltips->set_tip( $abort_b, + "Abort uml kernel processes." . + "Use with care, `shutdown -h now` " . + "is preferable.", + "" ); + $abort_b->signal_connect("clicked", + sub { + if ($entry_advanced[10]) { + # Most stuff + remove_matching_process($entry_advanced[10]); + # Debian + remove_matching_process("Virtual Console"); + # Good to remove uml_\w* + remove_matching_process("uml_\w*"); + # Again for good measure :) + remove_matching_process($entry_advanced[10]); + } + } ); + + #_______________________________________ + # Cancel button also kills UML kernel if still open + my $cancel_b = button_advanced(2,3,3,4,"Close",$table_uml); + $tooltips->set_tip( $cancel_b, + "Close uml box.", + "" ); + $cancel_b->signal_connect("clicked", + sub { + $uml_window->destroy() if $uml_window; + } ); + + $uml_window->show(); + +} + +sub remove_matching_process { + + my ($match_word) = @_; + + # Just an overkill + if ($match_word =~ m,/,) { + $match_word =~ s,/,\\/,g; + } + + my $ps = "ps auxw|"; + open(P,"$ps"); + while(

) { + # friendly approach + if (m,$match_word,) { + my $process = (split(/\s+/,$_,))[1]; + system "kill $process"; + # not so friendly approach + system "kill -9 $process"; + } + } + close(P); + +} # end remove_matching_process + +sub accept_button { + + my ($widget,$ear2_save) = @_; + + my($tool,$value); + if (-e "$tmp/$entry_advanced[4]" ) { + if (!$compression_off->active) { + if ($gz_toggle_root->active) { + $compress = "gzip"; + open(F,"file $tmp/$entry_advanced[4] |"); + while () { + if (/gzip/) { + info(0, "Already gzip compressed.\n"); + } + elsif (/bzip2/) { + info(0, "Already bzip2 compressed.\n"); + } + else { + system "$compress $tmp/$entry_advanced[4]"; + $entry_advanced[4] = "$entry_advanced[4].gz"; + $entry3->set_text("$tmp/$entry_advanced[4]"); + } + } + if ($ear2_save->active) { + return if errcp(sys("cp -a $tmp/$entry_advanced[4] $home_rootfs")) == 2; + } + } + elsif ($bz2_toggle_root->active) { + $compress = "bzip2"; + open(F,"file $tmp/$entry_advanced[4] |"); + while () { + if (/gzip/) { + info(0, "Already gzip compressed.\n"); + } + elsif (/bzip2/) { + info(0, "Already bzip2 compressed.\n"); + } + else { + system "$compress $tmp/$entry_advanced[4]"; + $entry_advanced[4] = "$entry_advanced[4].bz2"; + $entry3->set_text("$tmp/$entry_advanced[4]"); + } + } + if ($ear2_save->active) { + return if errcp(sys("cp -a $tmp/$entry_advanced[4] $home_rootfs")) == 2; + } + } + } + else { # off + $entry3->set_text("$tmp/$entry_advanced[4]"); + if ($ear2_save->active) { + return if errcp(sys("cp -a $tmp/$entry_advanced[4] $home_rootfs")) == 2; + } + } + } + else { + error("$entry_advanced[4] doesn't exist; create it first.\n"); + } + +} # end accept_button + +# Coming - .config storage, auto-matic kernel locus, all stages +# /usr/src/linux* Possible integration with other Projects .. modules +# will be in the logical place. Before ABS. +sub advanced_kernel_section { + + +} # end sub advanced_kernel_section + +# Stuff univeral for all root filesystem methods +# Compression, UML Kernel, and Method only need to be known by the Dock. + + +sub Generate { + + # @entry_advanced + # 0 = Development Drive + # 1 = Optional Devices + # 2 = Append Options + #------------------ + # 3 = Root Device + # 4 = Root Filename + # 5 = UML Kernel + $method = $entry_advanced[6]; # 6 = Method + # 7 = Template + # 8 = UML xterm + # 9 = UML options + # 10 = UML root_fs + # $root_device_size; + # $filesystem_size; + + $ars->{device} = $entry_advanced[3]; + $ars->{device_size} = $root_device_size; + $ars->{tmp} = $tmp; + $ars->{mnt} = $mnt; + $ars->{template_dir} = $template_dir; # static right now. + ars($ars); + + my $template = $ars->{template}; + $root_device = $ars->{device}; + $root_filename = $ars->{filename}; + + if (!$root_device || $root_device eq "") { + error_window("gBootRoot: ERROR: Root Device not defined"); + return; + } + # devfs may change this + if (!-b $root_device) { + error_window("gBootRoot: ERROR: Not a valid Block Device"); + return; + } + + if (!$root_filename || $root_filename eq "") { + error_window("gBootRoot: ERROR: Root Filename not given"); + return; + } + if (!$method || $method eq "") { + error_window("gBootRoot: ERROR: Method must be supplied"); + return; + } + if (!$template || $template eq "") { + error_window("gBootRoot: ERROR: Template name not given"); + return; + } + + + if ($method eq "yard") { + yard(); + } + + +} # end sub Generate + +sub button_advanced { + + # cretzu should like this + my ($left_attach,$right_attach,$top_attach, + $bottom_attach,$text,$widget) = @_; + my $button = Gtk::Button->new($text); + $widget->attach($button,$left_attach,$right_attach, + $top_attach,$bottom_attach, + ['shrink','fill','expand'],['fill','shrink'],2,2); + show $button; + return $button; + +} + +sub button_fileselect_advanced { + + # cretzu should like this + # $order does matter because it fills in $container[$order]. + my ($left_attach,$right_attach,$top_attach,$bottom_attach,$text,$ent, + $name,$order,$widget,$device) = @_; + + my $button = Gtk::Button->new($text); + $widget->attach($button,$left_attach,$right_attach, + $top_attach,$bottom_attach, + ['shrink','fill','expand'],['fill','shrink'],2,2); + + # example + if ($order == 12) { + $tooltips->set_tip( $button, "Select the Root Device.", "" ); + } + elsif ($order == 13) { + $tooltips->set_tip( $button, "Select the UML Kernel.", "" ); + } + elsif ($order == 14) { + $tooltips->set_tip( $button, "Select the Root Filesystem.", "" ); + } + + + $button->signal_connect( "clicked",\&fileselect,$ent,$name,$order,$device); + $button->show(); + + +} # end sub button_fileselect_advanced + + +sub entry_advanced { + + my $numa = $_[4]; + my $entry_advanced = Gtk::Entry->new(); + $entry_advanced->set_editable( $true ); + $entry_advanced->signal_connect( "changed", sub { + $entry_advanced[$numa] = $entry_advanced->get_text(); + if ($numa == 4) { + $ars->{filename} = $entry_advanced[$numa]; + ars($ars); + } + } ); + $entry_advanced->set_usize(100,20); + $_[5]->attach($entry_advanced,$_[0],$_[1],$_[2],$_[3], + ['shrink','fill','expand'],['fill','shrink'],0,0); + show $entry_advanced; + return $entry_advanced; + +} + +sub separator_advanced { + + $separator_advanced = Gtk::HSeparator->new(); + $_[0]->pack_start( $separator_advanced, $false, $true, 0 ); + $separator_advanced->show(); + +} + +sub label_advanced { + + my($text) = @_; + + $label_advanced = Gtk::Label->new( $text ); + $label_advanced->set_justify( "fill" ); + $_[5]->attach($label_advanced,$_[1],$_[2],$_[3],$_[4], ['expand'],['fill','shrink'],0,0); + $label_advanced->show(); + +} + +# I created two of these, one for help (eventually there may be a different +# approach), and one for verbosity. I am sure there is a better OO way to +# do it, though. +sub create_text { + + if (not defined $text_window) { + $text_window = Gtk::Window->new("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 = Gtk::VBox->new( $false, 0 ); + $text_window->add( $main_vbox ); + $main_vbox->show(); + + my $vbox = Gtk::VBox->new( $false, 10 ); + $vbox->border_width( 10 ); + $main_vbox->pack_start( $vbox, $true, $true, 0 ); + $vbox->show(); + + my $table = Gtk::Table->new( 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 = Gtk::Text->new( undef, undef ); + $text->set_editable($false); + $table->attach( $text, 0, 1, 0, 1, + [ 'expand', 'shrink', 'fill' ], + [ 'expand', 'shrink', 'fill' ], + 0, 0 ); + $text->grab_focus(); + $text->show(); + + # Add a vertical scrollbar to the GtkText widget + my $vscrollbar = Gtk::VScrollbar->new( $text->vadj ); + $table->attach( $vscrollbar, 1, 2, 0, 1, 'fill', + [ 'expand', 'shrink', 'fill' ], 0, 0 ); + #my $logadj = $vscrollbar->get_adjustment(); + #logadj($logadj); + #$vscrollbar->show(); + + $text->freeze(); + $text->insert( undef, undef, undef, help() ); + $text->thaw(); + + my $separator = Gtk::HSeparator->new(); + $main_vbox->pack_start( $separator, $false, $true, 0 ); + $separator->show(); + + $vbox = Gtk::VBox->new( $false, 10 ); + $vbox->border_width( 10 ); + $main_vbox->pack_start( $vbox, $false, $true, 0 ); + $vbox->show(); + + my $button = Gtk::Button->new( "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 + +# This monster needs different behavior than create_text. +sub verbosity_box { + + + $verbosity_window = Gtk::Window->new("toplevel"); + $verbosity_window->signal_connect("destroy", \&destroy_window, + \$verbosity_window); + $verbosity_window->signal_connect("delete_event", \&destroy_window, + \$verbosity_window); + $verbosity_window->set_usize( 450, 175 ); # 500 600 + $verbosity_window->set_policy( $true, $true, $false ); + $verbosity_window->set_title( "Verbosity Box" ); + $verbosity_window->border_width(0); + + my $main_vbox = Gtk::VBox->new( $false, 0 ); + $verbosity_window->add( $main_vbox ); + $main_vbox->show(); + + my $vbox = Gtk::VBox->new( $false, 10 ); + $vbox->border_width( 10 ); + $main_vbox->pack_start( $vbox, $true, $true, 0 ); + $vbox->show(); + + my $table = Gtk::Table->new( 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 = Gtk::Text->new( undef, undef ); + $text->set_editable($false); + $table->attach( $text, 0, 1, 0, 1, + [ 'expand', 'shrink', 'fill' ], + [ 'expand', 'shrink', 'fill' ], + 0, 0 ); + $text->grab_focus(); + $text->show(); + my $red = Gtk::Gdk::Color->parse_color("red"); + my $blue = Gtk::Gdk::Color->parse_color("blue"); + text_insert($text,$red,$blue); # yard thing + + # Add a vertical scrollbar to the GtkText widget + my $vscrollbar = Gtk::VScrollbar->new( $text->vadj ); + $table->attach( $vscrollbar, 1, 2, 0, 1, 'fill', + [ 'expand', 'shrink', 'fill' ], 0, 0 ); + my $logadj = $vscrollbar->get_adjustment(); + logadj($logadj); + $vscrollbar->show(); + + my $separator = Gtk::HSeparator->new(); + $main_vbox->pack_start( $separator, $false, $true, 0 ); + $separator->show(); + + $vbox = Gtk::VBox->new( $false, 10 ); + $vbox->border_width( 10 ); + $main_vbox->pack_start( $vbox, $false, $true, 0 ); + $vbox->show(); + + #my $button = Gtk::Button->new( "Close" ); + #$button->signal_connect( 'clicked', + # sub { destroy $verbosity_window; } ); + #$vbox->pack_start( $button, $true, $true, 0 ); + #$button->can_default( $true ); + #$button->grab_default(); + #$button->show(); + + show $verbosity_window; + +} # end sub verbosity_box + +sub fileselect { + + my ($widget,$ent,$name,$order,$device) = @_; + + if (not defined $file_dialog) { + # Create a new file selection widget + $file_dialog = Gtk::FileSelection->new( "$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( $device ) 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(); + if ($order != 14) { + $entry->set_text($file); + } + else { + $entry->set_text("ubd0=$file"); + } + $container[$order] = $file; + if ($order == 1) { + $ars->{kernel} = $container[$order]; + ars($ars); + } + + # auto-detect compression if system has file + if ($container[ROOT_DEVICE]) { + my $file = sys("which file > /dev/null 2>&1"); + if ($file == 0) { + open(F,"file $container[ROOT_DEVICE] |"); # no error check + # here + while () { + if (/gzip/) { + $gz_toggle->set_active( $true ); + } + elsif (/bzip2/) { + $bz2_toggle->set_active( $true ); + } + else { + info(0, "Neither gz or bz2 compression found\n"); + } + } + } + } + + destroy $file_dialog; + +} + +sub hbox { + my $homogeneous; + defined $_[0] ? ($homogeneous = 0) : ($homogeneous = 1); + $box2 = Gtk::HBox->new( $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 = Gtk::Label->new( $text ); + $label->set_justify( "fill" ); + $box2->pack_start( $label, $false, $false, 5 ); + $label->show(); + +} + +sub entry { + + my($edit,$num) = @_; + + my $entry = Gtk::Entry->new(); + $entry->set_editable( $true ); + + if ($num == 0) { + $entry->signal_connect( "activate", sub { + $container[$num] = $entry->get_text();}); + } + else { + $entry->signal_connect( "changed", sub { + $container[$num] = $entry->get_text(); + if ($num == 1) { + $ars->{kernel} = $container[$num]; + ars($ars); + } + # here's where types in entry3, types other places + if (defined $ea1 and $num == 3) { + $ea1->set_text($container[$num]); + } + if (defined $ear1 and $num == 3) { + $ear1->set_text($container[$num]); + } + + # auto-detect compression if system has file + if ($num == 2) { + my $file = sys("which file"); + if ($file == 0) { + if ($container[ROOT_DEVICE]) { + open(F,"file $container[ROOT_DEVICE] |"); # no error check here + while () { + if (/gzip/) { + $gz_toggle->set_active( $true ); + } + elsif (/bzip2/) { + $bz2_toggle->set_active( $true ); + } + else { + info(0, + "Neither gz or bz2 compression found\n"); + } + } + } + } + } + }); + } + if (defined $num and $num != 0) { + my $todo; + if ($num == 1) { + $todo = "the Kernel"; + } + elsif ($num == 2) { + $todo = "the Compressed Filesystem"; + } + else { + $todo = "the Block Device to use"; + } + $tooltips->set_tip( $entry, + "Type in the location of $todo.", "" ); + } + $box2->pack_start( $entry, $true, $true, 0 ); + $entry->show(); + + return $entry; + +} + +sub button { + + my ($text,$ent,$name,$order,$device) = @_; + + my $button = Gtk::Button->new($text); + if ($order == 1) { + $tooltips->set_tip( $button, "Select the Kernel.", "" ); + } + elsif ($order == 2) { + $tooltips->set_tip( $button, "Select the Root 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 + # Since only one filehandle is now used, this won't work + # anymore. + #unlink("$verbosefn"); + open (MTAB, "/etc/mtab") or die "no mtab!\n"; + while () { + if (m,$mnt,) { + sys("umount $mnt"); + } + } + 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[METHOD]) { + error_window("gBootRoot: ERROR: No Method supplied"); + return; +} +if (defined $container[KERNEL] && -e $container[KERNEL] && + !-d $container[KERNEL]) { + $kernel = $container[KERNEL]; + # 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[METHOD]) { + error_window("gBootRoot: ERROR: Kernel not found"); + return; +} +if (defined $container[ROOT_DEVICE] && -e $container[ROOT_DEVICE] && + !-d $container[ROOT_DEVICE] ) { + $root_image = $container[ROOT_DEVICE]; + 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[METHOD] && defined $container[KERNEL]) { + error_window("gBootRoot: ERROR: Rootimage not found"); + return; +} +# we need to check for this, too. +if (defined $container[BOOT_DEVICE] && -b $container[BOOT_DEVICE]) { + $device = $container[BOOT_DEVICE]; +} +elsif (defined $container[METHOD] && defined $container[KERNEL] + && defined $container[ROOT_DEVICE]) { + error_window("gBootRoot: ERROR: Not a valid Block Device"); + return; +} +if (defined $container[SIZE]) { + $size = $container[SIZE]; +} + +# pretty unlikely +elsif (defined $container[METHOD] && defined $container[KERNEL] && + defined $container[ROOT_DEVICE] && defined $container[BOOT_DEVICE]) { + 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[COMPRESS] = $compress; + + # 1 .. 4 - its a hash .. not too simple + !defined $lib_strip_check ? ($container[LIB_STRIP] = 1) + : ($container[LIB_STRIP] = $lib_strip_check->get_active()); + !$container[LIB_STRIP] ? ($container[LIB_STRIP] = 2) + : ($container[LIB_STRIP] = 1); + !defined $bin_strip_check ? ($container[BIN_STRIP] = 3) + : ($container[BIN_STRIP] = + $bin_strip_check->get_active()); + !$container[BIN_STRIP] ? ($container[BIN_STRIP] = 4) + : ($container[BIN_STRIP] = 3); + + if ($container[LIB_STRIP] == 1) { + $obj_count == 0 ? ($container[OBJCOPY_BOOL] = 5) + : ($container[OBJCOPY_BOOL] = 6); + } + + if (!defined $entry_advanced[0]) { + $container[ABS_DEVICE] = $device . "ea1"; + $entry_advanced[0] = $device; + } + else { + $container[ABS_DEVICE] = $entry_advanced[0] . "ea1"; + } + + # Works now .. whoosh! + if ($container[ABS_OPT_DEVICE]) { + if ($container[ABS_OPT_DEVICE] ne "") { + $container[ABS_OPT_DEVICE] = $entry_advanced[1] + if $entry_advanced[1]; + } + if (defined $entry_advanced[1] and $entry_advanced[1] eq "") { + $container[ABS_OPT_DEVICE] = ""; + } + elsif ($container[ABS_OPT_DEVICE] eq "") { + push(@original_container,$entry_advanced[1]); + } + } + else { + push(@original_container,$entry_advanced[1]) + if $entry_advanced[1]; + } + + # pretty complex and works properly even for !-e lilo.conf + if ($container[ABS_APPEND]) { + if ($container[ABS_APPEND] ne "") { + $container[ABS_APPEND] = $entry_advanced[2] + if $entry_advanced[2]; + } + if (defined $entry_advanced[2] and $entry_advanced[2] eq "") { + $container[ABS_APPEND] = ""; + } + elsif ($container[ABS_APPEND] eq "") { + push(@original_container,$entry_advanced[2]); + } + } + else { + push(@original_container,$entry_advanced[2]) + if $entry_advanced[2]; + } + + 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; + + # Got it! - how to deal with fields with no init value + if (defined $container[ABS_OPT_DEVICE] and + $container[ABS_OPT_DEVICE] eq "") { + $container[ABS_OPT_DEVICE] = $entry_advanced[1]; + } + if (!defined $container[ABS_OPT_DEVICE]) { + $container[ABS_OPT_DEVICE] = $entry_advanced[1]; + } + if (defined $container[ABS_APPEND] and + $container[ABS_APPEND] eq "") { + $container[ABS_APPEND] = $entry_advanced[2]; + } + if (!defined $container[ABS_APPEND]) { + $container[ABS_APPEND] = $entry_advanced[2]; + } + + # no sense looking at undef values + my (@temp_container2,@original_container2); + for (@temp_container) { + if ($_) { + push(@temp_container2,$_); + } + } + for (@original_container) { + if ($_) { + push(@original_container2,$_); + } + } + + @temp_container = @temp_container2; + @original_container = @original_container2; + + splice(@temp_container,1,1); + + # A test which I've had to run too often + #print "BEFORE @temp_container\nAFTER @original_container\n"; + + 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[METHOD], + $root_image, + $device, + $size, + $compress,$container[LIB_STRIP], + $container[BIN_STRIP], + $container[OBJCOPY_BOOL], + $container[ABS_DEVICE], + $container[ABS_OPT_DEVICE], + $container[ABS_APPEND] + ); + + lilo(); + } + +} # end sub submit + +sub lilo { + + # Do a little cleanup just in case + sys("rm $tmp/initrd_image.gz") if $ok == 1; + sys("umount $tmp/initrd_mnt"); + + $kernel = $container[KERNEL]; + $root_image = $container[ROOT_DEVICE]; + $device = $container[BOOT_DEVICE]; + $size = $container[SIZE]; + + 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 + info(0, "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); + + info(0, "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); + + info(0, "Making stuff for lilo\n"); + # will be 0 if mkdir fails, but 0 if cp succeeds ? + return if err(sys("mkdir $mnt/{boot,dev}")) == 2; + return if err(sys("cp -a /dev/{null,fd?,hda1} $mnt/dev")) == 2; + + # Hopefully, this works, but have never tested it + if ($device !~ m,/dev/fd\d{1}$,) { + return if err(sys("cp -a $device $mnt/dev")) == 2; + } + + # This adds that next device + ($norm_root_device) = gdkbirdaao(); + if (!-e "$mnt/dev/$norm_root_device") { + return if err(sys("cp -a /dev/$norm_root_device $mnt/dev")) == 2; + } + + # For frame buffer devices and the like. + if ($entry_advanced[1]) { + return if errcp(sys("cp -a $entry_advanced[1] $mnt/dev")) == 2; + } + + info(0, "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(sys("umount $mnt")) == 2; + info(0, "Umount device\n"); + info(0, "Remount device\n"); + pb($B,6); + return if errm(sys("mount -t ext2 $entry_advanced[0] $mnt")) == 2; + info(0, "Configuring lilo\n"); + pb($B,7); + chdir("$mnt"); #"boot_root: ERROR: Could not change directories\n"; + if ($device eq $entry_advanced[0]) { + 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"; + + info(0, "Umounting $mnt\n"); + my $um = errum(sys("umount $mnt")); + pb($B,10); + + if ($ok == 1 || $ok == 2) { + return if + errrm(sys("rmdir $tmp/initrd_mnt")) == 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"); + } + + info(0, "Copy over the compressed filesystem\n"); + return if errrm(sys("rmdir $mnt/lost+found")) == 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); + info(0, "Finished!\n"); + +} # end sub device 2 + +# Checks if lib or bin is stripped, if not proceeds to strip. Returns +# full file path and strip result. Right now this is specific to initrd. +sub stripper { + + # stripper (program,bin|lib); + if ((!defined $lib_strip_check && !defined $bin_strip_check) or + ($lib_strip_check->active || $bin_strip_check->active)) { + my $not_stripped = `file $_[0] >/dev/null 2>&1`; + my $filename = basename($_[0]); + + if ($not_stripped =~ m,not stripped,) { + if (($_[1] eq "lib" && !defined $lib_strip_check) or + ($_[1] eq "lib" && $lib_strip_check->active)) { + # --strip-all works for initrd + if ($obj_count == 0) { + sys("objcopy --strip-debug $_[0] $tmp/$filename"); + return ( "$tmp/$filename", 1 ); + } + elsif ($obj_count == 1) { + sys("objcopy --strip-all $_[0] $tmp/$filename"); + return ( "$tmp/$filename", 1 ); + } + } + elsif (($_[1] eq "bin" && !defined $bin_strip_check) or + ($_[1] eq "bin" && $bin_strip_check->active)) { + sys("objcopy --strip-all $_[0] $tmp/$filename"); + return ( "$tmp/$filename", 1 ); + } + } + else { + return ( $_[0], 0 ); + } + } + return ( $_[0], 0); + +} + +sub initrd_size { + + info(0,"Boot Method: 2 disk\n", + "Type: initrd boot disk with LILO/root filesystem disk\n"); + + my ($linuxrc_size) = @_; + my ($what,$lib); + my ($path,$value); + info(0, "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; + + # This and libs should be user accessible + # add other executables here + my @initrd_stuff = qw(ash gzip mount umount); + + foreach (@initrd_stuff) { + ($path,$value) = stripper(find_file_in_path($_),"bin"); + $initrd_size = $initrd_size + ((stat($path))[12]/2); + unlink($path) if $value == 1; + } + + if ($compress eq "bzip2" && -e find_file_in_path($compress)) { + ($path,$value) = stripper(find_file_in_path($compress),"bin"); + $initrd_size = $initrd_size + ((stat($path))[12]/2); + unlink($path) if $value == 1; + } + + # lib sizes This is going to be improved later with library_dependencies + 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; + ($path,$value) = stripper("/lib/$lib","lib"); + $initrd_size = $initrd_size + ((stat($path))[12]/2); + unlink($path) if $value == 1; + } + # no symbolic link + else { + ($path,$value) = stripper("/lib/$lib","lib"); + $initrd_size = $initrd_size + ((stat($path))[12]/2); + unlink($path) if $value == 1; + } + } + } + + $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,$path,$value,$tool); + 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"); + + info(0, "Using loop device to make initrd\n"); + info(0, "Make sure you have loop device capability in your running kernel\n"); + sys("dd if=/dev/zero of=$tmp/$initrd bs=1024 count=$size_needed"); + pb($I,2); + # no need to enter y every time .. could use -F + my $error; + open(T,"|mke2fs -m0 -i8192 $tmp/$initrd >/dev/null 2>&1") or + ($error = error("Can not make ext2 filesystem on initrd.\n")); + return "ERROR" if $error && $error eq "ERROR"; + print T "y\n"; close(T); + pb($I,3); + info(0, "Mounting initrd in $tmp/initrd_mnt\n"); + + if (!-d "$tmp/initrd_mnt") { + return if errmk(sys("mkdir $tmp/initrd_mnt")) == 2; + } + return if errm(sys("mount -o loop -t ext2 $tmp/$initrd $tmp/initrd_mnt")) + == 2; + pb($I,4); + + info(0, "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 + sys("chmod 755 $tmp/initrd_mnt/linuxrc"); + sys("rmdir $tmp/initrd_mnt/lost+found"); + pb($I,5); + + info(0, "... the dirs\n"); + return if errmk( + sys("mkdir $tmp/initrd_mnt/{bin,dev,etc,lib,mnt,proc,sbin,usr}")) == 2; + return if errmk(sys("mkdir $tmp/initrd_mnt/usr/lib")) == 2; + pb($I,6); + + return if errcp( + sys("cp -a /dev/{console,null,ram0,ram1,tty0} $tmp/initrd_mnt/dev")) == 2; + return if errcp(sys("cp -a $device $tmp/initrd_mnt/dev")) == 2; + pb($I,7); + + # This and libs should be user accessible + info(0, ".. the bins\n"); + my @initrd_stuff = qw(ash gzip mount umount); + foreach (@initrd_stuff) { + ($path,$value) = stripper(find_file_in_path($_),"bin"); + $value == 0 ? ($tool = "cp -a") : ($tool = "mv"); + if (!$path) { + info(1,"gBootRoot Error: Couldn't find $_\n"); + } + return if errcp(sys("$tool $path $tmp/initrd_mnt/bin")) == 2; + } + + if ($compress eq "bzip2" && -e find_file_in_path($compress)) { + ($path,$value) = stripper(find_file_in_path($compress),"bin"); + $value == 0 ? ($tool = "cp -a") : ($tool = "mv"); + return if errcp(sys("$tool $path $tmp/initrd_mnt/bin")) == 2; + } + + # Testing if init is sufficient for grabbing the correct libraries for the + # executables immediately above. This could be modified to test a + # list of executables. + info(0, ".. the libs\n"); + open(L,"ldd /sbin/init|") or die "Oops, no init could be found :)\n"; # safe to use ldd, this is going to be fixed later with library_dependencies + 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]; + ($path,$value) = stripper("/lib/$lib","lib"); + $value == 0 ? ($tool = "cp -a") : ($tool = "mv"); + return if errcp(sys("$tool $path $tmp/initrd_mnt/lib")) == 2; + ($path,$value) = stripper("/lib/$what","lib"); + $value == 0 ? ($tool = "cp -a") : ($tool = "mv"); + return if errcp(sys("$tool $path $tmp/initrd_mnt/lib")) == 2; + } + # no symbolic link + else { + ($path,$value) = stripper("/lib/$lib","lib"); + return if errcp(sys("cp -a $path $tmp/initrd_mnt/lib")) == 2; + } + } + } + + + info(0, "Determine run-time link bindings\n"); + # Has a return code of 0 regardless + # Also, produces false alarms even when it is working. + info(1, "Ignore warnings about missing directories\n"); + sys("ldconfig -v -r $tmp/initrd_mnt"); + info(0, "Umounting loop device, and compressing initrd\n"); + return if errum(sys("umount $tmp/initrd_mnt")) == 2; + sys("gzip -f9 $tmp/$initrd"); + pb($I,10); # This takes the longest. + + $initrd = $initrd . ".gz"; + +} # end sub initrd + +# This was submitted by Cristian "cretzu." +sub gdkbirdaao +{ + # Guess Default Kernel Boot Image Root Device And Append Options (gdbirdaao) + # + # We return a list with 3 elements: + # + # root device, kernel boot image path and append options + # + # The last list element (append options) could be returned as a list + # of options, but it probably might be cleaner if the caller splitted it. + # + # this should cover the following cases: + # + # 1. we have a 'root=...' somewhere above the 'image=...' block(s), and + # the image block may or may not have a root specified + # + # 2. there is no default label, in which case, we take the first one + # + # 3. there is a default label, and that's what we pick up + # + + my $ret_image_path = ''; + my $ret_root_dev = ''; + my $ret_append = ''; + + if (-e $lilo_conf and !-d $lilo_conf) + { + + my @lilo_lines; + open(LIL, $lilo_conf) or warn "*** $lilo_conf not found, perhaps because you are not root?"; + @lilo_lines = ; + close(LIL); + chomp(@lilo_lines); + + my $default_label = ''; + my %image_blocks; + my $image_block_name_prefix = 'ImageBlock'; + my $image_block_no = 1; + my $image_block_name = ''; + my $root_dev = ''; + + for (@lilo_lines) + { + # ignore comment lines + next if m/^\s*[#]/; + + # cleanup whitespace + s/\s*//; + s/\s*$//; + s/\s*=\s*/=/; + + # 'default=whatever' returns just a label + if (m/default=(.+)\s*/) + { + $default_label = $1; + } + # start of a new 'image=' image block or similar + elsif (m/(image|other)=(.+)\s*/) + { + $image_block_name = sprintf("%s%02d", + $image_block_name_prefix, + $image_block_no); + $image_blocks{$image_block_name}{'kernel_image_path'} = $2; + $image_blocks{$image_block_name}{'root_device'} = $root_dev; + $image_block_no += 1; + } + # image block label + elsif (m/label=(.+)\s*/) + { + $image_blocks{$image_block_name}{'block_label'} = $1; + } + # 'root=' + elsif (m#root=/dev/(.+)\s*#) + { + # inside an image block + if ($image_block_name and + defined($image_blocks{$image_block_name}{'root_device'})) + { + $image_blocks{$image_block_name}{'root_device'} = $1; + } + # loose + else + { + $root_dev = $1 if !$root_dev; + } + } + elsif (m#append=\"(.+)\"#) + { + $image_blocks{$image_block_name}{'append'} = $1; + } + else + { + # Ignore everything else + } + } + + # we'll now find the kernel image and root device + foreach $image_block_name (sort keys %image_blocks) + { + # Assume there's no specified default label; take the first + $ret_root_dev = $image_blocks{$image_block_name}{'root_device'} + if !$ret_root_dev; + $ret_image_path = $image_blocks{$image_block_name}{'kernel_image_path'} + if !$ret_image_path; + $ret_append = $image_blocks{$image_block_name}{'append'} + if !$ret_append; + + # do we have a default kernel? + if (defined $image_blocks{$image_block_name}{'block_label'}) { + if ($image_blocks{$image_block_name}{'block_label'} eq $default_label) + { + # Found the block match for the default label + $ret_root_dev = $image_blocks{$image_block_name}{'root_device'}; + $ret_image_path = $image_blocks{$image_block_name}{'kernel_image_path'}; + $ret_append = $image_blocks{$image_block_name}{'append'}; + last; + } + } + } + } + + # and some a small portion of paranoia + $ret_root_dev = 'hda1' if !$ret_root_dev; + + return ($ret_root_dev, $ret_image_path, $ret_append); + +} # end sub gdkbirdaao + +########### +# Mtab area +########### + +sub mtab_window { +# Will just use a dialog box. + my ($dialog,$error,$count,$pattern) = @_; + + if (not defined $mtab) { + $mtab = Gtk::Dialog->new(); + $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 = Gtk::Label->new($dialog); + $label->set_justify( 'left' ); + $label->set_pattern("_________") if defined $pattern; + $mtab->vbox->pack_start( $label, $true, $true, 15 ); + $label->show(); + my $button = Gtk::Button->new("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 = Gtk::Button->new("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 is 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 is 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,$entry_advanced[0],) { + # 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; + sys("mke2fs -m0 -i8192 $entry_advanced[0] $size"); + if ($? != 0) { + $dialog = "gBootRoot: ERROR: You need to insert a disk\n"; + mtab_window($dialog,$error,$count); + return; + } + return if errm(sys("mount -t ext2 $entry_advanced[0] $mnt")) == 2; + lilo_put_it_together() if $count == 0; + device2() if $count == 1; + } + +} # end sub mtab_check + +################## +# Here Doc Section +################## + +# This should be user accessible +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 $device readonly ... +mount -o ro -t ext2 $device /mnt + +echo -n Copying new root to ramdisk .. please wait ... +$compress -cd /mnt/$broot_image > /dev/ram1 +echo done. + +echo -n Unmounting $device ... +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) = @_; + $entry_advanced[2] ? $entry_advanced[2] = $entry_advanced[2] + : $entry_advanced[2] = $container[ABS_APPEND]; + +# 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 $entry_advanced[2]" +initrd = $initrd +root = $device +label = bootdisk +read-write + +# normalboot +image = kernel +append = "$entry_advanced[2]" +root = /dev/$norm_root_device +label = normalboot +read-only +LILOCONF + + return $brlilo; + +} # end sub brlilo + + +sub message { +# HEREDOC +my $message = << "MESSAGE"; + +gBootRoot $version $date GNU GPL +mailto: Jonathan Rosenbaum + +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/$norm_root_device + 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 $date GNU GPL +email contact -> Jonathan Rosenbaum +Homepage -> http://the.netpedia.net/gBootRoot.html +Submit a Bug -> http://sourceforge.net/bugs/?group_id=9513 +Development site -> http://sourceforge.net/projects/gbootroot +Help forum -> http://sourceforge.net/forum/forum.php?forum_id=29639 +Open forum -> http://sourceforge.net/forum/forum.php?forum_id=29638 +gbootroot-devel mailing list -> http://sourceforge.net/mail/?group_id=9513 + +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: + +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". + +The first row has only one choice "lilo." Clicking on the menu on the right +selects the boot 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. + +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. The +default size is 1722 which works fine with 1440 floppy drives. Click on the +appropriate radio button to choose either gzip or bzip2 compression if the +program doesn't automatically detect it. + +Advanced Section: + +"Stripping" On by default for libraries and binaries. The stripping +behavior for libraries may be changed by clicking on the right mouse button +to change from --strip-debug to --strip-all. + +"Devel Device" If the device used for development is different than the +actual boot device, use this field to indicate that device. You will have to +run lilo -v -C brlilo.conf -r "device mount point" manually at a later time +on the actual boot device. + +"Opt. Device" Add devices to the boot disk which are necessary for the +kernel to function properly. Put a space between each device. For instance, +/dev/fb0 for frame buffer devices. + +"append =" Add append options to brlilo.conf. If you are using a frame +buffer device you could add something like video=matrox:vesa:402,depth:16. + +Little things you may want to know: + +* gBootRoot requires ash for initrd. Ash is a feather weight version of Bash. + +HELP + +}