From 57b5ead0d007f040ca20cdb595a540a0ccc1a3cb Mon Sep 17 00:00:00 2001 From: Franklin-Qi Date: Sat, 10 Oct 2026 17:06:08 +0800 Subject: [PATCH] lightdm-session: do not block login on profile stderr Restore a distro-neutral session wrapper under data/ without the old modal config-error dialog, so profile stderr is logged only and installing zenity no longer stalls session start. Add a regression test. Fixes #482 --- data/Makefile.am | 3 + data/lightdm-session | 124 ++++++++++++++++++++++++++++++ tests/Makefile.am | 1 + tests/test-lightdm-session-stderr | 91 ++++++++++++++++++++++ 4 files changed, 219 insertions(+) create mode 100755 data/lightdm-session create mode 100755 tests/test-lightdm-session-stderr diff --git a/data/Makefile.am b/data/Makefile.am index 7f7b4a3fb..ffc3dce75 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -4,6 +4,9 @@ dist_init_DATA = init/lightdm.conf confdir = $(sysconfdir)/lightdm dist_conf_DATA = lightdm.conf users.conf keys.conf +# Default session-wrapper (see Seat:* session-wrapper / src/lightdm.c). +dist_sbin_SCRIPTS = lightdm-session + dbusconfdir = $(datadir)/dbus-1/system.d dist_dbusconf_DATA = org.freedesktop.DisplayManager.conf diff --git a/data/lightdm-session b/data/lightdm-session new file mode 100755 index 000000000..1dc32edb1 --- /dev/null +++ b/data/lightdm-session @@ -0,0 +1,124 @@ +#!/bin/bash +# +# LightDM wrapper to run around X sessions. +# +# Profile stderr is logged (typically into ~/.xsession-errors) but must not +# block session startup with a modal warning dialog. Non-empty stderr is not a +# reliable signal of fatal profile syntax errors (see issue #482). + +echo "Running X session wrapper" + +message () { + # pretty-print messages of arbitrary length; use xmessage if it + # is available and $DISPLAY is set + MESSAGE="$PROGNAME: $*" + echo "$MESSAGE" | fold -s -w ${COLUMNS:-80} >&2 + if [ -n "$DISPLAY" ] && which xmessage > /dev/null 2>&1; then + echo "$MESSAGE" | fold -s -w ${COLUMNS:-80} | xmessage -center -file - + fi +} + +errormsg () { + # exit script with error + message "$*" + exit 1 +} + +# temporary storage of error messages +ERR=$(mktemp --tmpdir config-err-XXXXXX) +trap 'rm -f "$ERR"' EXIT + +source_with_error_check () { + CONFIG_FILE="$1" + echo "Loading $CONFIG_FILE" + # Unset BASH_VERSION while sourcing so ~/.profile does not pull in bashrc. + BASH_VERSION= . "$CONFIG_FILE" 2>"$ERR" + # Keep stderr from profiles in the session log; do not present a blocking + # GUI dialog - stderr is not a reliable indicator of fatal syntax errors. + if [ -s "$ERR" ]; then + cat "$ERR" >&2 + fi + truncate -s 0 "$ERR" +} + +# Load profile +for file in "/etc/profile" "$HOME/.profile" "/etc/xprofile" "$HOME/.xprofile"; do + if [ -f "$file" ]; then + source_with_error_check "$file" + fi +done + +# Load resources +if type xrdb >/dev/null 2>&1; then + xresourcedir="/etc/X11/Xresources" + if [ -d "$xresourcedir" ]; then + for file in $xresourcedir/*; do + echo "Loading resource: $file" + xrdb -merge "$file" + done + fi + xresourcefile="$HOME/.Xresources" + if [ -f "$xresourcefile" ]; then + echo "Loading resource: $xresourcefile" + xrdb -merge "$xresourcefile" + fi +fi + +# Load keymaps +if type setxkbmap >/dev/null 2>&1; then + for file in "/etc/X11/Xkbmap" "$HOME/.Xkbmap"; do + if [ -f "$file" ]; then + echo "Loading keymap: $file" + setxkbmap `cat "$file"` + XKB_IN_USE=yes + fi + done +fi + +# Load xmodmap if not using XKB +if type xmodmap >/dev/null 2>&1; then + if [ -z "$XKB_IN_USE" ]; then + for file in "/etc/X11/Xmodmap" "$HOME/.Xmodmap"; do + if [ -f "$file" ]; then + echo "Loading modmap: $file" + xmodmap "$file" + fi + done + fi +fi + +unset XKB_IN_USE + +# Run all system xinitrc shell scripts. +xinitdir="/etc/X11/xinit/xinitrc.d" +if [ -d "$xinitdir" ]; then + for script in $xinitdir/*; do + echo "Loading xinit script $script" + if [ -x "$script" -a ! -d "$script" ]; then + . "$script" + fi + done +fi + +# Load Xsession scripts +# OPTIONFILE, USERXSESSION, USERXSESSIONRC and ALTUSERXSESSION are required +# by the scripts to work +xsessionddir="/etc/X11/Xsession.d" +OPTIONFILE=/etc/X11/Xsession.options +USERXSESSION=$HOME/.xsession +USERXSESSIONRC=$HOME/.xsessionrc +ALTUSERXSESSION=$HOME/.Xsession + +if [ -d "$xsessionddir" ]; then + for i in `ls $xsessionddir`; do + script="$xsessionddir/$i" + echo "Loading X session script $script" + if [ -r "$script" -a -f "$script" ] && expr "$i" : '^[[:alnum:]_-]\+$' > /dev/null; then + . "$script" + fi + done +fi + +echo "X session wrapper complete, running session $@" + +exec $@ diff --git a/tests/Makefile.am b/tests/Makefile.am index fc85348e0..dff3db82e 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -70,6 +70,7 @@ TESTS = \ test-session-stderr \ test-session-stderr-multi-write \ test-session-stderr-backup \ + test-lightdm-session-stderr \ test-xauthority \ test-corrupt-xauthority \ test-system-xauthority \ diff --git a/tests/test-lightdm-session-stderr b/tests/test-lightdm-session-stderr new file mode 100755 index 000000000..8b029240e --- /dev/null +++ b/tests/test-lightdm-session-stderr @@ -0,0 +1,91 @@ +#!/bin/sh +# Regression test for https://github.com/ubuntu/lightdm/issues/482 +# +# Profile scripts often write non-fatal messages to stderr. The session wrapper +# must log that output without invoking a blocking zenity/kdialog warning. + +set -eu + +if [ -n "${srcdir:-}" ]; then + ROOT="${srcdir}/.." +else + ROOT=$(CDPATH= cd -- "$(dirname "$0")/.." && pwd) +fi +WRAPPER="${ROOT}/data/lightdm-session" + +if [ ! -f "$WRAPPER" ]; then + echo "lightdm-session not found at $WRAPPER" >&2 + exit 1 +fi + +# Guard: shipped wrapper must not invoke the old blocking dialog helpers. +if grep -E '(^|[[:space:]])(\.|source)[[:space:]]+/usr/lib/lightdm/config-error-dialog\.sh|(^|[[:space:]])(zenity|kdialog)([[:space:]]|$)' "$WRAPPER" >/dev/null; then + echo "data/lightdm-session must not invoke config-error-dialog.sh, zenity, or kdialog" >&2 + exit 1 +fi + +TMP=$(mktemp -d) +trap 'rm -rf "$TMP"' EXIT + +export HOME="${TMP}/home" +mkdir -p "$HOME" "${TMP}/bin" + +cat > "${HOME}/.profile" <<'EOF' +echo "harmless profile noise" >&2 +EOF + +cat > "${TMP}/bin/zenity" <&2 +echo called > "${TMP}/dialog-called" +exit 1 +EOF +cat > "${TMP}/bin/kdialog" <&2 +echo called > "${TMP}/dialog-called" +exit 1 +EOF +chmod +x "${TMP}/bin/zenity" "${TMP}/bin/kdialog" + +for cmd in xrdb setxkbmap xmodmap; do + cat > "${TMP}/bin/${cmd}" <<'EOF' +#!/bin/sh +exit 0 +EOF + chmod +x "${TMP}/bin/${cmd}" +done + +cat > "${TMP}/bin/test-session" <"${TMP}/wrapper-out" 2>"${TMP}/wrapper-err"; then + echo "lightdm-session exited non-zero" >&2 + cat "${TMP}/wrapper-err" >&2 + exit 1 +fi + +if [ -f "${TMP}/dialog-called" ]; then + echo "blocking dialog helper was invoked" >&2 + exit 1 +fi + +if [ ! -f "${TMP}/session-ran" ]; then + echo "session command was not executed" >&2 + cat "${TMP}/wrapper-err" >&2 + exit 1 +fi + +if ! grep -F "harmless profile noise" "${TMP}/wrapper-err" >/dev/null; then + echo "profile stderr was not forwarded to the session log stream" >&2 + cat "${TMP}/wrapper-err" >&2 + exit 1 +fi + +exit 0