aboutsummaryrefslogtreecommitdiff
path: root/xalarm
blob: 63baf434530bfb1e926d7a8c5a6e70efa86e0193 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#!/bin/bash
#
# Simple alarm applicaton
# Example run: xalarm 1m mymessage
# See discussion at https://www.reddit.com/r/Gentoo/comments/1rryh1/kalarm_replacement/
#

# Parameters
FULLNAME="$0"
BASENAME="`basename $0`"
XALARMPID="$BASHPID"
XALARMPPID="$PPID"

# Set alarm
function xalarm_set {
  # Delay
  DELAY="${1:-10m}"

  # Message
  shift
  MESSAGE="${*:-Alarm!}"

  # Simple argument checking
  if ! echo $DELAY | grep -q '^[0-9]'; then
    xalarm_usage
  fi

  # Suppor for HH:MM format
  if echo $DELAY | grep -q '[0-9]:[0-9][0-9]'; then
    NOW="`date +%s`"
    LATER="`date -d $DELAY +%s`"
    DELAY="$(($LATER - $NOW))"

    if (($LATER < $NOW)); then
      echo "$BASENAME: deadline must be later than now"
      exit 1
    fi
  fi

  # AT(1) implementation
  # Example run: xalarm 1minute mymessage
  #echo "xmessage $MESSAGE" | at now +$DELAY

  # Sleep implementation
  #
  # We put sleep into background and tell bash to wait it
  # This way we can grab sleep PID and then be able to reset the timer if needed
  sleep $DELAY &
  SLEEP_PID="$!"
  wait

  if [ "$ALARM_RESET" == "1" ]; then
    ALARM_RESET=0
    echo "Resetting alarm..."
    xalarm_set $DELAY $MESSAGE
  else
    if which sm &> /dev/null; then
      #sm -f '#ffffff' -b '#1c1c1c' $MESSAGE
      (timer=0; while sleep 1; do let timer++; echo $MESSAGE - $timer; echo -e '\f'; done) | sm -f '#ffffff' -b '#1c1c1c' -
    else
      xmessage $MESSAGE
    fi
  fi
}

# List alarms
function xalarm_list {
  # Simpler process filtering, but might collide with alarm messages
  #ps -U $USER -o pid,state,lstart,command | grep xalarm | grep -v grep | grep -v list | grep -v cancel | grep -v pause | grep -v resume | grep -v reset | grep -v reset-loop | \
  #  sed -e "s|$FULLNAME||" -e "s|/bin/bash||" | grep -v -- "sed -e"

  # Better, butt more difficult way to filter processes
  THISPID="$BASHPID"
  PARENTPID="$PPID"
  ps -U $USER -o pid,state,lstart,command | grep xalarm | grep -v grep | \
    sed -e "s|$FULLNAME||" -e "s|/bin/bash||" | grep -v -- "sed -e" | grep -v "^ *$THISPID" | grep -v "^ *$PARENTPID" | grep -v "^ *$XALARMPID" | grep -v "^ *$XALARMPPID"
}

# Return xalarm PIDs
function xalarm_pids {
  if [ ! -z "$1" ]; then
    if xalarm_list | awk '{ print $1 }' | grep -q "^$1"; then
      echo $1
    fi
  else
    xalarm_list | awk '{ print $1 }'
  fi
}

# Send a signal to a process
function xalarm_signal {
  local pid="$1"
  local signal="$2"

  if [ -z "$signal" ]; then
    signal="-TERM"
  fi

  if ps $1 &> /dev/null; then
    kill $signal $pid
  fi
}

# Cancel alarms
function xalarm_cancel {
  for pid in `xalarm_pids $1`; do
    xalarm_signal $pid
  done
}

# Pause alarms
function xalarm_pause {
  for pid in `xalarm_pids $1`; do
    xalarm_signal $pid -STOP
  done
}

# Resume alarms
function xalarm_resume {
  for pid in `xalarm_pids $1`; do
    xalarm_signal $pid -CONT
  done
}

# Reset alarms
function xalarm_reset {
  for pid in `xalarm_pids $1`; do
    xalarm_signal $pid -USR1
  done
}

# Reset alarm loop counter
function xalarm_reset_loop {
  for pid in `xalarm_pids $1`; do
    xalarm_signal $pid -USR2
  done
}

# Usage
function xalarm_usage {
  echo "usage: $BASENAME [list|cancel|kill|resume|continue|help|usage|loop|reset|reset-loop] [timedef] [message]"
  echo ""
  echo "timedef: accepts both sleep(1) and date(1) formats"
  exit 1
}

# Respond to SIGUSR1
function xalarm_sigusr1 {
  if [ ! -z "$SLEEP_PID" ]; then
    ALARM_RESET="1"
    kill $SLEEP_PID 2> /dev/null
  fi
}

# Respond to SIGUSR2
function xalarm_sigusr2 {
  if [ ! -z "$COUNT" ]; then
    COUNT=0
  fi
}

# Register traps
trap xalarm_sigusr1 SIGUSR1
trap xalarm_sigusr2 SIGUSR2

# Dispatch
if [ -z "$1" ] || [ "$1" == "list" ]; then
  xalarm_list
elif [ "$1" == "cancel" ] || [ "$1" == "kill" ]; then
  xalarm_cancel $2
elif [ "$1" == "pause" ]; then
  xalarm_pause $2
elif [ "$1" == "resume" ] || [ "$1" == "continue" ]; then
  xalarm_resume $2
elif [ "$1" == "reset" ]; then
  xalarm_reset $2
elif [ "$1" == "reset-loop" ]; then
  xalarm_reset_loop $2
elif [ "$1" == "help" ] || [ "$1" == "usage" ]; then
  xalarm_usage
elif [ "$1" == "loop" ]; then
  COUNT="0"

  shift
  while true; do
    let COUNT++
    xalarm_set $* $COUNT
  done
else
  xalarm_set $*
fi