mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-29 12:03:03 +00:00
455 lines
16 KiB
Plaintext
455 lines
16 KiB
Plaintext
|
#!/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
|