-# WARN: not used in this repo, but gpgconf --list-dirs does not read
-# gpg-agent.conf to get socket path, see dev.gnupg.org/T3108
-
-### unset unwanted options that could be set in /etc/zshenv
-unsetopt SH_WORD_SPLIT KSH_ARRAYS
-
-### check if su
-if [[ -v _sev_olduser && $_sev_olduser != $USERNAME ]] _sev_reset_shell=
-export _sev_olduser=$USERNAME
-
-### exports for all new shells
-if [[ -v _sev_reset_shell || $SHLVL == 1 ]] {
- ## lang
- export CHARSET=UTF-8
- export LANG=en_US.UTF-8
- export LC_CTYPE=$LANG
-
- ## path
- # path and fpath should already be linked to PATH and FPATH
- # we don't want duplicates so turn on unique mode if it isn't already
- typeset -U path fpath
- # do not run more than once per session, even if resetting shell
- if [[ $SHLVL == 1 ]] {
- # take a backup before any customizations
- export _sev_sys_PATH=$PATH
- export _sev_sys_FPATH=$FPATH
- }
- # /usr/{pkg,local,games} are unix/bsdisms
- path=({~/,/,/usr/}sbin {~/,/,/usr/}bin /usr/pkg/{s,}bin /usr/X11R{7,6}/bin
- /usr/local/{s,}bin /usr/games)
- PATH=$PATH:$_sev_sys_PATH
- fpath=(${ZDOTDIR:-$HOME/.zsh}/functions/{*,Completions/*}(N))
- # fpath is not exported by default
- export FPATH=$FPATH:$_sev_sys_FPATH
- # take another backup, explained in .zprofile
- typeset -U _backup_path
- _backup_path=("${path[@]}")
-
- ## xdg
- # TODO: check for and merge existing XDG env vars
- export XDG_CONFIG_HOME=~/etc
- export XDG_CONFIG_DIRS=~/.config:/usr/pkg/etc/xdg:/usr/local/etc/xdg:/etc/xdg
- export XDG_DATA_HOME=~/share
- export XDG_DATA_DIRS=~/.local/share:/usr/pkg/share:/usr/local/share:/usr/share
- export XDG_CACHE_HOME=~/tmp
- export XDG_RUNTIME_DIR=~/tmp
- if [[ -e $XDG_CONFIG_HOME/user-dirs.dirs ]] {
- source $XDG_CONFIG_HOME/user-dirs.dirs
- }
-
- ## create tmp link
- t=${TMPDIR:-/tmp}/.home-$LOGNAME
- if [[ ! -e $t ]] {
- mkdir -m 700 $t 2>/dev/null
- if [[ ! -d $t ]] {
- [[ -o interactive ]] &&
- print -P "%F{red}!!! Can't create temp folder $t%f"
- [[ -h $XDG_RUNTIME_DIR ]] && unlink $XDG_RUNTIME_DIR 2>/dev/null
- [[ ! -e $XDG_RUNTIME_DIR ]] && mkdir $XDG_RUNTIME_DIR 2>/dev/null
- }
- }
- # allow opaque entries to override link creation
- [[ ! -e $XDG_RUNTIME_DIR ]] && ln -sf $t $XDG_RUNTIME_DIR 2>/dev/null
- unset t
-
- ## gpg forwarding
- # NOTE: while ssh automatically sets SSH_AUTH_SOCK with the ForwardSsh
- # directive, GPG must be forwarded manually. to support this, we
- # forward the restricted gpg-agent extra socket to the remote host
- # with a RemoteForward rule in ~/.ssh/config that uses the
- # _GNUPG_SOCK_* env vars.
- # to avoid conflicts with other ssh sessions where the same user is
- # connecting to the same host from different machines, gpg in each
- # environment should utilize its own forwarded socket, rather than
- # replace the sockets in GNUPGHOME which will be overridden on the
- # next connection. previously, you could provide a path to the agent
- # socket in GPG_AGENT_INFO, but that was deprecated in GPG v2.1.
- # instead, we must clone GNUPGHOME and replace the agent sockets
- # there with the forwarded one.
- # HACK: without SendEnv, which is disabled by default in most sshd configs,
- # there is no foolproof way to prevent race conditions or filename
- # collisions, pass the forward path to the remote host environment,
- # or even know if the forward path exists and is writable. we just
- # have to guess this path is good on the desination host, and assume
- # the newest matching socket is the correct one after connecting. in
- # theory we could occlude the ssh binary on PATH with an alias or
- # script that communicates with the remote host before opening a
- # shell, but that would open up too many edge cases where it wouldn't
- # work to make it worth the effort and extra overhead.
- # do not run more than once per session, even if resetting shell
- if [[ $SHLVL == 1 && -v commands[gpg] ]] {
- export _GNUPG_SOCK_DEST_BASE=/tmp/.gpg-agent-forward
- export _GNUPG_SOCK_DEST_EXT=$(date +%s).$RANDOM
- export _GNUPG_SOCK_DEST=$_GNUPG_SOCK_DEST_BASE.$_GNUPG_SOCK_DEST_EXT
- _sev_gpg_forward_dir=${GNUPGHOME:-~/.gnupg}/.ssh_forward
- s=($_GNUPG_SOCK_DEST_BASE*(N=oc[1]))
- # clean up forwards if its session is dead or we ask for it
- if [[ -d $_sev_gpg_forward_dir ]] {
- find $_sev_gpg_forward_dir -type d -mindepth 1 -maxdepth 1 |
- while read -r x; do
- # NOTE: the only way we can get here is if we are SHLVL 1. if
- # our own pid already has a dir, it is most likely stale,
- # or something is very broken—assume the former.
- p=$(basename $x)
- if [[ -v _sev_gpg_forward_clean || $$ == $p ]] ||
- ! kill -0 $p 2>/dev/null; then
- find $x -mindepth 1 -maxdepth 1 | while read -r y; do
- unlink $y
- done
- rmdir $x
- fi
- done
- unset x p y
- }
- # create new forward dir
- if [[ -n $s && -v SSH_CLIENT ]] {
- export _sev_gpg_forwarded=
- mkdir -pm700 $_sev_gpg_forward_dir
- h=$_sev_gpg_forward_dir/$$
- mkdir -pm700 $h
- # XXX: is it safe to link scdaemon socket? can its name be changed?
- for x in S.scdaemon gpg.conf gpg-agent.conf sshcontrol \
- pubring.kbx trustdb.gpg private-keys-v1.d crls.d; do
- ln -s ${GNUPGHOME:-~/.gnupg}/$x $h
- done
- export GNUPGHOME=$h
- unset h
- for x in $(gpgconf --list-dirs | grep 'agent-.*-\?socket:'); do
- # dirs are prefixed and percent-encoded—strip and decode
- # https://stackoverflow.com/a/64312099
- x=${${x/#agent-*socket:/}//(#b)%([[:xdigit:]](#c2))/${(#):-0x$match[1]}}
- if [[ ! -v orig ]] {
- mv $s $x
- orig=$x
- } else {
- ln -s $orig $x
- }
- done
- unset x orig
- }
- unset s
-
- # what we will forward if we start a new ssh connection
- # NOTE: do this after setting up GNUPGHOME to pick up new socket path;
- # if already connected over SSH, extra should be the remote one
- export _GNUPG_SOCK_SRC=$(gpgconf --list-dirs agent-extra-socket)
- } else {
- # required for RemoteForward to not error out if the vars are unset
- export _GNUPG_SOCK_SRC=/nonexistent
- export _GNUPG_SOCK_DEST=/nonexistent
- }
-
- ## gpg agent
- # always try to start agent during setup
- if [[ SHLVL == 1 ]] {
- gpg-connect-agent /bye >/dev/null 2>&1
- [[ $? -ne 0 && -o interactive ]] &&
- print -P "%F{red}!!! Can't communicate with GPG agent%f"
- }
- # set up tty if it isn't, and we're interactive or in xorg & not forwarded
- # do not run more than once per session, even if resetting shell
- if [[ -v commands[gpg-connect-agent] &&
- ! -v _sev_gpg_forward && ! -v GPG_TTY &&
- ( -o interactive || -v DISPLAY ) ]] {
- export GPG_TTY=$(tty)
- export PINENTRY_USER_DATA=USE_TTY=$((!${+DISPLAY}))
- gpg-connect-agent UPDATESTARTUPTTY /bye >/dev/null 2>&1
- }
+### load site-specific
+[[ -f ~/.zshenv.local ]] && source ~/.zshenv.local
+
+### fix broken term
+if [[ -o interactive && $#terminfo -eq 0 ]] {
+ _oldterm=$TERM
+ TERM=xterm-256color >/dev/null 2>&1
+ print -P "%F{red}!!! Can't find terminfo for $_oldterm, using $TERM%f"
+ unset _oldterm
+}
- ## ssh agents
- # NOTE: preferred order of agents to check: okcagent, gnupg, openssh
- # first block takes care of okcagent and openssh, second gnupg
- [[ -o interactive ]] && print -nP "%F{blue}>>>%f SSH: %F{green}"
- if [[ ! -v SSH_AUTH_SOCK && ( -v commands[okc-ssh-agent] ||
- ( -v commands[ssh-agent] && ! -v commands[gpg] ) ) ]] {
- okc=${commands[okc-ssh-agent]:+okc-}
- agentfile=~/tmp/${okc}ssh-agent-exports
- typeset sock=
- typeset -i pid=
- if [[ -f $agentfile ]] {
- IFS=$'\0' read -r sock pid <$agentfile
- }
- if [[ -S $sock && $pid > 0 ]] && kill -0 $pid; then
- [[ -o interactive ]] && echo "Reusing agent PID $pid"
- export SSH_AUTH_SOCK=$sock
- export SSH_AGENT_PID=$pid
- else
- # TODO: ensure ssh-agent path looks legit
- # to avoid unsafe eval?
- # NOTE: no way around doing redirection like this I think
- e=${okc}ssh-agent
- if [[ -o interactive ]] {
- eval `$e`
- } else {
- eval `$e` >/dev/null 2>&1
- }
- echo -n $SSH_AUTH_SOCK$'\0'$SSH_AGENT_PID >!$agentfile
- fi
- unset okc agentfile sock pid
- } elif [[ ! -v SSH_AUTH_SOCK && -v commands[gpg] ]] {
- # since gpg agent was started above, we just have to export and notify
- if [[ -o interactive ]] {
- if [[ -v _sev_gpg_forwarded ]] {
- echo 'Remote GPG agent'
- } else {
- gpg-connect-agent /subst /serverpid \
- '/echo GPG agent PID ${get serverpid}' /bye
- }
- }
- export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
- } elif [[ -v SSH_AUTH_SOCK ]] {
- [[ -o interactive ]] && echo "Preconfigured agent"
- } else {
- [[ -o interactive ]] && print -P "%F{red}No agent available"
+if [[ -o login ]] {
+ ### cd on login shell for convenience
+ cd ~
+} else {
+ if [[ ! -v _sev_first_display && ( -v DISPLAY || -v WAYLAND_DISPLAY ) ]] {
+ # this is to allow gpg and pinentry env to be updated
+ # XXX: will be sourced by every new child shell if zsh is not used to
+ # start the graphical session, but since .zprofile is light that
+ # shouldn't cause a noticeable performance impact
+ # NOTE: above happens with sway without a display manager or launcher
+ export _sev_first_display=
+ source ${ZDOTDIR:-~}/.zprofile
+ export _sev_first_display=0
+ } elif [[ $SHLVL == 1 ]] {
+ ### early zprofile sourcing for first shell
+ # NOTE: ensure profile is loaded for toplevel shells; should hopefully be 1
+ # under some Xorg or cron implementations, which is where this would be most useful
+ source ${ZDOTDIR:-~}/.zprofile
}
}
-
-### load site-specific
-if [[ -f ~/.zshenv.local ]] { source ~/.zshenv.local }
-
-### source .zprofile
-# if we used su, without --login, let's run zprofile ourselves
-# XXX: system zprofile is not run
-if [[ -v _sev_reset_shell || $SHLVL == 1 ]] source ~/.zprofile
-
-# vim: set et sts=4 sw=4 ts=8 tw=79 :
+# vim: et sts=4 sw=4 ts=8 tw=79