#!/bin/bash # # Stage4 addons setup script # ############################################################################### # Support stage4 addons residing under '/opt/openslx/addons'. # This script will loop over all addons found, in the form of # directories containing directory structures relative to '/' # # Additionally addons are expected to provide: # * /addon-required -> script to check whether the # addon should be installed (exit 0) or not (exit 1). # # * /opt/openslx/etc/.whiteout -> list of files # that were removed during the addon installation and thus need to be # removed after the addon was installed. # # * /opt/openslx/etc/ ld.so.cache -> ld cache containing # the newly installed libraries. CAVE: multiple addons -> ld cache combination # ### CURRENTLY NOT EXECUTED # * /addon-init -> script that will be automatically # be executed after the addon was installed. # NOTE: question remains if this should be done within stage3 # or by chroot'ing into the stage4 before executing it. ### CURRENTLY NOT EXECUTED: Since whiteouts could be handled for _all_addons # Check if we even have any addons to process if ! [ -d "$NEWROOT/opt/openslx/addons" ]; then echo "No stage4 addons found." exit 0 fi # This just activates the ldconfig service to run during the sysinit target # Since addons are likely to install libs, this is necessary to garantee # that the live system "sees" the libraries. activate_stage4_ldconfig() { local service_path="/opt/openslx/services/ldconfig-stage4.service" [ -e "$service_path" ] || return 1 local target_dir="${NEWROOT}/etc/systemd/system/sysinit.target.wants" mkdir -p "$target_dir" cp -f "$service_path" "${NEWROOT}/etc/systemd/system/${service_path##*/}" ln -sf "../${service_path##*/}" "${target_dir}/${service_path##*/}" } setup_addon() { if [ ! -d "$1" ]; then echo "Given '$1' not a directory, skipping." return 1 fi local addon_dir="$1" cd "$addon_dir" || return 1 if ! bash addon-required 2>&1 ; then echo "'$addon_dir/addon-required' missing or returned non-zero, skipping..." return 1 fi # purge addon-* files rm -f -- addon-* # make directory struct, replicate owners/perms - should we keep-old-files? echo "Replicating directory tree in $NEWROOT" # Doing this once in advance instead of doing a mkdir for each file's parent directory # every time in the loop below brought us from 3.6s down to 2.2s for VMware find . -type d -print0 | tar --no-recursion --null -T - -c | tar -C "$NEWROOT" --keep-old-files -x # move all the files over echo "Moving files over" while read -r entry || [ -n "$entry" ]; do # Doing the mv in parallel brought us from 2.2s to 380ms for VMware (~850 files), # but I've no idea if there'd be an adverse effect if we had a lot more files # to move and we'd spawn thousands of mv processes in parallel... mv -f -- "$entry" "${NEWROOT}/${entry}" & done < <( find . -not -type d ) # do it this way so we don't end up with a pipe-subshell wait # and can properly wait for all the mv processes. # post merge: remove files marked as whiteouts # (e.g. they were removed during the addon installation) echo "Applying whiteouts" for WHITEOUT in "$NEWROOT/opt/openslx/etc/"*.whiteout; do [ -e "$WHITEOUT" ] || continue while read -r line; do rm -f -- "${NEWROOT}/${line}" done < "$WHITEOUT" done return 0 } active=() for addon in "${NEWROOT}/opt/openslx/addons/"*; do if setup_addon "$addon"; then active+=("${addon#"${NEWROOT}/opt/openslx/addons/"}") echo "Activated '$addon' (@ $(date +%s))" fi done # if only one addon was installed, use its pre-generated ld.so.cache # if more than one were installed, make sure ldconfig is called in stage4 if [ "${#active[@]}" -eq 1 ]; then addon_cache="${NEWROOT}/opt/openslx/etc/${active[0]}.ld.so.cache" if [ -e "$addon_cache" ]; then echo "Using ld.so.cache of '${active[0]}'." mv -f -- "${NEWROOT}/etc/ld.so.cache"{,.stage4} mv -f -- "$addon_cache" "${NEWROOT}/etc/ld.so.cache" fi elif [ "${#active[@]}" -gt 1 ]; then echo "Activating ldconfig in stage4 due to multiple loaded addons: ${active[*]}" activate_stage4_ldconfig fi exit 0