timaging - libdevuansdk - common library for devuan's simple distro kits
 (HTM) git clone https://git.parazyd.org/libdevuansdk
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
 (DIR) README
 (DIR) LICENSE
       ---
       timaging (8971B)
       ---
            1 #!/usr/bin/env zsh
            2 # shellcheck shell=bash
            3 # Copyright (c) 2016-2021 Ivan J. <parazyd@dyne.org>
            4 # This file is part of libdevuansdk
            5 #
            6 # This source code is free software: you can redistribute it and/or modify
            7 # it under the terms of the GNU General Public License as published by
            8 # the Free Software Foundation, either version 3 of the License, or
            9 # (at your option) any later version.
           10 #
           11 # This software is distributed in the hope that it will be useful,
           12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
           13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
           14 # GNU General Public License for more details.
           15 #
           16 # You should have received a copy of the GNU General Public License
           17 # along with this source code. If not, see <http://www.gnu.org/licenses/>.
           18 
           19 vars+=(bootpart rootpart loopdevice)
           20 
           21 strapdir_to_image()
           22 {
           23         fn strapdir_to_image
           24         req=(workdir strapdir)
           25         ckreq || return 1
           26 
           27         notice "Copying strapdir to image ..."
           28 
           29         if [[ ! -d "$workdir/mnt" ]]; then
           30                 die "$workdir/mnt doesn't exist. Did you run image_mount?"
           31                 zerr; return 1
           32         fi
           33 
           34         pushd "$strapdir"
           35         sudo find . \
           36                 -not -path "./dev/*" \
           37                 -a -not -path "./proc/*" \
           38                 -a -not -path "./sys/*" \
           39                 | sudo cpio --quiet -adm -p "$workdir/mnt" || { zerr; return 1; }
           40         popd
           41 }
           42 
           43 image_prepare_raw()
           44 {
           45         fn image_prepare_raw
           46         req=(workdir size image_name)
           47         ckreq || return 1
           48 
           49         notice "Creating raw image of $size MB"
           50         touch "$workdir/${image_name}.img"
           51         chattr -f +C "$workdir/${image_name}.img"
           52         dd if=/dev/zero of="$workdir/${image_name}.img" bs=1M count="$size" || { zerr; return 1; }
           53 }
           54 
           55 image_prepare_qcow2()
           56 {
           57         fn image_prepare_qcow2
           58         req=(workdir size image_name)
           59         ckreq || return 1
           60 
           61         notice "Creating qcow2 image of $size MB"
           62         touch "$workdir/${image_name}.qcow2"
           63         chattr -f +C "$workdir/${image_name}.qcow2"
           64         qemu-img create -f qcow2 "${workdir}/${image_name}.qcow2" "${size}M" || { zerr; return 1; }
           65 }
           66 
           67 image_format_partitions()
           68 {
           69         fn image_format_partitions
           70         req=(bootfs bootpart rootpart)
           71         ckreq || return 1
           72 
           73         notice "Formatting image partitions"
           74 
           75         case "$bootfs" in
           76         none)
           77                 act "Skipping boot partition"
           78                 ;;
           79         vfat|fat|dos)
           80                 act "Formatting boot as VFAT"
           81                 sudo mkfs.vfat ${=bootopts} "${bootpart}" >>/dev/null || { zerr; return 1; }
           82                 ;;
           83         ext?)
           84                 act "Formatting boot as $bootfs"
           85                 sudo mkfs.${bootfs} ${=bootopts} "${bootpart}" || { zerr; return 1; }
           86                 ;;
           87         btrfs)
           88                 act "Formatting boot as btrfs"
           89                 sudo mkfs.btrfs ${=bootopts} "${bootpart}" || { zerr; return 1; }
           90                 ;;
           91         f2fs)
           92                 act "Formatting boot as f2fs"
           93                 sudo mkfs.f2fs ${=bootopts} "${bootpart}" || { zerr; return 1; }
           94                 ;;
           95         "")
           96                 die "No bootfs filesystem set!"
           97                 zerr; return 1
           98                 ;;
           99         *)
          100                 die "Unimplemented filesystem: $bootfs"
          101                 die "Please report it for inclusion."
          102                 zerr; return 1
          103                 ;;
          104         esac
          105 
          106         case "$rootfs" in
          107         none)
          108                 act "Skipping root partition"
          109                 ;;
          110         vfat|fat|dos)
          111                 act "Formatting root as VFAT"
          112                 sudo mkfs.vfat ${=rootopts} "${rootpart}" >>/dev/null || { zerr; return 1; }
          113                 ;;
          114         ext?)
          115                 act "Formatting root as $rootfs"
          116                 sudo mkfs.${rootfs} ${=rootopts} "${rootpart}" || { zerr; return 1; }
          117                 ;;
          118         btrfs)
          119                 act "Formatting root as btrfs"
          120                 sudo mkfs.btrfs ${=rootopts} "${rootpart}" || { zerr; return 1; }
          121                 ;;
          122         f2fs)
          123                 act "Formatting root as f2fs"
          124                 sudo mkfs.f2fs ${=rootopts} "${rootpart}" || { zerr; return 1; }
          125                 ;;
          126         "")
          127                 die "No rootfs filesystem set!"
          128                 zerr; return 1
          129                 ;;
          130         *)
          131                 die "Unimplemented filesystem: $rootfs"
          132                 die "Please report it for inclusion."
          133                 zerr; return 1
          134                 ;;
          135         esac
          136 }
          137 
          138 image_connect_raw()
          139 {
          140         fn image_connect_raw
          141 
          142         notice "Connecting raw image to loop device"
          143 
          144         loopdevice="$(findloopdev)"
          145         if [[ -z "$loopdevice" ]]; then
          146                 die "Didn't find a free loop device"
          147                 zerr; return 1
          148         fi
          149 
          150         bootpart="${loopdevice}p1"
          151         rootpart="${loopdevice}p2"
          152 }
          153 
          154 image_connect_qcow2()
          155 {
          156         fn image_connect_qcow2
          157         req=(workdir image_name)
          158         ckreq || return 1
          159 
          160         notice "Connecting qcow2 image to nbd device"
          161 
          162         sudo modprobe nbd max_part=8 || { zerr; return 1; }
          163         loopdevice="$(findnbddev)"
          164         if [[ -z "$loopdevice" ]]; then
          165                 die "Didn't find a free nbd device"
          166                 zerr; return 1
          167         fi
          168 
          169         sudo qemu-nbd --connect="${loopdevice}" "$workdir/${image_name}.qcow2" || { zerr; return 1; }
          170 }
          171 
          172 image_partition_dos()
          173 {
          174         fn image_partition_dos
          175         req=(loopdevice dos_boot dos_root)
          176         ckreq || return 1
          177 
          178         notice "Partitioning dos image"
          179 
          180         sudo parted "$loopdevice" --script -- mklabel msdos || { zerr; return 1; }
          181         sudo parted "$loopdevice" --script -- mkpart primary "$dos_boot" || { zerr; return 1; }
          182         sudo parted "$loopdevice" --script -- mkpart primary "$dos_root" || { zerr; return 1; }
          183         if [[ -n "$bootable_part" ]]; then
          184                 sudo parted "$loopdevice" --script -- set "$bootable_part" boot on
          185         fi
          186 
          187         sudo partprobe "$loopdevice" || { zerr; return 1; }
          188 }
          189 
          190 image_partition_gpt()
          191 {
          192         fn image_partition_gpt
          193         req=(loopdevice bootpart rootpart gpt_boot gpt_root)
          194         ckreq || return 1
          195 
          196         notice "Partitioning gpt image"
          197 
          198         sudo parted "$loopdevice" --script -- mklabel gpt || { zerr; return 1; }
          199         sudo cgpt create -z "$loopdevice" || { zerr; return 1; }
          200         sudo cgpt create    "$loopdevice" || { zerr; return 1; }
          201 
          202         sudo cgpt add -i 1 -t kernel -b ${gpt_boot[1]} -s ${gpt_boot[2]} \
          203                 -l kernel -S 1 -T 5 -P 10 "$loopdevice" || { zerr; return 1; }
          204 
          205         sudo cgpt add -i 2 -t data -b ${gpt_root[1]} -s \
          206                 $(expr $(sudo cgpt show "$loopdevice" \
          207                                 | awk '/Sec GPT table/ {print $1}') - ${gpt_root[1]}) \
          208                 -l Root "$loopdevice" || { zerr; return 1; }
          209 
          210         sudo partprobe "$loopdevice" || { zerr; return 1; }
          211 }
          212 
          213 image_mount()
          214 {
          215         fn image_mount
          216         req=(workdir bootpart rootpart bootfs)
          217         ckreq || return 1
          218 
          219         notice "Mounting image to $workdir/mnt"
          220 
          221         mkdir -p "$workdir/mnt"
          222         sudo mount "$rootpart" "$workdir/mnt" || { zerr; return 1; }
          223         act "Mounted root partition"
          224 
          225         if [[ "$bootfs" = none ]]; then
          226                 return
          227         fi
          228 
          229         sudo mkdir -p "$workdir/mnt/boot"
          230         sudo mount "$bootpart" "$workdir/mnt/boot" || { zerr; return 1; }
          231         act "Mounted boot partition"
          232 }
          233 
          234 image_umount()
          235 {
          236         fn image_umount
          237         req=(workdir loopdevice)
          238         ckreq || return 1
          239 
          240         notice "Umounting image from $workdir/mnt"
          241 
          242         sudo umount -R "$workdir/mnt" || { zerr; return 1; }
          243         act "Umounted"
          244 
          245         act "Flushing bytes and buffers"
          246         sudo blockdev --flushbufs "$loopdevice" || { zerr; return 1; }
          247         sudo python -c 'import os; os.fsync(open("'$loopdevice'", "r+b"))' || { zerr; return 1; }
          248 }
          249 
          250 image_disconnect_raw()
          251 {
          252         fn image_disconnect_raw
          253         req=(loopdevice bootfs rootfs bootpart rootpart)
          254         ckreq || return 1
          255 
          256         notice "Disconnecting image from $loopdevice"
          257 
          258         act "Rechecking filesystems"
          259         case "$bootfs" in
          260         ext?)
          261                 sudo e2fsck -fy "$bootpart"
          262                 sudo resize2fs "$bootpart"
          263                 ;;
          264         esac
          265 
          266         case "$rootfs" in
          267         ext?)
          268                 sudo e2fsck -fy "$rootpart"
          269                 sudo resize2fs "$rootpart"
          270                 ;;
          271         esac
          272 
          273         act "Disconnecting"
          274         sudo partx -dv "$loopdevice" >>/dev/null || {
          275                 die "partx failed to remove $loopdevice"
          276                 zerr; return 1
          277         }
          278 
          279         sudo losetup -d "$loopdevice" || {
          280                 die "losetup failed to remove $loopdevice"
          281                 zerr; return 1
          282         }
          283 }
          284 
          285 image_disconnect_qcow2()
          286 {
          287         fn image_disconnect_qcow2
          288         req=(loopdevice bootfs rootfs bootpart rootpart)
          289         ckreq || return 1
          290 
          291         notice "Disconnecting image from $loopdevice"
          292 
          293         act "Rechecking filesystems"
          294         case "$bootfs" in
          295         ext?)
          296                 sudo e2fsck -fy "$bootpart"
          297                 sudo resize2fs "$bootpart"
          298                 ;;
          299         esac
          300 
          301         case "$rootfs" in
          302         ext?)
          303                 sudo e2fsck -fy "$rootpart"
          304                 sudo resize2fs "$rootpart"
          305                 ;;
          306         esac
          307 
          308         act "Disconnecting"
          309 
          310         sudo qemu-nbd --disconnect "$loopdevice" || { zerr; return 1; }
          311 }
          312 
          313 image_raw_to_qcow2()
          314 {
          315         fn image_raw_to_qcow2
          316         req=(image_name workdir)
          317         ckreq || return 1
          318 
          319         notice "Converting raw image to qcow2"
          320         pushd "$workdir" || { zerr; return 1; }
          321         touch "${image_name}.qcow2"
          322         chattr -f +C "${image_name}.qcow2"
          323         qemu-img convert -f raw -O qcow2 "${image_name}.img" "${image_name}.qcow2" || { zerr; return 1; }
          324         popd
          325 }
          326 
          327 image_raw_to_vdi()
          328 {
          329         fn image_raw_to_vdi
          330         req=(image_name workdir)
          331         ckreq || return 1
          332 
          333         notice "Converting raw image to vdi"
          334         pushd "$workdir" || { zerr; return 1; }
          335         touch "${image_name}.vdi"
          336         chattr -f +C "${image_name}.vdi"
          337         qemu-img convert -f raw -O vdi "${image_name}.img" "${image_name}.vdi" || { zerr; return 1; }
          338         #VBoxManage modifyhd "${image_name}.vdi" --type immutable --compact || { zerr; return 1; }
          339         popd
          340 }
          341 
          342 image_pack_dist()
          343 {
          344         fn image_pack_dist
          345         req=(R image_name workdir)
          346         ckreq || return 1
          347 
          348         notice "Packing up built images"
          349 
          350         local _xzcomp=""
          351         local _rsuffix="img"
          352 
          353         if [[ -n "$COMPRESS_IMAGE" ]]; then
          354                 if command -v pixz >/dev/null; then
          355                         _xzcomp="$(command -v pixz)"
          356                 else
          357                         _xzcomp="$(command -v xz)"
          358                 fi
          359                 _rsuffix="img.xz"
          360         fi
          361 
          362         pushd "$workdir" || { zerr; return 1; }
          363 
          364         if [[ -n "$COMPRESS_IMAGE" ]]; then
          365                 act "Compressing images with $_xzcomp"
          366                 silly
          367                 $_xzcomp "${image_name}.img" || { zerr; return 1; }
          368                 # TODO: cpio image?
          369         fi
          370 
          371         act "Calculating sha256 checksums"
          372         silly
          373         sha256sum "${image_name}.${_rsuffix}" > "${image_name}.${_rsuffix}.sha256"
          374         # TODO: cpio image?
          375         mkdir -p "$R/dist"
          376         mv -v "${image_name}".* "$R/dist" || { zerr; return 1; }
          377 
          378         notice "Done! Thanks for being patient!"
          379 
          380         popd
          381 }