diff options
7 files changed, 271 insertions, 0 deletions
diff --git a/remote/modules/idleaction/data/etc/cron.d/openslx-idleaction b/remote/modules/idleaction/data/etc/cron.d/openslx-idleaction new file mode 100644 index 00000000..66dbcd5c --- /dev/null +++ b/remote/modules/idleaction/data/etc/cron.d/openslx-idleaction @@ -0,0 +1,6 @@ +# Trigger scripts that checks idle status of machine and triggers actions + +SHELL=/bin/ash + +*/5 * * * * root /opt/openslx/scripts/idleaction-cron_script + diff --git a/remote/modules/idleaction/data/opt/openslx/scripts/idleaction-cron_script b/remote/modules/idleaction/data/opt/openslx/scripts/idleaction-cron_script new file mode 100755 index 00000000..c59d0f3b --- /dev/null +++ b/remote/modules/idleaction/data/opt/openslx/scripts/idleaction-cron_script @@ -0,0 +1,97 @@ +#!/bin/ash + +. /opt/openslx/config || exit 1 + +# If existent, no session is open. Will contain timestamp of last activity. +# If not existent, at least one user is logged in +IDLEHINT="/dev/shm/idlehint" +NOW=$(date +%s) + +# +# 1) Check for idle timeout +# +if [ -n "${SLX_LOGOUT_TIMEOUT}" ]; then + # Logout timeout is set, see which users we should kick + IS_IDLE=yes + # get all sessions + SESSIONS=$(loginctl | awk '{print $1}') + if [ -n "$SESSIONS" ]; then + TMP=$(/dev/shm/idlecheck.tmp) + # Iterate over sessions + for ses in $SESSIONS; do + # Get information + loginctl show-session "$ses" > "$TMP" + NAME=$(grep '^Name=' "$TMP" | cut -c 6-) + [ -z "$NAME" ] && continue # No name - should not happen + export DISPLAY=$(grep '^Display=' "$TMP" | cut -c 9-) + # X11 + if [ -n "$DISPLAY" ]; then + # Seems to be x11 + USRHOME=$(getent passwd "$NAME" | awk -F ':' '{print $6}') + export XAUTHORITY="$USRHOME/.Xauthority" + # Now that we have DISPLAY and XAUTHORITY set, xprintidle should work + IDLE=$(xprintidle) + if [ -n "$IDLE" ]; then + IDLE=$(( $IDLE / 1000 )) + if [ "$IDLE" -lt "$SLX_LOGOUT_TIMEOUT" ]; then + IS_IDLE=no + else + loginctl terminate-session "$ses" + fi + fi + continue # Done with this session, skip normal tty/ssh checks + fi + # end X11 + # other sessions + IDLE=$(grep '^IdleSinceHint=' "$TMP" | cut -c 15-) + if [ "${#IDLE}" -lt 7 ]; then # wah wah waaaah + IS_IDLE=no + continue + fi + # divide by 1000000 by chopping of last 6 chars - number might be too large for $(( )) + IDLE=$(echo "$IDLE" | cut -c "-$(( ${#IDLE} - 6 ))") + [ "$IDLE" -gt "$NOW" ] && IDLE="$NOW" + IDLE=$(( $NOW - $IDLE )) + if [ "$IDLE" -lt "$SLX_LOGOUT_TIMEOUT" ]; then + IS_IDLE=no + else + loginctl terminate-session "$ses" + fi + # end other sessions + done + rm -f -- "$TMP" + if [ "$IS_IDLE" = "yes" ]; then + [ ! -e "$IDLEHINT" ] && echo "$NOW" > "$IDLEHINT" + else + rm -f -- "$IDLEHINT" + fi + fi +else + # No logout timeout is set, take shortcut for shutdown timeout (if set) + if [ -n "$SLX_SHUTDOWN_TIMEOUT" ]; then + SESSIONS=$(loginctl | wc -l) + if [ "$SESSIONS" = "0" ]; then + [ ! -e "$IDLEHINT" ] && echo "$NOW" > "$IDLEHINT" + else + rm -f -- "$IDLEHINT" + fi + fi +fi + +# +# 2) Check for no-session-shutdown timeout +# +if [ -n "$SLX_SHUTDOWN_TIMEOUT" ] && [ -e "$IDLEHINT" ]; then + IDLE=$(cat "$IDLEHINT") + [ "$IDLE" -gt "$NOW" ] && IDLE="$NOW" + IDLE=$(( $NOW - $IDLE )) + if [ "$IDLE" -gt "$SLX_SHUTDOWN_TIMEOUT" ]; then + poweroff -nf # TODO: Do proper shutdown once it works reliably + fi +fi + +# +# 3) Check for hard scheduled shutdown +# +# TODO + diff --git a/remote/modules/idleaction/idleaction.build b/remote/modules/idleaction/idleaction.build new file mode 100644 index 00000000..1b740aa1 --- /dev/null +++ b/remote/modules/idleaction/idleaction.build @@ -0,0 +1,16 @@ +fetch_source() { + : +} + +build() { + # We ship xprintidle's source as suse doesn't have it in one of the default repos + # and its just too tiny to do anything fancy like fetching source from somewhere + mkdir -p "$MODULE_BUILD_DIR/opt/openslx/bin" + gcc -o "$MODULE_BUILD_DIR/opt/openslx/bin/xprintidle" "$MODULE_DIR/xprintidle.c" -lX11 -lXss -lXext \ + || perror "Compilation of xprintidle failed!" +} + +post_copy() { + : +} + diff --git a/remote/modules/idleaction/idleaction.conf b/remote/modules/idleaction/idleaction.conf new file mode 100644 index 00000000..1661735b --- /dev/null +++ b/remote/modules/idleaction/idleaction.conf @@ -0,0 +1,4 @@ +REQUIRED_BINARIES=" + xprintidle +" + diff --git a/remote/modules/idleaction/idleaction.conf.opensuse b/remote/modules/idleaction/idleaction.conf.opensuse new file mode 100644 index 00000000..3aff5af0 --- /dev/null +++ b/remote/modules/idleaction/idleaction.conf.opensuse @@ -0,0 +1,6 @@ +REQUIRED_INSTALLED_PACKAGES=" + libX11-devel + libXss-devel + xorg-x11-proto-devel +" + diff --git a/remote/modules/idleaction/idleaction.conf.ubuntu b/remote/modules/idleaction/idleaction.conf.ubuntu new file mode 100644 index 00000000..0dad2e48 --- /dev/null +++ b/remote/modules/idleaction/idleaction.conf.ubuntu @@ -0,0 +1,6 @@ +REQUIRED_INSTALLED_PACKAGES=" + libx11-dev + libxss-dev + x11proto-scrnsaver-dev +" + diff --git a/remote/modules/idleaction/xprintidle.c b/remote/modules/idleaction/xprintidle.c new file mode 100644 index 00000000..7fc62486 --- /dev/null +++ b/remote/modules/idleaction/xprintidle.c @@ -0,0 +1,136 @@ +/* + +This program prints the "idle time" of the user to stdout. The "idle +time" is the number of milliseconds since input was received on any +input device. If unsuccessful, the program prints a message to stderr +and exits with a non-zero exit code. + +Copyright (c) 2005, 2008 Magnus Henoch <henoch@dtek.chalmers.se> +Copyright (c) 2006, 2007 by Danny Kukawka + <dkukawka@suse.de>, <danny.kukawka@web.de> +Copyright (c) 2008 Eivind Magnus Hvidevold <hvidevold@gmail.com> + +This program is free software; you can redistribute it and/or modify +it under the terms of version 2 of the GNU General Public License +as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the +Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +The function workaroundCreepyXServer was adapted from kpowersave-0.7.3 by +Eivind Magnus Hvidevold <hvidevold@gmail.com>. kpowersave is licensed under +the GNU GPL, version 2 _only_. + +*/ + +#include <X11/Xlib.h> +#include <X11/extensions/dpms.h> +#include <X11/extensions/scrnsaver.h> +#include <stdio.h> + +void usage(char *name); +unsigned long workaroundCreepyXServer(Display *dpy, unsigned long _idleTime ); + +int main(int argc, char *argv[]) +{ + XScreenSaverInfo ssi; + Display *dpy; + int event_basep, error_basep; + + if (argc != 1) { + usage(argv[0]); + return 1; + } + + dpy = XOpenDisplay(NULL); + if (dpy == NULL) { + fprintf(stderr, "couldn't open display\n"); + return 1; + } + + if (!XScreenSaverQueryExtension(dpy, &event_basep, &error_basep)) { + fprintf(stderr, "screen saver extension not supported\n"); + return 1; + } + + if (!XScreenSaverQueryInfo(dpy, DefaultRootWindow(dpy), &ssi)) { + fprintf(stderr, "couldn't query screen saver info\n"); + return 1; + } + + printf("%lu\n", workaroundCreepyXServer(dpy, ssi.idle)); + + XCloseDisplay(dpy); + return 0; +} + +void usage(char *name) +{ + fprintf(stderr, + "Usage:\n" + "%s\n" + "That is, no command line arguments. The user's idle time\n" + "in milliseconds is printed on stdout.\n", + name); +} + +/*! + * This function works around an XServer idleTime bug in the + * XScreenSaverExtension if dpms is running. In this case the current + * dpms-state time is always subtracted from the current idletime. + * This means: XScreenSaverInfo->idle is not the time since the last + * user activity, as descriped in the header file of the extension. + * This result in SUSE bug # and sf.net bug #. The bug in the XServer itself + * is reported at https://bugs.freedesktop.org/buglist.cgi?quicksearch=6439. + * + * Workaround: Check if if XServer is in a dpms state, check the + * current timeout for this state and add this value to + * the current idle time and return. + * + * \param _idleTime a unsigned long value with the current idletime from + * XScreenSaverInfo->idle + * \return a unsigned long with the corrected idletime + */ +unsigned long workaroundCreepyXServer(Display *dpy, unsigned long _idleTime ){ + int dummy; + CARD16 standby, suspend, off; + CARD16 state; + BOOL onoff; + + if (DPMSQueryExtension(dpy, &dummy, &dummy)) { + if (DPMSCapable(dpy)) { + DPMSGetTimeouts(dpy, &standby, &suspend, &off); + DPMSInfo(dpy, &state, &onoff); + + if (onoff) { + switch (state) { + case DPMSModeStandby: + /* this check is a littlebit paranoid, but be sure */ + if (_idleTime < (unsigned) (standby * 1000)) + _idleTime += (standby * 1000); + break; + case DPMSModeSuspend: + if (_idleTime < (unsigned) ((suspend + standby) * 1000)) + _idleTime += ((suspend + standby) * 1000); + break; + case DPMSModeOff: + if (_idleTime < (unsigned) ((off + suspend + standby) * 1000)) + _idleTime += ((off + suspend + standby) * 1000); + break; + case DPMSModeOn: + default: + break; + } + } + } + } + + return _idleTime; +} |
