#!/bin/sh -efux # # Copyright (c) 2014 Sulev-Madis Silber # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # set -efux src_host='bbb-install bbb-install.si.pri.ee' src_dist='/bbb-dist/minimal' src_root="$src_dist/root" src_boot="$src_dist/boot" #uboot_mmc_dev_num='0' uboot_mmc_dev_num='1' hybrid_emmc_sd_boot='' #hybrid_emmc_sd_boot='yes' rsync_ips='' sshd_pidfile='/var/run/sshd.pid' sshd_pid='' _make_part_and_fs() { local dev="$1" local l_boot="$2" local d_boot="$3" local l_root="$4" local d_root="$5" local l_rootalt="$6" local d_rootalt="$7" local l_boot_uc="`echo -n \"$l_boot\" | tr a-z A-Z`" gpart create -s mbr "$dev" gpart add -t !12 -a 4m -s 4m -i 1 "$dev" gpart add -t freebsd -a 4m -s 512m -i 2 "$dev" gpart add -t freebsd -a 4m -s 512m -i 3 "$dev" gpart set -a active -i 1 "$dev" gpart create -s bsd "${dev}s2" gpart create -s bsd "${dev}s3" gpart add -t freebsd-ufs -a 4m -i 1 "${dev}s2" gpart add -t freebsd-ufs -a 4m -i 1 "${dev}s3" newfs_msdos -F 12 -L "$l_boot_uc" "/dev/${dev}s1" newfs -L "$l_root" -U "/dev/${dev}s2a" newfs -L "$l_rootalt" -U "/dev/${dev}s3a" mkdir -v "$d_boot" "$d_root" "$d_rootalt" mount -v -t msdosfs -o noatime "/dev/msdosfs/$l_boot_uc" "$d_boot" mount -v -o noatime "/dev/ufs/$l_root" "$d_root" mount -v -o noatime "/dev/ufs/$l_rootalt" "$d_rootalt" } ___rsync() { local type="$1" local dest="$2" local host="$3" local opts="$4" local rsync_src='' local rsync_extra_opts='' rsync_extra_opts="$rsync_extra_opts -c $opts" if [ "$type" = root -o "$type" = rootinactive ] then rsync_src="$src_root/" rsync_extra_opts="$rsync_extra_opts --exclude .snap" [ "$type" = root -a "`mount -t devfs | grep '^devfs on /dev '`" ] \ && rsync_extra_opts="$rsync_extra_opts --exclude dev" elif [ "$type" = ufsboot ] then rsync_src="$src_root/" rsync_extra_opts="$rsync_extra_opts --include /boot/*** --include /dev/ --include /etc/ --include /etc/fstab --include /rescue/*** --include /tmp/ --include /var/ --exclude * --filter P_/.snap --delete-excluded" elif [ "$type" = boot ] then rsync_src="$src_boot/" rsync_extra_opts="$rsync_extra_opts -O --modify-window=1 --no-p" fi rsync \ \ -vhhixaHAXS \ \ $rsync_extra_opts \ \ --stats \ --progress \ --numeric-ids \ --delete \ --force \ --force-delete \ --force-change \ \ "[$host]:$rsync_src" \ \ "$dest" } __rsync() { local type="$1" local dest="$2" local host="$3" local rc='0' ___rsync "$type" "$dest" "$host" '--fileflags' || rc="$?" [ "$rc" = 0 ] && return "$rc" [ "$type" = root -o "$type" = rootinactive ] && chflags -vvR 0 "$dest" rc='0' ___rsync "$type" "$dest" "$host" '' || rc="$?" [ "$type" = boot ] && return "$rc" rc='0' ___rsync "$type" "$dest" "$host" '--fileflags' } _rsync() { local type="$1" local dest="$2" local rc='0' local host='' for host in $rsync_ips $src_host do rc='0' __rsync "$type" "$dest" "$host" || rc="$?" [ "$rc" = 0 ] && break done return "$rc" } _service() { local mode="$1" case "$mode" in start) for service in var ldconfig ldconfig do service "$service" start done [ "$sshd_pid" ] && echo -n "$sshd_pid" > "$sshd_pidfile" [ "${2:-}" != noreboot ] && return for service in newsyslog devd rtsold syslogd casperd do service "$service" start done ;; stop) [ -f "$sshd_pidfile" ] && sshd_pid="`cat \"$sshd_pidfile\"`" ;; esac grep -i '^ifconfig_.*dhcp' /etc/rc.conf | cut -d = -f 1 | cut -d _ -f 2 \ | xargs -n 1 service dhclient "$mode" || true case "$mode" in start) for service in ntpd cron do service "$service" start || true done service sshd restart || true poe stop poe start ;; stop) for service in devd rtsold syslogd casperd ntpd cron do service "$service" stop || true done ;; esac } _sysinfo() { ps wwaux ps wwauxd df -H mdconfig -vl } _ufslabel_to_slicenum() { local label="$1" local num="`glabel status | awk -v \"fs=$label\" '$1 == fs { print $3 }' | sed 's|^mmcsd[01]s||; s|a$||'`" case "$num" in [0-9]) echo "$num" ;; *) exit 1 ;; esac } _check_and_config_root() { local dir="$1" local rootfs="$2" ( cd "$dir" [ -d boot -a -d etc -a -d dev -a -d var -a -f boot/kernel/kernel ] || { cat <<- EOF UPGRADE ERROR: ROOT FILESYSTEM IS NOT SWITCHED EOF exit 1 } cd etc egrep -q "^.+[[:space:]]+/[[:space:]]+" fstab && { egrep -q "^$rootfs[[:space:]]+/" fstab || { sed -E "s|^/dev/ufs/bbbemmcroot(alt)?|$rootfs|" < fstab > fstab.new mv -v fstab.new fstab } } \ || true ) } _check_and_config_boot() { local dir="$1" local slicenum="$2" local uboot_rootfs="$3" ( cd "$dir" [ -f mlo -a -f u-boot.img -a -f uenv.txt -a -f ubldr ] || { cat <<- EOF SERIOUS UPGRADE ERROR: BOARD WILL NOT BOOT, FIX IT!!! EOF exit 1 } grep -q ^loaderdev= uenv.txt && { grep -q "^loaderdev=mmc$uboot_mmc_dev_num:$slicenum\.0\$" uenv.txt || { sed -E "s|^(loaderdev=mmc).*|\1$uboot_mmc_dev_num:$slicenum.0|" < uenv.txt > uenv.new mv -v uenv.new uenv.txt } } \ || true grep -q ^bbb_bootmode_default= uenv.txt && { grep -q "^bbb_bootmode_default=$uboot_rootfs\$" uenv.txt || { sed -E "s|^(bbb_bootmode_default=).*|\1$uboot_rootfs|" < uenv.txt > uenv.new mv -v uenv.new uenv.txt } } \ || true ) } fsck_pids="`pgrep -f fsck || true`" if [ "$fsck_pids" ] then echo "Found currently running fsck processes: $fsck_pids" for fsck_pid in $fsck_pids do echo "Wait until fsck (PID '$fsck_pid') exits..." pwait -v "$fsck_pid" done fi case "${1:-}" in selfcopy) dest_boot='/mnt' dest_root='' bootfs='/dev/msdosfs/BBBEMMCBOOT' _sysinfo _service stop for host in $src_host do rsync_ips="$rsync_ips `getent hosts \"$host\" | awk '{print $1}'`" done umount -vf /tmp /var || true umount -v "$dest_boot" || true mdconfig -l | xargs -n 1 mdconfig -du _sysinfo mount -vuw -o noatime "$dest_root" _rsync root "$dest_root/" time -h mount -vfur -o noatime "$dest_root" for fs in /tmp /var do mount -v "$fs" || true done _service start "${2:-}" mount -v -t msdosfs -o noatime "$bootfs" "$dest_boot" _rsync boot "$dest_boot/" umount -v "$dest_boot" _sysinfo [ "${2:-}" != noreboot ] && shutdown -r now ;; copyinactive|'') dest_boot='/mnt' dest_ufsboot='/mnt' dest_root='/mnt' bootfs='/dev/msdosfs/BBBEMMCBOOT' active_rootfs="`mount | fgrep ' on / ' | cut -d ' ' -f 1`" case "$active_rootfs" in /dev/ufs/bbbemmcroot) inactive_rootfs='/dev/ufs/bbbemmcrootalt' inactive_ufsbootfs='/dev/ufs/bbbsdufsbootalt' inactive_slicenum="`_ufslabel_to_slicenum \"ufs/bbbemmcrootalt\"`" inactive_uboot_rootfs='rootalt' ;; /dev/ufs/bbbemmcrootalt) inactive_rootfs='/dev/ufs/bbbemmcroot' inactive_ufsbootfs='/dev/ufs/bbbsdufsboot' inactive_slicenum="`_ufslabel_to_slicenum \"ufs/bbbemmcroot\"`" inactive_uboot_rootfs='root' ;; esac for fs in `echo "$dest_boot" "$dest_ufsboot" "$dest_root" | xargs -n 1 | sort | uniq` do umount -v "$fs" || true done fsck_ufs -yR "$inactive_rootfs" mount -v -o noatime "$inactive_rootfs" "$dest_root" _rsync rootinactive "$dest_root/" _check_and_config_root "$dest_root" "$inactive_rootfs" time -h umount -v "$dest_root" [ "$hybrid_emmc_sd_boot" = yes ] && { fsck_ufs -yR "$inactive_ufsbootfs" mount -v -o noatime "$inactive_ufsbootfs" "$dest_ufsboot" _rsync ufsboot "$dest_ufsboot/" _check_and_config_root "$dest_ufsboot" "$inactive_rootfs" time -h umount -v "$dest_ufsboot" } fsck_msdosfs -y "$bootfs" mount -v -t msdosfs -o noatime "$bootfs" "$dest_boot" _rsync boot "$dest_boot/" _check_and_config_boot "$dest_boot" "$inactive_slicenum" "$inactive_uboot_rootfs" umount -v "$dest_boot" cat <<- EOF ====================================================== ====================================================== ====================================================== UPGRADE OK active_rootfs = '$active_rootfs' inactive_rootfs = '$inactive_rootfs' inactive_ufsbootfs = '$inactive_ufsbootfs' inactive_slicenum = '$inactive_slicenum' uboot_mmc_dev_num = '$uboot_mmc_dev_num' SWITCHED BOOT FILESYSTEM TO: '$uboot_mmc_dev_num' / '$inactive_slicenum' / '$inactive_ufsbootfs' / '$inactive_rootfs' ====================================================== ====================================================== ====================================================== EOF [ "${2:-}" != noreboot ] && shutdown -r now ;; copy) dest_boot="$2" dest_root="$3" _rsync rootinactive "$dest_root/" _rsync boot "$dest_boot/" ;; newfs) dest_disk='mmcsd1' label_boot='bbbemmcboot' label_root='bbbemmcroot' label_rootalt='bbbemmcrootalt' dest_boot="/tmp/$label_boot" dest_root="/tmp/$label_root" dest_rootalt="/tmp/$label_rootalt" _make_part_and_fs "$dest_disk" "$label_boot" "$dest_boot" "$label_root" "$dest_root" "$label_rootalt" "$dest_rootalt" _rsync boot "$dest_boot/" _rsync rootinactive "$dest_root/" _rsync rootinactive "$dest_rootalt/" _check_and_config_boot "$dest_boot" "`_ufslabel_to_slicenum \"ufs/$label_root\"`" _check_and_config_root "$dest_root" "/dev/ufs/$label_root" _check_and_config_root "$dest_rootalt" "/dev/ufs/$label_rootalt" umount -v "$dest_boot" "$dest_root" "$dest_rootalt" ;; esac