File: formatting

package info (click to toggle)
debootstick 2.8
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 296 kB
  • sloc: sh: 1,364; makefile: 34
file content (279 lines) | stat: -rw-r--r-- 7,470 bytes parent folder | download
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# vim: filetype=sh

# partitioning and formatting
# ---------------------------

# Selection of ext4 features:
# We must select only features available on the *oldest* system
# version we want to support. We can get these features by
# creating a sample filesystem on such a system:

# $ cd /tmp
# $ dd of=test.ext4 bs=1G count=0 seek=100
# $ mkfs.ext4 -F -q -L ROOT -T big -m 2 test.ext4
# $ dumpe2fs test.ext4 | grep features

# Note about the '-T big' option:
# We try to create a USB stick as small as possible.
# However, the embedded system may later by copied on a
# potentially large disk.
# As a result, we should select appropriate ext4 features even if
# the filesystem might be considered 'small' at first.
# This may seem cosmetic but it's not: if initialized with
# '-T small' (or with no -T option and run on a small disk),
# when we move to a large disk, resize2fs apparently
# enables the 'meta_bg' option (supposedly trying to adapt as much
# as possible this 'small' filesystem to a much larger device).
# Since this option is not handled by grub, it prevents the
# system from booting properly.

EXT4_FEATURES=$(cat << EOF
has_journal ext_attr resize_inode dir_index filetype extent
flex_bg sparse_super large_file huge_file uninit_bg dir_nlink
extra_isize
EOF
)

format_fat()
{
    label="$1"
    device="$2"
    label_option=""
    if [ ! -z "$label" ]
    then
        label_option="-n $label"
    fi
    quiet mkfs.vfat $label_option "$device"
}

format_ext4()
{
    label="$1"
    device="$2"
    label_option=""
    if [ ! -z "$label" ]
    then
        label_option="-L $label"
    fi
    features="$(echo $EXT4_FEATURES | tr ' ' ',')"
    mkfs.ext4 -F -q $label_option -b 4096 -O "none,$features" -m 2 "$device"
}

get_loop_device_partitions()
{
    loop_device="$1"
    partx -o NR -g "$loop_device" | while read num
    do
        echo "${loop_device}p$num"
    done
}

