grover66 / kidtimer

Script to manage computer usage by time and schedule.
18 stars 23 forks source link

Multiple issues to fix - patch provided #20

Open StoicTheVast opened 9 years ago

StoicTheVast commented 9 years ago

Hi,

Thanks for the project. Unfortunately I had a number of issues getting it to work on my kids' computer (zorin-os 6, based on ubuntu 12.04 LTS).

Summary:

In /usr/local/bin/kidtimer, I had to make the following changes:

Here is my patch to /usr/local/bin/kidtimer ...

--- kidtimer.orig       2014-09-23 23:53:41.970147275 +0930
+++ kidtimer.fixed      2014-09-24 00:08:35.104446943 +0930
@@ -65,11 +65,16 @@

 go_check () {
 for I in `/bin/cat $configdir/kid.list | sort -u`; do
+        # This method ( /usr/bin/users ) to determine who is logged in is a kludge.  It ignores locked screens (screensaver active) and switched user states.
         /usr/bin/users | /bin/grep -q $I
         if [ $? -eq 0 ]; then
                 if [ -e $basedir/time/$I.ttl ]; then
                         C=`/bin/cat $basedir/time/$I.ttl`
-                        C=$((C - 1))
+                        if [ $C -le 0 ]; then
+                                C=0
+                        else
+                                C=$((C - 1))
+                       fi
                         echo $C > $basedir/time/$I.ttl
                 else
                        get_ttl_time $I > $basedir/time/$I.ttl
@@ -77,8 +82,8 @@
                 fi
                # check time
                if [ $C -le 5 ]; then
+                       /usr/bin/passwd $I -l
                        if [ ! -e /tmp/kidtimer.shutdown.$I ]; then
-                               /usr/bin/passwd $I -l
                                go_logout $I
                        fi
                fi
@@ -128,7 +133,13 @@
                                 /usr/bin/passwd $I -u
                         else
                                 /usr/bin/passwd $I -l
-                                /usr/bin/users | /bin/grep -q $I && /usr/local/bin/kidtimer shutdown $I
+                                # This method ( /usr/bin/users ) to determine who is logged in is a kludge.  It ignores locked screens (screensaver active) and switched user states.
+                                /usr/bin/users | /bin/grep -q $I
+                                if [ $? -eq 0 ]; then
+                                       if [ ! -e /tmp/kidtimer.shutdown.$I ]; then
+                                               go_logout $I
+                                       fi
+                               fi
                         fi
                 fi
         done
@@ -155,24 +166,45 @@
 TEXT=$((6-$T))
 TMPFILE="/tmp/kidtimer.send$T.bash.$K"
 /bin/rm -f $TMPFILE
+touch $TMPFILE
+chmod +x $TMPFILE
+
 echo "#!/bin/bash" > $TMPFILE
-D=`/usr/bin/who | grep $K | grep -m1 "(:" | cut -d\( -f2 | sed s/\)// | sed s/://`
+
+# This method to determine the correct display doesn't work, at least on zorin.
+# It only seems to detect a user who has an active shell running
+#D=`/usr/bin/who | grep $K | grep -m1 "(:" | cut -d\( -f2 | sed s/\)// | sed s/://`
+
+# So instead I'll just send the message to all the first 10 displays, and the ones owned by the correct user will show the message, the rest won't
 if [ -e $basedir/locale/$LANG ]; then
-       MSG=`/bin/sed -n "$LINE"p /usr/local/kidtimer/locale/$LANG`
+       MSG="$K: `/bin/sed -n "$LINE"p /usr/local/kidtimer/locale/$LANG`"
 else
-       MSG="Your computer time will end in $TEXT minutes."
+       MSG="$K's computer time will end in $TEXT minutes."
 fi
-echo "/bin/su $K -c 'DISPLAY=:$D /usr/bin/notify-send -i /usr/local/kidtimer/icons/kidtimer-$TEXT.png \
+
+for (( D = 0 ; D < 10 ; D = D + 1 )); do
+        echo "/bin/su $K -c 'DISPLAY=:$D /usr/bin/notify-send -i /usr/local/kidtimer/icons/kidtimer-$TEXT.png \
        \"ALERT\" \"$MSG\"'" >> $TMPFILE
+done
+
 echo "/bin/rm -f $TMPFILE" >> $TMPFILE
 echo "/bin/bash $TMPFILE" | /usr/bin/at now + $T minutes
+# Note you need the file /var/spool/cron/atjobs/.SEQ owned by daemon:daemon for at to work properly!!!
 }

 go_killall () {
 K=$1
 /bin/rm -f /tmp/killall.bash.$K
+touch /tmp/killall.bash.$K
+chmod +x /tmp/killall.bash.$K
+
 echo "#!/bin/bash" > /tmp/killall.bash.$K
+# Not sure if it is better or worse to do a normal kill first...
+# Programs like Firefox will reopen all their previous tabs if it is killed with -KILL
+# But other programs would probably do better if given a chance to save state/data and clean up after themselves eg open office???
+#echo "/usr/bin/pkill -TERM -u $K" >> /tmp/killall.bash.$K
+#echo "/bin/sleep 5" >> /tmp/killall.bash.$K
 echo "/usr/bin/pkill -KILL -u $K" >> /tmp/killall.bash.$K
 echo "/bin/rm -rf /tmp/kidtimer.shutdown.$K" >> /tmp/killall.bash.$K
 echo "/bin/rm -f /tmp/killall.bash.$K" >> /tmp/killall.bash.$K
@@ -450,4 +482,3 @@
         ;;
 esac
 exit 0
-

And here's the full text of the fixed version:

#!/bin/bash
# Restrict kids computer access to specific hours and total time.
# By: Michael Groves - grover66_at_gmail_dot_com

#variables
#LANG="en_US.UTF-8" #unremark to change preferred language.
basedir="/usr/local/kidtimer"
configdir="/etc/kidtimer"
Cdate=`/bin/date +%Y-%m-%d`
TUI=0
HOUR=`/bin/date +%H`
DOW=`/bin/date +%u`
WEEKEND="no"
[ "$DOW" == "6" ] && WEEKEND="yes"
[ "$DOW" == "7" ] && WEEKEND="yes"
[ ! -e $configdir/kid.list ] && touch $configdir/kid.list
[ ! -e $basedir/locale/$LANG ] && LANG="en_US.UTF-8"

#arguments
[ $# -eq 0 ] && TUI=1
[ $# -eq 1 ] && COMMAND=$1
[ $# -eq 2 ] && COMMAND=$1 && KID=$2
[ $# -eq 3 ] && COMMAND=$1 && KID=$2 && Time=$3

################# Subroutines ##################
################################################

get_info () {
echo "kidtimer info"
echo "---------------------------------------------"
/bin/date
echo "---"
echo "find /usr/local/kidtimer/ -print | sort"
/usr/bin/find /usr/local/kidtimer/ -print | /usr/bin/sort
echo "---"
echo "cat $configdir/kid.list"
/bin/cat $configdir/kid.list
echo "---"
echo "passwd -S -a"
/usr/bin/passwd -S -a
echo "---"
echo "cat /usr/local/kidtimer/schedule/*"
/bin/cat /usr/local/kidtimer/schedule/*
echo "---"
echo "cat /usr/local/kidtimer/time/*"
/bin/cat /usr/local/kidtimer/time/*
echo "---"
echo "cat /etc/cron.d/kidtimer"
/bin/cat /etc/cron.d/kidtimer
echo "---"
echo "apt-cache showpkg kidtimer"
/usr/bin/apt-cache showpkg kidtimer
echo "---"
echo "cat /etc/lsb-release"
/bin/cat /etc/lsb-release
echo "---"
echo "uname -a"
/bin/uname -a
echo "---"
echo "env"
/usr/bin/env
echo
}

go_check () {
for I in `/bin/cat $configdir/kid.list | sort -u`; do
        # This method ( /usr/bin/users ) to determine who is logged in is a kludge.  It ignores locked screens (screensaver active) and switched user states.
        /usr/bin/users | /bin/grep -q $I
        if [ $? -eq 0 ]; then
                if [ -e $basedir/time/$I.ttl ]; then
                        C=`/bin/cat $basedir/time/$I.ttl`
                        if [ $C -le 0 ]; then
                                C=0
                        else
                                C=$((C - 1))
            fi
                        echo $C > $basedir/time/$I.ttl
                else
            get_ttl_time $I > $basedir/time/$I.ttl
                        C=`/bin/cat $basedir/time/$I.ttl`
                fi
        # check time
        if [ $C -le 5 ]; then
                    /usr/bin/passwd $I -l
                    if [ ! -e /tmp/kidtimer.shutdown.$I ]; then
                            go_logout $I
                    fi
            fi
        else
                go_clean_jobs $I
        fi
done
}

get_ttl_time () {
        [ "$WEEKEND" == "no" ] && /bin/cat $basedir/schedule/$1 | /bin/grep ^MAX | /usr/bin/awk '{ print $2 }'
        [ "$WEEKEND" == "yes" ] && /bin/cat $basedir/schedule/$1 | /bin/grep ^MAX | /usr/bin/awk '{ print $3 }'
}

go_clean_jobs () {
K=$1
for I in `/usr/bin/atq | /usr/bin/awk '{ print $1 }' | /usr/bin/sort`; do
        /usr/bin/at -c $I | /bin/grep -q "bash.$K"
        [ $? -eq 0 ] && /usr/bin/at -d $I
done
[ -e /tmp/kidtimer.shutdown.$K ] && /bin/rm -rf /tmp/kidtimer.shutdown.$K
}

go_daily () {
for I in `/bin/cat $configdir/kid.list | sort -u`; do
        /usr/bin/stat -c %y $basedir/time/$I.ttl | /bin/grep -q $Cdate
        if [ ! $? -eq 0 ]; then
        get_ttl_time $I > $basedir/time/$I.ttl
        fi
done
go_hourly
}

go_hourly () {
if [ -s $configdir/kid.list ]; then
        for I in `/bin/cat $configdir/kid.list | sort -u`; do
                if [ -e $basedir/schedule/$I ]; then
                        [ -e $basedir/time/$I.ttl ] && C=`/bin/cat $basedir/time/$I.ttl`
                        [ $C -le 0 ] && /usr/bin/passwd $I -l && exit 0
                        [ "$WEEKEND" == "no" ] && R=`/bin/grep ^$HOUR $basedir/schedule/$I | /usr/bin/awk '{ print $2 }'`
                        [ "$WEEKEND" == "yes" ] && R=`/bin/grep ^$HOUR $basedir/schedule/$I | /usr/bin/awk '{ print $3 }'`
                        if [ "$R" == "y" ]; then
                                /usr/bin/passwd $I -u
                        else
                                /usr/bin/passwd $I -l
                                # This method ( /usr/bin/users ) to determine who is logged in is a kludge.  It ignores locked screens (screensaver active) and switched user states.
                                /usr/bin/users | /bin/grep -q $I
                                if [ $? -eq 0 ]; then
                            if [ ! -e /tmp/kidtimer.shutdown.$I ]; then
                                    go_logout $I
                    fi
                        fi
                        fi
                fi
        done
fi
}

go_logout () {
K=$1
go_send $K 5
go_send $K 4
go_send $K 3
go_send $K 2
go_send $K 1
go_killall $K
/usr/bin/touch /tmp/kidtimer.shutdown.$K
}

go_send () {
K=$1
T=$2
LINE=$((7-$T))
TEXT=$((6-$T))
TMPFILE="/tmp/kidtimer.send$T.bash.$K"
/bin/rm -f $TMPFILE
touch $TMPFILE
chmod +x $TMPFILE

echo "#!/bin/bash" > $TMPFILE

# This method to determine the correct display doesn't work, at least on zorin.
# It only seems to detect a user who has an active shell running
#D=`/usr/bin/who | grep $K | grep -m1 "(:" | cut -d\( -f2 | sed s/\)// | sed s/://`

# So instead I'll just send the message to all the first 10 displays, and the ones owned by the correct user will show the message, the rest won't
if [ -e $basedir/locale/$LANG ]; then
    MSG="$K: `/bin/sed -n "$LINE"p /usr/local/kidtimer/locale/$LANG`"
else
    MSG="$K's computer time will end in $TEXT minutes."
fi

for (( D = 0 ; D < 10 ; D = D + 1 )); do
        echo "/bin/su $K -c 'DISPLAY=:$D /usr/bin/notify-send -i /usr/local/kidtimer/icons/kidtimer-$TEXT.png \
    \"ALERT\" \"$MSG\"'" >> $TMPFILE
done

echo "/bin/rm -f $TMPFILE" >> $TMPFILE
echo "/bin/bash $TMPFILE" | /usr/bin/at now + $T minutes
# Note you need the file /var/spool/cron/atjobs/.SEQ owned by daemon:daemon for at to work properly!!!
}

go_killall () {
K=$1
/bin/rm -f /tmp/killall.bash.$K
touch /tmp/killall.bash.$K
chmod +x /tmp/killall.bash.$K

echo "#!/bin/bash" > /tmp/killall.bash.$K
# Not sure if it is better or worse to do a normal kill first...
# Programs like Firefox will reopen all their previous tabs if it is killed with -KILL
# But other programs would probably do better if given a chance to save state/data and clean up after themselves eg open office???
#echo "/usr/bin/pkill -TERM -u $K" >> /tmp/killall.bash.$K
#echo "/bin/sleep 5" >> /tmp/killall.bash.$K
echo "/usr/bin/pkill -KILL -u $K" >> /tmp/killall.bash.$K
echo "/bin/rm -rf /tmp/kidtimer.shutdown.$K" >> /tmp/killall.bash.$K
echo "/bin/rm -f /tmp/killall.bash.$K" >> /tmp/killall.bash.$K
echo "/bin/bash /tmp/killall.bash.$K" | /usr/bin/at now + 6 minutes
}

go_echo_error () {
echo "`/bin/sed -n '12p' /usr/local/kidtimer/locale/$LANG`"
}

go_echo_done () {
echo "`/bin/sed -n '13p' /usr/local/kidtimer/locale/$LANG`"
}

go_reset_time () {
get_ttl_time $KID > $basedir/time/$KID.ttl
/usr/bin/passwd $KID -u
go_clean_jobs $KID
go_echo_done
}

go_addtime () {
U=$KID
A=$Time
grep -q $U $configdir/kid.list
if [ $? -eq 0 ]; then
    if [ "$A" == "reset" ]; then
        get_ttl_time $U > $basedir/time/$U.ttl
            go_echo_done
            exit 0
    elif [ "$A" == "" ]; then
            go_echo_error
        #english: Syntax: addtime <user> <minutes|reset>
            echo "`/bin/sed -n '22p' /usr/local/kidtimer/locale/$LANG`"
            exit 1
    else
            C=`/bin/cat $basedir/time/$KID.ttl`
            C=$((C + Time))
            echo $C > $basedir/time/$KID.ttl
        get_time
    fi
    /usr/bin/passwd $KID -u
    go_clean_jobs $KID
else
    go_echo_error
    #english: User not setup.
    echo "`/bin/sed -n '19p' /usr/local/kidtimer/locale/$LANG`"
    exit 1
fi
}

get_time () {
if [ -e $basedir/time/$KID.ttl ]; then
    cat $basedir/time/$KID.ttl
else
    echo
    #english: User not setup.
    echo "`/bin/sed -n '19p' /usr/local/kidtimer/locale/$LANG`"
    echo
fi
}

go_tui () {
go_command_list
echo -n "Choose: "; read X
case "$X" in
1) go_setup_user
        ;;
2) go_modify_user
        ;;
3) go_remove_user
        ;;
4) go_list_users
        ;;
5) exit 0
        ;;
esac
go_tui
}

go_command_list () {
echo
echo "1) "`/bin/sed -n '7p' /usr/local/kidtimer/locale/$LANG`
echo "2) "`/bin/sed -n '8p' /usr/local/kidtimer/locale/$LANG`
echo "3) "`/bin/sed -n '9p' /usr/local/kidtimer/locale/$LANG`
echo "4) "`/bin/sed -n '10p' /usr/local/kidtimer/locale/$LANG`
echo "5) "`/bin/sed -n '11p' /usr/local/kidtimer/locale/$LANG`
echo
}

go_list_users () {
echo
#english: Users configured for kidtimer:
echo "`/bin/sed -n '14p' /usr/local/kidtimer/locale/$LANG`"
if [ -s $configdir/kid.list ]; then
        /bin/cat $configdir/kid.list
else
    #english: No configured users.
        echo "`/bin/sed -n '15p' /usr/local/kidtimer/locale/$LANG`"
    echo
fi
}

go_setup_user () {
echo
#english: Username:
echo -n "`/bin/sed -n '16p' /usr/local/kidtimer/locale/$LANG` "; read U
/usr/bin/id $U > /dev/null 2>&1
if [ $? -eq 0 ]; then
        /bin/cp $basedir/schedule/blank $basedir/schedule/$U
    get_ttl_time $U > $basedir/time/$U.ttl
        echo $U >> $configdir/kid.list
        go_echo_done
        echo
    #english: Modify limits now ?(y/n):
        echo -n "`/bin/sed -n '17p' /usr/local/kidtimer/locale/$LANG`"; read M
        if [ "$M" == "y" ]; then
                if [ -e /usr/bin/nano ]; then
                    /usr/bin/nano $basedir/schedule/$U
            get_ttl_time $U > $basedir/time/$U.ttl
                    go_echo_done
            else
                    /usr/bin/vi $basedir/schedule/$U
            get_ttl_time $U > $basedir/time/$U.ttl
                    go_echo_done
                fi
        fi
else
    go_echo_error
    #english: User does not exist. Please create user using the useradd command first.
        echo "`/bin/sed -n '18p' /usr/local/kidtimer/locale/$LANG`"
fi
}

go_modify_user () {
echo
#english: Username:
echo -n "`/bin/sed -n '16p' /usr/local/kidtimer/locale/$LANG` "; read U
grep -q ^$U $configdir/kid.list
if [ $? -eq 0 ]; then
        if [ -e /usr/bin/nano ]; then
                /usr/bin/nano $basedir/schedule/$U
                go_echo_done
        else
                /usr/bin/vi $basedir/schedule/$U
                go_echo_done
        fi
else
    go_echo_error
    #english: User not setup.
        echo "`/bin/sed -n '19p' /usr/local/kidtimer/locale/$LANG`"
    echo
fi
}

go_remove_user () {
echo
#english: Username:
echo -n "`/bin/sed -n '16p' /usr/local/kidtimer/locale/$LANG` "; read U
grep -q ^$U $configdir/kid.list
if [ $? -eq 0 ]; then
        /bin/grep -v ^$U $configdir/kid.list > /tmp/kidtimer.tmp
        /bin/cat /tmp/kidtimer.tmp > $configdir/kid.list
        go_echo_done
else
    go_echo_error
    #english: User not setup.
        echo "`/bin/sed -n '19p' /usr/local/kidtimer/locale/$LANG`"
    echo
fi
}

go_help () {
echo
echo "Commands:"
echo "--------------------------------------------------------------------------------"
echo "addtime <user> <minutes> ... Increases allowed time for the day."
echo "gettime <user> ... Prints remaining time for the day."
echo "reset <user> ... Reset time for the day."
echo "logout <user> ... Starts logout sequence for user."
echo "hourly ... Enables/disables user access based on the schedule."
echo "daily ... Resets time for the new day."
echo "update ... Updates kidtimer to the latest version."
echo "info ... Gather local configurations to troubleshoot issues."
echo "help ... This list."
echo "--------------------------------------------------------------------------------"
}

check_dependencies () {
#at
P1="";P2="";P3="";pstatus="0"
/usr/bin/dpkg -s at >/dev/null 2>/dev/null
if [ ! $? -eq 0 ]; then
    P1="at"
    pstatus=1
fi
#libnotify-bin
/usr/bin/dpkg -s libnotify-bin >/dev/null 2>/dev/null
if [ ! $? -eq 0 ]; then
        P2="libnotify-bin"
        pstatus=1
fi
#bsdutils
/usr/bin/dpkg -s bsdutils >/dev/null 2>/dev/null
if [ ! $? -eq 0 ]; then
        P3="bsdutils"
        pstatus=1
fi
if [ "$pstatus" == "1" ]; then
    echo
    #english: Error. Missing package dependencies.
    echo "`/bin/sed -n '20p' /usr/local/kidtimer/locale/$LANG`"
    #english: Please install using the following line;
    echo "`/bin/sed -n '21p' /usr/local/kidtimer/locale/$LANG`"
    echo "sudo apt-get install "$P1" "$P2" "$P3
    exit 1
fi
}

get_update () {
URL='https://github.com/grover66/kidtimer/raw/master/DEBS/kidtimer_latest.deb'
if [ -e /usr/bin/wget ]; then
    /usr/bin/wget "$URL" -qO /tmp/kidtimer_latest.deb
    /usr/bin/dpkg -i /tmp/kidtimer_latest.deb
    /bin/rm -f /tmp/kidtimer_latest.deb
else
    echo
    echo "Error. Requires wget"
    echo "To install wget; sudo apt-get install wget"
fi
}

###################### Code ####################
################################################

if [ $TUI -eq 1 ]; then
    check_dependencies
    go_tui
fi

case "$COMMAND" in
addtime) go_addtime
        ;;
reset) go_reset_time
        ;;
gettime) get_time
        ;;
logout) go_logout $KID
        ;;
hourly) go_hourly
        ;;
daily) go_daily
        ;;
update) get_update
        ;;
check) go_check
        ;;
info) get_info
        ;;
-h) go_help
        ;;
help) go_help
        ;;
esac
exit 0

Thanks, StoicTheVast

grover66 commented 9 years ago

Hey,

Thanks for the help... Switching users is a tough one... Because, to the system, they are still running all the things they were running before. I have tried to tackle this one for a while with no success. Will look over the rest of your changes and hopefully check it in soon... It has been a busy few months, since I started a new contract.

Mike :)

On Tue, Sep 23, 2014 at 11:32 AM, StoicTheVast notifications@github.com wrote:

Hi,

Thanks for the project. Unfortunately I had a number of issues getting it to work on my kids' computer (zorin-os 6, based on ubuntu 12.04 LTS).

Summary:

  • AT wasn't working out of the box - it was silently failing. I needed to create /var/spool/cron/atjobs/.SEQ owned by daemon:daemon for at to start working properly
  • Added the file /usr/lib/pm-utils/sleep.d/99zzkidtimer as suggested in another issue. Note this file must be executable! (chmod +x)
  • The use of /usr/bin/users to determine who is logged in is a kludge. It ignores locked screens (screensaver active) and switched user states. I don't have a fix for that right now - instead I just told the kids to log off when they are done rather than let the screensaver kick in, and log off rather than switch users between them. Not ideal. Any ideas about how to elegantly detect these subtle differences in current computer usage state????

In /usr/local/bin/kidtimer, I had to make the following changes:

  • Tweaked the timer countdown to not go negative, even if other things fail...
  • The script files created to do the warnings/logouts in /tmp weren't executable. They need to be chmod +x
  • /usr/local/bin/kidtimer shutdown is not a supported option - instead I have changed it to use go_logout if /tmp/kidtimer.shutdown.$I doesn't exist, as is done elsewhere in the code.
  • The user notification wasn't working because the x display detection using who doesn't work unless the user has an active shell running (my kids don't do that!). So instead I simply iterate through the first 10 displays and send the notification with the desired user to all of them - it fails gracefully on the screens that don't exist or have the wrong username, passes on the ones it needs to.
  • I couldn't decide if, when killing a user's processes they should be sent a TERM first before the KILL. Firefox will nicely reload its tabs if KILL'ed, but maybe other progs like Open Office would prefer to be TERM'ed first so they can clean up properly and only be KILL'ed if they fail to exit themselves.

Here is my patch to /usr/local/bin/kidtimer ...

--- kidtimer.orig 2014-09-23 23:53:41.970147275 +0930 +++ kidtimer.fixed 2014-09-24 00:08:35.104446943 +0930 @@ -65,11 +65,16 @@

go_check () { for I in /bin/cat $configdir/kid.list | sort -u; do

  • This method ( /usr/bin/users ) to determine who is logged in is a kludge. It ignores locked screens (screensaver active) and switched user states.

    /usr/bin/users | /bin/grep -q $I if [ $? -eq 0 ]; then if [ -e $basedir/time/$I.ttl ]; then C=/bin/cat $basedir/time/$I.ttl

  • C=$((C - 1))
  • if [ $C -le 0 ]; then
  • C=0
  • else
  • C=$((C - 1))
  • fi echo $C > $basedir/time/$I.ttl else get_ttl_time $I > $basedir/time/$I.ttl @@ -77,8 +82,8 @@ fi

    check time

          if [ $C -le 5 ]; then
  • /usr/bin/passwd $I -l if [ ! -e /tmp/kidtimer.shutdown.$I ]; then
  • /usr/bin/passwd $I -l go_logout $I fi fi @@ -128,7 +133,13 @@ /usr/bin/passwd $I -u else /usr/bin/passwd $I -l
  • /usr/bin/users | /bin/grep -q $I && /usr/local/bin/kidtimer shutdown $I
  • This method ( /usr/bin/users ) to determine who is logged in is a kludge. It ignores locked screens (screensaver active) and switched user states.

  • /usr/bin/users | /bin/grep -q $I
  • if [ $? -eq 0 ]; then
  • if [ ! -e /tmp/kidtimer.shutdown.$I ]; then
  • go_logout $I
  • fi
  • fi fi fi done @@ -155,24 +166,45 @@ TEXT=$((6-$T)) TMPFILE="/tmp/kidtimer.send$T.bash.$K" /bin/rm -f $TMPFILE +touch $TMPFILE +chmod +x $TMPFILE + echo "#!/bin/bash" > $TMPFILE -D=/usr/bin/who | grep $K | grep -m1 "(:" | cut -d\( -f2 | sed s/\)// | sed s/:// + +# This method to determine the correct display doesn't work, at least on zorin. +# It only seems to detect a user who has an active shell running +#D=/usr/bin/who | grep $K | grep -m1 "(:" | cut -d\( -f2 | sed s/\)// | sed s/:// + +# So instead I'll just send the message to all the first 10 displays, and the ones owned by the correct user will show the message, the rest won't if [ -e $basedir/locale/$LANG ]; then
  • MSG=/bin/sed -n "$LINE"p /usr/local/kidtimer/locale/$LANG
  • MSG="$K: /bin/sed -n "$LINE"p /usr/local/kidtimer/locale/$LANG" else
  • MSG="Your computer time will end in $TEXT minutes."
  • MSG="$K's computer time will end in $TEXT minutes." fi -echo "/bin/su $K -c 'DISPLAY=:$D /usr/bin/notify-send -i /usr/local/kidtimer/icons/kidtimer-$TEXT.png \ + +for (( D = 0 ; D < 10 ; D = D + 1 )); do
  •  echo "/bin/su $K -c 'DISPLAY=:$D /usr/bin/notify-send -i /usr/local/kidtimer/icons/kidtimer-$TEXT.png \
    \"ALERT\" \"$MSG\"'" >> $TMPFILE

    +done + echo "/bin/rm -f $TMPFILE" >> $TMPFILE echo "/bin/bash $TMPFILE" | /usr/bin/at now + $T minutes +# Note you need the file /var/spool/cron/atjobs/.SEQ owned by daemon:daemon for at to work properly!!! }

    go_killall () { K=$1 /bin/rm -f /tmp/killall.bash.$K +touch /tmp/killall.bash.$K +chmod +x /tmp/killall.bash.$K + echo "#!/bin/bash" > /tmp/killall.bash.$K +# Not sure if it is better or worse to do a normal kill first... +# Programs like Firefox will reopen all their previous tabs if it is killed with -KILL +# But other programs would probably do better if given a chance to save state/data and clean up after themselves eg open office??? +#echo "/usr/bin/pkill -TERM -u $K" >> /tmp/killall.bash.$K +#echo "/bin/sleep 5" >> /tmp/killall.bash.$K echo "/usr/bin/pkill -KILL -u $K" >> /tmp/killall.bash.$K echo "/bin/rm -rf /tmp/kidtimer.shutdown.$K" >> /tmp/killall.bash.$K echo "/bin/rm -f /tmp/killall.bash.$K" >> /tmp/killall.bash.$K @@ -450,4 +482,3 @@ ;; esac

    exit 0

And here's the full text of the fixed version:

!/bin/bash

Restrict kids computer access to specific hours and total time.

By: Michael Groves - grover66_at_gmail_dot_com

variables

LANG="en_US.UTF-8" #unremark to change preferred language.

basedir="/usr/local/kidtimer" configdir="/etc/kidtimer" Cdate=/bin/date +%Y-%m-%d TUI=0 HOUR=/bin/date +%H DOW=/bin/date +%u WEEKEND="no" [ "$DOW" == "6" ] && WEEKEND="yes" [ "$DOW" == "7" ] && WEEKEND="yes" [ ! -e $configdir/kid.list ] && touch $configdir/kid.list [ ! -e $basedir/locale/$LANG ] && LANG="en_US.UTF-8"

arguments

[ $# -eq 0 ] && TUI=1 [ $# -eq 1 ] && COMMAND=$1 [ $# -eq 2 ] && COMMAND=$1 && KID=$2 [ $# -eq 3 ] && COMMAND=$1 && KID=$2 && Time=$3

################# Subroutines ################## ################################################

getinfo () { echo "kidtimer info" echo "---------------------------------------------" /bin/date echo "---" echo "find /usr/local/kidtimer/ -print | sort" /usr/bin/find /usr/local/kidtimer/ -print | /usr/bin/sort echo "---" echo "cat $configdir/kid.list" /bin/cat $configdir/kid.list echo "---" echo "passwd -S -a" /usr/bin/passwd -S -a echo "---" echo "cat /usr/local/kidtimer/schedule/" /bin/cat /usr/local/kidtimer/schedule/ echo "---" echo "cat /usr/local/kidtimer/time/" /bin/cat /usr/local/kidtimer/time/_ echo "---" echo "cat /etc/cron.d/kidtimer" /bin/cat /etc/cron.d/kidtimer echo "---" echo "apt-cache showpkg kidtimer" /usr/bin/apt-cache showpkg kidtimer echo "---" echo "cat /etc/lsb-release" /bin/cat /etc/lsb-release echo "---" echo "uname -a" /bin/uname -a echo "---" echo "env" /usr/bin/env echo }

go_check () { for I in /bin/cat $configdir/kid.list | sort -u; do

This method ( /usr/bin/users ) to determine who is logged in is a kludge. It ignores locked screens (screensaver active) and switched user states.

    /usr/bin/users | /bin/grep -q $I
    if [ $? -eq 0 ]; then
            if [ -e $basedir/time/$I.ttl ]; then
                    C=`/bin/cat $basedir/time/$I.ttl`
                    if [ $C -le 0 ]; then
                            C=0
                    else
                            C=$((C - 1))
        fi
                    echo $C > $basedir/time/$I.ttl
            else
        get_ttl_time $I > $basedir/time/$I.ttl
                    C=`/bin/cat $basedir/time/$I.ttl`
            fi
    # check time
    if [ $C -le 5 ]; then
                /usr/bin/passwd $I -l
                if [ ! -e /tmp/kidtimer.shutdown.$I ]; then
                        go_logout $I
                fi
        fi
    else
            go_clean_jobs $I
    fi

done }

get_ttl_time () { [ "$WEEKEND" == "no" ] && /bin/cat $basedir/schedule/$1 | /bin/grep ^MAX | /usr/bin/awk '{ print $2 }' [ "$WEEKEND" == "yes" ] && /bin/cat $basedir/schedule/$1 | /bin/grep ^MAX | /usr/bin/awk '{ print $3 }' }

go_clean_jobs () { K=$1 for I in /usr/bin/atq | /usr/bin/awk '{ print $1 }' | /usr/bin/sort; do /usr/bin/at -c $I | /bin/grep -q "bash.$K" [ $? -eq 0 ] && /usr/bin/at -d $I done [ -e /tmp/kidtimer.shutdown.$K ] && /bin/rm -rf /tmp/kidtimer.shutdown.$K }

go_daily () { for I in /bin/cat $configdir/kid.list | sort -u; do /usr/bin/stat -c %y $basedir/time/$I.ttl | /bin/grep -q $Cdate if [ ! $? -eq 0 ]; then get_ttl_time $I > $basedir/time/$I.ttl fi done go_hourly }

go_hourly () { if [ -s $configdir/kid.list ]; then for I in /bin/cat $configdir/kid.list | sort -u; do if [ -e $basedir/schedule/$I ]; then [ -e $basedir/time/$I.ttl ] && C=/bin/cat $basedir/time/$I.ttl [ $C -le 0 ] && /usr/bin/passwd $I -l && exit 0 [ "$WEEKEND" == "no" ] && R=/bin/grep ^$HOUR $basedir/schedule/$I | /usr/bin/awk '{ print $2 }' [ "$WEEKEND" == "yes" ] && R=/bin/grep ^$HOUR $basedir/schedule/$I | /usr/bin/awk '{ print $3 }' if [ "$R" == "y" ]; then /usr/bin/passwd $I -u else /usr/bin/passwd $I -l

This method ( /usr/bin/users ) to determine who is logged in is a kludge. It ignores locked screens (screensaver active) and switched user states.

                            /usr/bin/users | /bin/grep -q $I
                            if [ $? -eq 0 ]; then
                        if [ ! -e /tmp/kidtimer.shutdown.$I ]; then
                                go_logout $I
                fi
                    fi
                    fi
            fi
    done

fi }

go_logout () { K=$1 go_send $K 5 go_send $K 4 go_send $K 3 go_send $K 2 go_send $K 1 go_killall $K /usr/bin/touch /tmp/kidtimer.shutdown.$K }

go_send () { K=$1 T=$2 LINE=$((7-$T)) TEXT=$((6-$T)) TMPFILE="/tmp/kidtimer.send$T.bash.$K" /bin/rm -f $TMPFILE touch $TMPFILE chmod +x $TMPFILE

echo "#!/bin/bash" > $TMPFILE

This method to determine the correct display doesn't work, at least on zorin.

It only seems to detect a user who has an active shell running

D=/usr/bin/who | grep $K | grep -m1 "(:" | cut -d\( -f2 | sed s/\)// | sed s/://

So instead I'll just send the message to all the first 10 displays, and the ones owned by the correct user will show the message, the rest won't

if [ -e $basedir/locale/$LANG ]; then MSG="$K: /bin/sed -n "$LINE"p /usr/local/kidtimer/locale/$LANG" else MSG="$K's computer time will end in $TEXT minutes." fi

for (( D = 0 ; D < 10 ; D = D + 1 )); do echo "/bin/su $K -c 'DISPLAY=:$D /usr/bin/notify-send -i /usr/local/kidtimer/icons/kidtimer-$TEXT.png \ \"ALERT\" \"$MSG\"'" >> $TMPFILE done

echo "/bin/rm -f $TMPFILE" >> $TMPFILE echo "/bin/bash $TMPFILE" | /usr/bin/at now + $T minutes

Note you need the file /var/spool/cron/atjobs/.SEQ owned by daemon:daemon for at to work properly!!!

}

go_killall () { K=$1 /bin/rm -f /tmp/killall.bash.$K touch /tmp/killall.bash.$K chmod +x /tmp/killall.bash.$K

echo "#!/bin/bash" > /tmp/killall.bash.$K

Not sure if it is better or worse to do a normal kill first...

Programs like Firefox will reopen all their previous tabs if it is killed with -KILL

But other programs would probably do better if given a chance to save state/data and clean up after themselves eg open office???

echo "/usr/bin/pkill -TERM -u $K" >> /tmp/killall.bash.$K

echo "/bin/sleep 5" >> /tmp/killall.bash.$K

echo "/usr/bin/pkill -KILL -u $K" >> /tmp/killall.bash.$K echo "/bin/rm -rf /tmp/kidtimer.shutdown.$K" >> /tmp/killall.bash.$K echo "/bin/rm -f /tmp/killall.bash.$K" >> /tmp/killall.bash.$K echo "/bin/bash /tmp/killall.bash.$K" | /usr/bin/at now + 6 minutes }

go_echo_error () { echo "/bin/sed -n '12p' /usr/local/kidtimer/locale/$LANG" }

go_echo_done () { echo "/bin/sed -n '13p' /usr/local/kidtimer/locale/$LANG" }

go_reset_time () { get_ttl_time $KID > $basedir/time/$KID.ttl /usr/bin/passwd $KID -u go_clean_jobs $KID go_echo_done }

go_addtime () { U=$KID A=$Time grep -q $U $configdir/kid.list if [ $? -eq 0 ]; then if [ "$A" == "reset" ]; then get_ttl_time $U > $basedir/time/$U.ttl go_echo_done exit 0 elif [ "$A" == "" ]; then go_echo_error

english: Syntax: addtime <minutes|reset>

        echo "`/bin/sed -n '22p' /usr/local/kidtimer/locale/$LANG`"
        exit 1
else
        C=`/bin/cat $basedir/time/$KID.ttl`
        C=$((C + Time))
        echo $C > $basedir/time/$KID.ttl
    get_time
fi
/usr/bin/passwd $KID -u
go_clean_jobs $KID

else go_echo_error

english: User not setup.

echo "`/bin/sed -n '19p' /usr/local/kidtimer/locale/$LANG`"
exit 1

fi }

get_time () { if [ -e $basedir/time/$KID.ttl ]; then cat $basedir/time/$KID.ttl else echo

english: User not setup.

echo "`/bin/sed -n '19p' /usr/local/kidtimer/locale/$LANG`"
echo

fi }

go_tui () { go_command_list echo -n "Choose: "; read X case "$X" in 1) go_setup_user ;; 2) go_modify_user ;; 3) go_remove_user ;; 4) go_list_users ;; 5) exit 0 ;; esac go_tui }

go_command_list () { echo echo "1) "/bin/sed -n '7p' /usr/local/kidtimer/locale/$LANG echo "2) "/bin/sed -n '8p' /usr/local/kidtimer/locale/$LANG echo "3) "/bin/sed -n '9p' /usr/local/kidtimer/locale/$LANG echo "4) "/bin/sed -n '10p' /usr/local/kidtimer/locale/$LANG echo "5) "/bin/sed -n '11p' /usr/local/kidtimer/locale/$LANG echo }

go_list_users () { echo

english: Users configured for kidtimer:

echo "/bin/sed -n '14p' /usr/local/kidtimer/locale/$LANG" if [ -s $configdir/kid.list ]; then /bin/cat $configdir/kid.list else

english: No configured users.

    echo "`/bin/sed -n '15p' /usr/local/kidtimer/locale/$LANG`"
echo

fi }

go_setup_user () { echo

english: Username:

echo -n "/bin/sed -n '16p' /usr/local/kidtimer/locale/$LANG "; read U /usr/bin/id $U > /dev/null 2>&1 if [ $? -eq 0 ]; then /bin/cp $basedir/schedule/blank $basedir/schedule/$U get_ttl_time $U > $basedir/time/$U.ttl echo $U >> $configdir/kid.list go_echo_done echo

english: Modify limits now ?(y/n):

    echo -n "`/bin/sed -n '17p' /usr/local/kidtimer/locale/$LANG`"; read M
    if [ "$M" == "y" ]; then
            if [ -e /usr/bin/nano ]; then
                /usr/bin/nano $basedir/schedule/$U
        get_ttl_time $U > $basedir/time/$U.ttl
                go_echo_done
        else
                /usr/bin/vi $basedir/schedule/$U
        get_ttl_time $U > $basedir/time/$U.ttl
                go_echo_done
            fi
    fi

else go_echo_error

english: User does not exist. Please create user using the useradd command first.

    echo "`/bin/sed -n '18p' /usr/local/kidtimer/locale/$LANG`"

fi }

go_modify_user () { echo

english: Username:

echo -n "/bin/sed -n '16p' /usr/local/kidtimer/locale/$LANG "; read U grep -q ^$U $configdir/kid.list if [ $? -eq 0 ]; then if [ -e /usr/bin/nano ]; then /usr/bin/nano $basedir/schedule/$U go_echo_done else /usr/bin/vi $basedir/schedule/$U go_echo_done fi else go_echo_error

english: User not setup.

    echo "`/bin/sed -n '19p' /usr/local/kidtimer/locale/$LANG`"
echo

fi }

go_remove_user () { echo

english: Username:

echo -n "/bin/sed -n '16p' /usr/local/kidtimer/locale/$LANG "; read U grep -q ^$U $configdir/kid.list if [ $? -eq 0 ]; then /bin/grep -v ^$U $configdir/kid.list > /tmp/kidtimer.tmp /bin/cat /tmp/kidtimer.tmp > $configdir/kid.list go_echo_done else go_echo_error

english: User not setup.

    echo "`/bin/sed -n '19p' /usr/local/kidtimer/locale/$LANG`"
echo

fi }

go_help () { echo echo "Commands:" echo "--------------------------------------------------------------------------------" echo "addtime ... Increases allowed time for the day." echo "gettime ... Prints remaining time for the day." echo "reset ... Reset time for the day." echo "logout ... Starts logout sequence for user." echo "hourly ... Enables/disables user access based on the schedule." echo "daily ... Resets time for the new day." echo "update ... Updates kidtimer to the latest version." echo "info ... Gather local configurations to troubleshoot issues." echo "help ... This list." echo "--------------------------------------------------------------------------------" }

check_dependencies () {

at

P1="";P2="";P3="";pstatus="0" /usr/bin/dpkg -s at >/dev/null 2>/dev/null if [ ! $? -eq 0 ]; then P1="at" pstatus=1 fi

libnotify-bin

/usr/bin/dpkg -s libnotify-bin >/dev/null 2>/dev/null if [ ! $? -eq 0 ]; then P2="libnotify-bin" pstatus=1 fi

bsdutils

/usr/bin/dpkg -s bsdutils >/dev/null 2>/dev/null if [ ! $? -eq 0 ]; then P3="bsdutils" pstatus=1 fi if [ "$pstatus" == "1" ]; then echo

english: Error. Missing package dependencies.

echo "`/bin/sed -n '20p' /usr/local/kidtimer/locale/$LANG`"
#english: Please install using the following line;
echo "`/bin/sed -n '21p' /usr/local/kidtimer/locale/$LANG`"
echo "sudo apt-get install "$P1" "$P2" "$P3
exit 1

fi }

get_update () { URL='https://github.com/grover66/kidtimer/raw/master/DEBS/kidtimer_latest.deb' if [ -e /usr/bin/wget ]; then /usr/bin/wget "$URL" -qO /tmp/kidtimer_latest.deb /usr/bin/dpkg -i /tmp/kidtimer_latest.deb /bin/rm -f /tmp/kidtimer_latest.deb else echo echo "Error. Requires wget" echo "To install wget; sudo apt-get install wget" fi }

###################### Code #################### ################################################

if [ $TUI -eq 1 ]; then check_dependencies go_tui fi

case "$COMMAND" in addtime) go_addtime ;; reset) go_reset_time ;; gettime) get_time ;; logout) go_logout $KID ;; hourly) go_hourly ;; daily) go_daily ;; update) get_update ;; check) go_check ;; info) get_info ;; -h) go_help ;; help) go_help ;; esac exit 0

Thanks, StoicTheVast

— Reply to this email directly or view it on GitHub https://github.com/grover66/kidtimer/issues/20.

grover66 commented 9 years ago

I do have a couple of other features coming;

  1. One time pass codes... Allows parent to give their child a six digit code which will give them additional time... This is needed when parents are out to dinner and their twelve year old wants more time.
  2. TUI additions... Adding "add time" and "get time" options into the kidtimer TUI application...

Mike

On Tue, Sep 23, 2014 at 11:32 AM, StoicTheVast notifications@github.com wrote:

Hi,

Thanks for the project. Unfortunately I had a number of issues getting it to work on my kids' computer (zorin-os 6, based on ubuntu 12.04 LTS).

Summary:

  • AT wasn't working out of the box - it was silently failing. I needed to create /var/spool/cron/atjobs/.SEQ owned by daemon:daemon for at to start working properly
  • Added the file /usr/lib/pm-utils/sleep.d/99zzkidtimer as suggested in another issue. Note this file must be executable! (chmod +x)
  • The use of /usr/bin/users to determine who is logged in is a kludge. It ignores locked screens (screensaver active) and switched user states. I don't have a fix for that right now - instead I just told the kids to log off when they are done rather than let the screensaver kick in, and log off rather than switch users between them. Not ideal. Any ideas about how to elegantly detect these subtle differences in current computer usage state????

In /usr/local/bin/kidtimer, I had to make the following changes:

  • Tweaked the timer countdown to not go negative, even if other things fail...
  • The script files created to do the warnings/logouts in /tmp weren't executable. They need to be chmod +x
  • /usr/local/bin/kidtimer shutdown is not a supported option - instead I have changed it to use go_logout if /tmp/kidtimer.shutdown.$I doesn't exist, as is done elsewhere in the code.
  • The user notification wasn't working because the x display detection using who doesn't work unless the user has an active shell running (my kids don't do that!). So instead I simply iterate through the first 10 displays and send the notification with the desired user to all of them - it fails gracefully on the screens that don't exist or have the wrong username, passes on the ones it needs to.
  • I couldn't decide if, when killing a user's processes they should be sent a TERM first before the KILL. Firefox will nicely reload its tabs if KILL'ed, but maybe other progs like Open Office would prefer to be TERM'ed first so they can clean up properly and only be KILL'ed if they fail to exit themselves.

Here is my patch to /usr/local/bin/kidtimer ...

--- kidtimer.orig 2014-09-23 23:53:41.970147275 +0930 +++ kidtimer.fixed 2014-09-24 00:08:35.104446943 +0930 @@ -65,11 +65,16 @@

go_check () { for I in /bin/cat $configdir/kid.list | sort -u; do

  • This method ( /usr/bin/users ) to determine who is logged in is a kludge. It ignores locked screens (screensaver active) and switched user states.

    /usr/bin/users | /bin/grep -q $I if [ $? -eq 0 ]; then if [ -e $basedir/time/$I.ttl ]; then C=/bin/cat $basedir/time/$I.ttl

  • C=$((C - 1))
  • if [ $C -le 0 ]; then
  • C=0
  • else
  • C=$((C - 1))
  • fi echo $C > $basedir/time/$I.ttl else get_ttl_time $I > $basedir/time/$I.ttl @@ -77,8 +82,8 @@ fi

    check time

          if [ $C -le 5 ]; then
  • /usr/bin/passwd $I -l if [ ! -e /tmp/kidtimer.shutdown.$I ]; then
  • /usr/bin/passwd $I -l go_logout $I fi fi @@ -128,7 +133,13 @@ /usr/bin/passwd $I -u else /usr/bin/passwd $I -l
  • /usr/bin/users | /bin/grep -q $I && /usr/local/bin/kidtimer shutdown $I
  • This method ( /usr/bin/users ) to determine who is logged in is a kludge. It ignores locked screens (screensaver active) and switched user states.

  • /usr/bin/users | /bin/grep -q $I
  • if [ $? -eq 0 ]; then
  • if [ ! -e /tmp/kidtimer.shutdown.$I ]; then
  • go_logout $I
  • fi
  • fi fi fi done @@ -155,24 +166,45 @@ TEXT=$((6-$T)) TMPFILE="/tmp/kidtimer.send$T.bash.$K" /bin/rm -f $TMPFILE +touch $TMPFILE +chmod +x $TMPFILE + echo "#!/bin/bash" > $TMPFILE -D=/usr/bin/who | grep $K | grep -m1 "(:" | cut -d\( -f2 | sed s/\)// | sed s/:// + +# This method to determine the correct display doesn't work, at least on zorin. +# It only seems to detect a user who has an active shell running +#D=/usr/bin/who | grep $K | grep -m1 "(:" | cut -d\( -f2 | sed s/\)// | sed s/:// + +# So instead I'll just send the message to all the first 10 displays, and the ones owned by the correct user will show the message, the rest won't if [ -e $basedir/locale/$LANG ]; then
  • MSG=/bin/sed -n "$LINE"p /usr/local/kidtimer/locale/$LANG
  • MSG="$K: /bin/sed -n "$LINE"p /usr/local/kidtimer/locale/$LANG" else
  • MSG="Your computer time will end in $TEXT minutes."
  • MSG="$K's computer time will end in $TEXT minutes." fi -echo "/bin/su $K -c 'DISPLAY=:$D /usr/bin/notify-send -i /usr/local/kidtimer/icons/kidtimer-$TEXT.png \ + +for (( D = 0 ; D < 10 ; D = D + 1 )); do
  •  echo "/bin/su $K -c 'DISPLAY=:$D /usr/bin/notify-send -i /usr/local/kidtimer/icons/kidtimer-$TEXT.png \
    \"ALERT\" \"$MSG\"'" >> $TMPFILE

    +done + echo "/bin/rm -f $TMPFILE" >> $TMPFILE echo "/bin/bash $TMPFILE" | /usr/bin/at now + $T minutes +# Note you need the file /var/spool/cron/atjobs/.SEQ owned by daemon:daemon for at to work properly!!! }

    go_killall () { K=$1 /bin/rm -f /tmp/killall.bash.$K +touch /tmp/killall.bash.$K +chmod +x /tmp/killall.bash.$K + echo "#!/bin/bash" > /tmp/killall.bash.$K +# Not sure if it is better or worse to do a normal kill first... +# Programs like Firefox will reopen all their previous tabs if it is killed with -KILL +# But other programs would probably do better if given a chance to save state/data and clean up after themselves eg open office??? +#echo "/usr/bin/pkill -TERM -u $K" >> /tmp/killall.bash.$K +#echo "/bin/sleep 5" >> /tmp/killall.bash.$K echo "/usr/bin/pkill -KILL -u $K" >> /tmp/killall.bash.$K echo "/bin/rm -rf /tmp/kidtimer.shutdown.$K" >> /tmp/killall.bash.$K echo "/bin/rm -f /tmp/killall.bash.$K" >> /tmp/killall.bash.$K @@ -450,4 +482,3 @@ ;; esac

    exit 0

And here's the full text of the fixed version:

!/bin/bash

Restrict kids computer access to specific hours and total time.

By: Michael Groves - grover66_at_gmail_dot_com

variables

LANG="en_US.UTF-8" #unremark to change preferred language.

basedir="/usr/local/kidtimer" configdir="/etc/kidtimer" Cdate=/bin/date +%Y-%m-%d TUI=0 HOUR=/bin/date +%H DOW=/bin/date +%u WEEKEND="no" [ "$DOW" == "6" ] && WEEKEND="yes" [ "$DOW" == "7" ] && WEEKEND="yes" [ ! -e $configdir/kid.list ] && touch $configdir/kid.list [ ! -e $basedir/locale/$LANG ] && LANG="en_US.UTF-8"

arguments

[ $# -eq 0 ] && TUI=1 [ $# -eq 1 ] && COMMAND=$1 [ $# -eq 2 ] && COMMAND=$1 && KID=$2 [ $# -eq 3 ] && COMMAND=$1 && KID=$2 && Time=$3

################# Subroutines ################## ################################################

getinfo () { echo "kidtimer info" echo "---------------------------------------------" /bin/date echo "---" echo "find /usr/local/kidtimer/ -print | sort" /usr/bin/find /usr/local/kidtimer/ -print | /usr/bin/sort echo "---" echo "cat $configdir/kid.list" /bin/cat $configdir/kid.list echo "---" echo "passwd -S -a" /usr/bin/passwd -S -a echo "---" echo "cat /usr/local/kidtimer/schedule/" /bin/cat /usr/local/kidtimer/schedule/ echo "---" echo "cat /usr/local/kidtimer/time/" /bin/cat /usr/local/kidtimer/time/_ echo "---" echo "cat /etc/cron.d/kidtimer" /bin/cat /etc/cron.d/kidtimer echo "---" echo "apt-cache showpkg kidtimer" /usr/bin/apt-cache showpkg kidtimer echo "---" echo "cat /etc/lsb-release" /bin/cat /etc/lsb-release echo "---" echo "uname -a" /bin/uname -a echo "---" echo "env" /usr/bin/env echo }

go_check () { for I in /bin/cat $configdir/kid.list | sort -u; do

This method ( /usr/bin/users ) to determine who is logged in is a kludge. It ignores locked screens (screensaver active) and switched user states.

    /usr/bin/users | /bin/grep -q $I
    if [ $? -eq 0 ]; then
            if [ -e $basedir/time/$I.ttl ]; then
                    C=`/bin/cat $basedir/time/$I.ttl`
                    if [ $C -le 0 ]; then
                            C=0
                    else
                            C=$((C - 1))
        fi
                    echo $C > $basedir/time/$I.ttl
            else
        get_ttl_time $I > $basedir/time/$I.ttl
                    C=`/bin/cat $basedir/time/$I.ttl`
            fi
    # check time
    if [ $C -le 5 ]; then
                /usr/bin/passwd $I -l
                if [ ! -e /tmp/kidtimer.shutdown.$I ]; then
                        go_logout $I
                fi
        fi
    else
            go_clean_jobs $I
    fi

done }

get_ttl_time () { [ "$WEEKEND" == "no" ] && /bin/cat $basedir/schedule/$1 | /bin/grep ^MAX | /usr/bin/awk '{ print $2 }' [ "$WEEKEND" == "yes" ] && /bin/cat $basedir/schedule/$1 | /bin/grep ^MAX | /usr/bin/awk '{ print $3 }' }

go_clean_jobs () { K=$1 for I in /usr/bin/atq | /usr/bin/awk '{ print $1 }' | /usr/bin/sort; do /usr/bin/at -c $I | /bin/grep -q "bash.$K" [ $? -eq 0 ] && /usr/bin/at -d $I done [ -e /tmp/kidtimer.shutdown.$K ] && /bin/rm -rf /tmp/kidtimer.shutdown.$K }

go_daily () { for I in /bin/cat $configdir/kid.list | sort -u; do /usr/bin/stat -c %y $basedir/time/$I.ttl | /bin/grep -q $Cdate if [ ! $? -eq 0 ]; then get_ttl_time $I > $basedir/time/$I.ttl fi done go_hourly }

go_hourly () { if [ -s $configdir/kid.list ]; then for I in /bin/cat $configdir/kid.list | sort -u; do if [ -e $basedir/schedule/$I ]; then [ -e $basedir/time/$I.ttl ] && C=/bin/cat $basedir/time/$I.ttl [ $C -le 0 ] && /usr/bin/passwd $I -l && exit 0 [ "$WEEKEND" == "no" ] && R=/bin/grep ^$HOUR $basedir/schedule/$I | /usr/bin/awk '{ print $2 }' [ "$WEEKEND" == "yes" ] && R=/bin/grep ^$HOUR $basedir/schedule/$I | /usr/bin/awk '{ print $3 }' if [ "$R" == "y" ]; then /usr/bin/passwd $I -u else /usr/bin/passwd $I -l

This method ( /usr/bin/users ) to determine who is logged in is a kludge. It ignores locked screens (screensaver active) and switched user states.

                            /usr/bin/users | /bin/grep -q $I
                            if [ $? -eq 0 ]; then
                        if [ ! -e /tmp/kidtimer.shutdown.$I ]; then
                                go_logout $I
                fi
                    fi
                    fi
            fi
    done

fi }

go_logout () { K=$1 go_send $K 5 go_send $K 4 go_send $K 3 go_send $K 2 go_send $K 1 go_killall $K /usr/bin/touch /tmp/kidtimer.shutdown.$K }

go_send () { K=$1 T=$2 LINE=$((7-$T)) TEXT=$((6-$T)) TMPFILE="/tmp/kidtimer.send$T.bash.$K" /bin/rm -f $TMPFILE touch $TMPFILE chmod +x $TMPFILE

echo "#!/bin/bash" > $TMPFILE

This method to determine the correct display doesn't work, at least on zorin.

It only seems to detect a user who has an active shell running

D=/usr/bin/who | grep $K | grep -m1 "(:" | cut -d\( -f2 | sed s/\)// | sed s/://

So instead I'll just send the message to all the first 10 displays, and the ones owned by the correct user will show the message, the rest won't

if [ -e $basedir/locale/$LANG ]; then MSG="$K: /bin/sed -n "$LINE"p /usr/local/kidtimer/locale/$LANG" else MSG="$K's computer time will end in $TEXT minutes." fi

for (( D = 0 ; D < 10 ; D = D + 1 )); do echo "/bin/su $K -c 'DISPLAY=:$D /usr/bin/notify-send -i /usr/local/kidtimer/icons/kidtimer-$TEXT.png \ \"ALERT\" \"$MSG\"'" >> $TMPFILE done

echo "/bin/rm -f $TMPFILE" >> $TMPFILE echo "/bin/bash $TMPFILE" | /usr/bin/at now + $T minutes

Note you need the file /var/spool/cron/atjobs/.SEQ owned by daemon:daemon for at to work properly!!!

}

go_killall () { K=$1 /bin/rm -f /tmp/killall.bash.$K touch /tmp/killall.bash.$K chmod +x /tmp/killall.bash.$K

echo "#!/bin/bash" > /tmp/killall.bash.$K

Not sure if it is better or worse to do a normal kill first...

Programs like Firefox will reopen all their previous tabs if it is killed with -KILL

But other programs would probably do better if given a chance to save state/data and clean up after themselves eg open office???

echo "/usr/bin/pkill -TERM -u $K" >> /tmp/killall.bash.$K

echo "/bin/sleep 5" >> /tmp/killall.bash.$K

echo "/usr/bin/pkill -KILL -u $K" >> /tmp/killall.bash.$K echo "/bin/rm -rf /tmp/kidtimer.shutdown.$K" >> /tmp/killall.bash.$K echo "/bin/rm -f /tmp/killall.bash.$K" >> /tmp/killall.bash.$K echo "/bin/bash /tmp/killall.bash.$K" | /usr/bin/at now + 6 minutes }

go_echo_error () { echo "/bin/sed -n '12p' /usr/local/kidtimer/locale/$LANG" }

go_echo_done () { echo "/bin/sed -n '13p' /usr/local/kidtimer/locale/$LANG" }

go_reset_time () { get_ttl_time $KID > $basedir/time/$KID.ttl /usr/bin/passwd $KID -u go_clean_jobs $KID go_echo_done }

go_addtime () { U=$KID A=$Time grep -q $U $configdir/kid.list if [ $? -eq 0 ]; then if [ "$A" == "reset" ]; then get_ttl_time $U > $basedir/time/$U.ttl go_echo_done exit 0 elif [ "$A" == "" ]; then go_echo_error

english: Syntax: addtime <minutes|reset>

        echo "`/bin/sed -n '22p' /usr/local/kidtimer/locale/$LANG`"
        exit 1
else
        C=`/bin/cat $basedir/time/$KID.ttl`
        C=$((C + Time))
        echo $C > $basedir/time/$KID.ttl
    get_time
fi
/usr/bin/passwd $KID -u
go_clean_jobs $KID

else go_echo_error

english: User not setup.

echo "`/bin/sed -n '19p' /usr/local/kidtimer/locale/$LANG`"
exit 1

fi }

get_time () { if [ -e $basedir/time/$KID.ttl ]; then cat $basedir/time/$KID.ttl else echo

english: User not setup.

echo "`/bin/sed -n '19p' /usr/local/kidtimer/locale/$LANG`"
echo

fi }

go_tui () { go_command_list echo -n "Choose: "; read X case "$X" in 1) go_setup_user ;; 2) go_modify_user ;; 3) go_remove_user ;; 4) go_list_users ;; 5) exit 0 ;; esac go_tui }

go_command_list () { echo echo "1) "/bin/sed -n '7p' /usr/local/kidtimer/locale/$LANG echo "2) "/bin/sed -n '8p' /usr/local/kidtimer/locale/$LANG echo "3) "/bin/sed -n '9p' /usr/local/kidtimer/locale/$LANG echo "4) "/bin/sed -n '10p' /usr/local/kidtimer/locale/$LANG echo "5) "/bin/sed -n '11p' /usr/local/kidtimer/locale/$LANG echo }

go_list_users () { echo

english: Users configured for kidtimer:

echo "/bin/sed -n '14p' /usr/local/kidtimer/locale/$LANG" if [ -s $configdir/kid.list ]; then /bin/cat $configdir/kid.list else

english: No configured users.

    echo "`/bin/sed -n '15p' /usr/local/kidtimer/locale/$LANG`"
echo

fi }

go_setup_user () { echo

english: Username:

echo -n "/bin/sed -n '16p' /usr/local/kidtimer/locale/$LANG "; read U /usr/bin/id $U > /dev/null 2>&1 if [ $? -eq 0 ]; then /bin/cp $basedir/schedule/blank $basedir/schedule/$U get_ttl_time $U > $basedir/time/$U.ttl echo $U >> $configdir/kid.list go_echo_done echo

english: Modify limits now ?(y/n):

    echo -n "`/bin/sed -n '17p' /usr/local/kidtimer/locale/$LANG`"; read M
    if [ "$M" == "y" ]; then
            if [ -e /usr/bin/nano ]; then
                /usr/bin/nano $basedir/schedule/$U
        get_ttl_time $U > $basedir/time/$U.ttl
                go_echo_done
        else
                /usr/bin/vi $basedir/schedule/$U
        get_ttl_time $U > $basedir/time/$U.ttl
                go_echo_done
            fi
    fi

else go_echo_error

english: User does not exist. Please create user using the useradd command first.

    echo "`/bin/sed -n '18p' /usr/local/kidtimer/locale/$LANG`"

fi }

go_modify_user () { echo

english: Username:

echo -n "/bin/sed -n '16p' /usr/local/kidtimer/locale/$LANG "; read U grep -q ^$U $configdir/kid.list if [ $? -eq 0 ]; then if [ -e /usr/bin/nano ]; then /usr/bin/nano $basedir/schedule/$U go_echo_done else /usr/bin/vi $basedir/schedule/$U go_echo_done fi else go_echo_error

english: User not setup.

    echo "`/bin/sed -n '19p' /usr/local/kidtimer/locale/$LANG`"
echo

fi }

go_remove_user () { echo

english: Username:

echo -n "/bin/sed -n '16p' /usr/local/kidtimer/locale/$LANG "; read U grep -q ^$U $configdir/kid.list if [ $? -eq 0 ]; then /bin/grep -v ^$U $configdir/kid.list > /tmp/kidtimer.tmp /bin/cat /tmp/kidtimer.tmp > $configdir/kid.list go_echo_done else go_echo_error

english: User not setup.

    echo "`/bin/sed -n '19p' /usr/local/kidtimer/locale/$LANG`"
echo

fi }

go_help () { echo echo "Commands:" echo "--------------------------------------------------------------------------------" echo "addtime ... Increases allowed time for the day." echo "gettime ... Prints remaining time for the day." echo "reset ... Reset time for the day." echo "logout ... Starts logout sequence for user." echo "hourly ... Enables/disables user access based on the schedule." echo "daily ... Resets time for the new day." echo "update ... Updates kidtimer to the latest version." echo "info ... Gather local configurations to troubleshoot issues." echo "help ... This list." echo "--------------------------------------------------------------------------------" }

check_dependencies () {

at

P1="";P2="";P3="";pstatus="0" /usr/bin/dpkg -s at >/dev/null 2>/dev/null if [ ! $? -eq 0 ]; then P1="at" pstatus=1 fi

libnotify-bin

/usr/bin/dpkg -s libnotify-bin >/dev/null 2>/dev/null if [ ! $? -eq 0 ]; then P2="libnotify-bin" pstatus=1 fi

bsdutils

/usr/bin/dpkg -s bsdutils >/dev/null 2>/dev/null if [ ! $? -eq 0 ]; then P3="bsdutils" pstatus=1 fi if [ "$pstatus" == "1" ]; then echo

english: Error. Missing package dependencies.

echo "`/bin/sed -n '20p' /usr/local/kidtimer/locale/$LANG`"
#english: Please install using the following line;
echo "`/bin/sed -n '21p' /usr/local/kidtimer/locale/$LANG`"
echo "sudo apt-get install "$P1" "$P2" "$P3
exit 1

fi }

get_update () { URL='https://github.com/grover66/kidtimer/raw/master/DEBS/kidtimer_latest.deb' if [ -e /usr/bin/wget ]; then /usr/bin/wget "$URL" -qO /tmp/kidtimer_latest.deb /usr/bin/dpkg -i /tmp/kidtimer_latest.deb /bin/rm -f /tmp/kidtimer_latest.deb else echo echo "Error. Requires wget" echo "To install wget; sudo apt-get install wget" fi }

###################### Code #################### ################################################

if [ $TUI -eq 1 ]; then check_dependencies go_tui fi

case "$COMMAND" in addtime) go_addtime ;; reset) go_reset_time ;; gettime) get_time ;; logout) go_logout $KID ;; hourly) go_hourly ;; daily) go_daily ;; update) get_update ;; check) go_check ;; info) get_info ;; -h) go_help ;; help) go_help ;; esac exit 0

Thanks, StoicTheVast

— Reply to this email directly or view it on GitHub https://github.com/grover66/kidtimer/issues/20.

StoicTheVast commented 9 years ago

Yes I agree it's tough to determine the actual active user info. If I find a solution I'll be sure to let you know! Regarding your new feature ideas:

  1. Sounds like a good idea - it might be a couple of years until I get to need that one I but I can definitely see its usefulness.

2a). Sounds OK, merely replicating what can be done in the command line already, but perhaps useful enough for the wife to drive...

2b) If that is being done, another option I would suggest is "subtract time". Currently I can do this (eg as part of a "grounding") simply by adding a negative time value. But providing that option explicitly eg implemented internally by adding (-1 * time), may make it easier for the less confident parent administrator.

grover66 commented 9 years ago

looks like the problem with AT is not kidtimer's, but a bug in Debian and Ubuntu starting in 10.10.

See: https://bugs.launchpad.net/ubuntu/+source/at/+bug/371536

Will work the other stuff soon,

Mike :)

On Tue, Sep 23, 2014 at 11:32 AM, StoicTheVast notifications@github.com wrote:

Hi,

Thanks for the project. Unfortunately I had a number of issues getting it to work on my kids' computer (zorin-os 6, based on ubuntu 12.04 LTS).

Summary:

  • AT wasn't working out of the box - it was silently failing. I needed to create /var/spool/cron/atjobs/.SEQ owned by daemon:daemon for at to start working properly
  • Added the file /usr/lib/pm-utils/sleep.d/99zzkidtimer as suggested in another issue. Note this file must be executable! (chmod +x)
  • The use of /usr/bin/users to determine who is logged in is a kludge. It ignores locked screens (screensaver active) and switched user states. I don't have a fix for that right now - instead I just told the kids to log off when they are done rather than let the screensaver kick in, and log off rather than switch users between them. Not ideal. Any ideas about how to elegantly detect these subtle differences in current computer usage state????

In /usr/local/bin/kidtimer, I had to make the following changes:

  • Tweaked the timer countdown to not go negative, even if other things fail...
  • The script files created to do the warnings/logouts in /tmp weren't executable. They need to be chmod +x
  • /usr/local/bin/kidtimer shutdown is not a supported option - instead I have changed it to use go_logout if /tmp/kidtimer.shutdown.$I doesn't exist, as is done elsewhere in the code.
  • The user notification wasn't working because the x display detection using who doesn't work unless the user has an active shell running (my kids don't do that!). So instead I simply iterate through the first 10 displays and send the notification with the desired user to all of them - it fails gracefully on the screens that don't exist or have the wrong username, passes on the ones it needs to.
  • I couldn't decide if, when killing a user's processes they should be sent a TERM first before the KILL. Firefox will nicely reload its tabs if KILL'ed, but maybe other progs like Open Office would prefer to be TERM'ed first so they can clean up properly and only be KILL'ed if they fail to exit themselves.

Here is my patch to /usr/local/bin/kidtimer ...

--- kidtimer.orig 2014-09-23 23:53:41.970147275 +0930 +++ kidtimer.fixed 2014-09-24 00:08:35.104446943 +0930 @@ -65,11 +65,16 @@

go_check () { for I in /bin/cat $configdir/kid.list | sort -u; do

  • This method ( /usr/bin/users ) to determine who is logged in is a kludge. It ignores locked screens (screensaver active) and switched user states.

    /usr/bin/users | /bin/grep -q $I if [ $? -eq 0 ]; then if [ -e $basedir/time/$I.ttl ]; then C=/bin/cat $basedir/time/$I.ttl

  • C=$((C - 1))
  • if [ $C -le 0 ]; then
  • C=0
  • else
  • C=$((C - 1))
  • fi echo $C > $basedir/time/$I.ttl else get_ttl_time $I > $basedir/time/$I.ttl @@ -77,8 +82,8 @@ fi

    check time

          if [ $C -le 5 ]; then
  • /usr/bin/passwd $I -l if [ ! -e /tmp/kidtimer.shutdown.$I ]; then
  • /usr/bin/passwd $I -l go_logout $I fi fi @@ -128,7 +133,13 @@ /usr/bin/passwd $I -u else /usr/bin/passwd $I -l
  • /usr/bin/users | /bin/grep -q $I && /usr/local/bin/kidtimer shutdown $I
  • This method ( /usr/bin/users ) to determine who is logged in is a kludge. It ignores locked screens (screensaver active) and switched user states.

  • /usr/bin/users | /bin/grep -q $I
  • if [ $? -eq 0 ]; then
  • if [ ! -e /tmp/kidtimer.shutdown.$I ]; then
  • go_logout $I
  • fi
  • fi fi fi done @@ -155,24 +166,45 @@ TEXT=$((6-$T)) TMPFILE="/tmp/kidtimer.send$T.bash.$K" /bin/rm -f $TMPFILE +touch $TMPFILE +chmod +x $TMPFILE + echo "#!/bin/bash" > $TMPFILE -D=/usr/bin/who | grep $K | grep -m1 "(:" | cut -d\( -f2 | sed s/\)// | sed s/:// + +# This method to determine the correct display doesn't work, at least on zorin. +# It only seems to detect a user who has an active shell running +#D=/usr/bin/who | grep $K | grep -m1 "(:" | cut -d\( -f2 | sed s/\)// | sed s/:// + +# So instead I'll just send the message to all the first 10 displays, and the ones owned by the correct user will show the message, the rest won't if [ -e $basedir/locale/$LANG ]; then
  • MSG=/bin/sed -n "$LINE"p /usr/local/kidtimer/locale/$LANG
  • MSG="$K: /bin/sed -n "$LINE"p /usr/local/kidtimer/locale/$LANG" else
  • MSG="Your computer time will end in $TEXT minutes."
  • MSG="$K's computer time will end in $TEXT minutes." fi -echo "/bin/su $K -c 'DISPLAY=:$D /usr/bin/notify-send -i /usr/local/kidtimer/icons/kidtimer-$TEXT.png \ + +for (( D = 0 ; D < 10 ; D = D + 1 )); do
  •  echo "/bin/su $K -c 'DISPLAY=:$D /usr/bin/notify-send -i /usr/local/kidtimer/icons/kidtimer-$TEXT.png \
    \"ALERT\" \"$MSG\"'" >> $TMPFILE

    +done + echo "/bin/rm -f $TMPFILE" >> $TMPFILE echo "/bin/bash $TMPFILE" | /usr/bin/at now + $T minutes +# Note you need the file /var/spool/cron/atjobs/.SEQ owned by daemon:daemon for at to work properly!!! }

    go_killall () { K=$1 /bin/rm -f /tmp/killall.bash.$K +touch /tmp/killall.bash.$K +chmod +x /tmp/killall.bash.$K + echo "#!/bin/bash" > /tmp/killall.bash.$K +# Not sure if it is better or worse to do a normal kill first... +# Programs like Firefox will reopen all their previous tabs if it is killed with -KILL +# But other programs would probably do better if given a chance to save state/data and clean up after themselves eg open office??? +#echo "/usr/bin/pkill -TERM -u $K" >> /tmp/killall.bash.$K +#echo "/bin/sleep 5" >> /tmp/killall.bash.$K echo "/usr/bin/pkill -KILL -u $K" >> /tmp/killall.bash.$K echo "/bin/rm -rf /tmp/kidtimer.shutdown.$K" >> /tmp/killall.bash.$K echo "/bin/rm -f /tmp/killall.bash.$K" >> /tmp/killall.bash.$K @@ -450,4 +482,3 @@ ;; esac

    exit 0

And here's the full text of the fixed version:

!/bin/bash

Restrict kids computer access to specific hours and total time.

By: Michael Groves - grover66_at_gmail_dot_com

variables

LANG="en_US.UTF-8" #unremark to change preferred language.

basedir="/usr/local/kidtimer" configdir="/etc/kidtimer" Cdate=/bin/date +%Y-%m-%d TUI=0 HOUR=/bin/date +%H DOW=/bin/date +%u WEEKEND="no" [ "$DOW" == "6" ] && WEEKEND="yes" [ "$DOW" == "7" ] && WEEKEND="yes" [ ! -e $configdir/kid.list ] && touch $configdir/kid.list [ ! -e $basedir/locale/$LANG ] && LANG="en_US.UTF-8"

arguments

[ $# -eq 0 ] && TUI=1 [ $# -eq 1 ] && COMMAND=$1 [ $# -eq 2 ] && COMMAND=$1 && KID=$2 [ $# -eq 3 ] && COMMAND=$1 && KID=$2 && Time=$3

################# Subroutines ################## ################################################

getinfo () { echo "kidtimer info" echo "---------------------------------------------" /bin/date echo "---" echo "find /usr/local/kidtimer/ -print | sort" /usr/bin/find /usr/local/kidtimer/ -print | /usr/bin/sort echo "---" echo "cat $configdir/kid.list" /bin/cat $configdir/kid.list echo "---" echo "passwd -S -a" /usr/bin/passwd -S -a echo "---" echo "cat /usr/local/kidtimer/schedule/" /bin/cat /usr/local/kidtimer/schedule/ echo "---" echo "cat /usr/local/kidtimer/time/" /bin/cat /usr/local/kidtimer/time/_ echo "---" echo "cat /etc/cron.d/kidtimer" /bin/cat /etc/cron.d/kidtimer echo "---" echo "apt-cache showpkg kidtimer" /usr/bin/apt-cache showpkg kidtimer echo "---" echo "cat /etc/lsb-release" /bin/cat /etc/lsb-release echo "---" echo "uname -a" /bin/uname -a echo "---" echo "env" /usr/bin/env echo }

go_check () { for I in /bin/cat $configdir/kid.list | sort -u; do

This method ( /usr/bin/users ) to determine who is logged in is a kludge. It ignores locked screens (screensaver active) and switched user states.

    /usr/bin/users | /bin/grep -q $I
    if [ $? -eq 0 ]; then
            if [ -e $basedir/time/$I.ttl ]; then
                    C=`/bin/cat $basedir/time/$I.ttl`
                    if [ $C -le 0 ]; then
                            C=0
                    else
                            C=$((C - 1))
        fi
                    echo $C > $basedir/time/$I.ttl
            else
        get_ttl_time $I > $basedir/time/$I.ttl
                    C=`/bin/cat $basedir/time/$I.ttl`
            fi
    # check time
    if [ $C -le 5 ]; then
                /usr/bin/passwd $I -l
                if [ ! -e /tmp/kidtimer.shutdown.$I ]; then
                        go_logout $I
                fi
        fi
    else
            go_clean_jobs $I
    fi

done }

get_ttl_time () { [ "$WEEKEND" == "no" ] && /bin/cat $basedir/schedule/$1 | /bin/grep ^MAX | /usr/bin/awk '{ print $2 }' [ "$WEEKEND" == "yes" ] && /bin/cat $basedir/schedule/$1 | /bin/grep ^MAX | /usr/bin/awk '{ print $3 }' }

go_clean_jobs () { K=$1 for I in /usr/bin/atq | /usr/bin/awk '{ print $1 }' | /usr/bin/sort; do /usr/bin/at -c $I | /bin/grep -q "bash.$K" [ $? -eq 0 ] && /usr/bin/at -d $I done [ -e /tmp/kidtimer.shutdown.$K ] && /bin/rm -rf /tmp/kidtimer.shutdown.$K }

go_daily () { for I in /bin/cat $configdir/kid.list | sort -u; do /usr/bin/stat -c %y $basedir/time/$I.ttl | /bin/grep -q $Cdate if [ ! $? -eq 0 ]; then get_ttl_time $I > $basedir/time/$I.ttl fi done go_hourly }

go_hourly () { if [ -s $configdir/kid.list ]; then for I in /bin/cat $configdir/kid.list | sort -u; do if [ -e $basedir/schedule/$I ]; then [ -e $basedir/time/$I.ttl ] && C=/bin/cat $basedir/time/$I.ttl [ $C -le 0 ] && /usr/bin/passwd $I -l && exit 0 [ "$WEEKEND" == "no" ] && R=/bin/grep ^$HOUR $basedir/schedule/$I | /usr/bin/awk '{ print $2 }' [ "$WEEKEND" == "yes" ] && R=/bin/grep ^$HOUR $basedir/schedule/$I | /usr/bin/awk '{ print $3 }' if [ "$R" == "y" ]; then /usr/bin/passwd $I -u else /usr/bin/passwd $I -l

This method ( /usr/bin/users ) to determine who is logged in is a kludge. It ignores locked screens (screensaver active) and switched user states.

                            /usr/bin/users | /bin/grep -q $I
                            if [ $? -eq 0 ]; then
                        if [ ! -e /tmp/kidtimer.shutdown.$I ]; then
                                go_logout $I
                fi
                    fi
                    fi
            fi
    done

fi }

go_logout () { K=$1 go_send $K 5 go_send $K 4 go_send $K 3 go_send $K 2 go_send $K 1 go_killall $K /usr/bin/touch /tmp/kidtimer.shutdown.$K }

go_send () { K=$1 T=$2 LINE=$((7-$T)) TEXT=$((6-$T)) TMPFILE="/tmp/kidtimer.send$T.bash.$K" /bin/rm -f $TMPFILE touch $TMPFILE chmod +x $TMPFILE

echo "#!/bin/bash" > $TMPFILE

This method to determine the correct display doesn't work, at least on zorin.

It only seems to detect a user who has an active shell running

D=/usr/bin/who | grep $K | grep -m1 "(:" | cut -d\( -f2 | sed s/\)// | sed s/://

So instead I'll just send the message to all the first 10 displays, and the ones owned by the correct user will show the message, the rest won't

if [ -e $basedir/locale/$LANG ]; then MSG="$K: /bin/sed -n "$LINE"p /usr/local/kidtimer/locale/$LANG" else MSG="$K's computer time will end in $TEXT minutes." fi

for (( D = 0 ; D < 10 ; D = D + 1 )); do echo "/bin/su $K -c 'DISPLAY=:$D /usr/bin/notify-send -i /usr/local/kidtimer/icons/kidtimer-$TEXT.png \ \"ALERT\" \"$MSG\"'" >> $TMPFILE done

echo "/bin/rm -f $TMPFILE" >> $TMPFILE echo "/bin/bash $TMPFILE" | /usr/bin/at now + $T minutes

Note you need the file /var/spool/cron/atjobs/.SEQ owned by daemon:daemon for at to work properly!!!

}

go_killall () { K=$1 /bin/rm -f /tmp/killall.bash.$K touch /tmp/killall.bash.$K chmod +x /tmp/killall.bash.$K

echo "#!/bin/bash" > /tmp/killall.bash.$K

Not sure if it is better or worse to do a normal kill first...

Programs like Firefox will reopen all their previous tabs if it is killed with -KILL

But other programs would probably do better if given a chance to save state/data and clean up after themselves eg open office???

echo "/usr/bin/pkill -TERM -u $K" >> /tmp/killall.bash.$K

echo "/bin/sleep 5" >> /tmp/killall.bash.$K

echo "/usr/bin/pkill -KILL -u $K" >> /tmp/killall.bash.$K echo "/bin/rm -rf /tmp/kidtimer.shutdown.$K" >> /tmp/killall.bash.$K echo "/bin/rm -f /tmp/killall.bash.$K" >> /tmp/killall.bash.$K echo "/bin/bash /tmp/killall.bash.$K" | /usr/bin/at now + 6 minutes }

go_echo_error () { echo "/bin/sed -n '12p' /usr/local/kidtimer/locale/$LANG" }

go_echo_done () { echo "/bin/sed -n '13p' /usr/local/kidtimer/locale/$LANG" }

go_reset_time () { get_ttl_time $KID > $basedir/time/$KID.ttl /usr/bin/passwd $KID -u go_clean_jobs $KID go_echo_done }

go_addtime () { U=$KID A=$Time grep -q $U $configdir/kid.list if [ $? -eq 0 ]; then if [ "$A" == "reset" ]; then get_ttl_time $U > $basedir/time/$U.ttl go_echo_done exit 0 elif [ "$A" == "" ]; then go_echo_error

english: Syntax: addtime <minutes|reset>

        echo "`/bin/sed -n '22p' /usr/local/kidtimer/locale/$LANG`"
        exit 1
else
        C=`/bin/cat $basedir/time/$KID.ttl`
        C=$((C + Time))
        echo $C > $basedir/time/$KID.ttl
    get_time
fi
/usr/bin/passwd $KID -u
go_clean_jobs $KID

else go_echo_error

english: User not setup.

echo "`/bin/sed -n '19p' /usr/local/kidtimer/locale/$LANG`"
exit 1

fi }

get_time () { if [ -e $basedir/time/$KID.ttl ]; then cat $basedir/time/$KID.ttl else echo

english: User not setup.

echo "`/bin/sed -n '19p' /usr/local/kidtimer/locale/$LANG`"
echo

fi }

go_tui () { go_command_list echo -n "Choose: "; read X case "$X" in 1) go_setup_user ;; 2) go_modify_user ;; 3) go_remove_user ;; 4) go_list_users ;; 5) exit 0 ;; esac go_tui }

go_command_list () { echo echo "1) "/bin/sed -n '7p' /usr/local/kidtimer/locale/$LANG echo "2) "/bin/sed -n '8p' /usr/local/kidtimer/locale/$LANG echo "3) "/bin/sed -n '9p' /usr/local/kidtimer/locale/$LANG echo "4) "/bin/sed -n '10p' /usr/local/kidtimer/locale/$LANG echo "5) "/bin/sed -n '11p' /usr/local/kidtimer/locale/$LANG echo }

go_list_users () { echo

english: Users configured for kidtimer:

echo "/bin/sed -n '14p' /usr/local/kidtimer/locale/$LANG" if [ -s $configdir/kid.list ]; then /bin/cat $configdir/kid.list else

english: No configured users.

    echo "`/bin/sed -n '15p' /usr/local/kidtimer/locale/$LANG`"
echo

fi }

go_setup_user () { echo

english: Username:

echo -n "/bin/sed -n '16p' /usr/local/kidtimer/locale/$LANG "; read U /usr/bin/id $U > /dev/null 2>&1 if [ $? -eq 0 ]; then /bin/cp $basedir/schedule/blank $basedir/schedule/$U get_ttl_time $U > $basedir/time/$U.ttl echo $U >> $configdir/kid.list go_echo_done echo

english: Modify limits now ?(y/n):

    echo -n "`/bin/sed -n '17p' /usr/local/kidtimer/locale/$LANG`"; read M
    if [ "$M" == "y" ]; then
            if [ -e /usr/bin/nano ]; then
                /usr/bin/nano $basedir/schedule/$U
        get_ttl_time $U > $basedir/time/$U.ttl
                go_echo_done
        else
                /usr/bin/vi $basedir/schedule/$U
        get_ttl_time $U > $basedir/time/$U.ttl
                go_echo_done
            fi
    fi

else go_echo_error

english: User does not exist. Please create user using the useradd command first.

    echo "`/bin/sed -n '18p' /usr/local/kidtimer/locale/$LANG`"

fi }

go_modify_user () { echo

english: Username:

echo -n "/bin/sed -n '16p' /usr/local/kidtimer/locale/$LANG "; read U grep -q ^$U $configdir/kid.list if [ $? -eq 0 ]; then if [ -e /usr/bin/nano ]; then /usr/bin/nano $basedir/schedule/$U go_echo_done else /usr/bin/vi $basedir/schedule/$U go_echo_done fi else go_echo_error

english: User not setup.

    echo "`/bin/sed -n '19p' /usr/local/kidtimer/locale/$LANG`"
echo

fi }

go_remove_user () { echo

english: Username:

echo -n "/bin/sed -n '16p' /usr/local/kidtimer/locale/$LANG "; read U grep -q ^$U $configdir/kid.list if [ $? -eq 0 ]; then /bin/grep -v ^$U $configdir/kid.list > /tmp/kidtimer.tmp /bin/cat /tmp/kidtimer.tmp > $configdir/kid.list go_echo_done else go_echo_error

english: User not setup.

    echo "`/bin/sed -n '19p' /usr/local/kidtimer/locale/$LANG`"
echo

fi }

go_help () { echo echo "Commands:" echo "--------------------------------------------------------------------------------" echo "addtime ... Increases allowed time for the day." echo "gettime ... Prints remaining time for the day." echo "reset ... Reset time for the day." echo "logout ... Starts logout sequence for user." echo "hourly ... Enables/disables user access based on the schedule." echo "daily ... Resets time for the new day." echo "update ... Updates kidtimer to the latest version." echo "info ... Gather local configurations to troubleshoot issues." echo "help ... This list." echo "--------------------------------------------------------------------------------" }

check_dependencies () {

at

P1="";P2="";P3="";pstatus="0" /usr/bin/dpkg -s at >/dev/null 2>/dev/null if [ ! $? -eq 0 ]; then P1="at" pstatus=1 fi

libnotify-bin

/usr/bin/dpkg -s libnotify-bin >/dev/null 2>/dev/null if [ ! $? -eq 0 ]; then P2="libnotify-bin" pstatus=1 fi

bsdutils

/usr/bin/dpkg -s bsdutils >/dev/null 2>/dev/null if [ ! $? -eq 0 ]; then P3="bsdutils" pstatus=1 fi if [ "$pstatus" == "1" ]; then echo

english: Error. Missing package dependencies.

echo "`/bin/sed -n '20p' /usr/local/kidtimer/locale/$LANG`"
#english: Please install using the following line;
echo "`/bin/sed -n '21p' /usr/local/kidtimer/locale/$LANG`"
echo "sudo apt-get install "$P1" "$P2" "$P3
exit 1

fi }

get_update () { URL='https://github.com/grover66/kidtimer/raw/master/DEBS/kidtimer_latest.deb' if [ -e /usr/bin/wget ]; then /usr/bin/wget "$URL" -qO /tmp/kidtimer_latest.deb /usr/bin/dpkg -i /tmp/kidtimer_latest.deb /bin/rm -f /tmp/kidtimer_latest.deb else echo echo "Error. Requires wget" echo "To install wget; sudo apt-get install wget" fi }

###################### Code #################### ################################################

if [ $TUI -eq 1 ]; then check_dependencies go_tui fi

case "$COMMAND" in addtime) go_addtime ;; reset) go_reset_time ;; gettime) get_time ;; logout) go_logout $KID ;; hourly) go_hourly ;; daily) go_daily ;; update) get_update ;; check) go_check ;; info) get_info ;; -h) go_help ;; help) go_help ;; esac exit 0

Thanks, StoicTheVast

— Reply to this email directly or view it on GitHub https://github.com/grover66/kidtimer/issues/20.

StoicTheVast commented 9 years ago

Yes, sorry if I didn't make that clear - I was just trying to document for other people who would be trying to get it to work for them :).

To be clear, on my system I had to do:

But without that there is no indication - it will fail silently.

Hey maybe your dependency check routine could ascertain whether at is functioning or not????