busybox.inc: Create temporary links during install

Message ID CH0PR20MB3948E1BBAA0BF3FB61BAF097BB289@CH0PR20MB3948.namprd20.prod.outlook.com
State New
Headers show
Series busybox.inc: Create temporary links during install | expand

Commit Message

Bryan Evenson Feb. 3, 2022, 10:08 p.m. UTC
Other packages may use busybox applets in their installation
scripts.  If busybox is also being upgraded, other package upgrades
may run between when the old busybox alternative links are removed
and when the new alternative links are installed.  This may prevent
other packages from installing correctly.

Copies the busybox binary and busybox.links files to a temporary
directory.  Installs temporary alternative links for each listed
link that points to the temporary binary that are live during the
busybox installation process.

Removes the prerm and populate_packages_updatealternatives steps
that were intended for the same purpose.

Tested with an core-image-minimal based image which uses opkg for
its package manager and sysvinit for init.

Signed-off-by: Bryan Evenson <bevenson@melinkcorp.com>
---
 meta/recipes-core/busybox/busybox.inc | 156 +++++++++++++-------------
 1 file changed, 78 insertions(+), 78 deletions(-)

--

Patch

diff --git a/meta/recipes-core/busybox/busybox.inc b/meta/recipes-core/busybox/busybox.inc
index 622325aabb..c0b63ad2c0 100644
--- a/meta/recipes-core/busybox/busybox.inc
+++ b/meta/recipes-core/busybox/busybox.inc
@@ -387,95 +387,95 @@  python do_package:prepend () {
         set_alternative_vars("${sysconfdir}/busybox.links.suid", "${base_bindir}/busybox.suid")
 }
 
