#!/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 }