package fs::format; # $Id$ use diagnostics; use strict; use run_program; use common; use fs::type; use fs::loopback; use log; my %cmds = ( ext2 => [ 'e2fsprogs', 'mke2fs', '-F' ], ext3 => [ 'e2fsprogs', 'mke2fs', '-F', '-j' ], reiserfs => [ 'reiserfsprogs', 'mkreiserfs', '-ff' ], xfs => [ 'xfsprogs', 'mkfs.xfs', '-f', '-q' ], jfs => [ 'jfsprogs', 'mkfs.jfs', '-f' ], hfs => [ 'hfsutils', 'hformat' ], dos => [ 'dosfstools', 'mkdosfs' ], vfat => [ 'dosfstools', 'mkdosfs', '-F', '32' ], swap => [ 'util-linux', 'mkswap' ], ); sub package_needed_for_partition_type { my ($part) = @_; my $l = $cmds{$part->{fs_type}} or return; $l->[0]; } sub known_type { my ($part) = @_; to_bool($cmds{$part->{fs_type}}); } sub check_package_is_installed { my ($do_pkgs, $fs_type) = @_; my ($pkg, $binary) = @{$cmds{$fs_type} || return}; $do_pkgs->ensure_binary_is_installed($pkg, $binary); } sub part { my ($raids, $part, $prefix, $wait_message) = @_; if (isRAID($part)) { $wait_message->(N("Formatting partition %s", $part->{device})) if $wait_message; require raid; raid::format_part($raids, $part); } elsif (isLoopback($part)) { $wait_message->(N("Creating and formatting file %s", $part->{loopback_file})) if $wait_message; fs::loopback::format_part($part, $prefix); } else { $wait_message->(N("Formatting partition %s", $part->{device})) if $wait_message; part_raw($part, $wait_message); } } sub part_raw { my ($part, $wait_message) = @_; $part->{isFormatted} and return; if ($part->{encrypt_key}) { require fs; fs::set_loop($part); } my $dev = $part->{real_device} || $part->{device}; my @options = if_($part->{toFormatCheck}, "-c"); log::l("formatting device $dev (type $part->{fs_type})"); my $fs_type = $part->{fs_type}; if ($fs_type eq 'ext2' || $fs_type eq 'ext3') { push @options, "-m", "0" if $part->{mntpoint} =~ m|^/home|; } elsif (isDos($part)) { $fs_type = 'dos'; } elsif ($fs_type eq 'hfs') { push @options, '-l', "Untitled"; } elsif (isAppleBootstrap($part)) { push @options, '-l', 'bootstrap'; } my ($_pkg, $cmd, @first_options) = @{$cmds{$fs_type} || die N("I do not know how to format %s in type %s", $part->{device}, $part->{fs_type})}; my @args = ($cmd, @first_options, @options, devices::make($dev)); if ($cmd eq 'mke2fs' && $wait_message) { mke2fs($wait_message, @args) or die N("%s formatting of %s failed", $fs_type, $dev); } else { run_program::raw({ timeout => 60 * 60 }, @args) or die N("%s formatting of %s failed", $fs_type, $dev); } if ($fs_type eq 'ext3') { disable_forced_fsck($dev); } if ($part->{device_LABEL}) { if (member($fs_type, qw(ext2 ext3))) { run_program::run("tune2fs", "-L", $part->{device_LABEL}, devices::make($dev)); } else { log::l("dropping LABEL=$part->{device_LABEL} since we don't know how to set labels for fs_type $part->{fs_type}"); delete $part->{device_LABEL}; delete $part->{prefer_device_LABEL}; } } set_isFormatted($part, 1); } sub mke2fs { my ($wait_message, @args) = @_; open(my $F, "@args |"); local $/ = "\b"; local $_; while (<$F>) { #- even if it still takes some time when format is over, we don't want the progress bar to stay at 85% $wait_message->('', $1, $2) if m!^\s*(\d+)/(\d+)\b!; } return close($F); } sub disable_forced_fsck { my ($dev) = @_; run_program::run("tune2fs", "-c0", "-i0", devices::make($dev)); } sub wait_message { my ($in) = @_; my ($w, $progress, $last_msg, $displayed); my $on_expose = sub { $displayed = 1; 0 }; #- declared here to workaround perl limitation $w, sub { my ($msg, $current, $total) = @_; if ($msg) { $last_msg = $msg; if (!$w) { $progress = Gtk2::ProgressBar->new if $in->isa('interactive::gtk'); $w = $in->wait_message('', [ '', if_($progress, $progress) ]); if ($progress) { #- don't show by default, only if we are given progress information $progress->hide; $progress->signal_connect(expose_event => $on_expose); } } $w->set($msg); } elsif ($total) { if ($progress) { $progress->set_fraction($current / $total); $progress->show; $displayed = 0; mygtk2::flush() while !$displayed; } else { $w->set([ $last_msg, "$current / $total" ]); } } }; } 1;