#!/bin/sh # Copyright Precedence Technologies Ltd 2017 machine=`uname -m` arch=`uname -p` version=7 usage() { cat << EOF Syntax: osupgrade [-poh] [-d dir] [-r root] -p = pause after every stage -o = OS upgrade only, no packages or other software -h = this help -d = path to upgrade data (should be autodetermined) -r = path to mounted root filesystem to upgrade EOF } dir="" root="" pause="" osonly="" while getopts pd:ohr: OPTION do case $OPTION in p) pause=y ;; d) dir="$OPTARG" ;; r) root="$OPTARG" ;; o) osonly=y ;; h|?) usage exit 1 ;; esac done shift `expr $OPTIND - 1` if [ -z "$root" ]; then echo "Please specify location of installed system with -r flag" exit 1 fi if [ ! -f $root/netbsd ]; then echo "No existing install found at $root" exit 1 fi if [ -z "$dir" ]; then dir=`echo $0 | awk -F/ ' BEGIN { if(substr("'$0'",1,1)!="/") printf "'$PWD'/" } { for (i=1;i /dev/stderr return 3 fi if [ ! -f "$root/$file" ]; then echo "file $file does not exist" > /dev/stderr return 3 fi if [ -x /usr/bin/readelf ]; then READELF=/usr/bin/readelf elif [ -x $root/usr/bin/readelf ]; then READELF="env LD_LIBRARY_PATH=$root/lib:$root/usr/lib $root/usr/bin/readelf" else echo "Could not locate readelf binary" return 2 fi [ -z "$READELF" ] && return 2 elf=`$READELF -hn $root/$file | awk '{ if ($1 == "Machine:") { machine = $2 for (n = 3; n <= NF; n++) machine = machine " " $n } if ($1 == "NetBSD" && $3 == "IDENT") { l = length($4) v = 0+substr($4, 1, l-8) } if ($1 == "NetBSD" && $3 == "NT_VERSION") { v = $2 } } END{ printf "%s/%s\n", v, machine }'` case "${elf%/*}" in 5|7) bvers="${elf%/*}" ;; 0x00000004) bvers=5 ;; *) echo "Existing $file binary is for unknown OS version ${elf%/*}" return 1 ;; esac case "${elf#*/}" in *80386) barch=i386 ;; *x86_64|*X86-64) barch="x86_64" ;; *) echo "Existing $file binary is for unknown architecture: ${elf#*/}" return 1 ;; esac echo "$barch/$bvers" return 0 } sets=$dir/$machine/binary/sets # Stage 1: check free space free=`df -m $root | awk -v root=$root '{if ($6 == root) print $4}'` if [ -z "$free" ]; then echo "$root is not a mountpoint" exit 1 fi if [ "$free" -lt 500 ]; then echo "Not enough free space to upgrade ($free MB)" exit 1 fi # Stage 2: check installed kernel if [ ! -f $root/netbsd ]; then echo "Cannot find installed kernel" exit 1 fi if [ -x /usr/bin/config ]; then CONFIG=/usr/bin/config elif [ -x $root/usr/bin/config ]; then CONFIG=$root/usr/bin/config else echo "Could not locate config binary" exit 1 fi ### START CONFIG FILE "/usr/src/5.0/sys/arch/i386/conf/NETMANXEN3" kv=`$CONFIG -x $root/netbsd | awk 'BEGIN{ q = sprintf("%c", 34) } { if ($1 == "###" && $2 == "START" && $3 == "CONFIG" && $4 == "FILE") { c = $5 gsub(q, "", c) n = split(c, p, "/") printf "%s/%s\n", p[n], p[n-2] } }'` if [ -z "$kv" ]; then echo "Could not determine kernel type" exit 1 fi kname=${kv%/*} kmachine=${kv#*/} kerntype=`readbin netbsd` if [ "$?" != 0 ]; then echo "Could not read kernel type" exit 1 fi echo "Kernel:$kname Machine:$kmachine Release:$kerntype" dopause if [ "$kerntype" != "$machine/$version" ]; then case "$kname" in XEN3PAE_DOMU|XEN3PAE_DOMUNMB) kname="XEN3_DOMU" ;; GENERICNMB) kname="GENERIC" ;; esac if [ -f $dir/build/version/$version/$machine/kernels/$kname.tgz ]; then kf=$dir/build/version/$version/$machine/kernels/$kname.tgz elif [ -f $dir/amd64/binary/sets/kern-$kname.tgz ]; then kf=$dir/amd64/binary/sets/kern-$kname.tgz else echo "Cannot find kernel for $version" exit 1 fi echo "Copying old kernel" cp $root/netbsd $root/netbsd.old echo "Installing kernel for $machine version $version" export kf (cd $root ; tar -xpzf $kf || exit 1) || exit 1 else echo "Kernel already installed" fi # Stage 3: check /dev dopause lnod=`ls -l /dev/wd1a | awk '/^b/{ printf "%s%s\n", $5, $6}'` tnod=`ls -l $root/dev/wd1a | awk '/^b/{ printf "%s%s\n", $5, $6}'` if [ "$lnod" != "$tnod" ]; then echo "Creating /dev for $machine" (cd $root ; tar -xpzf $sets/etc.tgz ./dev/MAKEDEV || exit 1) || exit 1 (cd $root/dev ; sh MAKEDEV all || exit 1) || exit 1 else echo "/dev already updated for $machine" fi continue_n() { local resp echo -n "Continue anyway? (y/n) [n]:" read resp [ "$resp" != y ] && exit 1 } # Stage 4: update userland dopause runup=0 lastfile=`tar -tvzf $sets/xserver.tgz | awk 'BEGIN { s = sprintf("%c.so%c.[0-9]+$", 92, 92) } { if ($1 ~ "^-r.[sx]..x..x$") lfile = $9 else if ($9 ~ s) lfile = $9 } END { if (substr(lfile, 1, 2) == "./") lfile = substr(lfile, 3) print lfile }'` if [ -z "$lastfile" ]; then echo "Cannot determine last file in archive" continue_n runup=1 oldversion="Unknown" else runup=0 oldversion=`readbin $lastfile` ret=$? case "$ret" in 1) continue_n ;; 2) continue_n runup=1 ;; esac if [ "$oldversion" = "$arch/$version" ]; then echo "Userland already upgraded" echo -n "Run userland upgrade again? (y/n) [n]:" read resp [ "$resp" = y ] && runup=1 else runup=1 fi [ -z "$oldversion" ] && oldversion="Unknown" fi if [ "$runup" = 1 ]; then echo "Upgrading userland from $oldversion to $arch/$version" cd $root if [ -d $root/usr/X11R7/lib/X11/xkb/symbols/pc ]; then rm -r $root/usr/X11R7/lib/X11/xkb/symbols/pc fi for i in base comp games man misc modules \ tests text \ xbase xcomp xfont xserver do echo "Extracting $i" tar -xpzf $sets/$i.tgz || continue_n done || exit 1 tar -xpzf $sets/etc.tgz ./etc/rc.d ./etc/rc.subr ./etc/defaults \ ./etc/man.conf rm -f ./etc/ld.so.conf ./etc/rc.d/lkm ./etc/rc.d/btattach \ ./etc/rc.d/btconfig ./etc/rc.d/btdevctl ./etc/rc.d/poffd fi echo "Copying bootloader" cp $root/usr/mdec/boot $root/boot || exit 1 echo "Checking for postinstall prerequisites" dopause if [ -d $root/usr/lkm ]; then rm -r $root/usr/lkm fi awk 'BEGIN { notfound = 1 } { if ($2 == "/var/shm" && $3 == "tmpfs") notfound = 0 } END { exit(notfound) }' /etc/fstab if [ "$?" != 0 ]; then echo "Configuring SHM" echo "tmpfs /var/shm tmpfs rw,-m1777,-sram%25" >> /etc/fstab fi cp $root/etc/master.passwd $root/etc/ptmp cp $root/etc/master.passwd $root/etc/master.passwd.orig for u in _rtadvd:30:/var/chroot/rtadvd \ _gpio:29:/nonexistent \ _tss:28:/var/tpm \ _tcpdump:27:/var/chroot/tcpdump \ _tests:26:/nonexistent \ _mdnsd:17:/nonexistent \ _httpd:24:/var/www \ _timedc:22:/nonexistent do user=${u%%:*} u=${u#*:} uid=${u%%:*} u=${u#*:} home=${u%%:*} cuser=`awk -F: -v user=$user -v gfile=$root/etc/group \ -v uid=$uid -v min=75 -v max=99 'BEGIN { while((getline line < gfile) >0) { split(line, gr, ":") gid[gr[3]] = gr[1] gname[gr[1]] = gr[3] } } { if ($3 == uid) { cname=$1 if (cgid == "") cgid=$4 } if ($1 == user) { cuid=$3 cgid=$4 } if ($3 >= min && $3 <= max) id[$3] = $1 } END { scangroup = 0 if (cuid != "") { cname=user } else if (user in gname) { usegid = gname[user] cgid = usegid } else if (uid in gid) { if (gid[uid] != user) scangroup = 1 else cgid = uid } else { cgid = uid } if ((cname != user && cname != "") || scangroup == 1) { for (n = min; n <= max; n++) if (n in id) { } else { if (scangroup == 1) { if (n in gid) if (gid[n] != user) continue } cuid = n cgid = n n = max } } usegid = cgid if (cgid in gid) { if (gid[cgid] == user) cgid = "" } printf "%s:%s:%s:%s\n", cname, cuid, usegid, cgid }' $root/etc/ptmp` # echo ${cuser} cname=${cuser%%:*} cuser=${cuser#*:} cuid=${cuser%%:*} cuser=${cuser#*:} usegid=${cuser%%:*} cuser=${cuser#*:} cgid=${cuser%%:*} # echo "$user:$uid $cname:$cuid $cgid" if [ -n "$cgid" ]; then echo "Create group $user with GID $cgid" echo "$user:*:$cgid:" >> $root/etc/group fi createuser="" if [ -z "$cname" ]; then createuser=1 if [ -z "$cuid" ]; then echo "Create user $user with UID $uid and GID $usegid" cuid=$uid else echo "Create user $user with UID $cuid instead of $uid. GID $usegid" fi elif [ "$cname" != "$user" ]; then createuser=1 echo "Create user $user with UID $cuid because of $cname having UID $uid. GID $usegid" fi if [ -n "$createuser" ]; then echo "$user:*:$cuid:$usegid::0:0:& pseudo-user:$home:/sbin/nologin" >> $root/etc/ptmp fi done echo "Rebuilding password database" pwd_mkdb -p -d $root $root/etc/ptmp || exit 1 sync;sync echo "Preparing for postinstall" dopause if [ -d $root/usr/X11R7/lib/X11/xkb/symbols/pc ]; then rm -r $root/usr/X11R7/lib/X11/xkb/symbols/pc fi for f in 10-autohint 10-no-sub-pixel 10-sub-pixel-bgr \ 10-sub-pixel-rgb 10-sub-pixel-vbgr \ 10-sub-pixel-vrgb 10-unhinted 25-unhint-nonlatin \ 65-khmer 70-no-bitmaps 70-yes-bitmaps do [ -f $root/etc/fonts/conf.d/${f}.conf ] && rm $root/etc/fonts/conf.d/${f}.conf done if [ -d $root/etc/disklabels ]; then if [ -d $root/etc/netmanager ]; then mv $root/etc/disklabels $root/etc/netmanager/disklabels else mv $root/etc/disklabels $root/etc/disklabels.old fi fi mkdir -p $root/postup cd $root/postup tar -xpzf $sets/etc.tgz tar -xpzf $sets/xetc.tgz tasks=`$root/usr/sbin/postinstall -s $root/postup list | awk 'BEGIN{ output=0 } { if ($1 == "----") output++ if ($1 == "uid" || $1 == "gid" || $1 == "Item") next if ($0~"^[[:space:]]+[a-zA-Z]" && output == 1) print $1 }'` if [ $root != / ]; then echo "Running postinstall in chroot" chroot $root /usr/sbin/postinstall -s /postup fix uid gid chroot $root /usr/sbin/postinstall -s /postup fix $tasks piexit=$? else echo "Running postinstall directly" /usr/sbin/postinstall -s /postup fix uid gid /usr/sbin/postinstall -s /postup fix $tasks piexit=$? fi cd / rm -r $root/postup if [ "$piexit" != 0 ]; then continue_n fi echo "Deleting i386-only files" dopause while read a do if [ -d $root/$a ]; then echo "Directory $a" rm -r $root/$a elif [ -f $root/$a ]; then echo "File $a" rm $root/$a fi done << EOF lib/libm387.so lib/libm387.so.0 lib/libm387.so.0.1 rescue/ldconfig sbin/ldconfig stand/i386 stand/i386-xen stand/i386pae-xen usr/X11R7/lib/modules/drivers/elographics_drv.so usr/X11R7/lib/modules/drivers/elographics_drv.so.1 usr/X11R7/lib/modules/drivers/geode_drv.so usr/X11R7/lib/modules/drivers/geode_drv.so.2 usr/X11R7/man/html4/elographics.html usr/X11R7/man/man4/elographics.4 usr/bin/pmc usr/include/pmc.h usr/lib/libi386.a usr/lib/libi386.so usr/lib/libi386.so.1 usr/lib/libi386.so.1.0 usr/lib/libi386_p.a usr/lib/libi386_pic.a usr/lib/libm387.a usr/lib/libm387.so usr/lib/libm387.so.0 usr/lib/libm387.so.0.1 usr/lib/libm387_p.a usr/lib/libm387_pic.a usr/lib/libpmc.a usr/lib/libpmc.so usr/lib/libpmc.so.1 usr/lib/libpmc.so.1.0 usr/lib/libpmc_p.a usr/lib/libpmc_pic.a usr/libexec/ld.so usr/sbin/apm usr/sbin/apmd usr/sbin/bad144 usr/sbin/ipwctl usr/sbin/ndiscvt usr/sbin/zzz EOF #echo "Fixing mail INBOX location" #if [ -d $root/var/mail -a -d $root/usr/mail ]; then # rmdir $root/var/mail # if [ "$?" != 0 ]; then # echo "Could not delete /var/mail" # exit 1 # fi # ln -s /usr/mail $root/var/mail #fi if [ "$osonly" = y ]; then echo "Completed. Warning: your old packages are still installed" exit fi echo "Removing all packages for wrong architecture or OS version" dopause for pkg in `pkg_info -K $root/var/db/pkg | awk '{print $1}'` do delete="" parch=`pkg_info -K $root/var/db/pkg -Q MACHINE_ARCH $pkg 2>/dev/null` if [ -z "$parch" ]; then echo "$pkg has already been deleted" elif [ "$parch" != $arch ]; then echo "Deleting $pkg for $parch" delete=1 else pvers=`pkg_info -K $root/var/db/pkg -Q OS_VERSION $pkg` pversmaj=`echo $pvers|awk '{print substr($1,1,1)}'` cvers=`echo $version|awk '{print substr($1,1,1)}'` if [ "$pversmaj" != "$cvers" ]; then echo "Deleting $pkg for $pvers" delete=1 fi fi if [ -n "$delete" ]; then if [ "$root" = / ]; then pkg_delete -fr $pkg || exit 1 else chroot $root /usr/sbin/pkg_delete -fr $pkg || exit 1 fi fi done