#!/usr/bin/perl # DrakFloppy # $Id$ # # Copyright (C) 2001-2003 MandrakeSoft # Yves Duret # Thierry Vignaud # # 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, 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 strict; use diagnostics; use lib qw(/usr/lib/libDrakX); use standalone; #- warning, standalone must be loaded very first, for 'explanations' use common; use ugtk2 qw(:helpers :create :wrappers); use detect_devices; #- languages that can't be displayed with gtk1, so we unset translations #- for them until this tool is ported to gtk2 $ENV{LANGUAGE} = "C" if $ENV{LANGUAGE} =~ /\b(ar|he|hi|ta)/; require_root_capability(); my $expert_mode = $::expert; my $list_model = Gtk2::ListStore->new((Gtk2::GType->STRING) x 2); my $list = Gtk2::TreeView->new_with_model($list_model); each_index { $list->append_column(my $col = Gtk2::TreeViewColumn->new_with_attributes($_, Gtk2::CellRendererText->new, 'text' => $::i)); $col->set_min_width((200, 50)[$::i]); # $col->set_alignment(1.0) if $::i == 1; } (N("Module name"), N("Size")); my $window = ugtk2->new('drakfloppy'); unless ($::isEmbedded) { $window->{rwindow}->signal_connect(delete_event => sub { ugtk2->exit(0) }); $window->{rwindow}->set_title(N("drakfloppy")); $window->{rwindow}->set_border_width(5); ### menus definition # the menus are not shown but they provides shiny shortcut like C-q create_factory_menu($window->{rwindow}, ( { path => N("/_File"), type => '<Branch>' }, { path => N("/File/_Quit"), accelerator => N("<control>Q"), callback => sub { ugtk2->exit(0) } }, ) ); } ######## up part # device part my $device_combo = new Gtk2::Combo(); $device_combo->entry->set_editable(0); $device_combo->set_popdown_strings(map { "/dev/" . $_->{device} } detect_devices::floppies()); # kernel part my $kernel_combo = new Gtk2::Combo(); $kernel_combo->disable_activate(); $kernel_combo->set_popdown_strings(sort grep { !/^\.\.?$/ } all("/lib/modules")); $kernel_combo->entry->set_text(chomp_(`uname -r`)); $kernel_combo->entry->signal_connect(changed => sub { change_tree($kernel_combo->entry->get_text()); $list_model->clear(); }); # Create root tree my $tree_model = Gtk2::TreeStore->new((Gtk2::GType->STRING) x 2); my $tree = Gtk2::TreeView->new_with_model($tree_model); #$tree->get_selection->set_mode('browse'); $tree->set_headers_visible(0); $tree->append_column(my $textcolumn = Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::CellRendererText->new, 'text' => 0)); #$tree->append_column(my $dummy_textcolumn = Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::CellRendererText->new, 'text' => 0)); $tree->signal_connect('row-expanded', \&expand_tree); $tree->get_selection()->signal_connect('changed' => \&selected_tree); fill_tree($kernel_combo->entry->get_text()); ### my ($output, @modules); # Create list box ########################################################## from here my $list ### main window $window->{window}->add( gtkpack_(Gtk2::VBox->new, if_($::isEmbedded, 0, new Gtk2::Label(N("boot disk creation"))), 0, gtkadd(Gtk2::Frame->new(N("General")), gtkpack__(new Gtk2::VBox(0, 0), gtkpack__(new Gtk2::HBox(1, 0), Gtk2::Label->new(N("device")), $device_combo, gtksignal_connect(Gtk2::Button->new(N("default")), clicked => sub { $device_combo->entry->set_text("/dev/fd0") }), ), gtkpack__(new Gtk2::HBox(1, 0), Gtk2::Label->new(N("kernel version")), $kernel_combo, gtksignal_connect(Gtk2::Button->new("default"), clicked => sub { $kernel_combo->entry->set_text(chomp_(`uname -r`)); $list_model->clear(); }), ), ), ), 1, gtkadd(my $expert_mod_frame = new Gtk2::Frame(N("Expert Area")), gtkpack_(gtkset_border_width(Gtk2::VBox->new(0, 5), 5), 0, gtkadd(Gtk2::Frame->new(N("mkinitrd optional arguments")), gtkpack__(Gtk2::HBox->new(0, 5), my $force_button = new Gtk2::ToggleButton(N("force")), my $raid_button = new Gtk2::ToggleButton(N("omit raid modules")), my $needed_button = new Gtk2::ToggleButton(N("if needed")), my $scsi_button = new Gtk2::ToggleButton(N("omit scsi modules")), ), ), 1, gtkadd(Gtk2::Frame->new(N("Add a module")), create_hpaned( gtkset_size_request( create_scrolled_window($tree), 200, $::isEmbedded ? 0 : 175), gtkpack_(Gtk2::VBox->new(0, 0), 1, gtkadd(Gtk2::ScrolledWindow->new, $list ), 0, gtksignal_connect(Gtk2::Button->new(N("Remove a module")), clicked => sub { my $iter = ($list->get_selection->get_selected)[1]; return unless $iter; $list_model->remove($iter); }), ), ), ), ), ), 1, gtkadd(Gtk2::Frame->new(N("Output")), gtkpack_(gtkset_size_request( gtkset_border_width( Gtk2::HBox->new(0, 0), 5), 30, 75), 1, $output = new Gtk2::Text(undef, undef), 0, Gtk2::VScrollbar->new($output->vadj), ), ), 0, gtkpack__(new Gtk2::HBox(0, 0), gtksignal_connect(Gtk2::Button->new(N("Cancel")), clicked => sub { ugtk2->exit(0) } ), gtksignal_connect(Gtk2::Button->new(N("Build the disk")), clicked => \&build_it ), gtksignal_connect(my $expert_button = Gtk2::Button->new(""), clicked => sub { $expert_mode = !$expert_mode; toggle_expert_button(); }), ), ), ); $window->{rwindow}->show_all(); toggle_expert_button(); $window->main; ugtk2->exit(0); sub toggle_expert_button { if ($expert_mode) { $expert_mod_frame->show(); $expert_button->child->set(N("Normal Mode")); } else { $expert_mod_frame->hide(); $expert_button->child->set(N("Expert Mode")); } } #------------------------------------------------------------- # tree functions #------------------------------------------------------------- ### Subroutines sub fill_tree { my ($root_dir) = @_; $root_dir = "/lib/modules/" . $root_dir; # Create root tree item widget my $parent_iter = $tree_model->append_set(undef, [ 0 => $root_dir, 1 => $root_dir ]); # Create the subtree expand_tree($tree, $parent_iter, $tree_model->get_path($parent_iter)) if has_sub_trees($root_dir); } sub change_tree { $tree_model->clear; fill_tree(@_); } # Called whenever an item is clicked on the tree widget. sub selected_tree { my ($select) = @_; my ($model, $iter) = $select->get_selected(); return unless $model; # no real selection my $file = $model->get($iter, 1); $iter->free; return if -d $file; my $size = (lstat($file))[7]; return if member($file, @modules); push @modules, $file; $file =~ s|/lib/modules/.*?/||g; $list_model->append_set([ 0 => $file, 1 => $size ])->free; } # Callback for expanding a tree - find subdirectories, files and add them to tree sub expand_tree { my ($tree, $parent_iter, $path) = @_; my $dir = $tree_model->get($parent_iter, 1); my $child = $tree_model->iter_children($parent_iter); #- hackish: if first child has '' as name, then we need to expand on the fly if ($child && $tree_model->get($child, 0) eq '') { $tree_model->remove($child); } unless ($child && $tree_model->iter_has_child($parent_iter)) { foreach my $dir_entry (all($dir)) { my $entry_path = $dir . "/" . $dir_entry; if (-d $entry_path || $dir_entry =~ /\.o(\.gz)?$/) { $entry_path =~ s|//|/|g; my $iter = $tree_model->append_set($parent_iter, [ 0 => $dir_entry, 1 => $entry_path ]); #- hackery for partial displaying of trees, used in rpmdrake: #- if leaf is void, we may create the parent and one child (to have the [+] in front of the parent in the ctree) #- though we use '' as the label of the child; then rpmdrake will connect on tree_expand, and whenever #- the first child has '' as the label, it will remove the child and add all the "right" children $tree_model->append_set($iter, [ 0 => '' ])->free if has_sub_trees($entry_path); } } } $tree->expand_row($path, 0); } #------------------------------------------------------------- # the function #------------------------------------------------------------- sub build_it { my $y; my $co = "/sbin/mkbootdisk --noprompt --verbose --device " . $device_combo->entry->get_text(); if ($expert_mode) { $co .= " --mkinitrdargs -f" if $force_button->get_active; $co .= " --mkinitrdargs --ifneeded" if $needed_button->get_active; $co .= " --mkinitrdargs --omit-scsi-modules" if $scsi_button->get_active; $co .= " --mkinitrdargs --omit-raid-modules" if $raid_button->get_active; my $val; $list_model->foreach(sub { my ($model, $_path, $iter) = @_; my $module = $model->get($iter, 0); $module =~ s|.*?/||g; $co .= " --mkinitrdargs --with=" . $y; #. "/usr/lib/" . $kernel_combo->entry->get_text() . "/" . $y; return 0; }, $val); } $co .= " " . $kernel_combo->entry->get_text(); $co .= " 2>&1 |"; create_dialog(N("Be sure a media is present for the device %s", $device_combo->entry->get_text()), 1) or return; # we test if the media is present test: my $a = "dd count=1 if=/dev/null of=" . $device_combo->entry->get_text() . " 2>&1"; my $b = `$a`; if ($b =~ /dd/) { create_dialog(N("There is no medium or it is write-protected for device %s.\nPlease insert one.", $device_combo->entry->get_text()), 1) ? goto test : return 0; } local *STATUS; open STATUS, $co or do { create_dialog(N("Unable to fork: %s", $!), 0); return }; local $_; while (<STATUS>) { $output->insert(undef, undef, undef, $_); } close STATUS or create_dialog(N("Unable to properly close mkbootdisk: \n %s \n %s", $!, $?), 0); return (0); } #### # This is put at the end of the file because any translatable string # appearing after this will not be found by xgettext, and so wont end in # the pot file... #### # Test whether a directory has subdirectories sub has_sub_trees { my ($dir) = @_; foreach my $file (glob_("$dir/*")) { return 1 if -d $file or $file =~ /\.o(\.gz)?$/; } return 0; }