timaging - libdevuansdk - common library for devuan's simple distro kits
git clone https://git.parazyd.org/libdevuansdk
Log
Files
Refs
Submodules
README
LICENSE
---
timaging (8971B)
---
     1 #!/usr/bin/env zsh
     2 # shellcheck shell=bash
     3 # Copyright (c) 2016-2021 Ivan J. 
     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 .
    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 }