|
| 1 | +#! /usr/bin/env sh |
| 2 | + |
| 3 | +# DESCRIPTION |
| 4 | +# |
| 5 | +# This script will log out the user and suspend the PC after a given period of inactivity. |
| 6 | +# A configurable warning is shown before the user is logged out and the pc suspended. |
| 7 | +# |
| 8 | +# The script will also suspend the PC after the same period of inactivity on the login screen. |
| 9 | +# This second part of the script requires "lightdm_greeter_setup_scripts" to be run and enabled to take effect |
| 10 | +# |
| 11 | +# The script is designed to wake up the PC 1 minute before a potential scheduled shutdown (on/off-schedule) |
| 12 | +# so that it can be shut down as planned. |
| 13 | +# If no scheduled shutdown exists, it will suspend the PC until it is woken manually. |
| 14 | +# |
| 15 | +# This script and "inactivity_logout_after_time.sh" are mutually exclusive, and each of them |
| 16 | +# are written to overwrite each other, so whichever was the last of them run takes effect. |
| 17 | +# |
| 18 | +# PARAMETERS |
| 19 | +# 1. Checkbox. Enables/disables the script. |
| 20 | +# 2. Integer. How many minutes to wait before showing the warning dialog |
| 21 | +# 3. Integer. How many minutes to wait before logging out and suspending |
| 22 | +# 4. String. (optional) The text to be shown in the warning dialog. If no input is given, a default is used |
| 23 | +# 5. String. (optional) The text to be shown on the dialog button. If no input is given, a default is used |
| 24 | + |
| 25 | +set -x |
| 26 | + |
| 27 | +ENABLE=$1 |
| 28 | +DIALOG_TIME_MINS=$2 |
| 29 | +LOGOUT_TIME_MINS=$3 |
| 30 | +DIALOG_TEXT=$4 |
| 31 | +BUTTON_TEXT=$5 |
| 32 | + |
| 33 | +# Note: Currently these logs are never rotated, so they'll grow and grow |
| 34 | +SUSPEND_SCRIPT="/usr/share/os2borgerpc/bin/inactive_logout.sh" |
| 35 | +SUSPEND_SCRIPT_LOG="/usr/share/os2borgerpc/bin/inactive_logout.log" |
| 36 | +LIGHTDM_SUSPEND_SCRIPT="/etc/lightdm/greeter-setup-scripts/suspend_after_time.sh" |
| 37 | +LIGHTDM_SUSPEND_SCRIPT_LOG="/etc/lightdm/scriptlogs/suspend_after_time.log" |
| 38 | +LIGHTDM_GREETER_SETUP_SCRIPT="/etc/lightdm/greeter_setup_script.sh" |
| 39 | + |
| 40 | +# Stop Debconf from interrupting when interacting with the package system |
| 41 | +export DEBIAN_FRONTEND=noninteractive |
| 42 | + |
| 43 | +error() { |
| 44 | + echo "$1" |
| 45 | + exit 1 |
| 46 | +} |
| 47 | + |
| 48 | +if get_os2borgerpc_config os2_product | grep --quiet kiosk; then |
| 49 | + error "Dette script er ikke designet til at blive anvendt på en kiosk-maskine." |
| 50 | +fi |
| 51 | + |
| 52 | +# Handle deactivating inactivity suspend |
| 53 | +if [ "$ENABLE" = "False" ]; then |
| 54 | + rm --force $SUSPEND_SCRIPT $LIGHTDM_SUSPEND_SCRIPT $SUSPEND_SCRIPT_LOG $LIGHTDM_SUSPEND_SCRIPT_LOG |
| 55 | + OLDCRON="/tmp/oldcron" |
| 56 | + crontab -l > $OLDCRON |
| 57 | + if [ -f "$OLDCRON" ]; then |
| 58 | + sed --in-place "\@$SUSPEND_SCRIPT@d" $OLDCRON |
| 59 | + crontab $OLDCRON |
| 60 | + rm --force $OLDCRON |
| 61 | + fi |
| 62 | + exit |
| 63 | +fi |
| 64 | + |
| 65 | +[ -z "$DIALOG_TIME_MINS" ] && error 'Please insert the time the user has to be inactive before dialog is shown.' |
| 66 | +[ -z "$LOGOUT_TIME_MINS" ] && error 'Please insert the time the user has to be inactive before being logged out.' |
| 67 | +[ "$DIALOG_TIME_MINS" -gt "$LOGOUT_TIME_MINS" ] && error 'Dialog time is greater than logout time and dialog will therefore not be shown. Edit dialog time!' |
| 68 | +[ -z "$DIALOG_TEXT" ] && DIALOG_TEXT="Du er inaktiv og bliver logget ud om kort tid..." |
| 69 | +[ -z "$BUTTON_TEXT" ] && BUTTON_TEXT="OK" |
| 70 | + |
| 71 | +# xprintidle uses milliseconds, so convert the user inputted minutes to that |
| 72 | +LOGOUT_TIME_MS=$(( LOGOUT_TIME_MINS * 60 * 1000 )) |
| 73 | +DIALOG_TIME_MS=$(( DIALOG_TIME_MINS * 60 * 1000 )) |
| 74 | + |
| 75 | +# Older versions of this script used sh, but our lightdm suspend script uses |
| 76 | +# bash specifics |
| 77 | +# The & after bash "$file" is necessary to prevent the lightdm suspend script from |
| 78 | +# blocking the login screen. It has to be escaped in sed |
| 79 | +# The spaces before sh and bash are necessary to prevent repeated runs of the script |
| 80 | +# from changing the file content to babash "$file" & & or similar |
| 81 | +if [ -f "$LIGHTDM_GREETER_SETUP_SCRIPT" ]; then |
| 82 | + # shellcheck disable=SC2016 |
| 83 | + sed --in-place 's/ sh "$file"/ bash "$file" \&/' "$LIGHTDM_GREETER_SETUP_SCRIPT" |
| 84 | +fi |
| 85 | + |
| 86 | +mkdir --parents "$(dirname $LIGHTDM_SUSPEND_SCRIPT)" "$(dirname $SUSPEND_SCRIPT_LOG)" |
| 87 | + |
| 88 | +TIMEOUT_SECS=$((LOGOUT_TIME_MINS * 60)) |
| 89 | + |
| 90 | +cat << EOF > "$LIGHTDM_SUSPEND_SCRIPT" |
| 91 | +#!/usr/bin/env bash |
| 92 | +
|
| 93 | +LOG=$LIGHTDM_SUSPEND_SCRIPT_LOG |
| 94 | +
|
| 95 | +while : |
| 96 | +do |
| 97 | + echo "Starting sleep for $TIMEOUT_SECS seconds" >> \$LOG |
| 98 | + sleep $TIMEOUT_SECS |
| 99 | + echo "Sleep over" >> \$LOG |
| 100 | + if [ -z \$(users) ]; then |
| 101 | + echo "no active users, suspending" >> \$LOG |
| 102 | + # If the pc has a time plan, don't use systemctl suspend, but instead rtcwake -m mem, |
| 103 | + # which is functionally the same and allows the machine to wake up in time to be shut down |
| 104 | + # by the time plan |
| 105 | + re="([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) .+" |
| 106 | + if [[ \$(crontab -l | grep scheduled_off) =~ \$re ]]; then |
| 107 | + MINUTES=\${BASH_REMATCH[1]} |
| 108 | + HOURS=\${BASH_REMATCH[2]} |
| 109 | + DAY=\${BASH_REMATCH[3]} |
| 110 | + MONTH=\${BASH_REMATCH[4]} |
| 111 | + YEAR=\$(date +%Y) |
| 112 | + # wake up 1 minute before shut down |
| 113 | + MINM1P60=\$(( \$(( MINUTES - 1)) + 60)) |
| 114 | + # Rounding minutes |
| 115 | + MINS=\$(( MINM1P60 % 60)) |
| 116 | + HRCORR=\$(( 1 - \$(( MINM1P60 / 60)))) |
| 117 | + HRS=\$(( HOURS - HRCORR)) |
| 118 | + HRS=\$(( \$(( HRS + 24)) % 24)) |
| 119 | + rtcwake -m mem --date "\$YEAR-\$MONTH-\$DAY \$HRS:\$MINS" |
| 120 | + else |
| 121 | + systemctl suspend |
| 122 | + fi |
| 123 | + else |
| 124 | + echo "should be logged in as \$(users) breaking loop" >> \$LOG |
| 125 | + break |
| 126 | + fi |
| 127 | +done |
| 128 | +
|
| 129 | +echo "exited loop" >> \$LOG |
| 130 | +exit 0 |
| 131 | +EOF |
| 132 | + |
| 133 | +# Install xprintidle |
| 134 | +apt-get update --assume-yes |
| 135 | + |
| 136 | +# Only try installing if it isn't already as otherwise it will exit with nonzero |
| 137 | +# and stop the script |
| 138 | +if ! dpkg --get-selections | grep -v deinstall | grep --quiet xprintidle; then |
| 139 | + if ! apt-get install --assume-yes xprintidle; then |
| 140 | + # apt install could fail due to debian frontend lock being unavailable |
| 141 | + # during automatic updates |
| 142 | + error "apt failed to install xprintidle" |
| 143 | + fi |
| 144 | +fi |
| 145 | + |
| 146 | +# if line already added to crontab: skip |
| 147 | +if ! crontab -l | grep "$SUSPEND_SCRIPT"; then |
| 148 | + line="* * * * * $SUSPEND_SCRIPT" |
| 149 | + (crontab -l -u root; echo "$line") | crontab -u root - |
| 150 | +fi |
| 151 | + |
| 152 | +# New auto_logout file, running as root |
| 153 | +cat <<- EOF > $SUSPEND_SCRIPT |
| 154 | + #!/usr/bin/env bash |
| 155 | +
|
| 156 | + # If the user is inactive for too long, a dialog will appear, warning the user that the session will end. |
| 157 | + # If the user do not touch the mouse or press any keyboard key the session will end. |
| 158 | + # Only have one dialog at a time, so remove preexisting ones. |
| 159 | + # Create a new message every time, in case someone didn't close it but |
| 160 | + # just put e.g. a browser in front, to ensure they or someone else gets a |
| 161 | + # new warning when/if inactivity is reached again |
| 162 | +
|
| 163 | + USER_DISPLAY=\$(who | grep -w 'user' | sed -rn 's/.*(:[0-9]*).*/\1/p') |
| 164 | +
|
| 165 | + # These are used by xprintidle |
| 166 | + export XAUTHORITY=/home/user/.Xauthority |
| 167 | + export DISPLAY=\$USER_DISPLAY |
| 168 | + su - user -c "DISPLAY=\$USER_DISPLAY xhost +localhost" |
| 169 | +
|
| 170 | + LOG=$SUSPEND_SCRIPT_LOG |
| 171 | +
|
| 172 | + echo $LOGOUT_TIME_MS \$(xprintidle) >> \$LOG |
| 173 | +
|
| 174 | + # If the pc has a time plan, don't use systemctl suspend, but instead rtcwake -m mem, |
| 175 | + # which is functionally the same and allows the machine to wake up in time to be shut down |
| 176 | + # by the time plan |
| 177 | +
|
| 178 | + if [ \$(xprintidle) -ge $LOGOUT_TIME_MS ]; then |
| 179 | + echo 'Logging user out' >> \$LOG |
| 180 | + pkill -KILL -u user |
| 181 | + echo 'suspending pc' >> \$LOG |
| 182 | + # If the pc has a time plan, don't use systemctl suspend, but instead rtcwake -m mem, |
| 183 | + # which is functionally the same and allows the machine to wake up in time to be shut down |
| 184 | + # by the time plan |
| 185 | + re="([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+) .+" |
| 186 | + if [[ \$(crontab -l | grep scheduled_off) =~ \$re ]]; then |
| 187 | + MINUTES=\${BASH_REMATCH[1]} |
| 188 | + HOURS=\${BASH_REMATCH[2]} |
| 189 | + DAY=\${BASH_REMATCH[3]} |
| 190 | + MONTH=\${BASH_REMATCH[4]} |
| 191 | + YEAR=\$(date +%Y) |
| 192 | + # wake up 1 minute before shut down |
| 193 | + MINM1P60=\$(( \$(( MINUTES - 1)) + 60)) |
| 194 | + # Rounding minutes |
| 195 | + MINS=\$(( MINM1P60 % 60)) |
| 196 | + HRCORR=\$(( 1 - \$(( MINM1P60 / 60)))) |
| 197 | + HRS=\$(( HOURS - HRCORR)) |
| 198 | + HRS=\$(( \$(( HRS + 24)) % 24)) |
| 199 | + # When run from the crontab, rtcwake needs the full path for some reason or it won't work |
| 200 | + /usr/sbin/rtcwake -m mem --date "\$YEAR-\$MONTH-\$DAY \$HRS:\$MINS" |
| 201 | + else |
| 202 | + systemctl suspend |
| 203 | + fi |
| 204 | + exit 0 |
| 205 | + fi |
| 206 | + # if idle time is past the dialog time: show the dialog |
| 207 | + if [ \$(xprintidle) -ge $DIALOG_TIME_MS ]; then |
| 208 | + # Do spare the poor lives of potential other zenity windows. |
| 209 | + PID_ZENITY="\$(pgrep --full 'Inaktivitet')" |
| 210 | + if [ -n \$PID_ZENITY ]; then |
| 211 | + kill \$PID_ZENITY |
| 212 | + fi |
| 213 | + # echo 'Running zenity...' >> \$LOG |
| 214 | + # We use the --title to match against above |
| 215 | + zenity --warning --text="$DIALOG_TEXT" --ok-label="$BUTTON_TEXT" --no-wrap --display=\$USER_DISPLAY --title "Inaktivitet" |
| 216 | + fi |
| 217 | +EOF |
| 218 | + |
| 219 | +chmod +x $SUSPEND_SCRIPT |
0 commit comments