summaryrefslogtreecommitdiffstats
path: root/modules.d/99img-lib/img-lib.sh
blob: efc647515bf55f11cdbc75c23e920323097605b0 (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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#!/bin/sh
# img-lib.sh: utilities for dealing with archives and filesystem images.
#
# TODO: identify/unpack rpm, deb, maybe others?

# super-simple "file" that only identifies archives.
# works with stdin if $1 is not set.
det_archive() {
    # NOTE: internal echo -e works in ash and bash, but not dash
    local bz xz gz zs
    local headerblock
    bz="BZh"
    # shellcheck disable=SC3037
    xz="$(/bin/echo -e '\xfd7zXZ')"
    # shellcheck disable=SC3037
    gz="$(/bin/echo -e '\x1f\x8b')"
    # shellcheck disable=SC3037
    zs="$(/bin/echo -e '\x28\xB5\x2F\xFD')"
    headerblock="$(dd ${1:+if=$1} bs=262 count=1 2> /dev/null | tr -d '\0')"
    case "$headerblock" in
        $xz*) echo "xz" ;;
        $gz*) echo "gzip" ;;
        $bz*) echo "bzip2" ;;
        $zs*) echo "zstd" ;;
        07070*) echo "cpio" ;;
        *ustar) echo "tar" ;;
    esac
}

# determine filesystem type for a filesystem image
det_fs_img() {
    local dev
    dev=$(losetup --find --show "$1") rv=""
    det_fs "$dev"
    rv=$?
    losetup -d "$dev"
    return $rv
}

# unpack_archive ARCHIVE OUTDIR
# unpack a (possibly compressed) cpio/tar archive
unpack_archive() {
    local img="$1" outdir="$2" archiver="" decompr=""
    local ft
    ft="$(det_archive "$img")"
    case "$ft" in
        xz | gzip | bzip2 | zstd) decompr="$ft -dc" ;;
        cpio | tar) decompr="cat" ;;
        *) return 1 ;;
    esac
    ft="$($decompr "$img" | det_archive)"
    case "$ft" in
        cpio) archiver="cpio -iumd" ;;
        tar) archiver="tar -xf -" ;;
        *) return 2 ;;
    esac
    mkdir -p "$outdir"
    (
        cd "$outdir" || exit
        $decompr | $archiver 2> /dev/null
    ) < "$img"
}

# unpack_fs FSIMAGE OUTDIR
# unpack a filesystem image
unpack_fs() {
    local img="$1" outdir="$2"
    local mnt
    mnt="$(mkuniqdir /tmp unpack_fs.)"
    mount -o loop "$img" "$mnt" || {
        rmdir "$mnt"
        return 1
    }
    mkdir -p "$outdir"
    outdir="$(
        cd "$outdir" || exit
        pwd
    )"
    copytree "$mnt" "$outdir"
    umount "$mnt"
    rmdir "$mnt"
}

# unpack an image file - compressed/uncompressed cpio/tar, filesystem, whatever
# unpack_img IMAGEFILE OUTDIR
unpack_img() {
    local img="$1" outdir="$2"
    [ -r "$img" ] || {
        warn "can't read img!"
        return 1
    }
    [ -n "$outdir" ] || {
        warn "unpack_img: no output dir given"
        return 1
    }

    if [ "$(det_archive "$img")" ]; then
        unpack_archive "$@" || {
            warn "can't unpack archive file!"
            return 1
        }
    else
        unpack_fs "$@" || {
            warn "can't unpack filesystem image!"
            return 1
        }
    fi
}

# parameter: <size of live image> in MiB
# Call emergency shell if ram size is too small for the image.
# Increase /run tmpfs size, if needed.
check_live_ram() {
    local minmem imgsize memsize runsize runavail
    minmem=$(getarg rd.minmem)
    imgsize=$1
    memsize=$(($(check_meminfo MemTotal:) >> 10))
    # shellcheck disable=SC2046
    set -- $(findmnt -bnro SIZE,AVAIL /run)
    # bytes to MiB
    runsize=$(($1 >> 20))
    runavail=$(($2 >> 20))

    [ "$imgsize" ] || {
        warn "Image size could not be determined"
        return 0
    }

    if [ $((memsize - imgsize)) -lt "${minmem:=1024}" ]; then
        sed -i "N;/and attach it to a bug report./s/echo$/echo\n\
         echo \n\
         echo 'Warning!!!'\n\
         echo 'The memory size of your system is too small for this live image.'\n\
         echo 'Expect killed processes due to out of memory conditions.'\n\
         echo \n/" /usr/bin/dracut-emergency

        emergency_shell
    elif [ $((runavail - imgsize)) -lt "$minmem" ]; then
        # Increase /run tmpfs size, if needed.
        mount -o remount,size=$((runsize - runavail + imgsize + minmem))M /run
    fi
}