1 #!/bin/bash
  2 
  3 #       -------------------------------------------------------------------
  4 #
  5 #       Shell program to display changes to "/var/log/messages",
  6 #       "/var/log/mail" and the "From:" and "Subject" lines of new mail to
  7 #       root and his normal user account via "root-tail" windowless on root
  8 #       window of your desktop in a terminal via "tail" colorized with
  9 #       "ccze".
 10 #
 11 #       Copyright 2002, Thorsten Bonow <toto@herrrossi>.
 12 #
 13 #       This program is free software; you can redistribute it and/or
 14 #       modify it under the terms of the GNU General Public License as
 15 #       published by the Free Software Foundation; either version 2 of the
 16 #       License, or (at your option) any later version. 
 17 #
 18 #       This program is distributed in the hope that it will be useful, but
 19 #       WITHOUT ANY WARRANTY; without even the implied warranty of
 20 #       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 21 #       General Public License for more details.
 22 #
 23 #       Description:
 24 #
 25 #
 26 #       NOTE: You must be the superuser to run this script.
 27 #
 28 #       Usage:
 29 #
 30 #               sm_watch [ -h | --help ] [-u user]
 31 #
 32 #       Options:
 33 #
 34 #               -h, --help      Display this help message and exit.
 35 #               -r              Display information on root desktop
 36 #               -t              Display information in a terminal
 37 #               -u  user        roots normal user account
 38 #
 39 #
 40 #       Revision History:
 41 #
 42 #       12/02/2002      File created by new_script ver. 2.1.0
 43 #       01/15/2003      Implemented alternativ output to terminal instead
 44 #                       of using root-tail
 45 #       09/09/2003      Adapted to Debian Linux
 46 #                       See ChangeLog for changes after CVS import
 47 #
 48 #       CVS: $Id: sm_watch,v 1.7 2007-01-21 11:10:53 toto Exp $
 49 #       -------------------------------------------------------------------
 50 
 51 
 52 #       -------------------------------------------------------------------
 53 #       Constants
 54 #       -------------------------------------------------------------------
 55 
 56         PROGNAME=$(basename $0)
 57         VERSION="0.9"
 58 
 59 #       -------------------------------------------------------------------
 60 #       Configuration: Adapt to your needs
 61 #       -------------------------------------------------------------------
 62 
 63         # full path required because script is used in root environment 
 64         # which does not necessarily has full path to applications
 65         ROOT_TAIL_BIN="/usr/bin/root-tail"
 66         TERMINAL_BIN="/usr/bin/rxvt"
 67         TAIL_BIN="/usr/bin/tail"
 68         CCZE_BIN="/usr/bin/ccze"
 69         NICE_CALL="/usr/bin/nice -n 19"
 70 
 71         DEFAULT_ROOT_USER="toto"          # default user for mailcheck
 72         MAIL_FILE_DIR="/var/mail"         # directory for mail files
 73         MESSAGES_FILE="/var/log/messages"
 74         MAIL_FILE="/var/log/exim4/mainlog"
 75 
 76         FONT_SIZE="-misc-fixed-medium-r-semicondensed--13-*-*-*-c-60-iso8859-1"
 77 
 78         MAIL_CHECK_TIMEOUT=10             # seconds to wait before 
 79                                           # rechecking email
 80         ROOT_TAIL_TIMEOUT=3              # seconds for root-tail to sleep
 81                                           # before updates
 82         TAIL_TIMEOUT=3                   # seconds for tail to sleep
 83                                           # before updates
 84 
 85         # Window manager dependent size and position of root-tail's area of
 86         # root window to draw on.
 87         # TWM
 88         TWM_SIZE="390x500"
 89         TWM_POSITION="-1-30"
 90         # Larswm
 91         LARSWM_SIZE="390x500"
 92         LARSWM_POSITION="-1-30"
 93         # Defaults:
 94         if [ -n "$VNCDESKTOP" ] ; then
 95             DEFAULT_SIZE="$TWM_SIZE"
 96             DEFAULT_POSITION="$TWM_POSITION"
 97         elif [ "800x600+0+0" == `xwininfo -root | grep "geometry" | awk '{print $2}'` ] ; then
 98             DEFAULT_SIZE="$TWM_SIZE"
 99             DEFAULT_POSITION="$TWM_POSITION"
