#!/bin/bash

# This script acts as a basic su wrapper using run0.
# It handles the common case of switching to root to run a command.

__run0_exec="run0"
RUN0_BACKGROUND="--background="

# --- Function to display usage information ---

show_help() {
    cat << 'EOF'
run0-su - run a command with substitute user and group ID via run0

Usage: run0-su [options] [-] [user [argument...]]

Options:
  -c, --command <command>  Pass command to the shell with the -c option
  -f, --fast               Pass -f to the shell
  -g, --group <group>      Run with <group> as primary group
  -l, --login, -           Start the shell as a login shell
  -P, --pty                Create a pseudo-terminal for the session
  -s, --shell <shell>      Run the specified <shell> instead of the default
  -w, --whitelist-environment <list>
                           Don’t reset specified environment variables
  -h, --help               Display help text and exit
  -V, --version            Display version and exit
EOF
}

show_usage() {
    echo "Try 'run0-su --help' for more information."
}

show_version() {
    local run0_version
    run0_version="$(run0 --version 2>/dev/null | head -n 1 | cut -d' ' -f3 | sed 's/[()]//g')"
    echo "run0-su (run0-wrappers) 0.4.0"
    echo "systemd run0 version $run0_version"
}

# --- Get shell for the target user or current user ---
get_shell() {
    local targetuser=$1

    if [ -n "$SHELL" ]; then
        echo "$SHELL"
    else
	# otherwise, get the shell of the target user
	local shell
	shell=$(getent passwd "$targetuser" 2>/dev/null | cut -d: -f7)
	echo "$shell"
    fi
}

# --- Main Logic ---

# Array to hold the final command and arguments for run0
__run0_args=("$RUN0_BACKGROUND")
__run0_commands=()
__run0_env=()

# Variables to track user and command
__run0_shell=""
__target_user=""
__target_group=""
__login_shell=0

while (( "$#" )); do
    arg="$1"

    case "$arg" in
        -c|--command)
            # The next argument is the command string
            if (( "$#" )); then
		__run0_commands+=("-c")
		__run0_commands+=("$2")
            else
                echo "run0-su: option requires an argument -- '$arg'" >&2
                show_usage >&2
		exit 1
            fi
	    shift 2
            ;;
	-f|--fast)
	    __run0_commands+=("-f")
            shift
            ;;
	-g|--group)
	    __target_group="--group=$2"
	    shift 2
	    ;;
	-G|--supp-group)
	    echo "run0-su: group option '$arg' is ignored." >&2
	    shift 2
	    ;;
        -|-l|--login)
	    __run0_commands+=("-l")
	    __login_shell=1
	    shift
            ;;
        -m|-p|--preserve-environment)
            echo "run0-su: preserve environment option '%arg' is ignored." >&2
            shift
            ;;
	-P |--pty)
	    __run0_args+=("--pty-late")
            shift
            ;;
	-s|--shell)
	    # The next argument is the shell
	    __run0_shell="$2"
	    shift 2
	    ;;
	--shell=*)
	    __run0_shell="${1#*=}"
            shift
            ;;
	-w|--whitelist-environment)
	    VARS=$(echo "$2" | tr ',' ' ')
	    for var in $VARS; do
		# Remove whitespace
		var="${var//[[:blank:]]/}"
		__run0_env+=("--setenv=$var")
	    done
	    shift 2
	    ;;
	-h|--help)
	    show_help
	    shift
	    exit 0
	    ;;
	-V|--version)
	    show_version
	    shift
	    exit 0
	    ;;
        -*)
	    echo "run0-su: invalid option -- '$arg'" >&2
	    show_usage
	    exit 1
            ;;
        root)
            __target_user="root"
            shift
            ;;
        *)
            # This must be the target user or the start of a command/arguments
            if [ -z "$__target_user" ]; then
                # First positional argument is the user
                __target_user="$arg"
                shift
            else
		echo "run0-su: invalid option -- '$arg'" >&2
		show_usage >&2
		exit 1
            fi
            ;;
    esac
done

__run0_commands+=("$@")

# we need a shell for -l and change CWD to ~
if [ $__login_shell -eq 1 ]; then
    if [ -z "$__target_user" ]; then
	# run0 will change home if target user is specified
	__target_user="root"
    fi
else
    # No login shell, keep current directory
    __run0_args+=("--chdir=$PWD")
fi

if [ -z "$__run0_shell" ]; then
    __run0_shell=$(get_shell "$__target_user")
fi

if [ -n "$__target_user" ]; then
    __run0_args+=("--user=${__target_user}")
fi
if [ -n "$__target_group" ]; then
    __run0_args+=("--group=${__target_group}")
fi

if [ ${__login_shell} -eq 0 ]; then
    mapfile -t __run0_env < <(printenv | grep -v ^_ | grep -v ^PATH= | awk '{print "--setenv="$0}')
fi

# shellcheck disable=SC2086
exec "${__run0_exec}" "${__run0_args[@]}" "${__run0_env[@]}" -- ${__run0_shell} "${__run0_commands[@]}"
