Open StoicTheVast opened 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
; doThis 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 -lThis 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." fifor (( 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 elseenglish: 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 echoenglish: 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_errorenglish: 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_errorenglish: 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.
I do have a couple of other features coming;
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
; doThis 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 -lThis 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." fifor (( 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 elseenglish: 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 echoenglish: 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_errorenglish: 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_errorenglish: 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.
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:
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.
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
; doThis 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 -lThis 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." fifor (( 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 elseenglish: 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 echoenglish: 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_errorenglish: 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_errorenglish: 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.
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????
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 ...
And here's the full text of the fixed version:
Thanks, StoicTheVast