100         else
101             DEFAULT_SIZE="$LARSWM_SIZE"
102             DEFAULT_POSITION="$LARSWM_POSITION"
103         fi
104 
105         # Window manager dependent colors 
106         # TWM
107         TWM_EMAILCOLOR="gray"
108         TWM_MESSAGESCOLOR="black"
109         TWM_MAILCOLOR="snow"
110         # Larswm
111         LARSWM_EMAILCOLOR="gray"
112         LARSWM_MESSAGESCOLOR="orange"
113         LARSWM_MAILCOLOR="snow"
114         # Defaults:
115         if [ -n "$VNCDESKTOP" ] ; then
116             DEFAULT_EMAILCOLOR="$TWM_EMAILCOLOR"
117             DEFAULT_MESSAGESCOLOR="$TWM_MESSAGESCOLOR"
118             DEFAULT_MAILCOLOR="$TWM_MAILCOLOR"
119         elif [ "800x600+0+0" == `xwininfo -root | grep "geometry" | awk '{print $2}'` ] ; then
120             DEFAULT_EMAILCOLOR="$TWM_EMAILCOLOR"
121             DEFAULT_MESSAGESCOLOR="$TWM_MESSAGESCOLOR"
122             DEFAULT_MAILCOLOR="$TWM_MAILCOLOR"
123         else
124             DEFAULT_EMAILCOLOR="$LARSWM_EMAILCOLOR"
125             DEFAULT_MESSAGESCOLOR="$LARSWM_MESSAGESCOLOR"
126             DEFAULT_MAILCOLOR="$LARSWM_MAILCOLOR"
127         fi
128 
129 
130         # Window manager dependent size and position of terminal
131         # TWM
132         TWM_TERMINAL_SIZE="54x23"
133         TWM_TERMINAL_POSITION="-0-0"
134         # Larswm (if terminal it automatically tiled, this values
135         #        are ignored)
136         LARSWM_TERMINAL_SIZE="54x23"
137         LARSWM_TERMINAL_POSITION="+890+661"
138         # Defaults:
139         if [ -n "$VNCDESKTOP" ] ; then
140             DEFAULT_TERMINAL_SIZE="$TWM_TERMINAL_SIZE"
141             DEFAULT_TERMINAL_POSITION="$TWM_TERMINAL_POSITION"
142         elif [ "800x600+0+0" == `xwininfo -root | grep "geometry" | awk '{print $2}'` ] ; then
143             DEFAULT_TERMINAL_SIZE="$TWM_TERMINAL_SIZE"
144             DEFAULT_TERMINAL_POSITION="$TWM_TERMINAL_POSITION"
145         else
146             DEFAULT_TERMINAL_SIZE="$LARSWM_TERMINAL_SIZE"
147             DEFAULT_TERMINAL_POSITION="$LARSWM_TERMINAL_POSITION"
148         fi
149 
150 
151 
152 #       NO CHANGES SHOULD BE REQUIRED FROM HERE!
153 
154 #       -------------------------------------------------------------------
155 #       Functions
156 #       -------------------------------------------------------------------
157 
158 
159 function clean_up
160 {
161 
162 #       -----------------------------------------------------------------------
163 #       Function to remove temporary files and other housekeeping
164 #               No arguments
165 #       -----------------------------------------------------------------------
166 
167         kill_root-tail
168         kill_terminal
169         rm -f ${TEMP_FILE1}
170 }
171 
172 
173 function error_exit
174 {
175 
176 #       -----------------------------------------------------------------------
177 #       Function for exit due to fatal program error
178 #               Accepts 1 argument:
179 #                       string containing descriptive error message
180 #       -----------------------------------------------------------------------
181 
182 
183         echo "${PROGNAME}: ${1:-"Unknown Error"}" >&2
184         clean_up
185         exit 1
186 }
187 
188 
189 function graceful_exit
190 {
191 
192 #       -----------------------------------------------------------------------
193 #       Function called for a graceful exit
194 #               No arguments
195 #       -----------------------------------------------------------------------
196 
197         clean_up
198         exit
199 }
200 
201 
202 function signal_exit
203 {
204 
205 #       -----------------------------------------------------------------------
206 #       Function to handle termination signals
207 #               Accepts 1 argument:
208 #                       signal_spec
209 #       -----------------------------------------------------------------------
210 
211         case $1 in
212                 INT)  echo "$PROGNAME: Program aborted by user" >&2
213                         clean_up
214                         exit
215                         ;;
216                 TERM) echo "$PROGNAME: Program terminated" >&2
217                         clean_up
218                         exit
219                         ;;
220                 *)    error_exit "$PROGNAME: Terminating on unknown signal"
221                         ;;
222         esac
223 }
224 
225 
226 function make_temp_files
227 {
228 
229 #       -----------------------------------------------------------------------
230 #       Function to create temporary files
231 #               No arguments
232 #       -----------------------------------------------------------------------
233 
234         # Use user's local tmp directory if it exists
235 
236         if [ -d ~/tmp ]; then
237                 TEMP_DIR=~/tmp
238         else
239                 TEMP_DIR=/tmp
240         fi
241 
242         # Temp file for this script, using paranoid method of creation to
243         # insure that file name is not predictable.  This is for security to
244         # avoid "tmp race" attacks.  If more files are needed, create using
245         # the same form.
246 
247         TEMP_FILE1=$(mktemp -q "${TEMP_DIR}/${PROGNAME}.$$.XXXXXX")
248         if [ "$TEMP_FILE1" == "" ]; then
249                 error_exit "cannot create temp file!"
250         fi
251 }
252 
253 
254 function usage
255 {
256 
257 #       -----------------------------------------------------------------------
258 #       Function to display usage message (does not exit)
259 #               No arguments
260 #       -----------------------------------------------------------------------
261 
262         echo "Usage: ${PROGNAME} [-h | --help] [-r] [-t] [-u user]"
263 }
264 
265 
266 function helptext
267 {
268 
269 #       -----------------------------------------------------------------------
270 #       Function to display help message for program
271 #               No arguments
272 #       -----------------------------------------------------------------------
273 
274         local tab=$(echo -en "\t\t")
275 
276         cat <<- -EOF-
277 
278         ${PROGNAME} ver. ${VERSION}
279         This is a program to display changes to "/var/log/messages", "/var/log/mail" and the "From:" and "Subject" lines of new mail to root and his normal user account via "root-tail" windowless on root window of your desktop or in a terminal via "tail" colorized with "ccze".
280 
281         $(usage)
282 
283         Options:
284 
285         -h, --help      Display this help message and exit.
286         -r              Display information on root desktop
287         -t              Display information in a terminal
288         -u  user        roots normal user account
289 
290         NOTE: You must be the superuser to run this script.
291         
292 -EOF-
293 }
294 
295 
296 function root_check
297 {
298         #####
299         #      Function to check if user is root
300         #      No arguments
301         #####
302 
303         if [ "$(id | sed 's/uid=\([0-9]*\).*/\1/')" != "0" ]; then
304                 error_exit "You must be the superuser to run this script."
305         fi
306 }
307 
308 
309 function grep_from_and_subject_from_mail
310 {
311 
312 #       -----------------------------------------------------------------------
313 #       Function to grep mail file for lines containing "From:" and "Subject:".
314 #       Prettyprinting the output.
315 #               Arguments:
316 #                       1       USERNAME (required)
317 #       -----------------------------------------------------------------------
318 
319         # Fatal error if required arguments are missing
320 
321         if [ "$1" == "" ]; then
322                 error_exit "USERNAME: missing argument 1"
323         fi
324 
325         grep "^\(From \|Subject:\)" "${MAIL_FILE_DIR}"/"${1}" | \
326             sed 's/From /From:    /' | sed '/^Subject/a --'  >> $TEMP_FILE1
327 
328         return
329 
330 }       # end of grep_from_and_subject_from_mail
331 
332 
333 function timestamp_mail_files
334 {
335 
336 #       -----------------------------------------------------------------------
337 #       Function to get the modificatin time of the mail files
338 #               No arguments
339 #       -----------------------------------------------------------------------
340 
341         if [[ ${CHECK_ROOT} == "true" ]]; then
342             TIMESTAMP_ROOT=`ls -l "${MAIL_FILE_DIR}"/root | awk '{print $8}'`
343         fi
344 
345         if [[ ${CHECK_USER} == "true" ]]; then
346             TIMESTAMP_USER=`ls -l "${MAIL_FILE_DIR}"/${ROOT_USER}| awk '{print $8}'`
347         fi
348 
349         return
350 
351 }       # end of timestamp_mail_files
352 
353 
354 function check_for_new_mails
355 {
356 
357 #       -----------------------------------------------------------------------
358 #       Function to compare modification time of mail files with times stored 
359 #       in "TIMESTAMP_USER/ROOT" variables; set variable "MAIL_UPDATE"
360 #       accordingly
361 #               No arguments
362 #       -----------------------------------------------------------------------
363 
364         if [[ ${CHECK_ROOT} == "true" ]]; then
365             TIMESTAMP_ROOT_NEW=`ls -l "${MAIL_FILE_DIR}"/root | awk '{print $8}'`
366         fi
367 
368         if [[ ${CHECK_USER} == "true" ]]; then
369             TIMESTAMP_USER_NEW=`ls -l "${MAIL_FILE_DIR}"/${ROOT_USER}| awk '{print $8}'`
370         fi
371 
372         if [[ $TIMESTAMP_ROOT_NEW != $TIMESTAMP_ROOT ]]; then
373             MAIL_UPDATE="true"
374             TIMESTAMP_ROOT="${TIMESTAMP_ROOT_NEW}"
375         fi
376 
377         if [[ $TIMESTAMP_USER_NEW != $TIMESTAMP_USER ]]; then
378             MAIL_UPDATE="true"
379             TIMESTAMP_USER="${TIMESTAMP_USER_NEW}"
380         fi
381 
382         return
383 
384 }       # end of check_for_new_mails
385 
386 
387 function start_root-tail
388 {
389 
390 #       -----------------------------------------------------------------------
391 #       Function to start root-tail with correct parameters
392 #               No arguments
393 #       -----------------------------------------------------------------------
394 
395         if [[ $CHECK_MAIL == "true" ]]; then
396             EMAIL_STRING=""${TEMP_FILE1}","${DEFAULT_EMAILCOLOR}",Mails"
397         else
398             EMAIL_STRING=""
399         fi
400 
401         $NICE_CALL $ROOT_TAIL_BIN -fn "${FONT_SIZE}" -i ${ROOT_TAIL_TIMEOUT} \
402             -g ${DEFAULT_SIZE}${DEFAULT_POSITION} \
403             ""${MESSAGES_FILE}","${DEFAULT_MESSAGESCOLOR}","$MESSAGES_FILE"" \
404             ""${MAIL_FILE}","${DEFAULT_MAILCOLOR}","$MAIL_FILE"" \
405             $EMAIL_STRING &
406         ROOT_TAIL_PID=$!
407 
408         return
409 
410 }       # end of start_root-tail
411 
412 
413 function kill_root-tail
414 {
415 
416 #       -----------------------------------------------------------------------
417 #       Function to kill the root-tail instance started by function
418 #       "start_root-tail"
419 #               No arguments
420 #       -----------------------------------------------------------------------
421 
422         if [[ ${ROOT_TAIL_PID} != "" ]]; then
423                 kill "${ROOT_TAIL_PID}"
424                 sleep 3
425                 kill -9 "${ROOT_TAIL_PID}"
426         fi
427 
428         return
429 
430 }       # end of kill_root-tail
431 
432 
433 function start_terminal
434 {
435 
436 #       -----------------------------------------------------------------------
437 #       Function to start terminal with correct parameters
438 #               No arguments
439 #       -----------------------------------------------------------------------
440 
441         if [[ $CHECK_MAIL == "true" ]]; then
442             EMAIL_STRING="${TEMP_FILE1}"
443         else
444             EMAIL_STRING=""
445         fi
446 
447         $TERMINAL_BIN +sb -title "${PROGNAME}" -fn "${FONT_SIZE}" \
448             -g "${DEFAULT_TERMINAL_SIZE}${DEFAULT_TERMINAL_POSITION}" \
449             -e bash -c "${NICE_CALL} ${TAIL_BIN} -F -s ${TAIL_TIMEOUT} \
450             ${MESSAGES_FILE} ${MAIL_FILE} ${EMAIL_STRING} | \
451             ${NICE_CALL} ${CCZE_BIN} --" &
452         TAIL_PID=$!
453 
454         return
455 
456 }       # end of start_terminal
457 
458 
459 function kill_terminal
460 {
461 
462 #       -----------------------------------------------------------------------
463 #       Function to kill the terminal instance started by function
464 #       "start_terminal"
465 #               No arguments
466 #       -----------------------------------------------------------------------
467 
468         if [[ ${TAIL_PID} != "" ]]; then
469                 kill "${TAIL_PID}"
470                 sleep 3
471                 kill -9 "${TAIL_PID}"
472         fi
473 
474         return
475 
476 }       # end of kill_terminal
477 
478 
479 #       -------------------------------------------------------------------
480 #       Program starts here
481 #       -------------------------------------------------------------------
482 
483 ##### Initialization And Setup #####
484 
485 # Set file creation mask so that all files are created with 600 permissions.
486 
487 umask 066
488 root_check
489 
490 # Trap TERM, HUP, and INT signals and properly exit
491 
492 trap "signal_exit TERM" TERM HUP
493 trap "signal_exit INT"  INT
494 
495 # Create temporary file(s)
496 
497 make_temp_files
498 
499 
500 ##### Command Line Processing #####
501 
502 if [ "$1" = "--help" ]; then
503         helptext
504         graceful_exit
505 fi
506 
507 while getopts ":hu:rt" opt; do
508         case $opt in
509                 r )     ROOT_OUTPUT="true" ;;
510                 t )     TERMINAL_OUTPUT="true" ;;
511                 u )   ROOT_USER="$OPTARG" ;;
512                 h )   helptext
513                         graceful_exit ;;
514                 * )   usage
515                         clean_up
516                         exit 1
517         esac
518 done
519 
520 
521 ##### Main Logic #####
522 
523 # Initialisation
524 ROOT_TAIL_PID=""  # pid of running root-tail
525 TAIL_PID=""       # pid of running tail
526 MAIL_UPDATE=""    # true if one of the mail files has changed
527 TIMESTAMP_ROOT="" # modification time of root's mail file
528 TIMESTAMP_USER="" # modification time of root users's mail file
529 MAIL_UPDATE=""    # true if new mail has arrived since last check
530 
531 if [[ $ROOT_USER == "" ]]; then
532     ROOT_USER=${DEFAULT_ROOT_USER}
533 fi
534 
535 # check for root's mail file
536 if [ -e "$MAIL_FILE_DIR/root" ]; then
537     CHECK_ROOT="true"
538     echo "Checking emails for root ..." >> ${TEMP_FILE1}
539     grep_from_and_subject_from_mail "root"
540 else
541     CHECK_ROOT=""
542 fi
543 
544 # check for root's normal user account mail file
545 if [ -e "$MAIL_FILE_DIR/$ROOT_USER" ]; then
546     CHECK_USER="true"
547     echo "Checking emails for $ROOT_USER ..." >> ${TEMP_FILE1}
548     grep_from_and_subject_from_mail "${ROOT_USER}"
549 else
550     CHECK_USER=""
551 fi
552 
553 # check if checking of mails is necessary
554 if [[ ${CHECK_ROOT} == "true" || ${CHECK_USER} == "true" ]]; then
555     CHECK_MAIL="true"
556     timestamp_mail_files
557 else
558     CHECK_MAIL=""
559 fi
560 
561 # finally start displaying output via root-tail or in a terminal
562 
563 if [[ ${TERMINAL_OUTPUT} == "true" ]]; then
564     start_terminal
565 fi
566 
567 # select at least one method of displaying data
568 if [[ ${ROOT_OUTPUT} == "true" || ${TERMINAL_OUTPUT} == "" ]]; then
569     start_root-tail
570 fi
571 
572 # loop to update emails if necessary
573 if [[ $CHECK_MAIL == "true" ]]; then
574     while [ 1 ]; do
575         sleep ${MAIL_CHECK_TIMEOUT}
576 
577         check_for_new_mails
578 
579         if [[ ${MAIL_UPDATE} == "true" ]]; then
580             echo "Checking emails ..." > ${TEMP_FILE1}
581             sleep ${ROOT_TAIL_TIMEOUT} # give root-tail time 
582                                        # to update
583             if [[ $CHECK_ROOT == "true" ]]; then
584                 grep_from_and_subject_from_mail root
585             fi
586 
587             if [[ $CHECK_USER == "true" ]]; then
588                 grep_from_and_subject_from_mail "$ROOT_USER"
589             fi
590             MAIL_UPDATE=""
591         fi
592     done
593 else
594     wait
595 fi
596 
597 graceful_exit
598