# Move shell into its own systemd scope if possible if ! hash busctl &>/dev/null; then return fi if [[ $_scope_loaded == 1 ]]; then # shell reload, ignore return fi _scope_loaded=1 # Load new scope unit busctl -q --user call org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager StartTransientUnit 'ssa(sv)a(sa(sv))' \ "zsh-$$.scope" \ replace \ 2 \ PIDs au 1 $$ \ Slice s app-shell.slice \ 0 \ &>/dev/null # this call fails on a shell re-exec, but we don't really care since the scope will already exist in that case, so forward to dave null # Set and unset variables export INVOCATION_ID=$(systemctl --user show "zsh-$$.scope" | awk -F= '/InvocationID=/{ print $2 }') export SYSTEMD_UNIT="zsh-$$.scope" unset SYSTEMD_EXEC_PID unset JOURNAL_STREAM unset MEMORY_PRESSURE_WATCH unset MEMORY_PRESSURE_WRITE function lift-constraints() { # Don't lift the PID constraint since there's really no reason a shell should have more than 100 active PIDs. Reap what you sow! env systemctl --user set-property zsh-$$.scope CPUQuota= env systemctl --user set-property zsh-$$.scope MemoryHigh= env systemctl --user set-property zsh-$$.scope MemoryMax= } function detach() { local args slice type unit passed_envs passed_envs=(SUDO_PROMPT EDITOR SUDO_EDITOR VISUAL) args=(--user --same-dir -q --collect) slice="app-shell.slice" type="scope" while true; do case $1 in --help) cat < [ARGS...] Invoke a command outside of the shell's execution context, detaching it from any resource constraints on the shell itself. It will be run by the user service manager using systemd-run. By default, the command is invoked in the app-shells slice, so is still subject to any restrictions placed on the set of all user shells. This is intended to simplify the act of intentionally launching resource-intensive programs (such as compilers) while still limiting most programs in terms of how much they are allowed to consume. Some environment variables are inherited by default, which can be disabled with --clean-env: $passed_envs OPTIONS: --help - display this help message and exit --app - launch in the main app slice rather than the app-shell slice. Equivalent to --slice app.slice --background - launch in the background slice. Equivalent to --slice background.slice --slice - launch in the specified user slice. --service - create a service unit, rather than a scope, producing a truly clean environment. This separates the program from the shell's process tree, preventing the shell's job management from managing it. --env [=VALUE] - inherit the given environment variable from the shell, or set it if a value is given. --clean-env - disable the default set of inherited environment variables --unit - set the unit name. Defaults to "invoke-@" for services, "invoke--" for scopes. EOF return 0 ;; --app) slice="app.slice" ;; --background) slice="background.slice" ;; --slice) slice=$2 shift ;; --service) type="service" ;; --env) args+="-E" args+=$2 shift ;; --clean-env) passed_envs=() ;; *) break ;; esac shift done for env in $passed_envs; do args+="--setenv=$env" done case $type in service) unit="invoke-$$@$RANDOM.service" args+=(--service-type=exec --pty --pipe --wait) ;; scope) unit="invoke-$$-$RANDOM.scope" args+="--scope" ;; esac systemd-run $args --slice=${slice} --unit=${unit} -- "$@" } for cmd in $always_detach; do eval $(echo alias $cmd=\"detach $cmd\") done for cmd in $always_detach_as_service; do eval $(echo alias $cmd=\"detach --service $cmd\") done