Re-exec through the login shell, so the session sees /etc/profile

The greeter starts this script with what pam and systemd put in the
environment and nothing else. start-cosmic re-execs itself through $SHELL to
pick up /etc/profile and the user's login files; not doing the same here is
why the two sessions disagreed about the environment.

Measured here, the difference is XDG_DATA_DIRS: empty without this, and with
it the two flatpak exports directories that hold the .desktop files and icons
the launcher reads. PATH is unchanged either way -- /etc/profile only appends
what is missing.

Differs from upstream in two ways. The recursion guard is an exported variable
rather than a positional --in-login-shell flag, because a flag has to survive
being quoted through another shell to be seen on the way back in, and if it
ever failed to, the login would hang instead of failing; an exported variable
survives exec by definition. And it uses bash's own `exec -l` rather than an
extra `bash -c` hop, since this script is already bash.

First in the file, deliberately: the login files may set XDG_CACHE_HOME, which
is where the log goes, so this happens while there is nothing to lose.
Verified the log still rotates exactly once per login.

see: https://github.com/pop-os/cosmic-session/issues/23
This commit is contained in:
2026-08-10 15:24:04 +07:00
parent f8fec1360b
commit e6f8d560ab
+46
View File
@@ -10,6 +10,52 @@
set -e
# Re-exec through the user's login shell, before anything else runs.
#
# The greeter starts this script with a minimal environment: what pam and
# systemd put there, and nothing from /etc/profile or the user's own login
# files. start-cosmic re-execs itself through $SHELL to pick those up, and not
# doing the same here is why the two sessions disagree about the environment.
# see: https://github.com/pop-os/cosmic-session/issues/23
#
# The measurable difference on this machine is XDG_DATA_DIRS. Without this pass
# it arrives empty; /etc/profile.d/flatpak.sh is what appends the two flatpak
# exports directories, and those are where flatpak applications keep the
# .desktop files and icons the launcher looks for. PATH is untouched either way
# -- /etc/profile only appends what is missing -- so this adds and does not
# rearrange.
#
# First in the file, deliberately. The login files are allowed to set
# XDG_CACHE_HOME, which is where the log below decides to go, so this has to
# happen while there is still nothing to lose. The cost is one extra process
# and, measured here, about 35ms.
#
# The guard is an exported variable rather than start-cosmic's positional
# `--in-login-shell`. A flag has to survive being quoted through another shell
# to be seen on the way back in; if it ever failed to, the script would re-exec
# itself forever and the login would hang instead of failing. An exported
# variable survives exec by definition, so the recursion cannot happen.
#
# `exec -l` is bash's own flag and this script is bash, so start-cosmic's extra
# `bash -c` hop buys nothing. The inner `exec` means the login shell replaces
# itself with the session rather than sitting there as its parent for the rest
# of the login.
#
# Whatever goes wrong here is unlogged, because the log does not exist yet --
# hence checking that the shell is real and runnable first rather than finding
# out from a session that dies silently.
if [[ -z "${HYPRCOSMIC_LOGIN_SHELL:-}" && -n "${SHELL:-}" && -x "${SHELL}" ]]; then
case "${SHELL##*/}" in
nologin | false)
# An account with no usable login shell still gets a desktop.
;;
*)
export HYPRCOSMIC_LOGIN_SHELL=1
exec -l "${SHELL}" -c "exec $(printf '%q' "$0")"
;;
esac
fi
# The forked binaries, installed alongside rather than over the stock ones.
#
# Pointing at /usr/bin/cosmic-session here would be a silent no-op: the system