1#!/bin/ksh 2# 3# $OpenBSD: sysupgrade.sh,v 1.57 2024/10/25 03:42:06 deraadt Exp $ 4# 5# Copyright (c) 1997-2015 Todd Miller, Theo de Raadt, Ken Westerback 6# Copyright (c) 2015 Robert Peichaer <rpe@openbsd.org> 7# Copyright (c) 2016, 2017 Antoine Jacoutot <ajacoutot@openbsd.org> 8# Copyright (c) 2019 Christian Weisgerber <naddy@openbsd.org> 9# Copyright (c) 2019 Florian Obser <florian@openbsd.org> 10# 11# Permission to use, copy, modify, and distribute this software for any 12# purpose with or without fee is hereby granted, provided that the above 13# copyright notice and this permission notice appear in all copies. 14# 15# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 16# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 17# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 18# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 19# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 20# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 21# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22 23set -e 24umask 0022 25export PATH=/usr/bin:/bin:/usr/sbin:/sbin 26 27ARCH=$(uname -m) 28SETSDIR=/home/_sysupgrade 29 30err() 31{ 32 echo "${0##*/}: ${1}" 1>&2 33 return ${2:-1} 34} 35 36usage() 37{ 38 echo "usage: ${0##*/} [-fkns] [-b base-directory] [-R version] [installurl | path]" 1>&2 39 return 1 40} 41 42unpriv() 43{ 44 local _file _rc=0 _user=_syspatch 45 46 if [[ $1 == -f ]]; then 47 _file=$2 48 shift 2 49 fi 50 if [[ -n ${_file} ]]; then 51 >${_file} 52 chown "${_user}" "${_file}" 53 fi 54 (($# >= 1)) 55 56 eval su -s /bin/sh ${_user} -c "'$@'" || _rc=$? 57 58 [[ -n ${_file} ]] && chown root "${_file}" 59 60 return ${_rc} 61} 62 63# Remove all occurrences of first argument from list formed by the remaining 64# arguments. 65rmel() { 66 local _a=$1 _b _c 67 68 shift 69 for _b; do 70 [[ $_a != "$_b" ]] && _c="${_c:+$_c }$_b" 71 done 72 echo -n "$_c" 73} 74 75SNAP=false 76FILE=false 77FORCE=false 78FORCE_VERSION=false 79KEEP=false 80REBOOT=true 81WHAT='release' 82 83VERSION=$(uname -r) 84NEXT_VERSION=$(echo ${VERSION} + 0.1 | bc) 85 86while getopts b:fknrR:s arg; do 87 case ${arg} in 88 b) SETSDIR=${OPTARG}/_sysupgrade;; 89 f) FORCE=true;; 90 k) KEEP=true;; 91 n) REBOOT=false;; 92 r) ;; 93 R) FORCE_VERSION=true 94 [[ ${OPTARG} == @([0-9]|[0-9][0-9]).[0-9] ]] || 95 err "invalid version: ${OPTARG}" 96 NEXT_VERSION=${OPTARG};; 97 s) SNAP=true;; 98 *) usage;; 99 esac 100done 101 102(($(id -u) != 0)) && err "need root privileges" 103 104shift $(( OPTIND -1 )) 105 106case $# in 1070) MIRROR=$(sed 's/#.*//;/^$/d' /etc/installurl) 2>/dev/null || 108 MIRROR=https://cdn.openbsd.org/pub/OpenBSD 109 ;; 1101) MIRROR=$1 111 ;; 112*) usage 113esac 114[[ $MIRROR == @(file|ftp|http|https)://* ]] || 115 FILE=true 116$FORCE_VERSION && $SNAP && 117 err "incompatible options: -s -R $NEXT_VERSION" 118$FORCE && ! $SNAP && 119 err "incompatible options: -f without -s" 120 121if $SNAP; then 122 WHAT='snapshot' 123 URL=${MIRROR}/snapshots/${ARCH}/ 124else 125 URL=${MIRROR}/${NEXT_VERSION}/${ARCH}/ 126 $FORCE_VERSION || ALT_URL=${MIRROR}/${VERSION}/${ARCH}/ 127fi 128 129# Oh wait, this is a path install 130if $FILE; then 131 URL=file://$MIRROR/ 132 ALT_URL= 133fi 134 135install -d -o 0 -g 0 -m 0755 ${SETSDIR} 136cd ${SETSDIR} 137 138echo "Fetching from ${URL}" 139if ! unpriv -f SHA256.sig ftp -N sysupgrade -Vmo SHA256.sig ${URL}SHA256.sig; then 140 if [[ -n ${ALT_URL} ]]; then 141 echo "Fetching from ${ALT_URL}" 142 unpriv -f SHA256.sig ftp -N sysupgrade -Vmo SHA256.sig ${ALT_URL}SHA256.sig 143 URL=${ALT_URL} 144 NEXT_VERSION=${VERSION} 145 else 146 exit 1 147 fi 148fi 149 150# The key extracted from SHA256.sig must precisely match a pattern 151KEY=$(head -1 < SHA256.sig | cut -d' ' -f5 | \ 152 egrep '^openbsd-[[:digit:]]{2,3}-base.pub$' || true) 153if [[ -z $KEY ]]; then 154 echo "Invalid SHA256.sig file" 155 exit 1 156fi 157 158# If required key is not in the system, get it from a signed bundle 159if ! [[ -r /etc/signify/$KEY ]]; then 160 HAVEKEY=$(cd /etc/signify && ls -1 openbsd-*-base.pub | \ 161 tail -2 | head -1 | cut -d- -f2) 162 BUNDLE=sigbundle-${HAVEKEY}.tgz 163 FWKEY=$(echo $KEY | sed -e 's/base/fw/') 164 echo "Adding missing keys from bundle $BUNDLE" 165 unpriv -f ${BUNDLE} ftp -N sysupgrade -Vmo $BUNDLE https://ftp.openbsd.org/pub/OpenBSD/signify/$BUNDLE 166 signify -Vzq -m - -x $BUNDLE | (cd /etc/signify && tar xfz - $KEY $FWKEY) 167 rm $BUNDLE 168fi 169 170unpriv -f SHA256 signify -Ve -x SHA256.sig -m SHA256 171rm SHA256.sig 172 173if cmp -s /var/db/installed.SHA256 SHA256 && ! $FORCE; then 174 echo "Already on latest ${WHAT}." 175 exit 0 176fi 177 178unpriv -f BUILDINFO ftp -N sysupgrade -Vmo BUILDINFO ${URL}BUILDINFO 179unpriv cksum -qC SHA256 BUILDINFO 180 181if [[ -e /var/db/installed.BUILDINFO ]]; then 182 installed_build_ts=$(cut -f3 -d' ' /var/db/installed.BUILDINFO) 183 build_ts=$(cut -f3 -d' ' BUILDINFO) 184 if (( $build_ts <= $installed_build_ts )) && ! $FORCE; then 185 echo "Downloaded ${WHAT} is older than installed system. Use -f to force downgrade." 186 exit 1 187 fi 188fi 189 190# INSTALL.*, bsd*, *.tgz 191SETS=$(sed -n -e 's/^SHA256 (\(.*\)) .*/\1/' \ 192 -e '/^INSTALL\./p;/^bsd/p;/\.tgz$/p' SHA256) 193 194OLD_FILES=$(ls) 195OLD_FILES=$(rmel SHA256 $OLD_FILES) 196DL=$SETS 197 198[[ -n ${OLD_FILES} ]] && echo Verifying old sets. 199for f in ${OLD_FILES}; do 200 if cksum -C SHA256 $f >/dev/null 2>&1; then 201 DL=$(rmel $f ${DL}) 202 OLD_FILES=$(rmel $f ${OLD_FILES}) 203 fi 204done 205 206[[ -n ${OLD_FILES} ]] && rm ${OLD_FILES} 207for f in ${DL}; do 208 unpriv -f $f ftp -N sysupgrade -Vmo ${f} ${URL}${f} 209done 210 211if [[ -n ${DL} ]]; then 212 echo Verifying sets. 213 unpriv cksum -qC SHA256 ${DL} 214fi 215 216cat <<__EOT >/auto_upgrade.conf 217Location of sets = disk 218Pathname to the sets = ${SETSDIR}/ 219Directory does not contain SHA256.sig. Continue without verification = yes 220__EOT 221 222if ! ${KEEP}; then 223 CLEAN=$(echo SHA256 ${SETS} | sed -e 's/ /,/g') 224 cat <<__EOT > /etc/rc.firsttime 225rm -f ${SETSDIR}/{${CLEAN}} 226__EOT 227fi 228 229echo Fetching updated firmware. 230set -A _NEXTKERNV -- $(what bsd | 231 sed -n '2s/^[[:blank:]]OpenBSD \([1-9][0-9]*\.[0-9]\)\([^ ]*\).*/\1 \2/p') 232 233if [[ ${_NEXTKERNV[1]} == '-current' ]]; then 234 FW_URL=http://firmware.openbsd.org/firmware/snapshots/ 235else 236 FW_URL=http://firmware.openbsd.org/firmware/${_NEXTKERNV[0]}/ 237fi 238VNAME="${_NEXTKERNV[0]}" fw_update -p ${FW_URL} || true 239 240install -F -m 700 bsd.rd /bsd.upgrade 241logger -t sysupgrade -p kern.info "installed new /bsd.upgrade. Old kernel version: $(sysctl -n kern.version)" 242sync 243 244if ${REBOOT}; then 245 echo Upgrading. 246 exec reboot 247else 248 echo "Will upgrade on next reboot" 249fi 250