#!/bin/bash # Time-stamp: <2025-02-10 06:32:43 nomad> # Michel Le Cocq # # Licence Art Libre 1.3 (LAL 1.3) # upsnapz.sh # Script to upgrade your system install on zfs root with zfs boot menu (only Debian for the moment). # # refresh apt # zfs snapshot # apt upgrade # apt autoremove # zfs clone promote # check zfs boot menu release # check zfs pool status # Depend : # - gh # To do or not : # # ajouter zpool upgrade or not # ajouter question cleanup zroot # # regarder si un nouveau kernel existe et si oui faire ce qu'il y a a faire function check_zpool_status { # check zpool status if it's upgradable printf 'Check ZFS pool status:\n' e=$(zpool status | grep action | grep 'zpool upgrade') if [ $? -eq 0 ] then printf 'One or more ZFS pool can be upgraded\n' zpool status printf 'In case of ZFS Root be carefull that your bootloader is up to date and compatible with this new ZFS feature.\n' else printf 'every things ok for ZFS pool.\n' fi } function check_ZFS_BOOT_MENU { # check last zfs boot menu release # compare if we are on last release printf '\nCheck ZFS_BOOT_MENU:\n' PA="https://get.zfsbootmenu.org/sha256.txt" echo " Hit:zfsbootmenu "$PA curl -s -o /tmp/sha256.txt -L $PA e=$(grep $(sha256sum /boot/efi/EFI/ZBM/VMLINUZ.EFI | awk '{print $1}') /tmp/sha256.txt | awk -F"[()]" '{print $2}' ) echo -n " Installed Release : " e=$(echo $e | awk -F'-' '{print $4}') echo $e # pas tout a fait satisfait de cette methode avec gh # force a s'authentifier sur github ! f=$(gh release list --repo https://github.com/zbm-dev/zfsbootmenu | grep Latest | awk -F' ' '{print $4}') if [ "$e" != "$f" ] then echo " /!\ Installed Release and lastest are not same !"$PA printf ' Latest Release : ' echo $f fi if [ -z $e ] then echo " /!\ not in sync with : "$PA echo ' avaible release :' cat /tmp/sha256.txt | grep EFI | grep release | awk -F"[()]" '{print $2}' fi rm /tmp/sha256.txt } function askpromote() { # ask if we wanted to promote that last snapshot # promote last bootfs snapshot to a new bootfs env # suggest name for new bootfs env # clone promote activate new bootfs # ask to reboot to new bootfs snapname=$1 bootfs=$2 parents=$(zfs list -o name | grep $bootfs | awk 'BEGIN{FS=OFS="/"}{NF--; print}') printf '\nclone and promote before upgrade %s or not \nhost will reboot to new bootfs : [Y-n]' $bootfs@$snapname read dopromote if [ -z $dopromote ] then dopromote='y' echo y fi if [[ "$dopromote" == "y" ]] then printf '\nactual bootfs : %s\n' $bootfs printf 'other bootfs :\n' $bootfs zfs list -o name,creation -r $parents -s creation | grep -v ^$parents$ e=$(lsb_release -is) f=$(date +%b) sugsname="${e,,}_"$(lsb_release -cs)"_"$(date +%Y)"_"$(date +%m)"_"$(date +%d) zfs list -H -o name | grep $sugsname if [ $? -eq 0 ] then sugsname=$sugsname"_"$(date +%Y-%m-%d-%H%M%S) fi printf '\nname suggestion for new zpool bootfs : %s [Y-n]' $sugsname read namepros if [ -z $namepros ] then echo y namepros='y' fi if [[ "$namepros" == "n" ]] then printf 'new bootfs name :' read sugsname if [ $(zfs list -H -o name | grep $sugsname) -eq 0 ] then sugsname=$newname_$(date +%Y-%m-%d-%H%M%S) printf '%s already exist I siggest : %s\n' fi printf 'name suggestion : %s\n' $sugsname fi sudo zfs clone $bootfs@$snapname $parents/$sugsname sudo zfs promote $parents/$sugsname sudo zfs set -u mountpoint=/ $parents/$sugsname sudo zfs set canmount=noauto $parents/$sugsname sudo zpool set bootfs=$parents/$sugsname zroot printf '%s will reboot to new bootfs %s in 5s\nHit Ctrl^c to abort' $(hostname) $sugsname printf "\nRun again current script $(basename $0) after reboot.\n" echo -n '.'; sleep 1; echo -n '.'; sleep 1; echo -n '.'; sleep 1; echo -n '.'; sleep 1; echo -n '.';sleep 1; echo -n '.';sleep 1; echo -n '.' sudo reboot else echo no fi } function askautoclean() { # ask to autoremove and zfs snapshot before printf '\napt-get -s autoremove\n' if [ $(apt-get -s autoremove | sed -n '/The following packages will be REMOVED:/,/^[0-9+] upgraded, [0-9+] newly installed, [0-9+] to remove and [0-9+] not upgraded.$/p' | wc -l) -gt 0 ] then apt-get -s autoremove | sed -n '/The following packages will be REMOVED:/,/^[0-9+] upgraded, [0-9+] newly installed, [0-9+] to remove and [0-9+] not upgraded.$/p' printf '\n%s\n' 'Do we run an autoremove ? : [Y-n]' read autoclean if [ -z $autoclean ] then echo y autoclean='y' fi if [[ "$autoclean" == "y" ]] then printf 'before autoremove : ' asksnap sudo apt-get -y autoremove else echo fi fi sudo apt autoclean } function asksnap() { # print creation info of last bootfs snapshot # ask if we want a snapshot of bootfs # snapshot bootfs bootfs=$(zpool get bootfs -o value -H zroot) l=$(zfs list -H -t snapshot -o creation,name -S creation $(zpool get bootfs -o value -H zroot) | head -n1) printf 'last snapshot : \n%s\n' "$l" printf '%s <- now\n' "$(date '+%a %b %d %H:%M %Y')" printf 'snapshot bootfs %s or not ? : [Y-n]' $bootfs read dosnap if [ -z $dosnap ] then echo y dosnap='y' fi if [[ "$dosnap" == "y" ]] then snapname=$(date +%Y-%m-%d-%H%M%S) sudo zfs snapshot $bootfs@$snapname zfs list -H -o name $bootfs@$snapname askpromote $snapname $bootfs else echo no fi } function askupgrade() { # run apt update # if there were upgrade ask for upgrade or not # ask for making a snapshot # run apt upgrade # else # ask for making a snapshot printf '%s\n' 'apt update' sudo apt update if [ $(apt list --upgradable 2>/dev/null | wc -l) -gt 1 ] then printf '\n%s\n' 'apt list --upgradable' apt list --upgradable printf '\nUpgrade or not : [Y-n]' read answer if [ -z $answer ] then echo y answer='y' fi if [[ "$answer" == "y" ]] then printf 'before upgrade : ' asksnap printf '%s\n' 'apt -y upgrade' sudo apt -y upgrade else echo no fi else echo asksnap fi } function usage() { echo "Usage: $(basename $0) [-h]" echo "-b : only check zfs boot menu" } while getopts 'hb' OPTION; do case "$OPTION" in h) usage exit 1 ;; b) check_ZFS_BOOT_MENU echo exit 1 ;; ?) usage exit 1 ;; esac done askupgrade askautoclean echo check_zpool_status check_ZFS_BOOT_MENU echo zpool status printf '\nNothing else to do.\n' #~/bin/clean-snapshot.sh