GalliumOS / galliumos-distro

Docs, issues, and artwork sources for GalliumOS
https://galliumos.org/
GNU General Public License v2.0
346 stars 11 forks source link

hdmi-change script (getXuser function) is broken #553

Open kinggrowler opened 4 years ago

kinggrowler commented 4 years ago

Acer Chromebook 14 (Edgar) with MrChromeBox Legacy firmware.

NAME="GalliumOS" VERSION="3.1 (Bismuth)" ID=galliumos ID_LIKE="ubuntu debian" PRETTY_NAME="GalliumOS 3.1" VERSION_ID="3.1" HOME_URL="https://galliumos.org/" SUPPORT_URL="https://galliumos.org/" BUG_REPORT_URL="https://https://github.com/GalliumOS/galliumos-distro/issues" VERSION_CODENAME=bismuth UBUNTU_CODENAME=bionic

Problem: /usr/bin/hdmi-change is broken. Or, more accurately, the 'getXuser' function fails because $user variable does not get populated. This script is provided by "galliumos-base" package.

This script is executed after every "resume from sleep" by the script in "/lib/systemd/system-sleep/hdmi-change.sh". On my system, I see an error message after each resume:

Jan 18 11:58:34 gally-51F9 systemd-sleep[14357]: sudo: unknown user: env
Jan 18 11:58:34 gally-51F9 systemd-sleep[14357]: sudo: unable to initialize policy plugin

This error is produced by /usr/bin/hdmi-change. You can see this error if you run the script manually:

]$ sudo /usr/bin/hdmi-change
sudo: unknown user: env
sudo: unable to initialize policy plugin

This happens because the 'getXuser' function no longer works correctly; the '$user' variable does not get populated:

# getXuser gets the X user belonging to the display in $displaynum.
getXuser() {
    export user=`pinky -fw | awk '{ if ($2 == "pts/'$displaynum'" || $2 == ":'$displaynum'" ) { print $1; exit; } }'`
}

for x in /tmp/.X11-unix/*; do
  displaynum=`echo $x | sed s#/tmp/.X11-unix/X##`
  getXuser;
  sudo -u $user env DISPLAY=":$displaynum" XAUTHORITY=/home/$user/.Xauthority /usr/bin/xrandr --auto
done

You can see the problem if you run each part separately:

]$ for x in /tmp/.X11-unix/*; do displaynum=`echo $x | sed s#/tmp/.X11-unix/X##` ; echo $displaynum ; done
0

(...we are using DISPLAY 0...)

]$ pinky -fw | awk '{ if ($2 == "pts/0" || $2 == ":0" ) { print $1; exit; } }'

(...we get NO value returned, which means that the variable '$user' is not getting populated...)

What is happening? 'pinky' never returns anything we look for:

]$ pinky -fw
kinggrowler     pts/1           2020-02-13 22:46 :pts/0:S.1
kinggrowler     pts/2    00:06  2020-02-15 05:27 :pts/0:S.0
kinggrowler     pts/3           2020-02-15 10:05 :pts/0:S.2

We see above that 'getXuser' is searching for "pts/0" however pinky never returns this value. The '$user' variable remains empty; the function is run with a null user:

sudo -u $user env...

is run with empty variable instead:

sudo -u env

...thus the error message in syslog about 'sudo: unknown user: env '.

This empty variable prevents the /usr/bin/hdmi-change script from ever running correctly.

Possible solution:

We need to tweak the 'getXuser' function. This is more difficult than expected; some possible solutions:

https://unix.stackexchange.com/a/542430

https://superuser.com/a/1122517

I have tested the following replacement for the 'getXuser' function and it works correctly for me. Disclosure: I have not tested expensively, or on hardware other than my Edgar.

# getXuser gets the X user belonging to the display in $displaynum.
getXuser() {
    export user=`loginctl --no-legend list-sessions | awk '{print $1}' | while read sessionid; do [ $(loginctl --property Type --value show-session $sessionid) = 'x11' ] && loginctl --property Name --value show-session $sessionid; done`
}

When run manually we see the correct user for the X DISPLAY:

]$ sudo loginctl --no-legend list-sessions | awk '{print $1}' | while read sessionid; do [ $(loginctl --property Type --value show-session $sessionid) = 'x11' ] && loginctl --property Name --value show-session $sessionid; done
kinggrowler

This accurately populates '$user' variable and the script /usr/bin/hdmi-change executes without error, and the mysterious messages in syslog goes away.

Here is a proposed patch for this solution:

--- ./hdmi-change.old   2018-05-11 22:26:13.000000000 -0700
+++ hdmi-change.new     2020-02-15 10:32:21.241707443 -0800
@@ -2,10 +2,10 @@

 # Run xrandr --auto when hdmi changes are detected

-# getXuser() taken from: http://askubuntu.com/questions/20585/how-to-lock-xscreensaver-on-suspend
+# getXuser() taken from ideas at: https://unix.stackexchange.com/a/542430
 # getXuser gets the X user belonging to the display in $displaynum.
 getXuser() {
-    export user=`pinky -fw | awk '{ if ($2 == "pts/'$displaynum'" || $2 == ":'$displaynum'" ) { print $1; exit; } }'`
+    export user=`loginctl --no-legend list-sessions | awk '{print $1}' | while read sessionid; do [ $(loginctl --property Type --value show-session $sessionid) = 'x11' ] && loginctl --property Name --value show-session $sessionid; done`
 }

 for x in /tmp/.X11-unix/*; do

Hope this helps some folks!