#!/bin/bash ## Copyright © 2018-2021 Bret Human ## https://cynop.me/ ## ## Documentation at: ## https://mage.cynop.me/en/bn3t ## https://psi.cynop.me/Caffarius/bn3t/ ## ## For questions or comments write: ## info@cynop.me ##################################################################### # bn3t script_ver="0.3.1" page="https://mage.cynop.me/en/bn3t" # author: Bret Human # date: Dec 6, 2018 # ##################################################################### # # A wrapper for wrappers, used to install/manage/own a Battle.net # installation within Wine in a Linux environment. # # Extra handy for running Battle.net under a secondary account for # added security. Can be used for lots of zany wine needs, like # spawning a multitude of Wine prefixes and installing Battle.net in # all of them. # # This is the first of two scripts. It is meant to be the sanitizer # crew and the firing squad for bn3t-run. bn3t-run must be installed. # # Install bn3t-run for your desired user with: # ./bn3t.sh -u username -i # # Then you can prep the environment and install Battle.net via: # ./bn3t.sh -u username -bxs # # Or I guess you could manually download the script from: dl_addr="https://psi.cynop.me/Caffarius/bn3t/raw/branch/master/bn3t-run.sh" ##################################################################### # # This is free software; you are free to change and redistribute it. # There is NO WARRANTY of any kind. # ##################################################################### runas_user="`whoami`" app_name="Battle.net" run_cmd="bn3t-run.sh" jail_dir="/var/jail" check_wait="3" usage="bn3t, version ${script_ver} Usage: ./`basename ${0}` -g (game) -u (user) -p (prefix) -a (arch) -dvksbwtnchxi -a | Selects the architecture to run as (32 | 64) -b | Runs wineboot -c | Launch a console session as specified user (can launch Xapps) -d | Debug messages on (turns verbose on) -g | Launches the game of your choice -h | Help (this message) -i | Install the bn3t-run script for the specified user - mandantory -j | Run ${run_cmd} inside a chroot jail at ${jail_dir} -k | Kill all processes for a user (not current user or root) -m | Runs Twitch Client (for /M/ods - I'm running out of letters) -n | No BS mode - doesn't launch an app (for boot/tricks/console safety) -p | Selects the location of the Wine prefix -s | Runs ${app_name} setup -t | Attempts to launch to the system tray -u | Runs ${app_name} as the user specified -v | Verbose messages on -w | Runs winetricks -x | Force upgrade DXVK -z | Set the DISPLAY variable used in ${run_cmd} See more documentation at: ${page}" # Catch CTRL+C and cleanup trap "echo '' && inform '---------------------------------' && inform 'Caught CTRL+C' && check" 2 ## Define our functions function refresh { app_dir="/home/${runas_user}/.script/" app_check="ps -ef | grep ${runas_user} | grep Battle.net.exe | grep -v grep" } function debug () { if [ "${app_debug}" ]; then echo -e "-D- ${1}" fi } function inform () { if [ "${app_verbose}" ]; then echo -e "--- ${1}" fi } function buff_cmd_output () { read cmd_input cmd_output=$(eval "${cmd_input}") if [ ! -z "${cmd_output}" ]; then debug "${cmd_output}" fi } function clean { debug "Clean" # Var unset script_ver unset page unset runas_user unset app_name unset run_cmd unset check_wait unset usage unset app_dir unset app_check unset app_debug unset app_verbose unset launch_opt unset nobs_mode unset dl_addr # Func unset refresh unset debug unset inform unset check } function die () { debug "die" echo "Cleaning up..." if [ "`whoami`" == "${runas_user}" ]; then debug "Launched as original user, not killing processes" else if [ "${runas_user}" == "root" ]; then debug "Root? Madness. Just removing xhost then..." inform "`xhost -SI:localuser:root`" else debug "Launched as ${runas_user}, killing processes and removing xhost..." sudo -u "${runas_user}" -- bash -c "kill -9 -1" inform "`xhost -SI:localuser:"${runas_user}"`" fi fi if [ "${jailbird}" == "1" ]; then debug "Removing root from xhost..." inform "`xhost -SI:localuser:root`" debug "Delaying jail demolition..." sleep 1 debug "Demolishing jail..." echo "sudo rm ${jail_dir}/${runas_user}/bin 2>&1" | buff_cmd_output echo "sudo rm ${jail_dir}/${runas_user}/sbin 2>&1" | buff_cmd_output echo "sudo rm ${jail_dir}/${runas_user}/lib 2>&1" | buff_cmd_output echo "sudo rm ${jail_dir}/${runas_user}/lib64 2>&1" | buff_cmd_output echo "sudo umount -l ${jail_dir}/${runas_user}/usr 2>&1" | buff_cmd_output echo "sudo umount -l ${jail_dir}/${runas_user}/etc 2>&1" | buff_cmd_output echo "sudo umount -l ${jail_dir}/${runas_user}/tmp/pulse-socket 2>&1" | buff_cmd_output echo "sudo umount -l ${jail_dir}/${runas_user}/dev 2>&1" | buff_cmd_output echo "sudo umount -l ${jail_dir}/${runas_user}/proc 2>&1" | buff_cmd_output echo "sudo umount -l ${jail_dir}/${runas_user}/sys 2>&1" | buff_cmd_output echo "sudo umount -l ${jail_dir}/${runas_user}/run 2>&1" | buff_cmd_output echo "sudo umount -l ${jail_dir}/${runas_user}/tmp 2>&1" | buff_cmd_output echo "sudo umount -l ${jail_dir}/${runas_user}/var 2>&1" | buff_cmd_output echo "sudo umount -l ${jail_dir}/${runas_user}/home/${runas_user} 2>&1" | buff_cmd_output debug "Jail demolished." fi clean unset clean unset fizzle if [ "$1" ]; then unset die && exit $1 else echo "...what?" unset die && exit 5 fi exit 5 } function fizzle () { debug "fizzle" # https://mtg.gamepedia.com/Fizzle echo "Exiting..." clean unset clean unset die if [ "$1" ]; then unset fizzle && exit $1 else echo "...what?" unset fizzle && exit 5 fi exit 5 } function check { debug "check" i="0" while [ "${i}" -lt "${check_wait}" ]; do if [ "$(eval ${app_check})" ]; then inform "${app_name} is still running. Waiting to see if we need to murder... $[ ${check_wait} - ${i} ]" sleep 1 else unset i die 0 fi i=$[ $i + 1 ] done unset i } ## Pick up any arguments provided # None are required, we'll use default values. launch_opt="" while getopts ":a:A:g:G:p:P:u:U:z:Z:bBcCdDhHiIjJkKmMnNsStTvVwWxX" option; do case "${option}" in "a"|"A") launch_opt="${launch_opt} -a ${OPTARG}";; "b"|"B") inform "Wineboot mode" launch_opt="${launch_opt} -b" ;; "c"|"C") inform "Console requested" nobs_mode="y" launch_opt="${launch_opt} -c" ;; "d"|"D") if [ ! "${app_debug}" ]; then # Let's not do this too much... app_debug="y" launch_opt=" -d${launch_opt}" debug "Debug enabled" if [ ! "${app_verbose}" ]; then debug "`realpath "${0}"` version ${script_ver} running as `whoami`" fi app_verbose="y" debug "" debug "This is free software; you are free to change and redistribute it." debug "There is NO WARRANTY of any kind." debug "" debug "Documentation at: ${page}" debug "" fi ;; "g"|"G") launch_opt="${launch_opt} -g ${OPTARG}";; "h"|"H") echo "${usage}" fizzle 0 ;; "i"|"I") debug "User-side install requested" refresh if [ "`whoami`" == "${runas_user}" ]; then debug "Running as original user, just downloading it" mkdir -p "${app_dir}" || (echo "Failed to make directory ${app_dir}" && fizzle 1) wget "${dl_addr}" -O "${app_dir}${run_cmd}" || (echo "Failed to download script from ${dl_addr}" && fizzle 1) chmod 700 "${app_dir}${run_cmd}" || (echo "Failed to change permissions on ${app_dir}${run_cmd}" && fizzle 1) else debug "Running as ${runas_user}, switching and downloading" sudo -u "${runas_user}" -- mkdir -p "${app_dir}" || (echo "Failed to make directory ${app_dir}" && fizzle 1) sudo -u "${runas_user}" -- wget "${dl_addr}" -O "${app_dir}${run_cmd}" || (echo "Failed to download script from ${dl_addr}" && fizzle 1) sudo -u "${runas_user}" -- chmod 700 "${app_dir}${run_cmd}" || (echo "Failed to change permissions on ${app_dir}${run_cmd}" && fizzle 1) fi echo "Install process completed." fizzle 0 ;; "j"|"J") debug "Running ${appname} in a chroot jail under ${jail_dir}/${runas_user}/" jailbird=1 ;; "k"|"K") die 0;; "m"|"M") inform "Twitch mode" launch_opt="${launch_opt} -m" ;; "n"|"N") inform "No BS mode" nobs_mode="y" launch_opt="${launch_opt} -n" ;; "p"|"P") launch_opt="${launch_opt} -p ${OPTARG}";; "s"|"S") inform "Setup mode" nobs_mode="y" launch_opt="${launch_opt} -s" ;; "t"|"T") debug "Hiding to system tray" launch_opt="${launch_opt} -t" ;; "u"|"U") debug "Setting user to ${OPTARG}" runas_user="${OPTARG}" ;; "v"|"V") if [ ! "${app_debug}" ]; then if [ ! "${app_verbose}" ]; then app_verbose="y" inform "Verbose enabled" inform "`realpath "${0}"` version ${script_ver} running as `whoami`" launch_opt=" -v${launch_opt}" fi fi ;; "w"|"W") inform "Winetricks mode" launch_opt="${launch_opt} -w" ;; "x"|"X") inform "Force upgrading dxvk" launch_opt="${launch_opt} -x" ;; "z"|"Z") inform "Setting DISPLAY to ${OPTARG}" launch_opt="${launch_opt} -z ${OPTARG}" ;; * ) echo "Unknown option: -${OPTARG}" echo "${usage}" fizzle 1 ;; esac done debug "launch_opt:${launch_opt}" ## Pass our knowledge on. refresh debug "run_app" if [ "`whoami`" == "${runas_user}" ]; then debug "Launching as original user, going native" ${app_dir}${run_cmd}${launch_opt} else debug "Checking xhost" if [ ! "`xhost | grep ${runas_user}`" ]; then inform "`xhost +SI:localuser:"${runas_user}"`" fi if [ ! "${jailbird}" == "1" ]; then # Just launch it as a regular secondary user app debug "Launching as ${runas_user}..." sudo -u "${runas_user}" -- dbus-launch ${app_dir}${run_cmd}${launch_opt} else # Hooooooowiiiiiiee. We're gonna build a jail! if [ ! "`xhost | grep root`" ]; then inform "`xhost +SI:localuser:root`" fi debug "Preparing ${runas_user}'s chroot environment..." sudo mkdir -p ${jail_dir}/${runas_user}/tmp sudo mkdir -p ${jail_dir}/${runas_user}/usr sudo mkdir -p ${jail_dir}/${runas_user}/var sudo mkdir -p ${jail_dir}/${runas_user}/proc sudo mkdir -p ${jail_dir}/${runas_user}/sys sudo mkdir -p ${jail_dir}/${runas_user}/dev sudo mkdir -p ${jail_dir}/${runas_user}/run sudo mkdir -p ${jail_dir}/${runas_user}/etc sudo mkdir -p ${jail_dir}/${runas_user}/home/${runas_user} if mountpoint ${jail_dir}/${runas_user}/tmp > /dev/null; then debug "/tmp is already mounted?" else debug "Mounting /tmp..." sudo mount -t tmpfs -o size=2G tmpfs ${jail_dir}/${runas_user}/tmp fi if mountpoint ${jail_dir}/${runas_user}/proc > /dev/null; then debug "/proc is already mounted?" else debug "Mounting /proc..." sudo mount --bind /proc ${jail_dir}/${runas_user}/proc fi if mountpoint ${jail_dir}/${runas_user}/sys > /dev/null; then debug "/sys is already mounted?" else debug "Mounting /sys..." sudo mount --bind /sys ${jail_dir}/${runas_user}/sys fi if mountpoint ${jail_dir}/${runas_user}/dev > /dev/null; then debug "/dev is already mounted?" else debug "Mounting /dev..." sudo mount --bind /dev ${jail_dir}/${runas_user}/dev fi if mountpoint ${jail_dir}/${runas_user}/run > /dev/null; then debug "/run is already mounted?" else debug "Mounting /run..." sudo mount --bind /run ${jail_dir}/${runas_user}/run fi if mountpoint ${jail_dir}/${runas_user}/var > /dev/null; then debug "/var is already mounted?" else debug "Mounting /var..." sudo mount --bind /var ${jail_dir}/${runas_user}/var fi if mountpoint ${jail_dir}/${runas_user}/etc > /dev/null; then debug "/etc is already mounted?" else debug "Mounting /etc..." sudo mount --bind /etc ${jail_dir}/${runas_user}/etc fi if mountpoint ${jail_dir}/${runas_user}/usr > /dev/null; then debug "/usr is already mounted?" else debug "Mounting /usr..." sudo mount --bind /usr ${jail_dir}/${runas_user}/usr fi if mountpoint ${jail_dir}/${runas_user}/home/${runas_user} > /dev/null; then debug "/home/${runas_user} is already mounted?" else debug "Mounting /home/${runas_user}..." sudo mount --bind /mnt/ace/home/${runas_user} ${jail_dir}/${runas_user}/home/${runas_user} fi if [ ! -d ${jail_dir}/${runas_user}/bin ]; then debug "Linking /bin to usr/bin..." sudo bash -c "cd ${jail_dir}/${runas_user}; ln -s usr/bin bin" fi if [ ! -d ${jail_dir}/${runas_user}/sbin ]; then debug "Linking /sbin to usr/bin (that's not a typo!)..." sudo bash -c "cd ${jail_dir}/${runas_user}; ln -s usr/bin sbin" fi if [ ! -d ${jail_dir}/${runas_user}/lib ]; then debug "Linking /lib to usr/lib..." sudo bash -c "cd ${jail_dir}/${runas_user}; ln -s usr/lib lib" fi if [ ! -d ${jail_dir}/${runas_user}/lib64 ]; then debug "Linking /lib64 to usr/lib (that's not a typo!)..." sudo bash -c "cd ${jail_dir}/${runas_user}; ln -s usr/lib lib64" fi if [ ! -S ${jail_dir}/${runas_user}/tmp/pulse-socket ]; then if [ ! -f ${jail_dir}/${runas_user}/tmp/pulse-socket ]; then debug "Creating /tmp/pulse-socket to link sound..." sudo -u ${runas_user} touch ${jail_dir}/${runas_user}/tmp/pulse-socket fi if mountpoint ${jail_dir}/${runas_user}/tmp/pulse-socket > /dev/null; then debug "/tmp/pulse-socket is already mounted?" else debug "Mounting /tmp/pulse-socket..." sudo mount --bind /tmp/pulse-socket ${jail_dir}/${runas_user}/tmp/pulse-socket fi else debug "/tmp/pulse-socket is already a socket?" fi debug "...chroot prepared." debug "Launching as ${runas_user} jailed inside ${jail_dir}/${runas_user}/..." sudo -u root -- chroot ${jail_dir}/${runas_user}/ sudo -u ${runas_user} dbus-launch ${app_dir}${run_cmd}${launch_opt} fi debug "...returned to wrapper." fi ## If we still exist, clean up. debug "Final Notice" if [ "${app_check}" ]; then check fizzle 0 fi