summaryrefslogtreecommitdiffstats
path: root/lib/MGA/DrakISO/BuildLoop.pm
blob: e325d095ebd32736ada687dfc16d70c73a55231d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# Copyright (C) 2005 Mandriva
#                    Olivier Blin <oblin@mandriva.com>
# Copyright (C) 2017-2018 Mageia
#                    Martin Whitaker <mageia@martin-whitaker.me.uk>
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA.

# SYNOPSIS
# --------
# This package provides a function to build the compressed images that will
# be mounted as loopback filesystems when booting a Live system.

package MGA::DrakISO::BuildLoop;

use strict;

use MDK::Common;

use File::Temp qw(tmpnam);

use MGA::DrakISO::LiveBuild;
use MGA::DrakISO::Loopback;
use MGA::DrakISO::Utils;

use Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(build_live_loopback_files list_loopback_modules);

# This is the top-level function called to build the loopback images. The Live
# root filesystem must have been prepared before calling this function.
#
sub build_live_loopback_files {
    my ($build) = @_;

    my $root = $build->get_live_root;

    # make sure no external filesystems are mounted before creating the loopback
    umount_all_in_root($root);

    my @excluded_files = expand_file_list($build, @{$build->{loopbacks}{exclude}{files} || []});
    my @modules_files = expand_file_list($build, @{$build->{loopbacks}{modules} || []});

    foreach (grep { exists $loop_types{$_->{type}}{build} } @{$build->{mount}{dirs} || []}) {
        local $_->{exclude} = [ @excluded_files, @modules_files ];
        $loop_types{$_->{type}}{build}->($build, $_);
    }

    foreach my $module (list_loopback_modules($build)) {
        my $copy_tree = $root . "/tmp/draklive/loop/$module->{name}";
        run_as_root('rm', '-rf', $copy_tree);
        hardlink_filtered($root, $copy_tree, $module->{files});
        my $loop = $loop_types{$module->{type}};
        $loop->{build}->($build, { path => "/modules/$module->{name}", root => $copy_tree, exclude => \@excluded_files });
        run_as_root('rm', '-rf', $copy_tree);
    }

    if (@excluded_files) {
        my $excluded_tree = $root . "/tmp/draklive/excluded/all";
        eval { rm_rf($excluded_tree) };
        hardlink_filtered($root, $excluded_tree, \@excluded_files);

        foreach my $module (list_loopback_modules($build)) {
            my $copy_tree = $root . "/tmp/draklive/excluded/$module->{name}";
            run_as_root('rm', '-rf', $copy_tree);
            hardlink_filtered($excluded_tree, $copy_tree, $module->{files});
            my $loop = $loop_types{$module->{type}};
            $loop->{build}->($build, { path => "/modules/excluded-$module->{name}", root => $copy_tree });
            run_as_root('rm', '-rf', $copy_tree);
        }

        my $loop = $loop_types{$build->{loopbacks}{exclude}{type}};
        $loop->{build}->($build, { path => "/excluded", root => $excluded_tree, exclude => \@modules_files });

        run_as_root('rm', '-rf', $excluded_tree);
    }
}

sub expand_file_list {
    my ($build, @files) = @_;
    map {
        $_->{path} ?
          $_->{path} :
          chomp_(cat_(glob(($_->{rooted} && $build->get_live_root) . $_->{source})));
    } @files;
}

#- hardlink recursively file list to a directory
sub hardlink_filtered {
    my ($src, $dest, $files) = @_;
    mkdir_p($dest);
    my $list_file = tmpnam();
    output_p($list_file, map { "$_\n" } grep { -e $src . $_ } @$files);
    #- cpio -pldm won't copy recursively, use rsync -r instead
    run_as_root('rsync', '-ar', '--files-from=' . $list_file, '--link-dest=' . $src, $src, $dest);
    unlink $list_file;
}

sub list_loopback_modules {
    my ($build) = @_;
    map {
        my $l = $_;
        map {
            my $list = $_;
            my $name = basename($list);
            $name =~ s/\.[^.]+$//;
            { type => $l->{type}, name => $name, files => [ expand_file_list($build, { source => $list }) ] };
        } glob(($_->{rooted} && $build->get_live_root) . $_->{source});
    } @{$build->{loopbacks}{modules}};
}

1;