If you have space to have two parallel filesystem trees, you could possibly have something like /bin
and /bin.old
. Repeat for all top-level directories.
Installation would be a case of creating /bin.new
, copying from the live system, overlaying the new files, and then switching /bin
to /bin.old
and /bin.new to
/bin`, etc. Rollback would be a switch back.
# Prepare a new filesystem tree
#
rm -rf /*.new /*.old
for item in /*
do
cp -al "$item" "$item.new" # Links avoid using too much disk space
done
# Overlay. Because we linked in the previous step, we must remove
# (or rename) each file that we're going to change. Do not change
# or replace any file in situ
#
# If you have space for two full filesystem trees you could just copy
# instead of linking, which could simplify this update code section.
#
echo installation code goes here
# Switch over
#
OPATH="$PATH" PATH="/bin.old:/bin:/bin.new:$PATH"
for item in /*.new
do
live="${item%.new}"
mv -f "$live" "$live.old"
mv -f "$item" "$live"
done
# Post-installation steps (rebuild kernel links, etc.)
#
echo post-installation code goes here
You might want to have vital system binaries in a place that could not get updated, so that the rollback didn't get burned by a poor shell. However, that's a bit of a chicken and egg situation, where you then by definition cannot update this code. Tricky.