dotfiles/.config/zsh/00-scope.zsh

126 lines
3.6 KiB
Bash

# 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 <<EOF
Usage: detach [OPTIONS] <COMMAND> [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 <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 <VAR>[=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
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