#!/bin/sh # -------+---------+---------+---------+---------+---------+---------+---------+ # Copyright (c) 2004 - Garance Alistair Drosehn <gad@FreeBSD.org>. # # 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. # # -------+---------+---------+---------+---------+---------+---------+---------+ # $FreeBSD$ # -------+---------+---------+---------+---------+---------+---------+---------+ # # This script does a 'make installworld' using the *old* versions of all # commands to do the work. It expects that the new kernel has been installed, # but that the system has not been rebooted (and is thus still running on the # previous kernel). This is useful when a major incompatible change is made, # and you want to do an installworld that uses NFS-mounted directories for # /usr/src and /usr/obj. This script was written for the change to # 64-bit time_t on FreeBSD/Sparc64, but it is not specific to that. # # IMPORTANT: This script does require that you are NOT YET running on # the new kernel that matches the 'world' that you want to install. # # -------+---------+---------+---------+---------+---------+---------+---------+ # This script expects that it will be run from /usr/src, or an # equivalent (perhaps NFS-mounted) directory. if [ -f MAINTAINERS -a -f UPDATING -a -f Makefile -a -f Makefile.inc1 ] ; then SOURCE_BWDIR="`make -V .OBJDIR`" else echo "This script must be run from /usr/src! (or equivalent)" exit 1 fi DOMAKE= DOMINI= SETMINPATH= SYMLINKS= VERBOSE= BADOPT= while test $# != 0 do case "$1" in -M) SETMINPATH=yes ;; -N) DOMINI=no ;; -S) echo "-S (symlinks) is ignored in installworld_oldk." ;; -Y) DOMINI=yes ;; -y) DOMAKE=yes ;; -n) DOMAKE=no ;; -v) VERBOSE=yes ;; *) echo "Invalid option: $1" ; BADOPT=yes ;; esac shift 1 done if [ -n "$BADOPT" ] ; then exit 1 fi echo "* + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - *" echo "* This script expects that a 'make installkernel' has already" echo "* been done, but that the system is still running the previous" echo "* kernel. Ie, that you have not rebooted." echo "*" echo "* Also note that this only does a PARTIAL installworld. You" echo "* will still have to do a full installworld after rebooting." echo "* + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - *" echo "" # See if the user wants us to create a mini-/bin inside of the # newly-installed kernel. These executables would only be used # *after* booting into the new kernel, so we want the new-world # versions of all files. # XXX - This is a idea which could be useful in many situations, but # it really should be implemented as an official make-target. # It would be particularly nice to make this a statically-linked # (and crunchgen-ed) collection of programs... if [ -z "${DOMINI}" -a -z "${DOMAKE}" ] ; then echo "Do you want a mini-/bin in that newly-installed /boot/kernel? " read -p "(y/n) ? " DOMINI remline echo " " elif [ -z "${DOMINI}" ] ; then DOMINI="${DOMAKE}" fi if [ -n "`echo /y/yes/okay/ok/ | grep -i \"/${DOMINI}/\"`" ] ; then KERNBINDIR=/boot/kernel/bin if [ -e ${KERNBINDIR} ] ; then rm -Rf ${KERNBINDIR} fi mkdir -p ${KERNBINDIR} # Much of this is done in a subshell, so values of DESTDIR, etc, # will only be in effect for this section of the script. ( DESTDIR=${KERNBINDIR} BINDIR="" NOINFO=YES NOMAN=YES export BINDIR DESTDIR NOINFO NOMAN MFLAG= for wantdir in bin/chflags bin/chmod bin/cp bin/ls bin/mkdir bin/mv bin/sh \ sbin/ifconfig sbin/mount sbin/mount_nfs sbin/reboot \ usr.bin/find usr.bin/xargs ; do if [ -n "$VERBOSE" ] ; then echo ".. Installing ${wantdir} to mini-/bin" fi (cd ${wantdir} && make ${MFLAG} install >/dev/null ) if [ $? -ne 0 ] ; then echo "** Error while in ${wantdir} doing 'make install'" echo "** for DESTDIR=${KERNBINDIR}" exit 1 fi done echo "Done building ${KERNBINDIR}" echo ) || exit 1 fi # Start out with no PATH at all. PATH= # Where all the binaries should be coming from. OW_BIN="/bin" OW_SBIN="/sbin" OW_UBIN="/usr/bin" OW_USBIN="/usr/sbin" OW_GUBIN="/usr/bin" MKTEMPCMD=/usr/bin/mktemp # I intentionally prefer to have a shorter name here... We just need a # unique name, we're not likely to be under attack during installworld! TMPHOLD=`"${MKTEMPCMD}" -q -d ${TMPDIR:-/tmp}/install-oldk.XXX` if [ $? -ne 0 ] ; then echo "** Unable to create temp program-holding directory" exit 1 fi # Set the most-restrictive value for PATH that the user is willing to # shoot for. The more restrictive we are here, the more likely we # will catch all references to "unexpected" executables. PATH=${TMPHOLD}:/sbin:/bin:/usr/sbin:/usr/bin if [ -n "$SETMINPATH" ] ; then PATH=${TMPHOLD} fi # Find the most-appropriate version of key commands for this script. # XXX - It would be nice if we could reliably find the exact kernel that # we booted up with, and check for the optional mini-/bin in it. COPYCMD=/missing/cp for chkexec in "/rescue/cp" /bin/cp ; do if [ -f "${chkexec}" ] ; then COPYCMD="${chkexec} -p" break fi done LINKCMD=/missing/ln for chkexec in "/rescue/ln" /bin/ln ; do if [ -f "${chkexec}" ] ; then LINKCMD="${chkexec}" break fi done COPYINFO="Copying" copy_exec () { srcdir="$1" cmdname="$2" alsoln="$3" srcfile="${srcdir}/${cmdname}" resfile="/rescue/${cmdname}" if [ -f "${resfile}" -a -x "${resfile}" ] ; then if [ -n "$VERBOSE" ] ; then echo ".. Linking ${TMPHOLD}/RESCUE to ${cmdname}" fi ${LINKCMD} "${TMPHOLD}/RESCUE" "${TMPHOLD}/${cmdname}" if [ $? -ne 0 ] ; then echo "** Error Linking '${cmdname}'" exit 1 fi elif [ -f "${srcfile}" -a -x "${srcfile}" ] ; then if [ -n "$VERBOSE" ] ; then echo ".. ${COPYINFO} ${srcfile}" fi ${COPYCMD} "${srcfile}" "${TMPHOLD}" if [ $? -ne 0 ] ; then echo "** Error ${COPYINFO} '${srcfile}'" exit 1 fi else echo "** Cannot find ${cmdname} in /rescue or ${srcdir}?" exit 1 fi if [ -n "${alsoln}" ] ; then if [ -n "$VERBOSE" ] ; then echo ".. Linking '${cmdname}' as '${alsoln}' " fi ${LINKCMD} "${TMPHOLD}/${cmdname}" "${TMPHOLD}/${alsoln}" if [ $? -ne 0 ] ; then echo "** Error Linking '${cmdname}'" exit 1 fi fi } # The programs listed in the following `do' loop are all the same programs # that the standard 'installworld' target wants to make copies of, except # that this has special-cases for `awk', `[', and `egrep'. This script # also adds the commands `cp', `install', `id' and `which', because those # are also *used* by the standard `make installworld' target, although # that target doesn't bother to make copies of those programs. The `sleep' # command is also added, but only because it is used in this script. And # `script' is included just because it can be useful when testing this script. # # Note that this means there will be two copies made of these files # (because the 'make installworld' target is still going to copy them a # second time). # Do the `cp' command first, because this script does so much with it. # This is done as a special case, because it's the initial program # from /rescue (if /rescue exists). chkfile="/rescue/cp" if [ -f "${chkfile}" -a -x "${chkfile}" ] ; then if [ -n "$VERBOSE" ] ; then echo ".. Copying ${chkfile} to 'RESCUE'" fi ${COPYCMD} "${chkfile}" "${TMPHOLD}/RESCUE" fi copy_exec "${OW_BIN}" cp # Do the `ln' command as the second one, for similar reasons. copy_exec "${OW_BIN}" ln # Awk is also called 'nawk' copy_exec "${OW_UBIN}" nawk awk # The `install' comand is not a special case in this script, # but it is in the installworld_newk script. copy_exec "${OW_UBIN}" install # Worried about the extra disk space that this script uses up in /tmp? Well, # just specify the -S option, and this script will create symlinks instead of # copying the files. Note that the original files might be NFS-mounted, and # /tmp might be a memory-based file system, so the `installworld' might go # much faster when copies are done here instead of symlinks. if [ -n "$SYMLINKS" ] ; then echo "The -S (symlinks) option is ignored in installworld_oldk" # COPYINFO="Linking to" # COPYCMD="ln -s" # LINKCMD="ln -s" fi for prog in cap_mkdb cat chflags chmod chown date \ echo find grep make mkdir mtree mv \ pwd_mkdb rm sed sh sysctl test true uname wc zic \ hostname id ls sleep script umount which xargs do gotmatch= for chkdir in "${OW_BIN}" "${OW_SBIN}" "${OW_UBIN}" "${OW_USBIN}" do if [ -f "${chkdir}/${prog}" -a -x "${chkdir}/${prog}" ] ; then gotmatch=yes copy_exec "${chkdir}" "${prog}" if [ $? -ne 0 ] ; then exit 1 fi break fi done if [ -z "$gotmatch" ] ; then echo "** Did not find '${prog}' ?" fi done # Special case to handle '[', which we know is the same as 'test' if [ -x ${TMPHOLD}/test ] ; then if [ -n "$VERBOSE" ] ; then echo ".. Linking 'test' as '[' " fi ${LINKCMD} ${TMPHOLD}/test ${TMPHOLD}/[ fi # Special case for 'egrep', which is the same as 'grep' if [ -x ${TMPHOLD}/grep ] ; then if [ -n "$VERBOSE" ] ; then echo ".. Linking 'grep' as 'egrep' " fi ${LINKCMD} ${TMPHOLD}/grep ${TMPHOLD}/egrep fi # Have to duplicate the standard makefile, to make a few changes. # First find the setting of PATH. Insert a line in front of that # which uses the (undocumented) .SHELL feature to get 'make' to # use the newer version of /bin/sh that we just made a copy of. # Then alter the PATH setting so that all make targets check our # directory of copied files first. If '-M' was given, then have # a PATH setting that looks ONLY at our copied files. # # XXX - the .SHELL feature did NOT seem to work the way that I # wanted it to, but that is not a problem for now. It can # be looked into at some later date... nawk '/^PATH=/ { \ print "# Try to get the make cmd to use an alternate /bin/sh." ; \ print ".SHELL : name=sh path=" TDIR "/sh" ; \ print "" ; \ if (WANTMIN == "yes") \ sub(/^PATH *=[ \t]*.*/, "PATH=\t" TDIR ); \ else \ sub(/^PATH *=[ \t]*/, "PATH=\t" TDIR ":"); \ } \ /-f Makefile.inc1/ { \ sub(/Makefile.inc1/, TDIR "/Makefile.inc1" ); \ } \ { print $0 }' \ "TDIR=${TMPHOLD}" "WANTMIN=${SETMINPATH}" Makefile > ${TMPHOLD}/Makefile # In the case of this script, we want the new libraries to be the # *last* things that are installed (since we will be running some # programs which expect the present libraries). However, we do # still have the problem that 'make' explicitly uses /bin/sh, so # the install of 'bin' must be delayed to after those libraries. # [Someone recently committed a total restructuring of Makefile.inc1, # so the following has to be setup such that it works with either # formats. That's why it seems to be doing everything twice.] nawk 'BEGIN { GOTSBIN = 0; } \ /^# Put initial settings/ { \ print "# Try to get the make cmd to use an alternate /bin/sh." ; \ print ".SHELL : name=sh path=" TDIR "/sh" ; \ print "" ; \ } \ /^SUBDIR=[\t ]*share\/info .*bin/ { \ print "# Try to get the make cmd to use an alternate /bin/sh." ; \ print ".SHELL : name=sh path=" TDIR "/sh" ; \ print "" ; \ } \ /exists\(.*\/sbin\)/ { \ if (GOTSBIN == 0) { \ GOTSBIN = 1; print "" ; \ print "# For installworld_oldk processing, forget" ; \ print "# all the subdirectories before sbin..."; \ print "SUBDIR=" ; \ } \ } \ /^SUBDIR\+=sbin/ { \ if (GOTSBIN == 0) { \ GOTSBIN = 1; print "" ; \ print "# For installworld_oldk processing, forget" ; \ print "# all the subdirectories before sbin..."; \ print "SUBDIR=" ; \ } \ } \ /^# These are last, since it is/ { \ print "# These dirs are done last for installworld_oldk." ; \ print ".if exists(${.CURDIR}/lib)" ; \ print "SUBDIR+= lib" ; \ print ".endif" ; \ print ".if exists(${.CURDIR}/libexec)" ; \ print "SUBDIR+= libexec"; \ print ".endif"; \ print ".if exists(${.CURDIR}/bin)" ; \ print "SUBDIR+= bin"; \ print ".endif"; \ } \ /-f Makefile.inc1/ { \ sub(/Makefile.inc1/, TDIR "/Makefile.inc1" ); \ } \ { print $0 } \ END { \ if (GOTSBIN == 0) { \ print "ERROR: No \"sbin\" match in Makefile.inc1" > "/dev/stderr"; \ } \ }' \ "TDIR=${TMPHOLD}" Makefile.inc1 > "${TMPHOLD}/Makefile.inc1" echo "" echo "The key programs needed by 'make installworld' have been copied." if [ -n "$VERBOSE" ] ; then ls -C ${TMPHOLD} echo "" fi # XXX - Add some "do-nothing" settings so that we won't clobber any # more than we need to. I wish we could avoid having to set # them as environment variables, particularly for the case # where the user chooses to type in all the commands. The # more a user has to type, the more chances for a typo... NO_FORTRAN=yes NO_RESCUE=yes NOGAMES=yes NOINFO=yes NOMAN=yes NOSHARE=yes export NO_FORTRAN NO_RESCUE NOGAMES NOINFO NOMAN NOSHARE # The sparc64_installcheck will want this in the environment. NEWSPARC_TIMETYPE=__int64_t export NEWSPARC_TIMETYPE # See if the user wants us to go ahead with 'installworld', # or just tell them what steps they need to do. if [ -z "${DOMAKE}" ] ; then echo "Do you want to proceed with the abridged 'installworld'? " read -p "(y/n) ? " DOMAKE remline echo " " fi if [ -n "`echo /y/yes/okay/ok/ | grep -i \"/${DOMAKE}/\"`" ] ; then echo "Okay then, this script has set:" echo " NO_FORTRAN NO_RESCUE NOGAMES NOINFO NOMAN NOSHARE" echo "and:" echo " NEWSPARC_TIMETYPE=__int64_t" echo " PATH=${PATH}" echo "and will now execute the command:" echo " make -f ${TMPHOLD}/Makefile installworld" sleep 4 make -f ${TMPHOLD}/Makefile installworld else echo "When you are ready to continue, enter the commands:" echo " NO_FORTRAN=yes" echo " NO_RESCUE=yes" echo " NOGAMES=yes" echo " NOINFO=yes" echo " NOMAN=yes" echo " NOSHARE=yes" echo " export NO_FORTRAN NO_RESCUE NOGAMES NOINFO NOMAN NOSHARE" echo " NEWSPARC_TIMETYPE=__int64_t" echo " export NEWSPARC_TIMETYPE" echo "and:" echo " PATH=${PATH}" echo "or:" echo " PATH=${TMPHOLD}:\${PATH}" echo "and:" echo " make -f ${TMPHOLD}/Makefile installworld" fi