partition_image()
{
    image_path="$1"
    layout_dir="$2"

    {
        part_table_type=$(cat "$layout_dir"/part_table_type)
        echo "label: $part_table_type"
        echo
        for vol in $(ls -1d "$layout_dir"/partitions/* | sort -n)
        do
            vol_id="$(basename $vol)"
            applied_size_mb=$(cat $vol/applied_size_mb)
            fdisk_type=$(cat $vol/fdisk_type)
            partdef="type=$fdisk_type"
            if [ $applied_size_mb -gt 0 ]
            then
                partdef="size=${applied_size_mb}MiB,$partdef"
            fi
            echo $partdef
        done
    } | sfdisk --no-tell-kernel "$image_path" >/dev/null
}

save_vol_uuid()
{
    vol_dir="$1"
    blkid -s UUID -o value $vol_dir/device > $vol_dir/uuid
}

format_volume()
{
    lvm_vg="$1"
    vol_dir="$2"
    vol_subtype=$(cat "$vol_dir/subtype")

    label=""
    if [ -f "$vol_dir/label" ]
    then
        label="$(cat "$vol_dir/label")"
    fi

    case $vol_subtype in
        efi|fat)
            format_fat "$label" $vol_dir/device
            echo vfat > $vol_dir/mounttype
            save_vol_uuid $vol_dir
            ;;
        ext4)
            format_ext4 "$label" $vol_dir/device
            echo ext4 > $vol_dir/mounttype
            save_vol_uuid $vol_dir
            ;;
        lvm)
            # this is our LVM PV partition
            quiet pvcreate $(readlink -f "$vol_dir/device")

            # we have to set the physical extent size to 1M otherwise
            # default value may be above (4M) and cause issues with
            # our volume size calculations
            quiet vgcreate -s 1M $lvm_vg $(readlink -f "$vol_dir/device")
            ;;
    esac
}

create_lvm_volume()
{
    lvm_vg="$1"
    vol_dir="$2"

    label=$(cat "$vol_dir/label")
    applied_size_mb=$(cat "$vol_dir/applied_size_mb")

    if [ "$applied_size_mb" -eq "0" ]
    then
        quiet lvcreate -n "$label" -l 100%FREE "$lvm_vg"
    else
        quiet lvcreate -n "$label" -L ${applied_size_mb}M "$lvm_vg"
    fi
    ln -sf "/dev/$lvm_vg/$label" "$vol_dir/device"
}

format_volumes()
{
    work_dir="$1"
    layout_dir="$2"
    lvm_vg="$3"
    device="$(readlink $work_dir/device)"

    # retrieve the partition devices
    partition_devices="$(get_loop_device_partitions $device)"

    # format partitions
    i=1
    for part_device in $(echo "$partition_devices")
    do
        wait_for_device $part_device
        part_vol="$layout_dir/partitions/$i"
        ln -sf "$part_device" "$part_vol/device"
        format_volume $lvm_vg $part_vol
        i=$((i+1))
    done

    # create and format lvm volumes
    for lvm_vol_id in $(ls -1 "$layout_dir"/lvm_volumes/ | sort -n)
    do
        lvm_vol="$layout_dir"/lvm_volumes/$lvm_vol_id
        create_lvm_volume $lvm_vg $lvm_vol
        format_volume $lvm_vg $lvm_vol
    done
}

generate_mount_info()
{
    layout_dir="$1"
    for vol_dir in $(ls -d "$layout_dir"/*/*)
    do
        echo "$(cat $vol_dir/mountpoint) $vol_dir"
    done | sort -k 1,1 | while read vol_mountpoint vol_dir
    do
        if [ "$vol_mountpoint" = 'none' ]
        then
            continue
        fi
        echo "$vol_dir" "$(cat $vol_dir/mounttype)" "$(cat $vol_dir/uuid)" "$vol_mountpoint"
    done
}

mount_volumes()
{
    work_dir="$1"
    layout_dir="$2"
    fs_dir="$1/fs"

    generate_mount_info "$layout_dir" | while read vol_dir mounttype uuid vol_mountpoint
    do
        if [ "$vol_mountpoint" = "/" ]
        then
            fs_mountpoint="$fs_dir"
        else
            fs_mountpoint="$fs_dir$vol_mountpoint"
        fi
        mkdir -p "$fs_mountpoint"
        failsafe mount $vol_dir/device "$fs_mountpoint"
        echo "undo mount $vol_dir/device \"$fs_mountpoint\"" >> $work_dir/release_info
        # if this is the rootfs volume, save a pointer to it
        if [ "$vol_mountpoint" = "/" ]
        then
            ln -s $vol_dir $work_dir/rootfs_vol
        fi
    done
}

create_formatted_image()
{
    image_name=$1   # 'draft' or 'final'
    sector_size=$2
    target_fs="$3"
    stick_os_id=$4
    image_file="$5"
    work_dir="$DBSTCK_TMPDIR/$image_name"
    layout_dir="$DBSTCK_TMPDIR/.layout"
    if [ -z "$image_file" ]
    then
        image_file="$work_dir/file"
    fi

    mkdir -p "$work_dir"

    # compute vg name for future use
    lvm_vg=$(get_vg_name $image_name $stick_os_id)
    echo $lvm_vg > "$work_dir/vg_name"

    # compute size of partitions and lvm volumes
    compute_applied_sizes $image_name $layout_dir "$target_fs"

    # create image file
    rm -f "$image_file"
    stick_size_mb=$(cat $layout_dir/needed_size_mb)
    $DD bs=$((1024*1024)) seek=$stick_size_mb count=0 of="$image_file"

    # create loop device
    image_device=$(losetup -f)
    failsafe_losetup --sector-size $sector_size $image_device "$image_file"
    echo undo losetup --sector-size $sector_size $image_device "$image_file" \
                 >> $work_dir/release_info

    # create partitions
    partition_image "$image_device" "$layout_dir"

    ln -sf "$image_device" "$work_dir/device"
    # let the kernel know about partitions of this device
    failsafe partx -a $image_device
    echo "undo partx -a $image_device" >> $work_dir/release_info

    # format partitions and lvm volumes, then mount them
    format_volumes "$work_dir" "$layout_dir" "$lvm_vg"
    mount_volumes "$work_dir" "$layout_dir"
}

release_image()
{
    image_name="$1"     # 'draft' or 'final'
    work_dir="$DBSTCK_TMPDIR/$image_name"

    eval "$(tac $work_dir/release_info)"
    rm $work_dir/file
}