How to Limit Daily Desktop Usage in Ubuntu

I have been looking for a way to limit the amount of time my kids spend on the computer. After toying with a couple of different things like timeoutd and pam_time, I decided to hack together something to meet my needs:

  1. My kids share a PC with their Mom using fast-user-switching, so I needed it to keep track of multiple sessions.
  2. I needed different times for different users ( Mom wouldn’t be too thrilled with me forcing her to log off after an hour or two )
  3. I wanted everyone to get ample warning so they could save their work and logout cleanly.

With those ideas in mind I came up with this:

timekpr

What timekpr does is watch for instances of the session manager, keep a running tally of the time they are running, and logs kills it when time is up. Several libnotify alerts let the user know when thier time is running out.

timekpr warning dialog

It’s pretty rough right now ( just a couple of hours of research and bash hacking ) but it just kicked my son of the PC after his alloted hour and a half, so it’s functional – YMMV – I need to allow for different time limits on the weekends, and it uses a less than elegant method for shutting down gnome-session, so it’s very much a work in progress.

To install it, down load the script, timekpr , and rename it. Copy it someplace useful and make it executable:

mv timekpr.txt timekpr.sh
chmod 755 timekpr.sh
sudo mv timekpr.sh /usr/local/bin

Next make a directory for the time tracking files and limits:

sudo mkdir /var/lib/timekpr

I added a line to /etc/rc.local

/usr/local/bin/timekpr &

to start the script after a re-boot.

to limit someone’s per day usage, just add the number of seconds they will be allowed to a file in /var/lib/timekpr

sudo echo 7200 > /var/lib/timekpr/username

where username is the account you want to time limit.

I hope some parent finds this useful, my kids hate it already! (Heaven forbid they should go outside now and then…)

* Update: 

8-Feb-07 – Found a little math bug – should be fixed now – Barbie sez, “Math is hard!”

03. February 2008 by Chris
Categories: Coding | Tags: | 23 comments

