diff options
Diffstat (limited to 'perl-install/fs/dmcrypt.pm')
| -rw-r--r-- | perl-install/fs/dmcrypt.pm | 216 | 
1 files changed, 216 insertions, 0 deletions
| diff --git a/perl-install/fs/dmcrypt.pm b/perl-install/fs/dmcrypt.pm new file mode 100644 index 000000000..a78a495d1 --- /dev/null +++ b/perl-install/fs/dmcrypt.pm @@ -0,0 +1,216 @@ +package fs::dmcrypt; + +use diagnostics; +use strict; + +#-###################################################################################### +#- misc imports +#-###################################################################################### +use common; +use fs::type; +use fs::get; +use run_program; + +=head1 SYNOPSYS + +Manage encrypted file systems using cryptsetup + +=head1 Functions + +=over + +=cut + +sub _crypttab() { "$::prefix/etc/crypttab" } + +=item init() + +Load kernel modules and init device mapper. + +=cut + +sub init() { +    whereis_binary('cryptsetup') or die "cryptsetup not installed"; + +    eval { modules::load('dm-crypt', list_modules::category2modules('various/crypto')) }; +    devices::init_device_mapper(); +    1; +} +my $initialized; +sub _ensure_initialized() { +    $initialized++ or init(); +} + +sub read_crypttab_ { +    my ($all_hds, $crypttab) = @_; + +    -e $crypttab or return; + +    my @raw_parts = grep { fs::type::isRawLUKS($_) } fs::get::really_all_fstab($all_hds); + +    foreach (cat_($crypttab)) { +	next if /^#/; +	my ($dm_name, $dev) = split; + +	my $raw_part = fs::get::device2part($dev, \@raw_parts) +	  or log::l("crypttab: unknown device $dev for $dm_name"), next; + +	$raw_part->{dm_name} = $dm_name; +	_get_existing_one_with_state($raw_part); +    } +} + +=item read_crypttab($all_hds) + +Read /etc/crypttab + +=cut + +sub read_crypttab { +    my ($all_hds) = @_; +    read_crypttab_($all_hds, _crypttab()); +} + +sub save_crypttab_ { +    my ($all_hds, $crypttab) = @_; + +    my @raw_parts = grep { $_->{dm_name} } fs::get::really_all_fstab($all_hds) or return; + +    my %names = map { $_->{dm_name} => fs::wild_device::from_part('', $_) } @raw_parts; + +    substInFile { +	my ($name, $_dev) = split; +	if (my $new_dev = delete $names{$name}) { +	    $_ = "$name $new_dev\n"; +	} +	if (eof) { +	    $_ .= join('', map { "$_ $names{$_}\n" } sort keys %names); +	} +    } $crypttab; +} + +=item save_crypttab($all_hds) + +Save /etc/crypttab + +=cut + +sub save_crypttab { +    my ($all_hds) = @_; +    save_crypttab_($all_hds, _crypttab()); +} + +sub format_part { +    my ($part) = @_; + +    my $tmp_key_file = "/tmp/.dmcrypt_key-$$"; +    common::with_private_tmp_file($tmp_key_file, $part->{dmcrypt_key}, sub { +	_run_or_die('--cipher=aes-xts-benbi', '--key-size=512', 'luksFormat', '--batch-mode', devices::make($part->{device}), $_[0]); +    }); +    fs::format::after_formatting($part); +} + +sub open_part { +    my ($dmcrypts, $part) = @_; + +    my $tmp_key_file = "/tmp/.dmcrypt_key-$$"; +    common::with_private_tmp_file($tmp_key_file, $part->{dmcrypt_key}, sub { +	_run_or_die('luksOpen', devices::make($part->{device}),  +				$part->{dm_name}, '--key-file', $_[0]); +    }); +    run_program::run('udevadm', 'settle'); + +    push @$dmcrypts, _get_existing_one_with_state($part); +} + + +sub _get_existing_one_with_state { +    my ($part) = @_; +    my $active_dmcrypt = _parse_dmsetup_table($part->{dm_name},  +					      run_program::get_stdout('dmsetup', 'table', $part->{dm_name})); +    _get_existing_one([$part], $active_dmcrypt); +} + +sub close_part { +    my ($dmcrypts, $part) = @_; +    my $dm_part = fs::get::device2part("mapper/$part->{dm_name}", $dmcrypts); +    _run_or_die('luksClose', devices::make($dm_part->{device})); +    $part->{dm_active} = 0; +    @$dmcrypts = grep { $_ != $dm_part } @$dmcrypts; +    # remove partition from /etc/crypttab when deleted (mga#25891) +    substInFile { +	my ($name, $_dev) = split; +	undef $_ if $name eq $part->{dm_name}; +    } _crypttab(); +} + +sub _run_or_die { +    my ($command, @para) = @_; + +    _ensure_initialized(); + +    run_program::run_or_die('cryptsetup', $command, @para); +} + +sub get_existing { +    my $fstab = \@_; +    map { _get_existing_one($fstab, $_) } active_dmcrypts(); +} + +sub _get_existing_one { +    my ($fstab, $active_dmcrypt) = @_; + +    my $p = fs::wild_device::to_subpart("/dev/mapper/$active_dmcrypt->{name}"); + +    my $part = { device => "mapper/$active_dmcrypt->{name}", size => $active_dmcrypt->{size},  +		 options => 'noatime', dmcrypt_name => $active_dmcrypt->{name}, +		 major => $p->{major}, minor => $p->{minor} }; + +    if (my $raw_part = find { fs::get::is_same_hd($active_dmcrypt, $_) } @$fstab) { +	$part->{rootDevice} = $raw_part->{device}; +	$raw_part->{dm_name} = $active_dmcrypt->{name}; +	$raw_part->{dm_active} = 1; +    } else { +	log::l("could not find the device $active_dmcrypt->{major}:$active_dmcrypt->{minor} for $part->{device}"); +    } + +    if (my $type = fs::type::type_subpart_from_magic($part)) { +	put_in_hash($part, $type); +    } +    fs::type::set_isFormatted($part, to_bool($part->{fs_type})); + +    unless (fs::type::cannotBeMountable($part)) { +	$part->{fs_type} or fs::type::set_fs_type($part, defaultFS()); +    } + +    log::l("dmcrypt: found $part->{device} type $part->{fs_type} with rootDevice $part->{rootDevice}"); + +    $part; +} + +sub active_dmcrypts() { +    grep { $_->{type} eq 'crypt' } active_dm(); +} + +sub _parse_dmsetup_table { +    my ($name, $s) = @_; + +    my @l = split(' ', $s); +    my ($major, $minor) = split(':', $l[6]); +    { name => $name, size => $l[1], type => $l[2], major => $major, minor => $minor }; +} + +sub active_dm() { +    run_program::run('udevadm', 'settle'); + +    map { +	my $name = s/(.*?):\s*// && $1; +	_parse_dmsetup_table($name, $_); +    } run_program::get_stdout('dmsetup', 'table'); +} + +=back + +=cut + +1; | 
