User Idle Time in Linux

How can I check a user's idle time in Linux?

The idle time measured by w is simply indicating how long since something was typed on the terminal a process is attached to. As seen e.g. here this is inaccurate for actually measuring user activity, since they might be using solely graphical input and not typing anything.

If your users are logged into an X11 session, the X client library has its own idle timer which can be queried; see e.g. User idle time being reset to 0 after 30 secs on Linux

Cloud monitoring systems appear to examine things like CPU load and network traffic to decide when to declare an instance as idle. They probably have a baseline of system processes which can be ignored, and then simply add a tick whenever a non-system process is detected.

For your use case, perhaps a simple network monitoring tool would be the easiest to set up. If your users are always logged in over SSH, check for traffic on port 22; if there is none over several minutes, the instance is idle. For X11 sessions, something similar could be set up for X protocol traffic (ports typically in the range from 6000 up).

How to compare the user idle session in bash to a limit in minutes?

This Shellshock-clean code prints details of sessions on the current machine that have been idle for more than 30 minutes:

#! /bin/bash -p

# Check if an idle time string output by 'who -u' represents a long idle time
# (more than 30 minutes)
function is_long_idle_time
{
local -r idle_time=$1

[[ $idle_time == old ]] && return 0
[[ $idle_time == *:* ]] || return 1

local -r hh=${idle_time%:*}
local -r mm=${idle_time#*:}
local -r idle_minutes=$((60*10#$hh + 10#$mm))

(( idle_minutes > 30 )) && return 0 || return 1
}

who_output=$(LC_ALL=C who -u)

while read -r user tty _ _ _ idle_time pid _ ; do
if is_long_idle_time "$idle_time" ; then
printf 'user=%s, tty=%s, idle_time=%s, pid=%s\n' \
"$user" "$tty" "$idle_time" "$pid"
fi
done <<<"$who_output"

The code assumes that the output of LC_ALL=C who -H -u looks like:

NAME     LINE         TIME         IDLE          PID COMMENT
username pts/9 Apr 25 18:42 06:44 3366 (:0)
username pts/10 Apr 25 18:42 old 3366 (:0)
username pts/11 Apr 25 18:44 . 3366 (:0)
username pts/12 Apr 25 18:44 00:25 3366 (:0)
...

It may look different on your system, in which case the code might need to be modified.

  • The "idle" string output by who -u can take several different forms. See who (The Open Group Base Specifications Issue 7) for details. Processing it is not completely trivial and is done by a function, is_long_idle_time, to keep the main code simpler.
  • The function extracts the hours (hh (06)) and minutes (mm (44)) from idle strings like '06:44' and calculates a total number of idle minutes (idle_minutes (404)). The base qualifiers (10#) in the arithmetic expression are necessary to prevent strings '08' and '09' being treated as invalid octal numbers. See Value too great for base (error token is "08").
  • The format of the who -u output can (and does) differ according to the Locale. Running it with LC_ALL=C who -u ensures that it will generate the same output regardless of the user's environment. See Explain the effects of export LANG, LC_CTYPE, LC_ALL.
  • Within the main loop you get the username, terminal/line, idle time, and PID of all sessions that have been idle for more than 30 minutes. However, it may not be straightforward to use this information to kill idle sessions. On some systems, multiple sessions may be associated with the same PID. Even if you can reliably determine the PIDs of idle sessions, the idleness may be false. For instance, a session that is running a long-running program that has generated no terminal output (yet) will appear to be idle. Killing it might not be a smart thing to do though. Consider using TMOUT instead. See How can one time out a root shell after a certain period of time? (and note that it can be used for any user, not just root).

multiplatform way to retrieve user idle time

Standard C has time.h, in there are the functions time
and difftime. These can be used to compute the time between
user inputs by storing the previous value between events.

Here is an example. (error checking has been removed for brevity)

void on_event() {
static time_t old = 0;
time_t new = time(NULL);
if (old != 0) {
double diff = difftime(new, old);
if (diff != 0)
printf("%g seconds idle\n", diff);
}
old = new;
}

Actually getting events requires platform-specific code, there are various libraries that have most, if not all, of that done already. GTK+ and SDL are popular libraries for C with different uses. There are ways to use Tk with C, and there are various cross-platform C++ libraries. It may also be helpful to note some of the questions regarding C GUI libraries that already exist.

How to get idle time in Linux?

import os
import time
import threading

# Starts inactivity timer
def start_timer():
platform = check_platform()
if platform == "Windows":
def timer_start():
while True:
time.sleep(1)
check_if_idle_windows()
thread1 = threading.Thread(target=timer_start)
thread1.start()

elif platform == "Linux":
def timer_start():
while True:
time.sleep(1)
check_if_idle_linux()
thread1 = threading.Thread(target=timer_start)
thread1.start()

# Checks what OS you're using
def check_platform():
if os.name == "nt":
platform = "Windows"
else:
platform = "Linux"
return platform

# Checks if the user is idle on Windows
def check_if_idle_windows():
import win32api
idle_time = (win32api.GetTickCount() - win32api.GetLastInputInfo()) / 1000.0
if idle_time > 3:
os.system("cls")
print("You have been logged out due to inactivity.")
os._exit(0)

# Checks if the user is idle on Linux
def check_if_idle_linux():
import subprocess
idle_time = int(subprocess.getoutput('xprintidle')) / 1000 # Requires xprintidle (sudo apt install xprintidle)
if idle_time > 3:
os.system("clear")
print("You have been logged out due to inactivity.")
os._exit(0)

def random_function_for_main_thread():
while True:
my_string = input("Enter something or stay inactive for 3 seconds : ")
print("You entered something.")

def main():
start_timer()
random_function_for_main_thread()

if __name__ == "__main__":
main()

User idle time being reset to 0 after 30 secs on Linux

Once you have the dbus sender (as shown on dbus-monitor there) you can do:

dbus-send --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.GetConnectionUnixProcessID string:':1.97538'

plugging in the actual sender. That gives you the pid that's sending the message.

Then say the pid is 2144, you'd do:

cat /proc/2144/cmdline

as one way to see what the program is.



Related Topics



Leave a reply



Submit