All,

the following is a script which will migrate a Gentoo system to the usr
merge layout. This is similar to the unsymlink-lib tool used to migrate
a system  from the 17.0 to the 17.1 profiles.

I'm attaching it here to get some comments before I package it, so
please let me know if I have missed something.

Thanks,

William

#!/bin/bb
# shellcheck disable=SC2039 shell=sh

rollback_path=/var/usrmerge-rollback

check_internal_commands() {
        for cmd in cp ln; do
                [ "$(command -v "${cmd}")" = ${cmd} ] && continue
                printf 'busybox does not include the %s command internally\n' 
"${cmd}"
                return 1
        done
        return 0
}

check_root() {
 [ "$(id -u)" = 0 ] && return 0
 printf 'This script must be run by root\n'
 return 1
}

run_command() {
        local cmd
        [ -n "${dryrun}" ] && cmd="echo"
        ${cmd} "$@" || exit
        return 0
}

setup_rollback() {
        if [ -e "${rollback_path}" ]; then
                printf '%s already exists\n' "${rollback_path}"
                printf 'please remove it before continuing\n'
                return 1
        fi
        printf 'Creating %s to allow rollbacks\n' "${rollback_path}"
        run_command mkdir "${rollback_path}"
        run_command mkdir "${rollback_path}/usr"
        local dir
        for dir in /bin /lib* /sbin; do
                run_command cp -a "${dir}" "${rollback_path}"
        done
        for dir in /usr/bin /usr/lib* /usr/sbin; do
                [ "${dir}" = /usr/libexec ] && continue
                run_command cp -a "${dir}" "${rollback_path}/usr"
        done
        return 0
}

action_finish() {
        run_command rm -fr "${rollback_path}"
        return 0
}

action_help() {
        local cmd
        cmd="$(basename "${0}")"
        printf 'usage: %s -h\n' "${cmd}"
        printf '       %s [-d] -f|-m|-r\n' "${cmd}"
        printf '\n'
        printf '-h | --help      - displays this message\n'
        printf '-d | --dry-run   - show what would be done\n'
        printf '-f | --finish    - remove the rollback data\n'
        printf '-m | --merge     - perform the usr merge\n'
        printf '-r | --roll-back - attempt to undo the usr merge\n'
        return 0
}

action_merge() {
        if [ -L /bin ] || [ -L /sbin ]; then
                printf 'The /usr merge has been completed on this system\n'
                return 0
        fi

        local dir
        for dir in /lib*; do
                [ -L "${dir}" ] || continue
                printf '%s is a symbolic link.\n' "${dir}"
                printf 'This means you have not migrated to the 17.1 profiles 
yet\n'
                printf 'please do so before running this script\n'
                return 1
        done

        setup_rollback || return

        # copy root directories to /usr counterparts and create
        # the /usr merge compatibility symlinks
        for dir in /bin /lib* /sbin; do
                run_command cp -a -i "${dir}"/* /usr/"${dir}"
                run_command rm -rf "${dir}"
                run_command ln -snf usr/"${dir}" "${dir}"
        done

        # merge /usr/sbin into /usr/bin
        run_cmd cp -a -i /usr/sbin/* /usr/bin
        run_cmd rm -fr /usr/sbin
        run_cmd ln -snf bin /usr/sbin
        return 0
}

action_rollback() {
        if [ ! -d "${rollback_path}" ]; then
                printf '%s does not exist, unable to roll back\n' 
"${rollback_path}"
                return 1
        fi
        local dir rollback_dir
        for dir in /bin /lib* /sbin /usr/bin /usr/lib* /usr/sbin; do
                [ "${dir}" = /usr/libexec ] && continue
                rollback_dir="${rollback_path}/${dir}"
                [ -d "${rollback_dir}" ] && continue
                printf 'Unable to perform rollback, %s is missing\n' 
"${rollback_dir}"
                return 1
        done
        for dir in /bin /lib* /sbin ; do
                rollback_dir="${rollback_path}/${dir}"
                run_cmd  rm -fr "${dir}"
                run_cmd cp -a "${rollback_dir}" /
        done
        for dir in /usr/bin /usr/lib* /usr/sbin; do
                [ "${dir}" = /usr/libexec ] && continue
                rollback_dir="${rollback_path}/${dir}"
                run_cmd  rm -f "${dir}"
                run_cmd cp -a "${rollback_dir}" /usr
        done
        return 0
}

main() {
        local dryrun finish merge rollback
        while [ $# -gt 0 ]; do
                case $1 in
                        -d|--dry-run)
                                dryrun=1
                                ;;
                        -h|--help)
                                action_help
                                return 0
                                ;;
                        -f|--finish)
                                finish=1
                                ;;
                        -m|--merge)
                                merge=1
                                ;;
                        -r|--roll-back)
                                rollback=1
                                ;;
                esac
                shift
        done
        check_internal_commands || return
        check_root || return
        if [ "${finish}" = "${merge}" ] && [ "${merge}" = "${rollback}" ]; then
                printf 'You must select -f, -m or -r\n'
                action_help
                return 1
        elif [ -n "${finish}" ]; then
                action_finish || return
        elif [ -n "${merge}" ]; then
                action_merge || return
        elif [ -n "${rollback}" ]; then
                action_rollback || return
        fi
        return 0
}

main "$@" || exit
exit 0

Attachment: signature.asc
Description: PGP signature

Reply via email to