Index: usr.sbin/freebsd-update/freebsd-update.8 =================================================================== --- usr.sbin/freebsd-update/freebsd-update.8 (revision 282245) +++ usr.sbin/freebsd-update/freebsd-update.8 (working copy) @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd July 14, 2010 +.Dd March 2, 2015 .Dt FREEBSD-UPDATE 8 .Os FreeBSD .Sh NAME @@ -36,10 +36,12 @@ .Op Fl b Ar basedir .Op Fl d Ar workdir .Op Fl f Ar conffile +.Op Fl F .Op Fl k Ar KEY .Op Fl r Ar newrelease .Op Fl s Ar server .Op Fl t Ar address +.Op Fl -not-running-from-cron .Cm command ... .Sh DESCRIPTION The @@ -49,21 +51,21 @@ updates to the FreeBSD base system. Note that updates are only available if they are being built for the FreeBSD release and architecture being used; in particular, the .Fx -Security Team only builds updates for releases shipped in binary form +Security Team only builds updates for releases shipped in binary form by the .Fx Release Engineering Team, e.g., .Fx -7.3-RELEASE and +9.3-RELEASE and .Fx -8.0, but not +10.1-RELEASE, but not .Fx -6.3-STABLE or +9.3-STABLE or .Fx -9.0-CURRENT. +11-CURRENT. .Sh OPTIONS The following options are supported: -.Bl -tag -width "-f conffile" +.Bl -tag -width "-r newrelease" .It Fl b Ar basedir Operate on a system mounted at .Ar basedir . @@ -81,6 +83,10 @@ Read configuration options from .Ar conffile . (default: .Pa /etc/freebsd-update.conf ) +.It Fl F +Force +.Nm Cm fetch +to proceed where it normally would not, such as an unfinished upgrade .It Fl k Ar KEY Trust an RSA key with SHA256 of .Ar KEY . @@ -98,13 +104,21 @@ Mail output of command, if any, to .Ar address . (default: root, or as given in the configuration file.) +.It Fl -not-running-from-cron +Force +.Nm Cm fetch +to proceed when there is no controlling tty. +This is for use by automated scripts and orchestration tools. +Please do not run +.Nm Cm fetch +from crontab or similar using this flag, see: +.Nm Cm cron .El .Sh COMMANDS The .Cm command can be any one of the following: -.Pp -.Bl -tag -width "-f conffile" +.Bl -tag -width "rollback" .It Cm fetch Based on the currently installed world and the configuration options set, fetch all available binary updates. @@ -128,6 +142,11 @@ Fetch files necessary for upgrading to a Before using this command, make sure that you read the announcement and release notes for the new release in case there are any special steps needed for upgrading. +Note that this command may require up to 500 MB of space in +.Ar workdir +depending on which components of the +.Fx +base system are installed. .It Cm install Install the most recently fetched updates or upgrade. .It Cm rollback @@ -149,7 +168,7 @@ other than 3AM, to avoid overly imposing on the server(s) hosting the updates. .It In spite of its name, -.Cm +.Nm IDS should not be relied upon as an "Intrusion Detection System", since if the system has been tampered with it cannot be trusted to operate correctly. @@ -158,11 +177,11 @@ purposes, make sure you boot from a secu .El .Sh FILES .Bl -tag -width "/etc/freebsd-update.conf" -.It /etc/freebsd-update.conf +.It Pa /etc/freebsd-update.conf Default location of the .Nm configuration file. -.It /var/db/freebsd-update/ +.It Pa /var/db/freebsd-update/ Default location where .Nm stores temporary files and downloaded updates. @@ -170,4 +189,4 @@ stores temporary files and downloaded up .Sh SEE ALSO .Xr freebsd-update.conf 5 .Sh AUTHORS -.An Colin Percival Aq cperciva@FreeBSD.org +.An Colin Percival Aq Mt cperciva@FreeBSD.org Index: usr.sbin/freebsd-update/freebsd-update.sh =================================================================== --- usr.sbin/freebsd-update/freebsd-update.sh (revision 282245) +++ usr.sbin/freebsd-update/freebsd-update.sh (working copy) @@ -43,12 +43,15 @@ Options: (default: /var/db/freebsd-update/) -f conffile -- Read configuration options from conffile (default: /etc/freebsd-update.conf) + -F -- Force a fetch operation to proceed -k KEY -- Trust an RSA key with SHA256 hash of KEY -r release -- Target for upgrade (e.g., 6.2-RELEASE) -s server -- Server from which to fetch updates (default: update.FreeBSD.org) -t address -- Mail output of cron command, if any, to address (default: root) + --not-running-from-cron + -- Run without a tty, for use by automated tools Commands: fetch -- Fetch updates from server cron -- Sleep rand(3600) seconds, fetch updates, and send an @@ -284,6 +287,9 @@ config_TargetRelease () { else return 1 fi + if echo ${TARGETRELEASE} | grep -qE '^[0-9.]+$'; then + TARGETRELEASE="${TARGETRELEASE}-RELEASE" + fi } # Define what happens to output of utilities @@ -396,6 +402,12 @@ init_params () { # No commands specified yet COMMANDS="" + + # Force fetch to proceed + FORCEFETCH=0 + + # Run without a TTY + NOTTYOK=0 } # Parse the command line @@ -408,6 +420,12 @@ parse_cmdline () { if [ ! -z "${CONFFILE}" ]; then usage; fi shift; CONFFILE="$1" ;; + -F) + FORCEFETCH=1 + ;; + --not-running-from-cron) + NOTTYOK=1 + ;; # Configuration file equivalents -b) @@ -569,7 +587,7 @@ fetch_setup_verboselevel () { # running *-p[0-9]+, strip off the last part; if the # user is running -SECURITY, call it -RELEASE. Chdir # into the working directory. -fetch_check_params () { +fetchupgrade_check_params () { export HTTP_USER_AGENT="freebsd-update (${COMMAND}, `uname -r`)" _SERVERNAME_z=\ @@ -577,6 +595,7 @@ fetch_check_params () { _KEYPRINT_z="Key must be given via -k option or configuration file." _KEYPRINT_bad="Invalid key fingerprint: " _WORKDIR_bad="Directory does not exist or is not writable: " + _WORKDIR_bad2="Directory is not on a persistent filesystem: " if [ -z "${SERVERNAME}" ]; then echo -n "`basename $0`: " @@ -600,6 +619,13 @@ fetch_check_params () { echo ${WORKDIR} exit 1 fi + case `df -T ${WORKDIR}` in */dev/md[0-9]* | *tmpfs*) + echo -n "`basename $0`: " + echo -n "${_WORKDIR_bad2}" + echo ${WORKDIR} + exit 1 + ;; + esac chmod 700 ${WORKDIR} cd ${WORKDIR} || exit 1 @@ -652,9 +678,29 @@ fetch_check_params () { BDHASH=`echo ${BASEDIR} | sha256 -q` } +# Perform sanity checks etc. before fetching updates. +fetch_check_params () { + fetchupgrade_check_params + + if ! [ -z "${TARGETRELEASE}" ]; then + echo -n "`basename $0`: " + echo -n "-r option is meaningless with 'fetch' command. " + echo "(Did you mean 'upgrade' instead?)" + exit 1 + fi + + # Check that we have updates ready to install + if [ -f ${BDHASH}-install/kerneldone -a $FORCEFETCH -eq 0 ]; then + echo "You have a partially completed upgrade pending" + echo "Run '$0 install' first." + echo "Run '$0 fetch -F' to proceed anyway." + exit 1 + fi +} + # Perform sanity checks etc. before fetching upgrades. upgrade_check_params () { - fetch_check_params + fetchupgrade_check_params # Unless set otherwise, we're upgrading to the same kernel config. NKERNCONF=${KERNCONF} @@ -1185,7 +1231,7 @@ fetch_metadata_sanity () { # Some aliases to save space later: ${P} is a character which can # appear in a path; ${M} is the four numeric metadata fields; and # ${H} is a sha256 hash. - P="[-+./:=%@_[~[:alnum:]]" + P="[-+./:=,%@_[~[:alnum:]]" M="[0-9]+\|[0-9]+\|[0-9]+\|[0-9]+" H="[0-9a-f]{64}" @@ -1456,7 +1502,7 @@ fetch_inspect_system () { sort -k 3,3 -t '|' > $2.tmp rm filelist - # Check if an error occured during system inspection + # Check if an error occurred during system inspection if [ -f .err ]; then return 1 fi @@ -2240,6 +2286,19 @@ upgrade_oldall_to_oldnew () { mv $2 $3 } +# Helper for upgrade_merge: Return zero true iff the two files differ only +# in the contents of their RCS tags. +samef () { + X=`sed -E 's/\\$FreeBSD.*\\$/\$FreeBSD\$/' < $1 | ${SHA256}` + Y=`sed -E 's/\\$FreeBSD.*\\$/\$FreeBSD\$/' < $2 | ${SHA256}` + + if [ $X = $Y ]; then + return 0; + else + return 1; + fi +} + # From the list of "old" files in $1, merge changes in $2 with those in $3, # and update $3 to reflect the hashes of merged files. upgrade_merge () { @@ -2323,6 +2382,14 @@ upgrade_merge () { # Ask the user to handle any files which didn't merge. while read F; do + # If the installed file differs from the version in + # the old release only due to RCS tag expansion + # then just use the version in the new release. + if samef merge/old/${F} merge/${OLDRELNUM}/${F}; then + cp merge/${RELNUM}/${F} merge/new/${F} + continue + fi + cat <<-EOF The following file could not be merged automatically: ${F} @@ -2337,9 +2404,18 @@ manually... # Ask the user to confirm that he likes how the result # of merging files. while read F; do - # Skip files which haven't changed. - if [ -f merge/new/${F} ] && - cmp -s merge/old/${F} merge/new/${F}; then + # Skip files which haven't changed except possibly + # in their RCS tags. + if [ -f merge/old/${F} ] && [ -f merge/new/${F} ] && + samef merge/old/${F} merge/new/${F}; then + continue + fi + + # Skip files where the installed file differs from + # the old file only due to RCS tags. + if [ -f merge/old/${F} ] && + [ -f merge/${OLDRELNUM}/${F} ] && + samef merge/old/${F} merge/${OLDRELNUM}/${F}; then continue fi @@ -2526,6 +2602,10 @@ upgrade_run () { # Leave a note behind to tell the "install" command that the kernel # needs to be installed before the world. touch ${BDHASH}-install/kernelfirst + + # Remind the user that they need to run "freebsd-update install" + # to install the downloaded bits, in case they didn't RTFM. + echo "To install the downloaded upgrades, run \"$0 install\"." } # Make sure that all the file hashes mentioned in $@ have corresponding @@ -2577,14 +2657,14 @@ backup_kernel_finddir () { while true ; do # Pathname does not exist, so it is OK use that name # for backup directory. - if [ ! -e $BACKUPKERNELDIR ]; then + if [ ! -e $BASEDIR/$BACKUPKERNELDIR ]; then return 0 fi # If directory do exist, we only use if it has our # marker file. - if [ -d $BACKUPKERNELDIR -a \ - -e $BACKUPKERNELDIR/.freebsd-update ]; then + if [ -d $BASEDIR/$BACKUPKERNELDIR -a \ + -e $BASEDIR/$BACKUPKERNELDIR/.freebsd-update ]; then return 0 fi @@ -2592,7 +2672,7 @@ backup_kernel_finddir () { # the end and try again. CNT=$((CNT + 1)) if [ $CNT -gt 9 ]; then - echo "Could not find valid backup dir ($BACKUPKERNELDIR)" + echo "Could not find valid backup dir ($BASEDIR/$BACKUPKERNELDIR)" exit 1 fi BACKUPKERNELDIR="`echo $BACKUPKERNELDIR | sed -Ee 's/[0-9]\$//'`" @@ -2619,17 +2699,17 @@ backup_kernel () { # Remove old kernel backup files. If $BACKUPKERNELDIR was # "not ours", backup_kernel_finddir would have exited, so # deleting the directory content is as safe as we can make it. - if [ -d $BACKUPKERNELDIR ]; then - rm -fr $BACKUPKERNELDIR + if [ -d $BASEDIR/$BACKUPKERNELDIR ]; then + rm -fr $BASEDIR/$BACKUPKERNELDIR fi # Create directories for backup. - mkdir -p $BACKUPKERNELDIR - mtree -cdn -p "${KERNELDIR}" | \ - mtree -Ue -p "${BACKUPKERNELDIR}" > /dev/null + mkdir -p $BASEDIR/$BACKUPKERNELDIR + mtree -cdn -p "${BASEDIR}/${KERNELDIR}" | \ + mtree -Ue -p "${BASEDIR}/${BACKUPKERNELDIR}" > /dev/null # Mark the directory as having been created by freebsd-update. - touch $BACKUPKERNELDIR/.freebsd-update + touch $BASEDIR/$BACKUPKERNELDIR/.freebsd-update if [ $? -ne 0 ]; then echo "Could not create kernel backup directory" exit 1 @@ -2647,8 +2727,8 @@ backup_kernel () { fi # Backup all the kernel files using hardlinks. - (cd $KERNELDIR && find . -type f $FINDFILTER -exec \ - cp -pl '{}' ${BACKUPKERNELDIR}/'{}' \;) + (cd ${BASEDIR}/${KERNELDIR} && find . -type f $FINDFILTER -exec \ + cp -pl '{}' ${BASEDIR}/${BACKUPKERNELDIR}/'{}' \;) # Re-enable patchname expansion. set +f @@ -2746,7 +2826,7 @@ install_files () { # Update linker.hints if necessary if [ -s INDEX-OLD -o -s INDEX-NEW ]; then - kldxref -R /boot/ 2>/dev/null + kldxref -R ${BASEDIR}/boot/ 2>/dev/null fi # We've finished updating the kernel. @@ -2797,14 +2877,14 @@ Kernel updates have been installed. Ple install_delete INDEX-OLD INDEX-NEW || return 1 # Rebuild /etc/spwd.db and /etc/pwd.db if necessary. - if [ /etc/master.passwd -nt /etc/spwd.db ] || - [ /etc/master.passwd -nt /etc/pwd.db ]; then - pwd_mkdb /etc/master.passwd + if [ ${BASEDIR}/etc/master.passwd -nt ${BASEDIR}/etc/spwd.db ] || + [ ${BASEDIR}/etc/master.passwd -nt ${BASEDIR}/etc/pwd.db ]; then + pwd_mkdb -d ${BASEDIR}/etc ${BASEDIR}/etc/master.passwd fi # Rebuild /etc/login.conf.db if necessary. - if [ /etc/login.conf -nt /etc/login.conf.db ]; then - cap_mkdb /etc/login.conf + if [ ${BASEDIR}/etc/login.conf -nt ${BASEDIR}/etc/login.conf.db ]; then + cap_mkdb ${BASEDIR}/etc/login.conf fi # We've finished installing the world and deleting old files @@ -3011,21 +3091,8 @@ IDS_compare () { mv INDEX-NOTMATCHING.tmp INDEX-NOTMATCHING # Go through the lines and print warnings. - while read LINE; do - FPATH=`echo "${LINE}" | cut -f 1 -d '|'` - TYPE=`echo "${LINE}" | cut -f 2 -d '|'` - OWNER=`echo "${LINE}" | cut -f 3 -d '|'` - GROUP=`echo "${LINE}" | cut -f 4 -d '|'` - PERM=`echo "${LINE}" | cut -f 5 -d '|'` - HASH=`echo "${LINE}" | cut -f 6 -d '|'` - LINK=`echo "${LINE}" | cut -f 7 -d '|'` - P_TYPE=`echo "${LINE}" | cut -f 8 -d '|'` - P_OWNER=`echo "${LINE}" | cut -f 9 -d '|'` - P_GROUP=`echo "${LINE}" | cut -f 10 -d '|'` - P_PERM=`echo "${LINE}" | cut -f 11 -d '|'` - P_HASH=`echo "${LINE}" | cut -f 12 -d '|'` - P_LINK=`echo "${LINE}" | cut -f 13 -d '|'` - + local IFS='|' + while read FPATH TYPE OWNER GROUP PERM HASH LINK P_TYPE P_OWNER P_GROUP P_PERM P_HASH P_LINK; do # Warn about different object types. if ! [ "${TYPE}" = "${P_TYPE}" ]; then echo -n "${FPATH} is a " @@ -3153,7 +3220,7 @@ get_params () { # Fetch command. Make sure that we're being called # interactively, then run fetch_check_params and fetch_run cmd_fetch () { - if [ ! -t 0 ]; then + if [ ! -t 0 -a $NOTTYOK -eq 0 ]; then echo -n "`basename $0` fetch should not " echo "be run non-interactively." echo "Run `basename $0` cron instead."