-# This part of code is dedicated to the on target upgrade problem.  It's known
-# that if we don't make appropriate symlinks before update-alternatives calls,
-# there will be errors indicating missing commands such as 'sed'.
-# These symlinks will later be updated by update-alternatives calls.
-# The update-alternatives.bbclass' postinst script runs firstly before other
-# postinst, but this part of code needs run firstly, so add this funtion.
-python populate_packages_updatealternatives:append() {
-    postinst = """
-test -n 2 > /dev/null || alias test='busybox test'
-if test "x$D" = "x"; then
-    # Remove busybox.nosuid if it's a symlink, because this situation indicates
-    # that we're installing or upgrading to a one-binary busybox.
-    if test -h ${base_bindir}/busybox.nosuid; then
-        rm -f ${base_bindir}/busybox.nosuid
-    fi
-    for suffix in "" ".nosuid" ".suid"; do
-        if test -e ${sysconfdir}/busybox.links$suffix; then
-            while read link; do
-                if test ! -e "$link"; then
-                    # we can use busybox here because even if we are using splitted busybox
-                    # we've made a symlink from /bin/busybox to /bin/busybox.nosuid.
-                    busybox rm -f $link
-                    busybox ln -s "${base_bindir}/busybox$suffix" $link
-                fi
-            done < ${sysconfdir}/busybox.links$suffix
-        fi
-    done
-fi
-if grep -q "^${base_bindir}/bash$" $D${sysconfdir}/busybox.links*; then
-    grep -q "^${base_bindir}/bash$" $D${sysconfdir}/shells || echo ${base_bindir}/bash >> $D${sysconfdir}/shells
-fi
-
-"""
-    d.prependVar('pkg_postinst:%s' % pkg, postinst)
-}
-
-pkg_postinst:${PN}:prepend () {
-        # Need path to saved utils, but they may have be removed on upgrade of busybox
-        # Only use shell to get paths. Also capture if busybox was saved.
-        BUSYBOX=""
-        if [ "x$D" = "x" ] ; then 
+pkg_postinst:${PN}:append () {
+        if [ "x$D" = "x" ] ; then
+           # Older versions may have added a temporary directory and an alternative
+           # to sh in a prerm step.  Remove these if they are present.
            for busybox_rmdir in /tmp/busyboxrm-*; do
                if [ "$busybox_rmdir" != '/tmp/busyboxrm-*' ] ; then
-                  export PATH=$busybox_rmdir:$PATH
                   if [ -e $busybox_rmdir/busybox* ] ; then
                     BUSYBOX="$busybox_rmdir/busybox*"
+                    update-alternatives --remove sh $BUSYBOX
+                    rm -f $BUSYBOX
                   fi
                fi
            done
-        fi
-}
 
-pkg_postinst:${PN}:append () {
-        # If busybox exists in the remove directory it is because it was the only shell left.
-        if [ "x$D" = "x" ] ; then
-           if [ "x$BUSYBOX" != "x" ] ; then
-              update-alternatives --remove sh $BUSYBOX
-              rm -f $BUSYBOX
-           fi
+           # Remove the temporary alternatives
+           for busybox_preinstdir in /tmp/busyboxpreinst-*; do
+               if [ "$busybox_preinstdir" != '/tmp/busyboxpreinst-*' ] ; then
+                  BUSYBOX_PREINST_DIR="$busybox_preinstdir"
+                  BUSYBOX="$BUSYBOX_PREINST_DIR/busybox"
+                  if [ -e $BUSYBOX ] ; then
+                      for suffix in "" ".nosuid" ".suid"; do
+                          if [ -e $BUSYBOX_PREINST_DIR/busybox.links$suffix ] ; then
+                              while read link; do
+                                  update-alternatives --remove $($BUSYBOX basename $link) $BUSYBOX
+                              done < $BUSYBOX_PREINST_DIR/busybox.links$suffix
+                          fi
+                      done
+                  fi
+                  rm -rf $BUSYBOX_PREINST_DIR
+               fi
+           done
         fi
 } 
 
-pkg_prerm:${PN} () {
-	# This is so you can make busybox commit suicide - removing busybox with no other packages
-	# providing its files, this will make update-alternatives work, but the update-rc.d part
-	# for syslog, httpd and/or udhcpd will fail if there is no other package providing sh
-	tmpdir=`mktemp -d /tmp/busyboxrm-XXXXXX`
-	ln -s ${base_bindir}/busybox $tmpdir/[
-	ln -s ${base_bindir}/busybox $tmpdir/test
-	ln -s ${base_bindir}/busybox $tmpdir/head
-	ln -s ${base_bindir}/busybox $tmpdir/sh
-	ln -s ${base_bindir}/busybox $tmpdir/basename
-	ln -s ${base_bindir}/busybox $tmpdir/echo
-	ln -s ${base_bindir}/busybox $tmpdir/mv
-	ln -s ${base_bindir}/busybox $tmpdir/ln
-	ln -s ${base_bindir}/busybox $tmpdir/dirname
-	ln -s ${base_bindir}/busybox $tmpdir/rm
-	ln -s ${base_bindir}/busybox $tmpdir/sed
-	ln -s ${base_bindir}/busybox $tmpdir/sort
-	ln -s ${base_bindir}/busybox $tmpdir/grep
-	ln -s ${base_bindir}/busybox $tmpdir/tail
-	export PATH=$PATH:$tmpdir
-
-        # If busybox is the shell, we need to save it since its the lowest priority shell
-        # Register saved bitbake as the lowest priority shell possible as back up.
-        if [ -n "$(readlink -f /bin/sh | grep busybox)" ] ; then
-           BUSYBOX=$(readlink -f /bin/sh)
-           cp $BUSYBOX $tmpdir/$(basename $BUSYBOX)
-           update-alternatives --install /bin/sh sh $tmpdir/$(basename $BUSYBOX) 1 
+pkg_preinst:${PN} () {
+
+        # Create a temporary copy the busybox binary and the links files.  Then,
+        # install an alternative link for all the links.  Other packages use these
+        # commands during their upgrade process.  This ensures the links are available
+        # to all the other packages.  We do this in the preinst step because it is
+        # the first step guaranteed to be used from the new package.  The prerm is
+        # used from the old package.  Placing this here ensures it runs on upgrade even
+        # on older systems.
+
+        if [ "x$D" = "x" ] ; then
+           # Create a temporary directory for the busybox binary and the link lists
+           BUSYBOX=${base_bindir}/busybox
+           BUSYBOX_TMP_DIR=`$BUSYBOX mktemp -d /tmp/busyboxpreinst-XXXXXX`
+           BUSYBOX_TMP_LOC="$BUSYBOX_TMP_DIR/busybox"
+           $BUSYBOX cp $BUSYBOX $BUSYBOX_TMP_LOC
+
+           # Commands needed by update-alternatives may not exist anymore.  Set softlinks
+           # for these commands so update-alternatives will function.
+           $BUSYBOX ln -s $BUSYBOX_TMP_LOC $BUSYBOX_TMP_DIR/[
+           $BUSYBOX ln -s $BUSYBOX_TMP_LOC $BUSYBOX_TMP_DIR/test
+           $BUSYBOX ln -s $BUSYBOX_TMP_LOC $BUSYBOX_TMP_DIR/head
+           $BUSYBOX ln -s $BUSYBOX_TMP_LOC $BUSYBOX_TMP_DIR/sh
+           $BUSYBOX ln -s $BUSYBOX_TMP_LOC $BUSYBOX_TMP_DIR/basename
+           $BUSYBOX ln -s $BUSYBOX_TMP_LOC $BUSYBOX_TMP_DIR/echo
+           $BUSYBOX ln -s $BUSYBOX_TMP_LOC $BUSYBOX_TMP_DIR/mv
+           $BUSYBOX ln -s $BUSYBOX_TMP_LOC $BUSYBOX_TMP_DIR/ln
+           $BUSYBOX ln -s $BUSYBOX_TMP_LOC $BUSYBOX_TMP_DIR/dirname
+           $BUSYBOX ln -s $BUSYBOX_TMP_LOC $BUSYBOX_TMP_DIR/rm
+           $BUSYBOX ln -s $BUSYBOX_TMP_LOC $BUSYBOX_TMP_DIR/sed
+           $BUSYBOX ln -s $BUSYBOX_TMP_LOC $BUSYBOX_TMP_DIR/sort
+           $BUSYBOX ln -s $BUSYBOX_TMP_LOC $BUSYBOX_TMP_DIR/grep
+           $BUSYBOX ln -s $BUSYBOX_TMP_LOC $BUSYBOX_TMP_DIR/tail
+           $BUSYBOX ln -s $BUSYBOX_TMP_LOC $BUSYBOX_TMP_DIR/cp
+
+           # Export the path to the temporary directory so update-alternatives can find the
+           # new links
+           OLD_PATH=$PATH
+           export PATH=$PATH:$BUSYBOX_TMP_DIR
+
+           # Go through all the links and install an alternative that points to the temporary
+           # busybox binary.
+           for suffix in "" ".nosuid" ".suid"; do
+               if [ -e ${sysconfdir}/busybox.links$suffix ] ; then
+                   cp ${sysconfdir}/busybox.links$suffix $BUSYBOX_TMP_DIR
+                   while read link; do
+                       # Old packages may have installed an alternative to sh at priority 1.
+                       # Install these at priority 2 to avoid conflict.
+                       update-alternatives --install $link $(basename $link) $BUSYBOX_TMP_LOC 2
+                   done < $BUSYBOX_TMP_DIR/busybox.links$suffix
+               fi
+           done
+
+           # Reset PATH to its previous value
+           PATH=$OLD_PATH
         fi
 }