Comments (23)

  1. Hi, I was looking for a program that does exactly this, and I found something called timeoutd in the repos as well. I was wondering if you have seen this or if you have made any changes to your script since the last update.

  2. I had tried timeoutd – one of the problems I found with it is that it doesn’t seem to give any warnings to the desktop when it is about to kill your session. I does fit a real need, it can limit console and shell sessions as well, but it doesn’t really fit my need/want as well.

    My script is in active use at our house and has been effective in limiting my teens computer time – that being said, I really need to add a GUI so my wife can control their time allotments and I would like to add some kind of a reward system where Mom can give them extra time to use when they want when they have earned it.

  3. Hi Chris, I loved this script. I’ll put it to use as is to do the same need you mentioned.

    But I’ll also try to upgrade it, here is a list of functionalities I believe we can improve:

    Must Have
    1) Different limitations per day of the week
    2) Limit not only by seconds in use, also by specific times of the day, it would be like the user connects but has only 30 seconds to logout (or will be forced logout) if he is not inside a allowed window.
    3) Hability to extend the allowed time for the current day if an administrator types in a password and how many time to extend (this would attend your need to give extra time as reward).

    Good to Have
    4) A graphical interface to administer these options
    5) Prevent the user to manually change his control file to “obtain” extra time.
    6) A better logout method, something that pushes a logout allowing to save data
    7) Support for different languages, best if it is done by plug ins (will allow anyone to create a plug in)
    8) Create a control window for the user, so he can check the remaining time at any time and giving him some options, could be the ability to use extra credit (off course reducing the credit from a pool)
    9) Create a .deb package

    I personally don’t have much available time, but I also need to ensure proper usage for my teenagers (that is thought) so I will try, first thing first, I will translate the script to Brazilian-Portuguese as I am from Brazil and post it for anyone else to use.

  4. Thanks for the ideas, wagnerpereirasp! I have just started to play with pygtk to see how easy a UI would be and have been thinking about moving the time and limits data to sqlite3.
    I currently limit access to the data files by making them only editable but root or an sudoer – there should be a better way. The script has to run as root to force shutdown someone anyone’s session. I wish there was a cleaner way to shutdown gnome-session other than just killing it, but I haven’t found one yet.

    A system tray applet that displays the remaining time and can launch the time editor (after a gksudo login) sounds like a great idea!

    Translations is also a great idea – I am afraid I’m personally limited to English, so any help is appreciated!

  5. Hy Chris! I tried to use your script, but no way. I tried to execute it at console, then CLI sends a error message like this:

    /usr/local/bin/timekpr.sh: 94: [[: not found
    /usr/local/bin/timekpr.sh: 94: [[: not found
    robson, 6202, 20

    The value stored in /var/lib/timekpr/robson.time is 20, never more than it.

    Could you help me?

  6. redbob -
    You must be using Ubuntu? Ubuntu has changed the default shell from bash to dash. I coded this for bash so running it with:

    $ sh /usr/local/bin/timekpr.sh

    will over ride the #! line in the script and use the wrong shell. To fix it, either run as:

    $ bash /usr/local/bin/timekpr.sh

    or set it executable ( “$ chmod 755 /usr/local/bin/timekpr.sh” ) and execute it directly.

    I’ll have to look at making it “dash” compatible at some point.

  7. Pingback: Hogyan?

  8. Wow! I really want to thank you for this. I’ve been looking for EXACTLY this script at the request of my wife. She had my back against the wall and was going to make me install windows so that NetNanny could be installed. I sure hope this works as described on my system. Life will be good again. Thanks. I use Ubuntu 8.04.1

  9. I can’t get this to work on Hardy 8.04.1 32bit. Here is the error

    test@MSI-K8N-NEO4-PLAT-SLI:~$ sudo echo 300 > /var/lib/timekpr/test
    bash: /var/lib/timekpr/test: Permission denied
    test@MSI-K8N-NEO4-PLAT-SLI:~$

    I logged in as the primary original and as the newly created test account and get the same error each time.

    Help me make this work please.

  10. Okay, I got past the permissions error by running sudo -i and then running the command.

    The file was made and I set it to 300 for testing. I watched it tick away, and then several more minutes went bye. Then suddenly it logged me off. It NEVER displayed a warning. I’m fine with that.

    PROBLEM: Once it logged me out of my test user, it let me log right back in again. I waiting to see if this will kick me off again.

    There needs to be a way to prevent the person from logging back in and stealing yet a few more minutes.

  11. bucknasty:
    Yes, there is a bit of a bug that allows one loop or so worth of time before checking for live sessions so, 20 – 40 seconds passes before a new login gets kicked.
    The code depends on a utility called ‘notify-send’ which I think is in the libnotify package on Fedora and Ubuntu. Without this, notification area applet, and d-bus running, you don’t get alerts, but these are common defaults on current Ubuntu and Fedora systems.
    If you still have issues, drop a message here – I have been needing to put some time into making this more useful to people other than myself, so the feedback helps.

  12. Cris,

    I added the libnotify package and it worked out great. I also have a modified version of your script I’d like to send you. It limits the users login so that if they are logged out at 10pm (for instance), they can’t simply wait until midnight and start over. You can set the allowed time frame for usage to prevent sneaky kids.

    I have one problem though. I added the line indicated above that should start the script upon reboot but it doesn’t restart. My youngest has already learned all she needs to do is reboot the computer and she has unlimited time (unless I login and launch the script).

    I added a line to /etc/rc.local

    /usr/local/bin/timekpr &

    This isn’t working, can you help me with this?

  13. Have a look at this…

    #!/bin/bash
    ###
    # timekpr.sh – simple
    # watches gnome sessions and logs them out once the user has exceeded a set, per day limit
    # /var/lib/timekpr/$username.time hold a count of seconds user has had a gnome session
    # /var/lib/timekpr/$username hold the daily allowed seconds for the user
    #
    # you may need to install notify-send with: $apt-get install libnotify-bin
    #
    # Copyright 2008 Chris Jackson
    #
    # This program is free software: you can redistribute it and/or modify
    # it under the terms of the GNU General Public License as published by
    # the Free Software Foundation, either version 3 of the License, or
    # (at your option) any later version.
    #
    # 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.
    #
    # See .
    #

    default_limit=86400 # All day, new users is given this value
    grace_period=60 # how much time do we give to let the user log out?
    poll_time=20 # How often the script should check the timelogs
    from=7 # When is the users allowed to log in
    to=22 # When is the users no longer allowed to be loged in

    #Ubuntu uses alternatives so we look for x-session-manager instead of gnome-session
    SESSION_MANAGER=x-session-manager

    function logOut() {
    ## get the display and xauthority used by out session manager
    UDISPLAY=`grep -z DISPLAY
    /proc/$pid/environ | sed -e ‘s/DISPLAY=//’`
    XAUTHORITY=`grep -z XAUTHORITY
    /proc/$pid/environ | sed -e ‘s/XAUTHORITY=//’`

    # find DBUS session bus for this session
    DBUS_SESSION_BUS_ADDRESS=`grep -z DBUS_SESSION_BUS_ADDRESS
    /proc/$pid/environ | sed -e ‘s/DBUS_SESSION_BUS_ADDRESS=//’`
    # use it – give a warning, then another one 1/2 way through grace_period
    XAUTHORITY=”$XAUTHORITY” DISPLAY=”$UDISPLAY” DBUS_SESSION_BUS_ADDRESS=”$DBUS_SESSION_BUS_ADDRESS”
    notify-send –icon=gtk-dialog-warning –urgency=critical -t 10000 “$1″ “Your session is about to expire! You have $grace_period sec to save your work and logout.”
    sleep $(($grace_period/2)) # FIXME: this gives other sessions a free grace_period added to their accounting

    XAUTHORITY=”$XAUTHORITY” DISPLAY=”$UDISPLAY” DBUS_SESSION_BUS_ADDRESS=”$DBUS_SESSION_BUS_ADDRESS”
    notify-send –icon=gtk-dialog-warning –urgency=critical -t 10000 “$1″ “Your session is about to expire! You have $(($grace_period/2)) sec to save your work and logout.”
    sleep $(($grace_period/2)) # FIXME: this gives other sessions a free grace_period added to their accounting

    XAUTHORITY=”$XAUTHORITY” DISPLAY=”$UDISPLAY” DBUS_SESSION_BUS_ADDRESS=”$DBUS_SESSION_BUS_ADDRESS”
    notify-send –icon=gtk-dialog-warning –urgency=critical -t 10 “Shutting Down” “Shutting down session ($pid) now!”
    # FIXME – should really check to see if user has logged out yet
    sleep 10
    kill -HUP $pid #this is a pretty bad way of killing a gnome-session, but we warned ‘em

    ## uncomment the following to brutally kill all of the users processes
    sleep 10
    pkill -u $username

    ## killing gnome-session should be more like:
    #DISPLAY=”:0″ XAUTHORITY=”/tmp/.gdmEQ0V5T” SESSION_MANAGER=”local/wretched:/tmp/.ICE-unix/$pid” su -c ‘gnome-session-save –kill –silent’ $username
    ## but this can still leave processes to cleanup – plus it’s not easy to get SESSION_MANAGER

    }

    # get the usernames and PIDs of sessions

    while(true); do
    pidlists=$( ps –no-heading -fC $SESSION_MANAGER | awk ‘BEGIN{ FS=” ” } { print $1 “,” $2 }’ )
    for pidlist in $pidlists; do

    # split username and pid – FIXME – I bet this would be faster with bash arrays and substitution
    username=$( echo $pidlist | awk ‘BEGIN{ FS=”,”} { print $1}’ )
    pid=$( echo $pidlist | awk ‘BEGIN{ FS=”,”} { print $2}’ )

    # If the user is not enabled, give him $default_limit
    if [[ ! -e "/var/lib/timekpr/$username" ]]; then
    echo $default_limit > /var/lib/timekpr/$username
    fi

    if [[ -e "/var/lib/timekpr/$username.time" && `( stat -c '%z' /var/lib/timekpr/$username.time | cut -c9,10 )` == `date +%d` ]]; then
    # the time file exists and was last touched today, add $poll_time seconds to it
    timekpr=$(( `cat /var/lib/timekpr/$username.time` + $poll_time ))
    echo $timekpr > /var/lib/timekpr/$username.time
    else # the time file is missing or was last touched yesterday
    timekpr=$poll_time
    echo $timekpr > /var/lib/timekpr/$username.time
    fi

    echo $username, $pid, $timekpr

    # Is the user allowed to be loged in at this time?
    # We take it for granted that if they are allowed to log in all day ($default_limit) then
    # they can log in whenever they want, ie they are normal users
    if [ $(cat /var/lib/timekpr/$username) -ne $default_limit ]; then
    # Are we out of hours?
    if ( [ $(date +%k) -lt $from ] || [ $(date +%k) -ge $to ] ); then
    # Has the user been given extended log in hours?
    if [[ -e "/var/lib/timekpr/$username.allow" ]]; then
    # Was the extended log in hours given today?
    if [[ $(stat -c '%z' /var/lib/timekpr/$username.allow | cut -c9,10) != $(date +%d) ]]; then
    logOut “Only log in between $from and $to”
    rm /var/lib/timekpr/$username.allow
    fi
    else
    # User has not been given extended log in hours
    logOut “Only log in between $from and $to”
    fi
    fi
    fi

    # Is the limit exeeded
    if [[ $timekpr -ge `cat /var/lib/timekpr/$username` ]]
    then
    logOut “Daily time limit”
    fi
    done
    # Wait a while before we check again
    sleep $poll_time
    done

  14. Here is a rewards script called addtime.sh

    #!/bin/bash

    if [ $# -ne 2 ]; then
    echo “Usage $(basename $0) ”
    exit
    fi

    adj=$(($2*60))
    now=$(cat /var/lib/timekpr/$1.time)
    new=$(($now-$adj))
    echo $new > /var/lib/timekpr/$1.time
    limit=$(cat /var/lib/timekpr/$1)
    left=$(($limit-$new))
    echo
    echo “$2 minute(s) added to ${1}s account.”
    echo “$1 now has $(($left/60)) minute(s) left.”
    echo

  15. and extendlimits.sh

    #!/bin/bash

    if [ $# -ne 1 ]; then
    echo “Usage $(basename $0) ”
    exit
    fi

    if [[ -e "/var/lib/timekpr/$1.allow" ]]; then
    rm “/var/lib/timekpr/$1.allow”
    echo
    echo “$1 has been disallowed to log in outside of normal logon hours”
    echo
    else
    touch /var/lib/timekpr/$1.allow
    echo
    echo “$1 has been allowed to log in outside of normal logon hours”
    echo
    fi

  16. The modifications were done by a helpful person (.nedberg) on the Ubuntu forums. I take no credit for his hard work. I wish I knew how to program / script but it’s way over my head. Thanks to people like you and .nedberg, Ubuntu is a joy to run.

  17. Bucknasty, I copied the timekpr.sh script you posted and pasted over my existing file. When I run it, system raise the following message from Console:

    /usr/local/bin/timekpr.sh: 34: Syntax error: “(” unexpected

    :-

  18. I have the same error too.

  19. Hi Chris!

    I am .nedberg from the Ubuntuforums as bucknasty reffered to.

    Me and another forum user, forger, has made a completely new version of timekpr, rewritten in python. It has a GUI to configure time limits and when a user is allowed to log in.

    As bucknasty states abow I started making changes to your timekpr.sh script. forger and me still want to use the name timekpr for the project.

    Is this OK with you?

    You can follow the development at https://launchpad.net/timekpr.

  20. Pingback: Waggle Dance » Blog Archive » timekpr Grows Up ( or “Why I Love Open Source” )

  21. @redbob & alecava,

    You can download the latest deb and instructions from:

    “http://buck-nasty.blogspot.com/2008/09/timekeepr-keep-control-of-your-computer.html”

    Remove the quotation marks from the link..

    -Charles

  22. Pingback: Control parental en Ubuntu con Timekpr | El atareao

Leave a Reply